/** * Controle de acesso — delega ao Access Control Hub * Spec 040 · DS-FE-005 */ (function () { 'use strict'; const ROLE_CODES = { super_admin: 'SU', ops_lead: 'CO', technician: 'TEC', noc: 'NOC', sales_admin: 'SAD', sales_support: 'SSU', finance: 'FIN', marketing: 'MKT', seo: 'SEO', developer: 'DEV', devops: 'DVO', security_analyst: 'SOC', content_editor: 'CMS', agentic_operator: 'AIO', partner: 'PTR', root: 'RO', }; const ACCESS_ACTIONS = [ { id: 'create_user', actionId: 'desk.auth.user.create', label: 'Criar usuário', hint: 'Provisionar conta directa' }, { id: 'edit_user', actionId: 'desk.auth.user.edit', label: 'Editar usuário', hint: 'Nome, perfil e metadados' }, { id: 'freeze_user', actionId: 'desk.auth.user.freeze', label: 'Congelar conta', hint: 'Bloquear login — SSU nunca' }, { id: 'approve_registration', actionId: 'desk.auth.user.approve_registration', label: 'Aprovar pedidos de cadastro', hint: 'SU + CO' }, { id: 'manage_passwords', actionId: 'desk.auth.user.password.reset', label: 'Gerenciar senhas', hint: 'Reset admin' }, { id: 'reset_2fa', actionId: 'desk.auth.user.2fa.reset', label: 'Resetar 2FA', hint: 'Recuperação autenticador' }, { id: 'manage_modules', actionId: 'desk.auth.modules.toggle', label: 'Módulos Desk ON/OFF', hint: 'Feature flags' }, { id: 'purge_domain', actionId: 'vm112.domain.purge', label: 'Purge domínio', hint: 'Irreversível' }, { id: 'openpanel_delete', actionId: 'vm123_openpanel.site.delete', label: 'Deletar instância OpenPanel', hint: 'SU + CO' }, { id: 'validate_billing', actionId: 'desk.billing.state.validate', label: 'Validar billing', hint: 'billing_state' }, { id: 'agent_approve', actionId: 'desk.agent.runbook.approve', label: 'Aprovar remediação A7', hint: 'Agentes' }, ]; let levelsCache = null; let levelsRole = null; let catalogEditable = false; function esc(s) { return String(s ?? '').replace(/&/g, '&').replace(//g, '>'); } async function loadLevelsForRole(roleId) { if (levelsCache && levelsRole === roleId) return levelsCache; const r = await fetchWithTimeout('/api/v1/rbac/actions', { headers: authHeaders() }); if (!r.ok) throw new Error(String(r.status)); const data = await r.json(); catalogEditable = !!data.editable; const map = {}; (data.actions || []).forEach((a) => { map[a.id] = { effective: a.effective?.[roleId] || 'none', default: a.defaults?.[roleId] || 'none', overridden: a.overridden_roles?.includes(roleId), }; }); levelsCache = map; levelsRole = roleId; return map; } function actionOn(level) { return level === 'full' || level === 'approve' || level === 'api' || level === 'system'; } function renderPermToggles(selectedRole, roleMeta, levels, editable) { const code = ROLE_CODES[selectedRole] || selectedRole?.slice(0, 3).toUpperCase() || '—'; const rows = ACCESS_ACTIONS.map((a) => { const lv = levels[a.actionId]?.effective || 'none'; const on = actionOn(lv); const partial = on && lv !== 'full'; const ro = !editable ? ' acs-toggle--readonly' : ''; const dis = editable ? '' : ' disabled'; return `
Função ${esc(roleMeta?.label || selectedRole)}. ${editHint}
Carregando capacidades…
'; let levels = {}; try { levels = await loadLevelsForRole(selectedRole); } catch (e) { host.innerHTML = `Catálogo indisponível: ${esc(e.message)}
`; return; } const canEdit = editable && catalogEditable; host.innerHTML = renderPermToggles(selectedRole, roleMeta, levels, canEdit); host.querySelector('[data-goto-exec]')?.addEventListener('click', (e) => { e.preventDefault(); document.querySelector('[data-am-tab="quem-faz-o-que"]')?.click(); }); host.querySelectorAll('[data-acs-toggle]').forEach((inp) => { inp.addEventListener('change', async () => { if (!canEdit) return; const actionId = inp.dataset.acsToggle; try { await patchToggle(actionId, selectedRole, inp.checked); } catch (err) { inp.checked = !inp.checked; window.alert(`Erro ao gravar: ${err.message}`); } }); }); } async function paint(host, opts = {}) { if (!host) return; if (window.DeskAccessControlHub?.paint) { return window.DeskAccessControlHub.paint(host, opts); } return paintCapabilitiesOnly(host, opts); } window.DeskAccessControlPanel = { ROLE_CODES, ACCESS_ACTIONS, paint, paintCapabilitiesOnly, invalidateCache: () => { levelsCache = null; levelsRole = null; }, resetUserMgmt: () => window.DeskUserManagement?.reset?.(), }; })();