137 lines
4.7 KiB
JavaScript
137 lines
4.7 KiB
JavaScript
let currentUser = null;
|
|
|
|
function getCookie(name) {
|
|
const match = document.cookie.match('(^|;)\\s*' + name + '\\s*=\\s*([^;]+)');
|
|
return match ? match[2] : null;
|
|
}
|
|
|
|
function setCookie(name, value, maxAgeSec) {
|
|
document.cookie = name + '=' + value + ';path=/;max-age=' + maxAgeSec;
|
|
}
|
|
|
|
function getLockedUntil() { return parseInt(getCookie('lockout_until') || '0', 10); }
|
|
function setLockedUntil(ts) { setCookie('lockout_until', ts, 300); }
|
|
function getLoginAttempts() { return parseInt(getCookie('login_attempts') || '0', 10); }
|
|
function setLoginAttempts(count) { setCookie('login_attempts', count, 300); }
|
|
function clearLoginCookies() {
|
|
setCookie('login_attempts', 0, 0);
|
|
setCookie('lockout_until', 0, 0);
|
|
}
|
|
|
|
function isLocked() {
|
|
return Date.now() < getLockedUntil();
|
|
}
|
|
|
|
function getRemainingLockoutSeconds() {
|
|
const rem = Math.floor((getLockedUntil() - Date.now()) / 1000);
|
|
return Math.max(0, rem);
|
|
}
|
|
|
|
async function checkAuth() {
|
|
try {
|
|
const response = await fetch('/api/user', { credentials: 'include' });
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
currentUser = data.user;
|
|
if (data.csrfToken) {
|
|
window.__CSRF_TOKEN = data.csrfToken;
|
|
}
|
|
showMainInterface();
|
|
} else {
|
|
showLoginInterface();
|
|
}
|
|
} catch (error) {
|
|
showLoginInterface();
|
|
}
|
|
}
|
|
|
|
function showLoginInterface() {
|
|
document.getElementById('app').style.display = 'none';
|
|
document.getElementById('login-screen').style.display = 'flex';
|
|
}
|
|
|
|
function showMainInterface() {
|
|
document.getElementById('login-screen').style.display = 'none';
|
|
document.getElementById('app').style.display = 'block';
|
|
const userEl = document.getElementById('currentUser');
|
|
if (userEl && currentUser) {
|
|
userEl.textContent = (currentUser.role === 'admin' ? '👑 ' : '') + currentUser.name;
|
|
}
|
|
if (typeof loadFilters === 'function') loadFilters();
|
|
if (typeof loadAll === 'function') loadAll();
|
|
}
|
|
|
|
async function login(event) {
|
|
event.preventDefault();
|
|
if (isLocked()) {
|
|
const rem = getRemainingLockoutSeconds();
|
|
document.getElementById('login-error').textContent = 'Слишком много попыток. Подождите ' + rem + ' секунд.';
|
|
document.getElementById('login-error').style.display = 'block';
|
|
document.getElementById('login-attempts').textContent = '';
|
|
return;
|
|
}
|
|
|
|
const login = document.getElementById('login').value;
|
|
const password = document.getElementById('password').value;
|
|
const errorEl = document.getElementById('login-error');
|
|
const attemptsEl = document.getElementById('login-attempts');
|
|
|
|
try {
|
|
const response = await fetch('/api/login', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ login, password })
|
|
});
|
|
|
|
if (response.ok) {
|
|
clearLoginCookies();
|
|
const data = await response.json();
|
|
currentUser = data.user;
|
|
if (data.csrfToken) {
|
|
window.__CSRF_TOKEN = data.csrfToken;
|
|
}
|
|
showMainInterface();
|
|
} else if (response.status === 429) {
|
|
const data = await response.json();
|
|
errorEl.textContent = data.error;
|
|
errorEl.style.display = 'block';
|
|
} else {
|
|
let attempts = getLoginAttempts() + 1;
|
|
setLoginAttempts(attempts);
|
|
if (attempts >= 10) {
|
|
setLockedUntil(Date.now() + 300000);
|
|
errorEl.textContent = 'Слишком много попыток. Подождите 5 минут.';
|
|
attemptsEl.textContent = '';
|
|
} else {
|
|
errorEl.textContent = 'Неверный логин или пароль';
|
|
attemptsEl.textContent = 'Попыток: ' + attempts + ' из 10';
|
|
}
|
|
errorEl.style.display = 'block';
|
|
}
|
|
} catch (error) {
|
|
document.getElementById('login-error').textContent = 'Ошибка соединения';
|
|
document.getElementById('login-error').style.display = 'block';
|
|
}
|
|
}
|
|
|
|
async function logout() {
|
|
try {
|
|
await fetch('/api/logout', { method: 'POST' });
|
|
} catch (e) {}
|
|
currentUser = null;
|
|
window.__CSRF_TOKEN = null;
|
|
showLoginInterface();
|
|
}
|
|
|
|
function togglePasswordVisibility() {
|
|
const pwd = document.getElementById('password');
|
|
const icon = document.querySelector('.password-toggle i');
|
|
if (pwd.type === 'password') {
|
|
pwd.type = 'text';
|
|
if (icon) icon.className = 'fas fa-eye-slash';
|
|
} else {
|
|
pwd.type = 'password';
|
|
if (icon) icon.className = 'fas fa-eye';
|
|
}
|
|
}
|