Boas práticas
Nada de conselho genérico aqui. Esta página é a lista do que já quebrou.
Menção é texto puro
O Concord não tem <@47>. Menção é literalmente o texto @usuario, @everyone, @todos,
@aqui, @here.
Parece detalhe de formatação. É um buraco de segurança.
Se o seu bot ecoa qualquer texto que veio de fora — o título de um vídeo, o nome de uma música, o
resultado de uma busca, o corpo de uma issue — ele pode estar publicando um @everyone escrito por
um estranho. Quem pagou a conta foi o servidor inteiro, de madrugada.
Higienize tudo que você não escreveu, antes de publicar:
// U+FF20 (@, fullwidth) se parece com @ e não aciona menção nenhuma.
const sanitizeMention = (texto: string) => texto.replace(/@/g, '@');
await client.chat(canal, `tocando: ${sanitizeMention(faixa.titulo)}`);
Apagar o @ também funciona. O que não funciona é confiar que "esse texto é inofensivo".
O bot recebe as próprias mensagens
O servidor reemite cada chat para todo mundo do canal, inclusive para quem mandou. Um bot que
responde a toda mensagem responde a si mesmo, para sempre.
client.on('messageCreate', (msg) => {
if (msg.from === client.user.id) return; // a primeira linha, sempre
…
});
state substitui, não soma
O state é a foto inteira do que você vê, e chega de novo a cada mudança. Troque o seu estado por
ele. Mesclar produz canal fantasma e membro duplicado — e a sua lógica começa a agir sobre coisas
que não existem mais.
Ninguém dá o que não tem
Pedir todas as permissões no link de convite não faz o bot receber todas: o que é concedido é
pedido & permissões_de_quem_autoriza, e Administrador só o dono entrega.
O efeito real de pedir demais é a tela de autorização ficar assustadora e a pessoa desistir. Peça o que você usa. Para a maioria dos bots de chat: ver canais, enviar mensagens, reagir.
Não guarde permissão em cache
Cargo muda, canal muda, a pessoa sai do servidor. Leia a permissão do state mais recente no
momento de agir, não do que você guardou quando conectou.
E lembre: a checagem que vale é a do servidor. A do seu lado serve para dar uma mensagem melhor, não para proteger nada.
Reconectar é parte do trabalho
A conexão cai: deploy, rede, reinício. Reconecte com espera crescente (1s, 2s, 4s… com um teto) e nunca em laço apertado — um bot que reconecta sem pausa vira um ataque ao próprio servidor.
A vaga na voz é guardada por 20 segundos. Voltando dentro disso, o welcome traz room
preenchido e não é preciso mandar join de novo.
O token é a aplicação inteira
- Variável de ambiente. Nunca no repositório, nunca em log, nunca numa mensagem de erro.
- Vazou? Gere outro no portal: o antigo morre na hora.
- Em
git, um token comitado continua no histórico depois de "apagado". Gerar outro é o único conserto de verdade.
Se o bot vai buscar coisas na internet
Bot de música, bot que lê link, bot que faz preview — todos aceitam uma URL de quem usa o chat. Isso é um pedido feito pelo seu servidor, com a rede dele. É SSRF esperando acontecer.
O que aprendemos escrevendo o Tocadiscos:
- Lista de permitidos, não lista de proibidos. Bloquear
127.0.0.1e169.254.169.254não resolve: sobram[::ffff:7f00:1],100.64.0.1,0x7f.1e o DNS que resolve para interno. - Normalize antes de comparar.
http://youtube.com\@127.0.0.1/é lido como hostyoutube.compor um analisador e127.0.0.1por outro. Passe peloURLe compare ohostnameresultante — nunca a string original. - Prenda a ferramenta de fora também. Passar a URL para um programa auxiliar (
yt-dlp, por exemplo) devolve a ele a liberdade que você acabou de tirar. Restrinja o que ele aceita, e tire o extrator genérico da lista.
Erro é mensagem, não silêncio
Quando o bot não consegue fazer o que pediram — sem permissão, link inválido, serviço fora —, diga no canal. Bot que falha em silêncio parece bot quebrado, e a pessoa tenta de novo, e de novo.
Mensagem curta, sem stack trace, sem o nome de variável interna. "Não consigo entrar nessa sala:
me falta permissão de voz" resolve; Error: ECONNREFUSED não.