PageSourceSearch

https://appagendaconsultor.web.app/js/auth.js?v=125

js appagendaconsultor.web.app collected 2026-10-03 12:16:57 UTC 18,751 bytes, 333 lines download raw bytes

1// V48: fallback local para evitar "normalizarPerfilNome is not defined" no login caso session.js esteja em cache/ordem incorreta.
2function normalizarPerfilNomeAuthFallback(perfil) {
3  const bruto = String(perfil || '').trim().toLowerCase();
4  const p = bruto
5    .normalize('NFD').replace(/[\u0300-\u036f]/g, '')
6    .replace(/[\s-]+/g, '_')
7    .replace(/__+/g, '_');
8  if (['superadm', 'super_adm', 'superadmin', 'super_admin', 'super_administrador', 'superadministrador', 'master', 'root'].includes(p)) return 'superadm';
9  if (['admin', 'administrador', 'adm', 'adm01'].includes(p)) return 'admin';
10  if ([
11    'administrativo_operacional', 'admin_operacional', 'operacional', 'gestor_os', 'gestor_de_os',
12    'administrador_operacional', 'administracao_operacional', 'administrativo', 'admin_os',
13    'administrativo_os', 'operacional_os'
14  ].includes(p)) return 'administrativo_operacional';
15  if (['cliente', 'client'].includes(p)) return 'cliente';
16  if (['consultor', 'consultores'].includes(p)) return 'consultor';
17  if (['financeiro', 'fin'].includes(p)) return 'financeiro';
18  return p || 'consultor';
19}
20if (typeof window !== 'undefined' && typeof window.normalizarPerfilNome !== 'function') {
21  window.normalizarPerfilNome = normalizarPerfilNomeAuthFallback;
22}
23function normalizarPerfilNomeSeguro(perfil) {
24  if (typeof window !== 'undefined' && typeof window.normalizarPerfilNome === 'function') {
25    return window.normalizarPerfilNome(perfil);
26  }
27  return normalizarPerfilNomeAuthFallback(perfil);
28}
29
30
31function valorBooleanoTrue(v) {
32  return v === true || String(v || '').toLowerCase() === 'true' || String(v || '').toLowerCase() === 'sim';
33}
34
35function valorBooleanoFalse(v) {
36  return v === false || String(v || '').toLowerCase() === 'false' || String(v || '').toLowerCase() === 'nao' || String(v || '').toLowerCase() === 'não';
37}
38
39function deveTrocarSenhaPrimeiroAcesso(registro, perfil) {
40  const usuario = normalizarLoginValor(registro?.usuarioFinal || registro?.usuario || registro?.login || '');
41  if (usuario === 'adm01' && !registro?.id) return false;
42  if (perfil === 'admin' && usuario === 'adm01' && registro?._loginEmergenciaAdm01) return false;
43  if (perfil === 'superadm' && usuario === 'superadm' && registro?._loginEmergenciaSuperAdm) return false;
44
45  if (valorBooleanoTrue(registro?.obrigarTrocaSenha) || valorBooleanoTrue(registro?.trocaSenhaObrigatoria) || valorBooleanoTrue(registro?.senhaProvisoria) || valorBooleanoTrue(registro?.primeiroAcesso)) return true;
46  if (valorBooleanoFalse(registro?.obrigarTrocaSenha) || valorBooleanoFalse(registro?.trocaSenhaObrigatoria)) return false;
47
48  const alterada = valorBooleanoTrue(registro?.senhaAlteradaPrimeiroAcesso) || valorBooleanoTrue(registro?.primeiroAcessoConcluido) || valorBooleanoTrue(registro?.senhaAlteradaPeloUsuario) || valorBooleanoTrue(registro?.senhaAlteradaPrimeiroAcessoCliente);
49  return !alterada;
50}
51
52function redirecionarPorPerfil(perfil) {
53  if (perfil === 'cliente') { window.location.href = 'cliente-os.html'; return; }
54  if (perfil === 'superadm' || perfil === 'admin' || perfil === 'administrativo_operacional') { window.location.href = 'dashboard.html'; return; }
55  window.location.href = 'minha-fila.html';
56}
57
58function inferirPerfilFallback(usuario) {
59  const u = String(usuario || '').trim().toLowerCase();
60  if (u === 'superadm') return 'superadm';
61  if (u === 'adm01') return 'admin';
62  if (u.startsWith('cliente') || u.startsWith('cli')) return 'cliente';
63  return 'consultor';
64}
65
66function normalizarLoginValor(v) {
67  return String(v || '').trim().toLowerCase();
68}
69
70
71/* V92 - seleção de empresa na tela de login */
72function empresasFixasLoginAuthV92() {
73  if (typeof empresasFixasLoginV92 === 'function') return empresasFixasLoginV92();
74  return [
75    { id: 'LEGADO_ATUAL', codigo: 'P2P_SOLUCOES', nome: 'P2P Soluções', fixo: true, legado: true, ativo: true, dadosAtuais: true },
76    { id: 'P2P', codigo: 'P2P', nome: 'P2P', fixo: true, legado: false, ativo: true }
77  ];
78}
79function normalizarEmpresaLoginAuthV92(v) {
80  if (typeof normalizarEmpresaValorV92 === 'function') return normalizarEmpresaValorV92(v);
81  return String(v || '').trim().toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g,'').replace(/[^a-z0-9]+/g,'_').replace(/^_+|_+$/g,'');
82}
83function empresaSelecionadaLoginAuthV92() {
84  const select = document.getElementById('empresaLoginV92');
85  const fixas = empresasFixasLoginAuthV92();
86  if (select && select.value) {
87    const opt = select.options[select.selectedIndex];
88    return { id: select.value, codigo: opt?.dataset?.codigo || select.value, nome: opt?.dataset?.nome || opt?.textContent || select.value, legado: opt?.dataset?.legado === '1' };
89  }
90  if (typeof empresaLoginSelecionadaV92 === 'function') return empresaLoginSelecionadaV92();
91  return fixas[0];
92}
93function empresaDocumentoCompativelLoginAuthV92(d = {}) {
94  const emp = empresaSelecionadaLoginAuthV92();
95  if (typeof documentoPertenceEmpresaV92 === 'function') return documentoPertenceEmpresaV92(d, emp);
96  const id = String(d.empresaId || d.idEmpresa || d.empresaDocId || d.empresaCodigo || d.codigoEmpresa || '').trim();
97  const nome = String(d.empresaNome || d.nomeEmpresa || d.empresa || '').trim();
98  const alvo = normalizarEmpresaLoginAuthV92((emp && (emp.id || emp.nome)) || 'LEGADO_ATUAL');
99  if (['legado_atual','atual','empresa_atual','dados_atuais'].includes(alvo)) return !id && !nome || normalizarEmpresaLoginAuthV92(id+' '+nome).includes('legado');
100  if (!id && !nome) return false;
101  const texto = normalizarEmpresaLoginAuthV92(id + ' ' + nome);
102  return texto.includes(alvo) || alvo.includes(texto);
103}
104function aplicarEmpresaLoginNoRegistroAuthV92(registro = {}) {
105  const emp = empresaSelecionadaLoginAuthV92();
106  if (typeof salvarEmpresaLoginSelecionadaV92 === 'function') salvarEmpresaLoginSelecionadaV92(emp.id, emp.nome, emp.codigo);
107  try {
108    if (emp && emp.id) localStorage.setItem('appconsultores_empresa_atual_v92', emp.id === '*' ? '*' : JSON.stringify({ id: emp.id, codigo: emp.codigo || emp.id, nome: emp.nome || emp.id, legado: !!emp.legado }));
109  } catch (_) {}
110  if (typeof enriquecerRegistroComEmpresaLoginV92 === 'function') return enriquecerRegistroComEmpresaLoginV92(registro, emp);
111  return { ...registro, empresaId: emp.id, idEmpresa: emp.id, empresaNome: emp.nome, nomeEmpresa: emp.nome, empresa: emp.nome };
112}
113function mesclarEmpresasLoginAuthV92(lista = []) {
114  if (typeof mesclarEmpresasComFixasV92 === 'function') return mesclarEmpresasComFixasV92(lista);
115  const mapa = new Map();
116  [...empresasFixasLoginAuthV92(), ...Array.from(lista || [])].forEac
116h(e => { const id = String(e.id || e.codigo || e.nome || '').trim(); if (id && !mapa.has(normalizarEmpresaLoginAuthV92(id))) mapa.set(normalizarEmpresaLoginAuthV92(id), { id, codigo: e.codigo || id, nome: e.nome || id, ativo: e.ativo !== false, legado: !!e.legado }); });
117  return Array.from(mapa.values());
118}
119async function carregarEmpresasLoginAuthV92() {
120  const select = document.getElementById('empresaLoginV92');
121  const msg = document.getElementById('msgLogin');
122  if (!select) return;
123  let empresas = [];
124  try {
125    await ensureFirebaseAuth({ obrigatorio:false });
126    const snap = await db.collection('empresas').get();
127    empresas = snap.docs.map(doc => { const d = doc.data() || {}; return { id: doc.id, codigo: d.codigoEmpresa || d.codigo || doc.id, nome: d.nomeEmpresa || d.empresaNome || d.nome || d.razaoSocial || doc.id, ativo: d.ativo !== false, logo: d.logoEmpresaBase64 || d.empresaLogoBase64 || d.logoBase64 || d.logoEmpresa || d.empresaLogo || d.logoUrl || d.urlLogoEmpresa || '' }; }).filter(e => e.ativo !== false);
128  } catch (e) {
129    console.warn('Não foi possível carregar empresas no login. Usando empresas fixas.', e);
130    if (msg) msg.textContent = 'Empresas fixas carregadas. Para listar outras empresas, libere leitura da coleção empresas no Firestore.';
131  }
132  empresas = mesclarEmpresasLoginAuthV92(empresas);
133  const salvo = empresaSelecionadaLoginAuthV92();
134  select.innerHTML = empresas.map(e => `<option value="${escapeHtml(e.id)}" data-codigo="${escapeHtml(e.codigo || e.id)}" data-nome="${escapeHtml(e.nome || e.id)}" data-legado="${e.legado ? '1' : '0'}" data-logo="${escapeHtml(e.logo || e.logoEmpresaBase64 || '')}">${escapeHtml(e.codigo || e.id)} - ${escapeHtml(e.nome || e.id)}</option>`).join('');
135  const alvo = salvo && salvo.id ? salvo.id : 'LEGADO_ATUAL';
136  if (Array.from(select.options).some(o => o.value === alvo)) select.value = alvo;
137  select.addEventListener('change', () => {
138    const opt = select.options[select.selectedIndex];
139    if (typeof salvarEmpresaLoginSelecionadaV92 === 'function') salvarEmpresaLoginSelecionadaV92(select.value, opt?.dataset?.nome || opt?.textContent || select.value, opt?.dataset?.codigo || select.value, opt?.dataset?.logo || '');
140    if (typeof aplicarIdentidadeEmpresaV92 === 'function') aplicarIdentidadeEmpresaV92();
141  });
142  const opt = select.options[select.selectedIndex];
143  if (typeof salvarEmpresaLoginSelecionadaV92 === 'function') salvarEmpresaLoginSelecionadaV92(select.value, opt?.dataset?.nome || opt?.textContent || select.value, opt?.dataset?.codigo || select.value, opt?.dataset?.logo || '');
144  if (typeof aplicarIdentidadeEmpresaV92 === 'function') aplicarIdentidadeEmpresaV92();
145}
146
147function campoUsuario(doc) {
148  const d = doc.data();
149  return {
150    id: doc.id,
151    ...d,
152    usuarioFinal: d.usuario || d.login || d.user || d.nomeUsuario || doc.id,
153    senhaFinal: d.senha || d.password || d.senhaAcesso || d.senhaPortal || '',
154    perfilFinal: d.perfil || d.tipoPerfil || d.tipo || d.perfilAcesso || 'consultor'
155  };
156}
157
158function campoClienteLogin(doc) {
159  const d = doc.data();
160  const nome = pick(d, ['nomeCliente', 'cliente', 'nome', 'razaoSocial', 'nomeFantasia', 'descricao', 'NOME', 'nome_cliente'], doc.id);
161  const codigo = pick(d, ['codigoCliente', 'codCliente', 'codigo', 'idCliente'], doc.id);
162  return {
163    id: doc.id,
164    ...d,
165    usuarioFinal: nome,
166    senhaFinal: d.senhaCliente || d.senhaPortal || d.senhaAcesso || d.senha || d.password || '',
167    perfilFinal: 'cliente',
168    perfil: 'cliente',
169    clienteId: doc.id,
170    clienteCodigo: codigo,
171    codigoCliente: codigo,
172    codCliente: codigo,
173    clienteNome: nome,
174    nomeCliente: nome,
175    clienteDocumento: pick(d, ['cpfCnpj', 'cnpj', 'cpf', 'documento', 'cpf_cnpj', 'doc']),
176    ativo: d.ativo === false || d.status === 'Inativo' ? false : true,
177    origemLoginCliente: 'clientes'
178  };
179}
180
181async function buscarUsuarioPerfil(usuario) {
182  await ensureFirebaseAuth({ obrigatorio: false });
183  const nomes = ['usuarios', 'Usuarios', 'USUARIOS', 'perfis', 'Perfis', 'PERFIS'];
184  const tentativas = [];
185  for (const nome of nomes) {
186    try {
187      const snap = await db.collection(nome).get();
188      tentativas.push(`${nome}=${snap.size}`);
189      const lista = snap.docs.map(campoUsuario).filter(u => empresaDocumentoCompativelLoginAuthV92(u));
190      const alvo = normalizarLoginValor(usuario);
191      const encontrado = lista.find(u => normalizarLoginValor(u.usuarioFinal) === alvo || normalizarLoginValor(u.login) === alvo || normalizarLoginValor(u.id) === alvo);
192      if (encontrado) return { usuario: encontrado, origem: nome, tentativas };
193    } catch (e) {
194      console.warn('Falha ao consultar usuários/perfis:', nome, e);
195      tentativas.push(`${nome}=ERRO ${e.message || e}`);
196    }
197  }
198  return { usuario: null, origem: '', tentativas };
199}
200
201async function buscarClienteComoUsuario(usuario) {
202  await ensureFirebaseAuth({ obrigatorio: false });
203  const nomes = ['clientes', 'Clientes', 'CLIENTES', 'cliente', 'Cliente', 'cadClientes', 'cad_clientes'];
204  const alvo = normalizarLoginValor(usuario);
205  const tentativas = [];
206  for (const nome of nomes) {
207    try {
208      const snap = await db.collection(nome).get();
209      tentativas.push(`${nome}=${snap.size}`);
210      const lista = snap.docs.map(campoClienteLogin).filter(c => c.usuarioFinal).filter(c => empresaDocumentoCompativelLoginAuthV92(c));
211      const encontrado = lista.find(c => {
212        const termos = [c.usuarioFinal, c.nomeCliente, c.clienteNome, c.cliente, c.nome, c.razaoSocial, c.nomeFantasia, c.clienteCodigo, c.codigoCliente, c.codCliente, c.id]
213          .map(normalizarLoginValor)
214          .filter(Boolean);
215        return termos.some(t => t === alvo);
216      });
217      if (encontrado) return { usuario: encontrado, origem: nome, tentativas };
218    } catch (e) {
219      console.warn('Falha ao consultar clientes para login:', nome, e);
220      tentativas.push(`${nome}=ERRO ${e.message || e}`);
221    }
222  }
223  return { usuario: null, origem: '', tentativas };
224}
225
226async function entrar() {
227  const usuario = document.getElementById('usuario').value.trim();
228  const senha = document.getElementById('senha').value.trim();
229  const msg = document.getElementById('msgLogin');
230
231  if (!usuario) { msg.textContent = 'Informe o usuário.'; return; }
232  msg.textContent = 'Validando perfil ...';
233  const empresaLoginAtualV92 = empresaSelecionadaLoginAuthV92();
234  if (typeof salvarEmpresaLoginSelecionadaV92 === 'function') salvarEmpresaLoginSelecionadaV92(empresaLoginAtualV92.id, empresaLoginAtualV92.nome, empresaLoginAtualV92.codigo);
235
236  try {
237    const result = await buscarUsuarioPerfil(usuario);
238    let registro = result.usuario;
239    if (registro) { registro._origemLoginColecao = result.origem || 'usuarios'; registro._origemLoginTipo = 'usuarios'; }
240    if (normalizarLoginValor(usuario) === 'superadm' && String(senha) === '197512') {
241      registro = { ...(registro || {}), id: 'SUPERADM', usuarioFinal: 'SUPERADM', usuario: 'SUPERADM', login: 'SUPERADM', senhaFinal: '197512', perfilFinal: 'superadm', perfil: 'superadm', grupo: 'SUPERADM', ativo: true, _loginEmergenciaSuperAdm: true, _origemLoginColecao: 'usuarios' };
242      try {
243        await db.collection('usuarios').doc('SUPERADM').set({
244          usuario: 'SUPERADM', login: 'SUPERADM', senha: '197512', perfil: 'superadm', grupo: 'SUPERADM', ativo: true,
245          acessoTotal: true, acessoFinanceiro: true, senhaAlteradaPrimeiroAcesso: true, primeiroAcessoConcluido: true,
246          origemSistema: 'AppConsultoresWebOS', atualizadoEm: firebase.firestore.FieldValue.serverTimestamp()
247        }, { merge: true });
248      } catch (e) { console.warn('Não foi possível gravar usuário SUPERADM automaticamente:', e); }
249    }
250
251    if (!registro && normalizarLoginValor(usuario) === 'superadm' && String(senha) === '197512') {
252      registro = { id: 'SUPERADM', usuarioFinal: 'SUPERADM', usuario: 'SUPERADM', login: 'SUPERADM', senhaFinal: '197512', perfilFinal: 'superadm', perfil: 'superadm', grupo: 'SUPERADM', ativo: true, _loginEmergenciaSuperAdm: true, _origemLoginColecao: 'emergencia' };
253      try {
254        await db.collection('usuarios').doc('SUPERADM').set({
255          usuario: 'SUPERADM', login: 'SUPERADM', senha: '197512', perfil: 'superadm', grupo: 'SUPERADM', ativo: true,
256          acessoTotal: true, acessoFinanceiro: true, senhaAlteradaPrimeiroAcesso: true, primeiroAcessoConcluido: true,
257          origemSistema: 'AppConsultoresWebOS', atualizadoEm: firebase.firestore.FieldValue.serverTimestamp()
258        }, { merge: true });
259      } catch (e) { console.warn('Não foi possível gravar usuário SUPERADM automaticamente:', e); }
260    }
261
262    if (!registro && normalizarLoginValor(usuario) === 'adm01' && empresaDocumentoCompativelLoginAuthV92({})) {
263      registro = { id: 'Adm01', usuarioFinal: 'Adm01', usuario: 'Adm01', perfilFinal: 'admin', perfil: 'admin', grupo: 'Administradores', ativo: true, _loginEmergenciaAdm01: true, _origemLoginColecao: 'emergencia' };
264    }
265
266    if (!registro) {
267      msg.textContent = 'Perfil não localizado em usuários. Tentando localizar cliente pelo próprio nome...';
268      const clienteResult = await buscarClienteComoUsuario(usuario);
269      registro = clienteResult.usuario;
270      if (registro) { registro._origemLoginColecao = clienteResult.origem || 'clientes'; registro._origemLoginTipo = 'clientes'; }
271      if (registro && !registro.senhaFinal) {
272        msg.textContent = 'Cliente localizado, mas sem senha cadastrada. Entre como Adm01 e cadastre uma senha no perfil do cliente ou no cadastro do cliente.';
273        return;
274      }
275    }
276
277    if (!registro) {
278      msg.textContent = 'Usuário/perfil não cadastrado. Para cliente, use o nome do cliente e senha cadastrada. Para demais usuários, entre como Adm01 e cadastre em Perfis.';
279      return;
280    }
281
282    if (registro.ativo === false || registro.status === 'Inativo') {
283      msg.textContent = 'Usuário/perfil inativo.';
284      return;
285    }
286
287    if (registro.senhaFinal && String(registro.senhaFinal) !== senha) {
288      msg.textContent = 'Senha inválida.';
289      return;
290    }
291
292    if (!registro.senhaFinal && !['admin','superadm'].includes(normalizarPerfilNomeSeguro(registro.perfilFinal))) {
293      msg.textContent = 'Senha não cadastrada para este usuário. Cadastre uma senha em Perfis.';
294      return;
295    }
296
297    registro = aplicarEmpresaLoginNoRegistroAuthV92(registro);
298    const perfil = normalizarPerfilNomeSeguro(registro.perfilFinal);
299    const forcarTrocaSenha = deveTrocarSenhaPrimeiroAcesso(registro, perfil);
300    registro.trocaSenhaPendente = forcarTrocaSenha;
301    salvarSessaoUsuario(registro.usuarioFinal || usuario, perfil, registro);
302    try {
303      if (typeof registrarAuditoriaPortalV106 === 'function') {
304        await registrarAuditoriaPortalV106('login_sucesso', 'Login do Portal', {
305          perfil: perfil,
306          origemLogin: registro._origemLoginColecao || registro._origemLoginTipo || '',
307          empresaSelecionada: empresaLoginAtualV92 || null
308        });
309      }
310    } catch (e) { console.warn('Auditoria de login V106 não registrada:', e); }
311
312    if (forcarTrocaSenha) {
313      if (typeof marcarTrocaSenhaPendente === 'function') marcarTrocaSenhaPendente(registro);
314      msg.textContent = 'Primeiro acesso identificado. Altere sua senha para continuar.';
315      window.location.href = 'alterar-senha.html';
316      return;
317    }
318
319    if (typeof limparTrocaSenhaPendente === 'function') limparTrocaSenhaPendente();
320    try {
321      if (perfil === 'admin' || perfil === 'superadm') sessionStorage.setItem('mostrarAniversariantesAdminV67', '1');
322      if (perfil === 'consultor') sessionStorage.setItem('mostrarPopupChamadosConsultorV83', '1');
323    } catch (_) {}
324    redirecionarPorPerfil(perfil);
325  } catch (error) {
326    console.error(error);
327    msg.textContent = 'Erro ao validar login: ' + mensagemErroFirebase(error);
328  }
329}
330
331document.addEventListener('DOMContentLoaded', carregarEmpresasLoginAuthV92);
332document.getElementById('btnEntrar').addEventListener('click', entrar);
333document.addEventListener('keydown', (event) => { if (event.key === 'Enter') entrar(); });

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.