Pular para o conteúdo principal

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.1 e 169.254.169.254 não resolve: sobram [::ffff:7f00:1], 100.64.0.1, 0x7f.1 e o DNS que resolve para interno.
  • Normalize antes de comparar. http://youtube.com\@127.0.0.1/ é lido como host youtube.com por um analisador e 127.0.0.1 por outro. Passe pelo URL e compare o hostname resultante — 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.