diff --git a/src/bot/handler.js b/src/bot/handler.js index dc60467..da3205a 100644 --- a/src/bot/handler.js +++ b/src/bot/handler.js @@ -1276,18 +1276,27 @@ Digite /help para ver todos os comandos disponíveis! .catch(e => logger.warn(`[GenieACS] Falha ao sincronizar TAG: ${e.message}`)); } + // Escapa caracteres especiais do Markdown em textos livres (vindos de + // sistemas externos/erros) para evitar "can't parse entities" do Telegram + // quando o texto contém um número ímpar de _, *, ` ou [ (ex: nomes de OLT + // como "AN5516-06_172.16.10.6"). + const escMd = (v) => { + if (v === null || v === undefined || v === '') return ''; + return String(v).replace(/[_*`\[]/g, '\\$&'); + }; + // Montar relatório let msg = `🩺 *Diagnóstico do Cliente*\n`; msg += `━━━━━━━━━━━━━━━━━━━━━\n\n`; // Bloco 1: TopSapp msg += `📋 *Serviço TopSapp*\n`; - msg += ` 📦 Plano: ${nomePlano}\n`; - msg += ` 🔌 Status: ${statusServico}\n`; + msg += ` 📦 Plano: ${escMd(nomePlano)}\n`; + msg += ` 🔌 Status: ${escMd(statusServico)}\n`; if (pppoeLogin) msg += ` 👤 Login PPPoE: \`${pppoeLogin}\`\n`; if (servico.dhcp_username) msg += ` 👤 DHCP Username: \`${servico.dhcp_username}\`\n`; if (circuitId) msg += ` 🔗 Circuit\-ID: \`${circuitId}\`\n`; - if (endereco) msg += ` 📍 Endereço: ${endereco}${cidade ? `, ${cidade}` : ''}\n`; + if (endereco) msg += ` 📍 Endereço: ${escMd(endereco)}${cidade ? `, ${escMd(cidade)}` : ''}\n`; msg += '\n'; // Bloco 2: Concentrador Juniper @@ -1295,7 +1304,7 @@ Digite /help para ver todos os comandos disponíveis! if (juniperResult.skipped && !circuitId) { msg += ` ⚫ Login PPPoE/Circuit\-ID não informado no cadastro\n`; } else if (!juniperResult.success) { - msg += ` ⚠️ Erro ao consultar: ${juniperResult.error || 'falha na consulta'}\n`; + msg += ` ⚠️ Erro ao consultar: ${escMd(juniperResult.error) || 'falha na consulta'}\n`; } else if (juniperResult.connected) { const modoAuth = juniperResult.viaCircuitId ? 'IPoE/Circuit\-ID' : 'PPPoE'; msg += ` 🟢 *Conectado* (${modoAuth})\n`; @@ -1311,7 +1320,7 @@ Digite /help para ver todos os comandos disponíveis! if (onuResult.skipped) { msg += ` ⚫ Serial não informado no cadastro\n`; } else if (!onuResult.success) { - msg += ` ❌ ${onuResult.error || 'ONU não encontrada'}\n`; + msg += ` ❌ ${escMd(onuResult.error) || 'ONU não encontrada'}\n`; if (serial) msg += ` 📋 Serial buscado: \`${serial}\`\n`; } else { const rxLabel = onuResult.rxPower || 'N/A'; @@ -1319,19 +1328,19 @@ Digite /help para ver todos os comandos disponíveis! const rxEmoji = isNaN(rxNum) ? '⚫' : rxNum >= -27 ? '🟢' : rxNum >= -30 ? '🟡' : '🔴'; msg += ` 📋 Serial: \`${serial}\`\n`; - msg += ` 🏢 OLT: ${onuResult.oltName || onuResult.oltType || 'N/A'}\n`; + msg += ` 🏢 OLT: ${escMd(onuResult.oltName || onuResult.oltType) || 'N/A'}\n`; if (onuResult.slot || onuResult.pon) { - msg += ` 📍 Slot/PON: ${onuResult.slot || '?'}/${onuResult.pon || '?'}\n`; + msg += ` 📍 Slot/PON: ${escMd(onuResult.slot) || '?'}/${escMd(onuResult.pon) || '?'}\n`; } msg += ` 🔌 Estado: ${onuResult.online ? '🟢 Online' : '🔴 Offline'}\n`; if (onuResult.uptime) { - msg += ` ⏱️ Uptime: ${onuResult.uptime}\n`; + msg += ` ⏱️ Uptime: ${escMd(onuResult.uptime)}\n`; } - msg += ` ${rxEmoji} Rx Power: *${rxLabel}*\n`; + msg += ` ${rxEmoji} Rx Power: *${escMd(rxLabel)}*\n`; if (onuResult.portaEthernet) { const ethOk = /forward|up|active|1gbit|100mbit/i.test(onuResult.portaEthernet); - msg += ` ${ethOk ? '🟢' : '🔴'} Porta Ethernet: ${onuResult.portaEthernet}\n`; + msg += ` ${ethOk ? '🟢' : '🔴'} Porta Ethernet: ${escMd(onuResult.portaEthernet)}\n`; } }