mirror of
https://github.com/wowlikon/LiB.git
synced 2026-02-04 12:31:09 +00:00
358 lines
24 KiB
HTML
358 lines
24 KiB
HTML
{% extends "base.html" %} {% block title %}LiB - Авторизация{% endblock %}
|
||
{% block content %}
|
||
<div class="flex flex-1 items-center justify-center p-4">
|
||
<div class="w-full max-w-md">
|
||
<div class="bg-white rounded-lg shadow-md overflow-hidden">
|
||
<div id="auth-tabs" class="flex border-b border-gray-200">
|
||
<button type="button" id="login-tab"
|
||
class="flex-1 py-4 text-center font-medium transition duration-200 text-gray-700 bg-gray-50 border-b-2 border-gray-500">
|
||
Вход
|
||
</button>
|
||
<button type="button" id="register-tab"
|
||
class="flex-1 py-4 text-center font-medium transition duration-200 text-gray-400 hover:text-gray-600">
|
||
Регистрация
|
||
</button>
|
||
</div>
|
||
|
||
<form id="login-form" class="p-6">
|
||
<div id="credentials-section">
|
||
<div class="mb-4">
|
||
<label for="login-username" class="block text-sm font-medium text-gray-700 mb-2">
|
||
Имя пользователя
|
||
</label>
|
||
<input type="text" id="login-username" name="username"
|
||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-gray-500 focus:border-transparent outline-none transition duration-200"
|
||
placeholder="Введите имя пользователя" required />
|
||
</div>
|
||
<div class="mb-4">
|
||
<label for="login-password" class="block text-sm font-medium text-gray-700 mb-2">Пароль</label>
|
||
<div class="relative">
|
||
<input type="password" id="login-password" name="password"
|
||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-gray-500 focus:border-transparent outline-none transition duration-200"
|
||
placeholder="Введите пароль" required />
|
||
<button type="button"
|
||
class="toggle-password absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600">
|
||
<svg class="eye-open w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z">
|
||
</path>
|
||
</svg>
|
||
<svg class="eye-closed w-5 h-5 hidden" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||
d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21">
|
||
</path>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="flex items-center justify-between mb-6">
|
||
<label class="custom-checkbox flex items-center text-sm text-gray-600">
|
||
<input type="checkbox" id="remember-me" />
|
||
<span class="checkmark"></span>Запомнить меня
|
||
</label>
|
||
<button type="button" id="forgot-password-btn"
|
||
class="text-sm text-gray-500 hover:text-gray-700 transition">
|
||
Забыли пароль?
|
||
</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="totp-section" class="hidden">
|
||
<div class="text-center mb-4">
|
||
<div class="w-20 h-20 mx-auto relative flex items-center justify-center mb-3">
|
||
<svg class="absolute inset-0 w-full h-full -rotate-90" viewBox="0 0 80 80">
|
||
<circle cx="40" cy="40" r="38" fill="none" stroke="#e5e7eb" stroke-width="2" />
|
||
<circle id="lock-progress-circle" cx="40" cy="40" r="38" fill="none" stroke="#000000"
|
||
stroke-width="2" stroke-linecap="round"
|
||
style="stroke-dasharray: 238.761; stroke-dashoffset: 238.761;" />
|
||
</svg>
|
||
<div class="w-16 h-16 bg-gray-100 rounded-full flex items-center justify-center z-10">
|
||
<svg class="w-8 h-8 text-gray-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||
d="M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z">
|
||
</path>
|
||
</svg>
|
||
</div>
|
||
</div>
|
||
<h3 class="text-lg font-semibold text-gray-800">Двухфакторная аутентификация</h3>
|
||
<p class="text-sm text-gray-500 mt-1">
|
||
Введите код из приложения аутентификатора
|
||
</p>
|
||
</div>
|
||
|
||
<div class="mb-6">
|
||
<input type="text" id="login-totp" name="totp_code"
|
||
class="w-full p-4 border border-gray-300 rounded-lg focus:ring-2 focus:ring-gray-500 focus:border-transparent outline-none transition duration-200 text-center text-3xl tracking-[0.5em] font-mono"
|
||
placeholder="000000" maxlength="6" inputmode="numeric" autocomplete="one-time-code" />
|
||
</div>
|
||
|
||
<button type="button" id="back-to-credentials-btn"
|
||
class="w-full mb-4 text-gray-500 hover:text-gray-700 text-sm flex items-center justify-center gap-1">
|
||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7"></path>
|
||
</svg>
|
||
Назад
|
||
</button>
|
||
</div>
|
||
|
||
<button type="submit" id="login-submit"
|
||
class="w-full bg-gray-500 text-white py-2 px-4 rounded-lg hover:bg-gray-600 transition duration-200 font-medium">
|
||
Войти
|
||
</button>
|
||
</form>
|
||
|
||
<form id="register-form" class="p-6 hidden">
|
||
<div class="mb-4">
|
||
<label for="register-username" class="block text-sm font-medium text-gray-700 mb-2">
|
||
Имя пользователя
|
||
</label>
|
||
<input type="text" id="register-username" name="username"
|
||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-gray-500 focus:border-transparent outline-none transition duration-200"
|
||
placeholder="Придумайте имя пользователя" required minlength="3" maxlength="50" />
|
||
</div>
|
||
<div class="mb-4">
|
||
<label for="register-email" class="block text-sm font-medium text-gray-700 mb-2">Email</label>
|
||
<input type="email" id="register-email" name="email"
|
||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-gray-500 focus:border-transparent outline-none transition duration-200"
|
||
placeholder="example@mail.com" required />
|
||
</div>
|
||
<div class="mb-4">
|
||
<label for="register-fullname" class="block text-sm font-medium text-gray-700 mb-2">
|
||
Полное имя <span class="text-gray-400">(необязательно)</span>
|
||
</label>
|
||
<input type="text" id="register-fullname" name="full_name"
|
||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-gray-500 focus:border-transparent outline-none transition duration-200"
|
||
placeholder="Иван Иванов" maxlength="100" />
|
||
</div>
|
||
<div class="mb-4">
|
||
<label for="register-password" class="block text-sm font-medium text-gray-700 mb-2">Пароль</label>
|
||
<div class="relative">
|
||
<input type="password" id="register-password" name="password"
|
||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-gray-500 focus:border-transparent outline-none transition duration-200"
|
||
placeholder="Минимум 8 символов" required minlength="8" maxlength="100" />
|
||
<button type="button"
|
||
class="toggle-password absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600">
|
||
<svg class="eye-open w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z">
|
||
</path>
|
||
</svg>
|
||
<svg class="eye-closed w-5 h-5 hidden" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||
d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21">
|
||
</path>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
<div class="mt-2">
|
||
<div class="h-1 w-full bg-gray-200 rounded-full overflow-hidden">
|
||
<div id="password-strength-bar" class="h-full w-0 transition-all duration-300"></div>
|
||
</div>
|
||
<p id="password-strength-text" class="text-xs mt-1 text-gray-500"></p>
|
||
</div>
|
||
</div>
|
||
<div class="mb-4">
|
||
<label for="register-password-confirm" class="block text-sm font-medium text-gray-700 mb-2">
|
||
Подтвердите пароль
|
||
</label>
|
||
<div class="relative">
|
||
<input type="password" id="register-password-confirm" name="password_confirm"
|
||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-gray-500 focus:border-transparent outline-none transition duration-200"
|
||
placeholder="Повторите пароль" required />
|
||
<button type="button"
|
||
class="toggle-password absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600">
|
||
<svg class="eye-open w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z">
|
||
</path>
|
||
</svg>
|
||
<svg class="eye-closed w-5 h-5 hidden" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||
d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21">
|
||
</path>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
<p id="password-match-error" class="text-xs mt-1 text-red-500 hidden">
|
||
Пароли не совпадают
|
||
</p>
|
||
</div>
|
||
|
||
<div class="mb-4">
|
||
<cap-widget id="cap"
|
||
data-cap-api-endpoint="/api/cap/"
|
||
style="
|
||
--cap-widget-width: 100%;
|
||
--cap-background: #fdfdfd;
|
||
--cap-border-color: #d1d5db;
|
||
--cap-border-radius: 8px;
|
||
--cap-widget-height: auto;
|
||
--cap-color: #212121;
|
||
--cap-checkbox-size: 32px;
|
||
--cap-checkbox-border: 1.5px dashed #d1d5db;
|
||
--cap-checkbox-border-radius: 6px;
|
||
--cap-checkbox-background: #fafafa;
|
||
--cap-checkbox-margin: 2px;
|
||
--cap-spinner-color: #4b5563;
|
||
--cap-spinner-background-color: #eee;
|
||
--cap-spinner-thickness: 5px;"
|
||
></cap-widget>
|
||
</div>
|
||
|
||
<button type="submit" id="register-submit"
|
||
class="w-full bg-gray-500 text-white py-3 px-4 rounded-lg hover:bg-gray-600 transition duration-200 font-medium disabled:bg-gray-300 disabled:cursor-not-allowed">
|
||
Зарегистрироваться
|
||
</button>
|
||
</form>
|
||
|
||
<form id="reset-password-form" class="p-6 hidden">
|
||
<div class="mb-4 text-center">
|
||
<h3 class="text-lg font-semibold text-gray-800">Сброс пароля</h3>
|
||
<p class="text-sm text-gray-500 mt-1">
|
||
Используйте один из резервных кодов, полученных при регистрации
|
||
</p>
|
||
</div>
|
||
<div class="mb-4">
|
||
<label for="reset-username" class="block text-sm font-medium text-gray-700 mb-2">
|
||
Имя пользователя
|
||
</label>
|
||
<input type="text" id="reset-username" name="username"
|
||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-gray-500 focus:border-transparent outline-none transition duration-200"
|
||
placeholder="Введите имя пользователя" required />
|
||
</div>
|
||
<div class="mb-4">
|
||
<label for="reset-recovery-code" class="block text-sm font-medium text-gray-700 mb-2">
|
||
Резервный код
|
||
</label>
|
||
<input type="text" id="reset-recovery-code" name="recovery_code"
|
||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-gray-500 focus:border-transparent outline-none transition duration-200 text-center font-mono uppercase"
|
||
placeholder="XXXX-XXXX-XXXX-XXXX" maxlength="19" required
|
||
pattern="[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}" />
|
||
</div>
|
||
<div class="mb-4">
|
||
<label for="reset-new-password" class="block text-sm font-medium text-gray-700 mb-2">
|
||
Новый пароль
|
||
</label>
|
||
<div class="relative">
|
||
<input type="password" id="reset-new-password" name="new_password"
|
||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-gray-500 focus:border-transparent outline-none transition duration-200"
|
||
placeholder="Минимум 8 символов" required minlength="8" maxlength="100" />
|
||
<button type="button"
|
||
class="toggle-password absolute right-3 top-1/2 transform -translate-y-1/2 text-gray-400 hover:text-gray-600">
|
||
<svg class="eye-open w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||
d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||
d="M2.458 12C3.732 7.943 7.523 5 12 5c4.478 0 8.268 2.943 9.542 7-1.274 4.057-5.064 7-9.542 7-4.477 0-8.268-2.943-9.542-7z">
|
||
</path>
|
||
</svg>
|
||
<svg class="eye-closed w-5 h-5 hidden" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||
d="M13.875 18.825A10.05 10.05 0 0112 19c-4.478 0-8.268-2.943-9.543-7a9.97 9.97 0 011.563-3.029m5.858.908a3 3 0 114.243 4.243M9.878 9.878l4.242 4.242M9.88 9.88l-3.29-3.29m7.532 7.532l3.29 3.29M3 3l3.59 3.59m0 0A9.953 9.953 0 0112 5c4.478 0 8.268 2.943 9.543 7a10.025 10.025 0 01-4.132 5.411m0 0L21 21">
|
||
</path>
|
||
</svg>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="mb-6">
|
||
<label for="reset-confirm-password" class="block text-sm font-medium text-gray-700 mb-2">
|
||
Подтвердите новый пароль
|
||
</label>
|
||
<input type="password" id="reset-confirm-password" name="confirm_password"
|
||
class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-gray-500 focus:border-transparent outline-none transition duration-200"
|
||
placeholder="Повторите новый пароль" required />
|
||
<p id="reset-password-match-error" class="text-xs mt-1 text-red-500 hidden">
|
||
Пароли не совпадают
|
||
</p>
|
||
</div>
|
||
|
||
<button type="submit" id="reset-submit"
|
||
class="w-full bg-gray-500 text-white py-3 px-4 rounded-lg hover:bg-gray-600 transition duration-200 font-medium">
|
||
Сбросить пароль
|
||
</button>
|
||
<button type="button" id="back-to-login-btn"
|
||
class="w-full mt-3 text-gray-500 hover:text-gray-700 text-sm">
|
||
← Вернуться к входу
|
||
</button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="recovery-codes-modal"
|
||
class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
|
||
<div class="bg-white rounded-lg shadow-xl max-w-md w-full mx-4 max-h-[90vh] overflow-y-auto">
|
||
<div class="p-6">
|
||
<div class="flex items-center justify-center w-12 h-12 mx-auto bg-yellow-100 rounded-full mb-4">
|
||
<svg class="w-6 h-6 text-yellow-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||
d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z">
|
||
</path>
|
||
</svg>
|
||
</div>
|
||
<h3 class="text-lg font-semibold text-center text-gray-800 mb-2">
|
||
Сохраните резервные коды!
|
||
</h3>
|
||
<p class="text-sm text-gray-500 text-center mb-4">
|
||
Эти коды понадобятся для восстановления доступа к аккаунту.
|
||
<strong class="text-red-600">Сохраните их в надёжном месте!</strong>
|
||
</p>
|
||
|
||
<div id="recovery-codes-list"
|
||
class="bg-gray-50 rounded-lg p-4 font-mono text-sm text-center space-y-2 mb-4">
|
||
</div>
|
||
|
||
<div class="flex gap-2 mb-4">
|
||
<button type="button" id="copy-codes-btn"
|
||
class="flex-1 flex items-center justify-center gap-2 px-4 py-2 bg-gray-100 hover:bg-gray-200 rounded-lg text-sm font-medium transition">
|
||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||
d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z">
|
||
</path>
|
||
</svg>
|
||
Копировать
|
||
</button>
|
||
<button type="button" id="download-codes-btn"
|
||
class="flex-1 flex items-center justify-center gap-2 px-4 py-2 bg-gray-100 hover:bg-gray-200 rounded-lg text-sm font-medium transition">
|
||
<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
|
||
d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path>
|
||
</svg>
|
||
Скачать
|
||
</button>
|
||
</div>
|
||
|
||
<label class="flex items-center gap-2 text-sm text-gray-600 mb-4">
|
||
<input type="checkbox" id="codes-saved-checkbox" class="rounded" />
|
||
Я сохранил(а) коды в надёжном месте
|
||
</label>
|
||
|
||
<button type="button" id="close-recovery-modal-btn" disabled
|
||
class="w-full bg-gray-500 text-white py-3 px-4 rounded-lg hover:bg-gray-600 transition duration-200 font-medium disabled:bg-gray-300 disabled:cursor-not-allowed">
|
||
Продолжить
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<style>
|
||
#auth-tabs {
|
||
transition: transform 0.3s ease, opacity 0.2s ease, height 0.1s ease;
|
||
transform: translateY(0);
|
||
}
|
||
#auth-tabs.hide-animated {
|
||
transform: translateY(-12px);
|
||
pointer-events: none;
|
||
height: 0; opacity: 0;
|
||
}
|
||
</style>
|
||
{% endblock %} {% block scripts %}
|
||
<script src="https://cdn.jsdelivr.net/npm/@cap.js/widget"></script>
|
||
<script src="/static/page/auth.js"></script>
|
||
{% endblock %}
|