Permissões
Permissão no Concord é um inteiro de 23 bits. Cada bit é uma autorização; o valor inteiro é o
conjunto. O SDK espelha exatamente os bits de hub::perm do servidor — se um dia divergirem, o
servidor está certo.
A tabela
| Bit | Nome | Decimal | Autoriza |
|---|---|---|---|
1 << 0 | ADMIN | 1 | Tudo. Implica todos os outros bits |
1 << 1 | MANAGE_SERVER | 2 | Editar nome, descrição, banner, categoria, verificação |
1 << 2 | MANAGE_CHANNELS | 4 | Criar, editar e apagar canais |
1 << 3 | MANAGE_ROLES | 8 | Criar, editar e apagar cargos; atribuir cargos |
1 << 4 | KICK | 16 | Expulsar do servidor (pode voltar com convite) |
1 << 5 | BAN | 32 | Banir e desbanir |
1 << 6 | MANAGE_MESSAGES | 64 | Apagar e fixar mensagem de outra pessoa |
1 << 7 | CREATE_INVITE | 128 | Gerar convite |
1 << 8 | MENTION_EVERYONE | 256 | Usar @everyone, @todos, @aqui, @here |
1 << 9 | SEND_MESSAGES | 512 | Escrever em canal de texto |
1 << 10 | ATTACH_FILES | 1024 | Anexar arquivo |
1 << 11 | CREATE_THREADS | 2048 | Abrir tópico |
1 << 12 | ADD_REACTIONS | 4096 | Reagir |
1 << 13 | CONNECT | 8192 | Entrar em canal de voz |
1 << 14 | SPEAK | 16384 | Publicar microfone |
1 << 15 | VIDEO | 32768 | Publicar câmera e tela |
1 << 16 | MUTE_MEMBERS | 65536 | Silenciar e desconectar da voz |
1 << 17 | VIEW_AUDIT | 131072 | Ler o log de auditoria |
1 << 18 | CREATE_ROOMS | 262144 | Criar sala temporária de voz |
1 << 19 | VIEW_CHANNEL | 524288 | Ver o canal |
1 << 20 | MANAGE_EVENTS | 1048576 | Criar e editar eventos |
1 << 21 | MODERATE_MEMBERS | 2097152 | Moderar membros |
1 << 22 | MANAGE_APPS | 4194304 | Instalar e revogar bots no servidor |
Duas constantes derivadas:
| Constante | Valor | O que é |
|---|---|---|
ALL_PERMISSIONS | 8388607 | (1 << 23) - 1, todos os bits |
EVERYONE_DEFAULT_PERMISSIONS | 327552 | O que o @everyone recebe num servidor novo |
O padrão do @everyone é CREATE_INVITE | MENTION_EVERYONE | SEND_MESSAGES | ATTACH_FILES | CREATE_THREADS | ADD_REACTIONS | CONNECT | SPEAK | VIDEO | CREATE_ROOMS — ou seja, participar
plenamente, sem moderar nada.
Como o servidor resolve
A ordem importa, e é exatamente esta — a mesma de hub::perms_of:
- É o dono do servidor? Então tudo, e para aqui.
- Não é membro? Então zero, e para aqui.
- Senão:
everyone_perms | VIEW_CHANNEL | (soma das permissões dos cargos). - Deu
ADMINno passo 3? Então tudo.
Dois detalhes que surpreendem:
VIEW_CHANNELé dado a todo membro, independentemente de cargo. Visibilidade de canal no Concord não é negada por bit.- Não existe permissão negativa. Cargos somam, nunca subtraem. Se um bit precisa ser tirado de
alguém, ele não pode estar no
@everyonenem em nenhum cargo da pessoa.
Checando
A forma curta
import { PermissionFlags } from 'concord.js';
if (!member.hasPermission(PermissionFlags.BAN)) return;
Vários bits de uma vez — exige todos:
if (!member.hasPermission([PermissionFlags.CONNECT, PermissionFlags.SPEAK])) return;
O nome em texto também resolve, o que deixa a leitura mais limpa:
if (!member.hasPermission(['MANAGE_MESSAGES'])) return;
As minhas, as de alguém, as do canal
// As minhas, resolvidas pelo próprio servidor (`my_perms` do snapshot).
const minhas = server.myPermissions;
// De qualquer membro, resolvidas localmente com a mesma regra do servidor.
const dele = server.permissionsFor(userId);
// Neste canal. Hoje vêm de `my_perms`: o Concord não tem override por canal.
const aqui = channel.permissions;
A classe Permissions
import { Permissions, PermissionFlags } from 'concord.js';
const p = new Permissions(PermissionFlags.SEND_MESSAGES | PermissionFlags.ADD_REACTIONS);
p.has(PermissionFlags.SEND_MESSAGES); // true
p.has(PermissionFlags.BAN); // false
p.toArray(); // ['SEND_MESSAGES', 'ADD_REACTIONS']
p.missing([PermissionFlags.BAN, PermissionFlags.KICK]); // ['BAN', 'KICK']
p.add(PermissionFlags.BAN).bits; // novo Permissions, imutável
Number(p); // o inteiro, via valueOf()
checkAdminhas() considera ADMIN como "tem tudo", porque é assim que o servidor decide. Para perguntar
pelo bit literal — ao desenhar uma tela de edição de cargo, por exemplo — passe
{ checkAdmin: false }.
missing dá a mensagem de erro
Em vez de dizer "sem permissão", diga qual falta:
const faltando = new Permissions(ctx.member!.permissions.bits)
.missing([PermissionFlags.MANAGE_MESSAGES, PermissionFlags.VIEW_AUDIT]);
if (faltando.length) {
await ctx.reply(`Faltam estas permissões: ${faltando.join(', ')}`);
return;
}
No decorator
O caminho mais curto é não checar no corpo do método:
@SlashCommand({
name: 'banir',
description: 'Bane alguém do servidor',
options: [{ name: 'quem', description: 'A pessoa', type: 'user', required: true }],
permissions: [PermissionFlags.BAN],
})
async banir(@Ctx() [ctx]: SlashCommandContext, @Opt('quem') quem: User) {
await ctx.server!.ban(quem.id, 'pedido por comando');
}
Os permissions do decorator checam quem chamou. As permissões do bot são outra coisa — e
o servidor as checa de todo jeito, devolvendo um frame error que o SDK transforma em
GatewayError.
Resolvendo na mão
Para calcular permissão fora de um Member — num cache próprio, ou para simular:
import { resolveMemberPermissions, Permissions } from 'concord.js';
const bits = resolveMemberPermissions({
ownerId: server.ownerId,
userId: 7,
memberIds: server.members.map((m) => m.id),
everyonePerms: server.everyonePermissions.bits,
roles: server.roles.toArray().map((r) => r.raw),
memberRoleIds: [3, 5],
});
new Permissions(bits).toArray();
A função segue a ordem do servidor, incluindo os casos de dono e de não-membro.
O que o bot precisa
Um mínimo útil por tipo de bot:
| Bot | Bits |
|---|---|
| Só responde no chat | VIEW_CHANNEL, SEND_MESSAGES |
| Reage e abre tópico | + ADD_REACTIONS, CREATE_THREADS |
| Manda arquivo | + ATTACH_FILES |
| Música | + CONNECT, SPEAK |
| Câmera ou tela | + VIDEO |
| Moderação | + MANAGE_MESSAGES, KICK, BAN, MODERATE_MEMBERS |
Em decimal, o cargo de um bot de música seria
VIEW_CHANNEL | SEND_MESSAGES | ADD_REACTIONS | CONNECT | SPEAK = 553472.
ADMIN ao botADMIN é 1 bit e vale 23. Um bot com ADMIN que seja comprometido — ou que tenha um comando com
bug — apaga canais. Dê exatamente os bits da tabela acima.