Files
LibraryAPI/library_service/templates/auth.html

347 lines
24 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{% 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 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 px-4 py-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-3 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>
{% endblock %} {% block scripts %}
<script src="https://cdn.jsdelivr.net/npm/@cap.js/widget"></script>
<script src="/static/page/auth.js"></script>
{% endblock %}