import { S } from './state.js'; // ── Auth ───────────────────────────────────────────────────────────────────── function handleSignIn() { try { startAuth().catch(function(e) { alert('Sign-in error: ' + (e.message || String(e))); }); } catch(e) { alert('Sign-in error: ' + (e.message || String(e))); } } async function startAuth() { const clientId = document.getElementById('clientId').value.trim(); const tenantId = document.getElementById('tenantId').value.trim(); const clientSecret = document.getElementById('clientSecret').value.trim(); if (!clientId || !tenantId) { alert('Enter Client ID and Tenant ID'); return; } // Persist credentials first so they survive restarts regardless of auth outcome await fetch('/api/auth/config', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({client_id: clientId, tenant_id: tenantId, client_secret: clientSecret}) }); const r = await fetch('/api/auth/start', { method: 'POST', headers: {'Content-Type':'application/json'}, body: JSON.stringify({client_id: clientId, tenant_id: tenantId, client_secret: clientSecret}) }); const d = await r.json(); if (d.error) { alert(d.error); return; } if (d.mode === 'application') { // App mode — token acquired immediately, no device code step needed document.getElementById('configForm').style.display = 'none'; document.getElementById('deviceCodeBackdrop').classList.add('open'); document.getElementById('deviceCode').textContent = '—'; document.getElementById('authStatus').className = 'auth-status success'; document.getElementById('authStatus').textContent = '✓ Connected (Application mode — org-wide access)'; setTimeout(onAuthenticated, 900); return; } document.getElementById('configForm').style.display = 'none'; document.getElementById('deviceCodeBackdrop').classList.add('open'); document.getElementById('deviceCode').textContent = d.user_code; pollAuth(); } async function pollAuth() { const r = await fetch('/api/auth/poll', {method: 'POST'}); const d = await r.json(); if (d.status === 'pending') { setTimeout(pollAuth, 3000); } else if (d.status === 'ok') { document.getElementById('authStatus').className = 'auth-status success'; document.getElementById('authStatus').textContent = '✓ Signed in!'; setTimeout(onAuthenticated, 800); } else { document.getElementById('authStatus').className = 'auth-status error'; document.getElementById('authStatus').textContent = '✗ ' + (d.error || 'Sign-in failed'); document.getElementById('configForm').style.display = 'block'; document.getElementById('deviceCodeBackdrop').classList.remove('open'); } } function cancelAuth() { document.getElementById('configForm').style.display = 'block'; document.getElementById('deviceCodeBackdrop').classList.remove('open'); } let _currentDisplayName = ''; function _setModeBadge(isAppMode, displayName) { S._currentAppMode = isAppMode; _currentDisplayName = displayName || ''; // Keep Sources modal status dot in sync if it's open const dot = document.getElementById('srcM365StatusDot'); if (dot) dot.className = 'srcmgmt-status ' + (isAppMode !== null && isAppMode !== undefined ? 'green' : 'grey'); } async function onAuthenticated() { const r = await fetch('/api/auth/status'); const d = await r.json(); if (d.display_name || d.displayName || d.email) { _setModeBadge(d.app_mode, d.display_name || d.displayName || d.email); } document.getElementById('authScreen').style.display = 'none'; document.getElementById('scannerScreen').style.display = 'flex'; loadUsers(); loadTrend(); // show existing trend if DB has history loadProfiles(); // populate profile dropdown (15c) } function reconfigure() { // Show the auth screen with current credentials pre-filled so user can // update the client secret without losing client_id / tenant_id. document.getElementById('scannerScreen').style.display = 'none'; document.getElementById('authScreen').style.display = 'flex'; document.getElementById('configForm').style.display = 'block'; document.getElementById('deviceCodeBackdrop').classList.remove('open'); } async function signOut() { await fetch('/api/auth/signout', {method: 'POST'}); document.getElementById('scannerScreen').style.display = 'none'; document.getElementById('authScreen').style.display = 'flex'; document.getElementById('configForm').style.display = 'block'; document.getElementById('deviceCodeBackdrop').classList.remove('open'); S.flaggedData = []; S.filteredData = []; document.getElementById('grid').innerHTML = ''; document.getElementById('grid').style.display = 'none'; const _lss2 = document.getElementById('lastScanSummary'); if (_lss2) _lss2.style.display = 'none'; document.getElementById('emptyState').style.display = 'flex'; } // ── Check auth on load ──────────────────────────────────────────────────────── // Date presets (function() { const presets = document.querySelectorAll('.date-preset'); const hidden = document.getElementById('olderThan'); const dateIn = document.getElementById('olderThanDate'); function setPreset(btn) { presets.forEach(p => p.classList.remove('selected')); btn.classList.add('selected'); const years = parseInt(btn.dataset.years); if (years === 0) { hidden.value = '0'; dateIn.value = new Date().toISOString().slice(0, 10); } else { const d = new Date(); d.setFullYear(d.getFullYear() - years); hidden.value = Math.round(years * 365.25).toString(); dateIn.value = d.toISOString().slice(0, 10); } } presets.forEach(btn => btn.addEventListener('click', () => setPreset(btn))); dateIn.addEventListener('change', () => { presets.forEach(p => p.classList.remove('selected')); if (dateIn.value) { const diffDays = Math.round((Date.now() - new Date(dateIn.value)) / 86400000); hidden.value = diffDays.toString(); } else { hidden.value = '0'; } }); // Trigger default (2yr selected) const def = document.querySelector('.date-preset.selected'); if (def) setPreset(def); // Toggle attach size row visibility document.getElementById('optAttachments').addEventListener('change', function() { document.getElementById('attachSizeRow').style.opacity = this.checked ? '1' : '0.4'; }); })(); // ── Viewer mode bootstrap ───────────────────────────────────────────────────── if (window.VIEWER_MODE) { document.body.classList.add('viewer-mode'); document.getElementById('authScreen').style.display = 'none'; document.getElementById('scannerScreen').style.display = 'flex'; // If this token is role-scoped, lock the filter to that role and hide the dropdown. const _scopeRole = (window.VIEWER_SCOPE || {}).role || ''; if (_scopeRole) { const _fr = document.getElementById('filterRole'); if (_fr) { _fr.value = _scopeRole; _fr.style.display = 'none'; } } // If this token is user-scoped, show a locked identity badge and hide irrelevant filters. const _scopeUserRaw = (window.VIEWER_SCOPE || {}).user; if (_scopeUserRaw && (Array.isArray(_scopeUserRaw) ? _scopeUserRaw.length : _scopeUserRaw)) { const _fr = document.getElementById('filterRole'); if (_fr) _fr.style.display = 'none'; const _badge = document.getElementById('viewerIdentityBadge'); if (_badge) { _badge.textContent = (window.VIEWER_SCOPE || {}).display_name || (Array.isArray(_scopeUserRaw) ? _scopeUserRaw[0] : _scopeUserRaw); _badge.style.display = ''; } } try { loadTrend(); } catch(e) {} } else { (async function() { try { const r = await fetch('/api/auth/status'); const d = await r.json(); if (d.authenticated) { // Load saved credentials into fields if (d.client_id) document.getElementById('clientId').value = d.client_id; if (d.tenant_id) document.getElementById('tenantId').value = d.tenant_id; if (d.client_secret) document.getElementById('clientSecret').value = d.client_secret; _setModeBadge(d.app_mode, d.display_name || d.email || ''); document.getElementById('authScreen').style.display = 'none'; document.getElementById('scannerScreen').style.display = 'flex'; try { loadUsers(); } catch(e) {} try { loadProfiles(); } catch(e) {} try { loadTrend(); } catch(e) {} } else { // Pre-fill saved credentials if (d.client_id) document.getElementById('clientId').value = d.client_id; if (d.tenant_id) document.getElementById('tenantId').value = d.tenant_id; if (d.client_secret) document.getElementById('clientSecret').value = d.client_secret; } } catch(e) { console.error('Auth status check failed:', e); } })(); } // ── Window exports (HTML handlers + cross-module calls) ───────────────────── window.handleSignIn = handleSignIn; window.startAuth = startAuth; window.pollAuth = pollAuth; window.cancelAuth = cancelAuth; window._setModeBadge = _setModeBadge; window.onAuthenticated = onAuthenticated; window.reconfigure = reconfigure; window.signOut = signOut; window._currentDisplayName = _currentDisplayName;