- Real email/password login backed by SQLite (better-sqlite3) - HttpOnly cookie sessions with 8h sliding TTL - Admin role: invite users via Mailgun magic-link, manage roles/status - Per-user One2Edit username mapping for job filtering - Self-service forgot-password / reset-password via email - Admin console (admin.html) with user table, invite modal, row actions - New pages: change-password, forgot-password, reset-password, accept-invite - Gated /api proxy: requires valid session, anti-hijack sessionId check - Bootstrap initial admins from INITIAL_ADMINS env var on first boot - Remove Oliver login button, SSO buttons, and legacy api.js/login.js - deploy.sh: add build-essential (for native module), npm install, data dir Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
47 lines
1.7 KiB
JavaScript
47 lines
1.7 KiB
JavaScript
async function handleLogin() {
|
|
const email = document.getElementById('email').value.trim();
|
|
const password = document.getElementById('password').value;
|
|
const errorMessage = document.getElementById('errorMessage');
|
|
const loginButton = document.getElementById('loginButton');
|
|
const buttonText = document.getElementById('loginButtonText');
|
|
const spinner = document.getElementById('loginSpinner');
|
|
|
|
errorMessage.style.display = 'none';
|
|
|
|
if (!email || !password) {
|
|
errorMessage.textContent = 'Please enter your email and password.';
|
|
errorMessage.style.display = 'block';
|
|
return;
|
|
}
|
|
|
|
loginButton.disabled = true;
|
|
buttonText.textContent = 'Signing in...';
|
|
spinner.style.display = 'inline-block';
|
|
|
|
try {
|
|
const res = await fetch('/api/auth/login', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ email, password }),
|
|
});
|
|
const data = await res.json();
|
|
|
|
if (!res.ok) {
|
|
throw new Error(data.error || 'Login failed');
|
|
}
|
|
|
|
if (data.mustChangePassword) {
|
|
window.location.href = 'change-password.html';
|
|
} else {
|
|
window.location.href = 'dashboard.html';
|
|
}
|
|
} catch (error) {
|
|
errorMessage.textContent = error.message || 'An error occurred. Please try again.';
|
|
errorMessage.style.display = 'block';
|
|
loginButton.disabled = false;
|
|
buttonText.textContent = 'Sign In';
|
|
spinner.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
document.getElementById('loginButton').addEventListener('click', handleLogin);
|