const SESSION_STORAGE_KEY = 'cc_session'; const state = { user: 'admin', role: 'admin', token: null, authSource: 'local', oidc: { enabled: false, loginPath: '/auth/oidc/start?return_mode=popup', providerLabel: 'Keycloak', }, }; const $ = (id) => document.getElementById(id); function destinationForRole(role) { if (role === 'admin') { return '/admin'; } if (role === 'supervisor') { return '/supervisor'; } if (role === 'analyst') { return '/analyst'; } return '/operator'; } function syncSessionFromInputs() { state.user = $('sessionUser').value.trim() || 'admin'; } function writeLog(message, payload) { const suffix = payload ? ` ${JSON.stringify(payload, null, 2)}` : ''; $('loginLog').textContent = `${message}${suffix}`; } function persistSession(data) { const payload = { access_token: data.access_token, user: data.username || state.user, role: data.role, auth_source: data.auth_source || 'local', provider: data.provider || null, full_name: data.full_name || null, }; window.localStorage.setItem(SESSION_STORAGE_KEY, JSON.stringify(payload)); } function updateSessionInfo(extra = '') { if (!state.token) { $('sessionInfo').textContent = 'Токен: отсутствует'; return; } const source = state.authSource === 'oidc' ? 'корпоративный' : 'локальный'; $('sessionInfo').textContent = `Токен активен | роль: ${state.role} | вход: ${source}${extra ? ` | ${extra}` : ''}`; } function applyAuthenticatedSession(data) { state.token = data.access_token; state.role = data.role; state.user = data.username || state.user; state.authSource = data.auth_source || 'local'; $('sessionUser').value = state.user; updateSessionInfo(data.provider ? `provider: ${data.provider}` : ''); persistSession(data); } async function api(service, path, options = {}) { syncSessionFromInputs(); const headers = { 'Content-Type': 'application/json', ...(options.headers || {}), }; if (state.token) { headers.Authorization = `Bearer ${state.token}`; } const response = await fetch(`/proxy/${service}/${path}`, { ...options, headers, }); let data; try { data = await response.json(); } catch { data = { error: 'Non-JSON response' }; } if (!response.ok) { throw new Error(`${response.status}: ${JSON.stringify(data)}`); } return data; } async function loadOidcConfig() { try { const response = await fetch('/proxy/auth/auth/oidc/config'); const data = await response.json(); state.oidc.enabled = Boolean(data.enabled); state.oidc.loginPath = data.login_path || '/auth/oidc/start?return_mode=popup'; state.oidc.providerLabel = data.provider_label || 'Keycloak'; $('corporateLoginBtn').disabled = !state.oidc.enabled; $('corporateLoginBtn').textContent = state.oidc.enabled ? `Корпоративный вход (${state.oidc.providerLabel})` : 'Корпоративный вход недоступен'; } catch { $('corporateLoginBtn').disabled = true; $('corporateLoginBtn').textContent = 'Корпоративный вход недоступен'; } } function startCorporateLogin() { if (!state.oidc.enabled) { writeLog('Корпоративный вход недоступен.'); return; } const popup = window.open(`/proxy/auth${state.oidc.loginPath}`, 'oidc-login', 'width=620,height=760'); if (!popup) { writeLog('Не удалось открыть окно корпоративного входа.'); return; } writeLog('Открыт корпоративный вход.', { provider: state.oidc.providerLabel }); } function handleOidcMessage(event) { if (!event?.data || typeof event.data !== 'object') { return; } if (event.data.type === 'oidc-login' && event.data.access_token) { applyAuthenticatedSession(event.data); writeLog('Корпоративный вход выполнен.', { user: state.user, role: state.role }); window.location.href = destinationForRole(state.role); return; } if (event.data.type === 'oidc-error') { writeLog('Корпоративный вход не выполнен.', { error: event.data.message || 'unknown' }); } } async function login() { syncSessionFromInputs(); try { const data = await api('auth', 'auth/login', { method: 'POST', body: JSON.stringify({ username: state.user, password: $('sessionPassword').value, }), }); applyAuthenticatedSession({ ...data, username: state.user, auth_source: data.auth_source || 'local', }); writeLog('Локальный вход выполнен.', { user: state.user, role: data.role }); window.location.href = destinationForRole(data.role); } catch (err) { $('sessionInfo').textContent = `Ошибка входа: ${err.message}`; writeLog('Вход не выполнен.', { error: err.message }); } } function wire() { $('loginBtn').addEventListener('click', login); $('corporateLoginBtn').addEventListener('click', startCorporateLogin); $('refreshBtn').addEventListener('click', loadOidcConfig); window.addEventListener('message', handleOidcMessage); } async function init() { wire(); updateSessionInfo(); await loadOidcConfig(); const raw = window.localStorage.getItem(SESSION_STORAGE_KEY); if (raw) { try { const payload = JSON.parse(raw); if (payload?.access_token) { state.token = payload.access_token; state.user = payload.user || state.user; state.role = payload.role || state.role; state.authSource = payload.auth_source || 'local'; $('sessionUser').value = state.user; updateSessionInfo(payload.provider ? `provider: ${payload.provider}` : ''); writeLog('Найдена активная сессия.', { user: state.user, role: state.role }); } } catch { window.localStorage.removeItem(SESSION_STORAGE_KEY); } } } init();