import { renderHeader } from '../components/header.js'; import { authService, clearAuthMessages, setAuthBusy, setAuthError, state, } from '../state.js'; import { toUserMessage } from '../services/ui-error-texts.js'; import { emptyPasswordWords, PASSWORD_MAX_LENGTH } from '../services/password-words.js'; export const pageMeta = { id: 'login-password-view', title: 'Введите пароль', showAppChrome: false }; function setStatus(statusEl, message) { statusEl.textContent = message; statusEl.style.display = message ? '' : 'none'; } function createSecretOverlay() { const overlay = document.createElement('div'); overlay.className = 'secret-generation-overlay'; overlay.style.display = 'none'; const card = document.createElement('div'); card.className = 'secret-generation-card stack'; const spinner = document.createElement('div'); spinner.className = 'secret-generation-spinner'; spinner.setAttribute('aria-hidden', 'true'); const title = document.createElement('div'); title.className = 'secret-generation-title'; title.textContent = 'Генерируем секрет…'; const progress = document.createElement('div'); progress.className = 'secret-generation-progress'; progress.textContent = ''; card.append(spinner, title, progress); overlay.append(card); return { overlay, progress }; } export function render({ navigate }) { const screen = document.createElement('section'); screen.className = 'stack auth-screen auth-screen--lower'; clearAuthMessages(); const login = String(state.loginDraft.login || '').trim(); if (!login) { window.setTimeout(() => navigate('login-view'), 0); } const panel = document.createElement('section'); panel.className = 'login-panel stack'; const title = document.createElement('h1'); title.className = 'login-panel-title'; title.textContent = 'Введите пароль'; const passwordField = document.createElement('label'); passwordField.className = 'stack'; const passwordInput = document.createElement('input'); passwordInput.className = 'input'; passwordInput.type = 'password'; passwordInput.name = 'shine-login-password'; passwordInput.autocomplete = 'current-password'; passwordInput.autocapitalize = 'off'; passwordInput.spellcheck = false; passwordInput.maxLength = PASSWORD_MAX_LENGTH; passwordInput.placeholder = 'Пароль'; passwordInput.value = ''; passwordField.append(passwordInput); const status = document.createElement('p'); status.className = 'status-line is-unavailable'; status.style.display = 'none'; const enterButton = document.createElement('button'); enterButton.className = 'primary-btn'; enterButton.type = 'button'; enterButton.textContent = 'Войти'; const actions = document.createElement('div'); actions.className = 'auth-footer-actions'; actions.append(enterButton); const { overlay, progress } = createSecretOverlay(); const submit = async () => { const currentLogin = String(state.loginDraft.login || '').trim(); const password = String(passwordInput.value || ''); setStatus(status, ''); if (!currentLogin) { navigate('login-view'); return; } if (password.length > PASSWORD_MAX_LENGTH) { setStatus(status, `Пароль слишком длинный. Максимальная длина: ${PASSWORD_MAX_LENGTH} символов.`); return; } state.loginDraft.password = password; state.loginDraft.passwordMode = 'single'; state.loginDraft.passwordWords = emptyPasswordWords(); setAuthBusy(true); setAuthError(''); enterButton.disabled = true; try { await authService.reconnect(state.entrySettings.shineServer); // Повторная проверка защищает UI от смены access server между первым экраном и входом. const resolved = await authService.resolveLoginForAuth(currentLogin); if (String(resolved?.resolution || '').toUpperCase() !== 'LOCAL') { state.loginDraft.login = String(resolved?.login || currentLogin).trim(); navigate('login-view'); return; } overlay.style.display = 'grid'; const keyBundle = await authService.derivePasswordKeyBundle(currentLogin, password, { onProgress: ({ percent }) => { const value = Math.max(0, Math.min(100, Number(percent) || 0)); progress.textContent = value > 0 && value < 100 ? `${Math.round(value)}%` : ''; }, }); overlay.style.display = 'none'; enterButton.textContent = 'Проверяем пароль…'; const result = await authService.createAuthSession(currentLogin, keyBundle); // Существующую дальнейшую логику после успешного пароля сохраняем без изменений. state.registrationDraft.flowType = 'login'; state.registrationDraft.login = result.login; state.registrationDraft.password = password; state.registrationDraft.passwordMode = 'single'; state.registrationDraft.passwordWords = emptyPasswordWords(); state.registrationDraft.sessionId = result.sessionId; state.registrationDraft.storagePwd = result.storagePwd; state.registrationDraft.pendingKeyBundle = keyBundle; state.registrationDraft.pendingSessionMaterial = result.sessionMaterial; navigate('registration-keys-view'); } catch (error) { overlay.style.display = 'none'; const message = toUserMessage(error, 'Не удалось выполнить вход.'); setAuthError(message); setStatus(status, message); passwordInput.select(); } finally { setAuthBusy(false); enterButton.disabled = false; enterButton.textContent = 'Войти'; } }; enterButton.addEventListener('click', submit); passwordInput.addEventListener('keydown', (event) => { if (event.key === 'Enter') { event.preventDefault(); void submit(); } }); panel.append(title, passwordField, status, actions); screen.append( renderHeader({ title: '', leftAction: { label: '←', onClick: () => navigate('login-view') }, }), panel, overlay, ); window.setTimeout(() => passwordInput.focus(), 0); return screen; }