366 lines
7.9 KiB
Markdown
366 lines
7.9 KiB
Markdown
# 🔒 Sistema de Seguridad para Comandos Administrativos
|
|
|
|
## Descripción
|
|
|
|
Sistema de permisos para restringir comandos sensibles a:
|
|
- **Guild de Testing** (variable `guildTest` en `.env`)
|
|
- **Usuarios Autorizados** (whitelist por ID)
|
|
- **Administradores del Servidor**
|
|
- **Dueño del Bot**
|
|
|
|
---
|
|
|
|
## 📦 Instalación
|
|
|
|
El módulo está en: `src/core/lib/security.ts`
|
|
|
|
```typescript
|
|
import {
|
|
requireTestGuild,
|
|
requireTestGuildAndAdmin,
|
|
requireAuthorizedUser,
|
|
withTestGuild,
|
|
withTestGuildAndAdmin
|
|
} from "@/core/lib/security";
|
|
```
|
|
|
|
---
|
|
|
|
## ⚙️ Configuración en `.env`
|
|
|
|
```env
|
|
# Guild de testing (requerido)
|
|
guildTest=123456789012345678
|
|
|
|
# Dueño del bot (opcional)
|
|
OWNER_ID=987654321098765432
|
|
|
|
# Whitelist de usuarios autorizados (opcional, separados por comas)
|
|
AUTHORIZED_USER_IDS=111111111111111111,222222222222222222
|
|
```
|
|
|
|
---
|
|
|
|
## 🛡️ Funciones Disponibles
|
|
|
|
### 1. `requireTestGuild(source)`
|
|
Verifica que el comando se ejecute solo en el guild de testing.
|
|
|
|
```typescript
|
|
import { requireTestGuild } from "@/core/lib/security";
|
|
|
|
export const command: CommandSlash = {
|
|
name: "debug",
|
|
description: "Comandos de debug",
|
|
type: "slash",
|
|
run: async (interaction, client) => {
|
|
// Bloquea si no es guild de testing
|
|
if (!await requireTestGuild(interaction)) {
|
|
return; // Ya respondió al usuario automáticamente
|
|
}
|
|
|
|
// Tu código aquí (solo se ejecuta en guild de testing)
|
|
await interaction.reply("🐛 Debug activado");
|
|
}
|
|
};
|
|
```
|
|
|
|
**Respuesta automática si falla:**
|
|
```
|
|
🔒 Este comando solo está disponible en el servidor de testing.
|
|
```
|
|
|
|
---
|
|
|
|
### 2. `requireTestGuildAndAdmin(source)`
|
|
Requiere **guild de testing** Y **permisos de administrador**.
|
|
|
|
```typescript
|
|
import { requireTestGuildAndAdmin } from "@/core/lib/security";
|
|
|
|
export const command: CommandSlash = {
|
|
name: "featureflags",
|
|
description: "Gestión de feature flags",
|
|
type: "slash",
|
|
run: async (interaction, client) => {
|
|
// Bloquea si no es guild de testing O no es admin
|
|
if (!await requireTestGuildAndAdmin(interaction)) {
|
|
return;
|
|
}
|
|
|
|
// Tu código aquí (solo admins en guild de testing)
|
|
await interaction.reply("⚙️ Configuración de flags");
|
|
}
|
|
};
|
|
```
|
|
|
|
**Respuestas automáticas:**
|
|
- Si no es guild de testing: `🔒 Este comando solo está disponible en el servidor de testing.`
|
|
- Si no es admin: `🔒 Este comando requiere permisos de administrador.`
|
|
|
|
---
|
|
|
|
### 3. `requireAuthorizedUser(source)`
|
|
Requiere que el usuario esté en la whitelist de `AUTHORIZED_USER_IDS`.
|
|
|
|
```typescript
|
|
import { requireAuthorizedUser } from "@/core/lib/security";
|
|
|
|
export const command: CommandSlash = {
|
|
name: "shutdown",
|
|
description: "Apagar el bot",
|
|
type: "slash",
|
|
run: async (interaction, client) => {
|
|
// Solo usuarios autorizados
|
|
if (!await requireAuthorizedUser(interaction)) {
|
|
return;
|
|
}
|
|
|
|
await interaction.reply("🛑 Apagando bot...");
|
|
process.exit(0);
|
|
}
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
### 4. `withTestGuild(command)` - Wrapper
|
|
Envuelve todo el comando para restringirlo al guild de testing.
|
|
|
|
```typescript
|
|
import { withTestGuild } from "@/core/lib/security";
|
|
import { CommandSlash } from "@/core/types/commands";
|
|
|
|
const debugCommand: CommandSlash = {
|
|
name: "debug",
|
|
description: "Debug tools",
|
|
type: "slash",
|
|
run: async (interaction, client) => {
|
|
await interaction.reply("🐛 Debug mode");
|
|
}
|
|
};
|
|
|
|
// Exportar con wrapper de seguridad
|
|
export const command = withTestGuild(debugCommand);
|
|
```
|
|
|
|
---
|
|
|
|
### 5. `withTestGuildAndAdmin(command)` - Wrapper
|
|
Envuelve el comando para requerir guild de testing + admin.
|
|
|
|
```typescript
|
|
import { withTestGuildAndAdmin } from "@/core/lib/security";
|
|
|
|
const adminCommand: CommandSlash = {
|
|
name: "config",
|
|
description: "Configuración",
|
|
type: "slash",
|
|
run: async (interaction, client) => {
|
|
await interaction.reply("⚙️ Configuración");
|
|
}
|
|
};
|
|
|
|
export const command = withTestGuildAndAdmin(adminCommand);
|
|
```
|
|
|
|
---
|
|
|
|
## 🎯 Funciones Auxiliares
|
|
|
|
### `isTestGuild(source)`
|
|
Retorna `true` si es el guild de testing (no responde automáticamente).
|
|
|
|
```typescript
|
|
if (isTestGuild(interaction)) {
|
|
console.log("Estamos en guild de testing");
|
|
}
|
|
```
|
|
|
|
### `isGuildAdmin(member)`
|
|
Retorna `true` si el miembro tiene permisos de administrador.
|
|
|
|
```typescript
|
|
const member = interaction.member as GuildMember;
|
|
if (isGuildAdmin(member)) {
|
|
console.log("Usuario es admin");
|
|
}
|
|
```
|
|
|
|
### `isBotOwner(userId)`
|
|
Retorna `true` si el userId coincide con `OWNER_ID` en `.env`.
|
|
|
|
```typescript
|
|
if (isBotOwner(interaction.user.id)) {
|
|
console.log("Es el dueño del bot");
|
|
}
|
|
```
|
|
|
|
### `isAuthorizedUser(userId)`
|
|
Retorna `true` si está en la whitelist o es el dueño.
|
|
|
|
```typescript
|
|
if (isAuthorizedUser(interaction.user.id)) {
|
|
console.log("Usuario autorizado");
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 📊 Ejemplo Real: Comando Feature Flags
|
|
|
|
```typescript
|
|
import { requireTestGuildAndAdmin } from "@/core/lib/security";
|
|
import { CommandSlash } from "@/core/types/commands";
|
|
|
|
export const command: CommandSlash = {
|
|
name: "featureflags",
|
|
description: "Administra feature flags del bot",
|
|
type: "slash",
|
|
cooldown: 5,
|
|
options: [
|
|
{
|
|
name: "list",
|
|
description: "Lista todos los flags",
|
|
type: 1,
|
|
},
|
|
{
|
|
name: "create",
|
|
description: "Crea un nuevo flag",
|
|
type: 1,
|
|
options: [
|
|
{ name: "name", description: "Nombre del flag", type: 3, required: true },
|
|
{ name: "status", description: "Estado", type: 3, required: true },
|
|
],
|
|
},
|
|
],
|
|
run: async (interaction) => {
|
|
// 🔒 SECURITY: Solo guild de testing + admin
|
|
if (!await requireTestGuildAndAdmin(interaction)) {
|
|
return;
|
|
}
|
|
|
|
const subcommand = interaction.options.getSubcommand();
|
|
|
|
switch (subcommand) {
|
|
case "list":
|
|
await interaction.reply("📋 Listando flags...");
|
|
break;
|
|
case "create":
|
|
const name = interaction.options.getString("name", true);
|
|
await interaction.reply(`✅ Flag "${name}" creado`);
|
|
break;
|
|
}
|
|
},
|
|
};
|
|
```
|
|
|
|
---
|
|
|
|
## 🔐 Niveles de Seguridad
|
|
|
|
| Función | Guild Test | Admin | Whitelist | Owner |
|
|
|---------|------------|-------|-----------|-------|
|
|
| `requireTestGuild` | ✅ | ❌ | ❌ | ❌ |
|
|
| `requireTestGuildAndAdmin` | ✅ | ✅ | ❌ | Auto-admin |
|
|
| `requireAuthorizedUser` | ❌ | ❌ | ✅ | ✅ |
|
|
|
|
---
|
|
|
|
## 🚨 Logs de Seguridad
|
|
|
|
Cuando un comando es bloqueado, se registra en los logs:
|
|
|
|
```json
|
|
{
|
|
"level": "warn",
|
|
"msg": "[Security] Comando bloqueado - no es guild de testing",
|
|
"guildId": "123456789",
|
|
"userId": "987654321"
|
|
}
|
|
```
|
|
|
|
```json
|
|
{
|
|
"level": "warn",
|
|
"msg": "[Security] Comando bloqueado - sin permisos de admin",
|
|
"guildId": "123456789",
|
|
"userId": "987654321"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## ✅ Checklist de Implementación
|
|
|
|
1. **Configurar `.env`:**
|
|
```env
|
|
guildTest=TU_GUILD_ID_AQUI
|
|
OWNER_ID=TU_USER_ID_AQUI
|
|
```
|
|
|
|
2. **Importar el guard:**
|
|
```typescript
|
|
import { requireTestGuildAndAdmin } from "@/core/lib/security";
|
|
```
|
|
|
|
3. **Aplicar al comando:**
|
|
```typescript
|
|
run: async (interaction) => {
|
|
if (!await requireTestGuildAndAdmin(interaction)) {
|
|
return;
|
|
}
|
|
// Tu código...
|
|
}
|
|
```
|
|
|
|
4. **Reiniciar el bot:**
|
|
```bash
|
|
pm2 restart amayo
|
|
```
|
|
|
|
5. **Probar en Discord:**
|
|
- En guild de testing con admin → ✅ Funciona
|
|
- En otro guild → ❌ Bloqueado
|
|
- En guild de testing sin admin → ❌ Bloqueado
|
|
|
|
---
|
|
|
|
## 🎮 Casos de Uso
|
|
|
|
### Comando de Testing
|
|
```typescript
|
|
export const command = withTestGuild({
|
|
name: "test",
|
|
run: async (interaction) => {
|
|
await interaction.reply("🧪 Test mode");
|
|
}
|
|
});
|
|
```
|
|
|
|
### Comando Admin
|
|
```typescript
|
|
export const command = withTestGuildAndAdmin({
|
|
name: "config",
|
|
run: async (interaction) => {
|
|
await interaction.reply("⚙️ Configuración");
|
|
}
|
|
});
|
|
```
|
|
|
|
### Comando Ultra-Sensible
|
|
```typescript
|
|
run: async (interaction) => {
|
|
if (!await requireAuthorizedUser(interaction)) {
|
|
return;
|
|
}
|
|
// Solo usuarios whitelisteados
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
**Fecha:** 2025-10-31
|
|
**Archivo:** `src/core/lib/security.ts`
|
|
**Estado:** ✅ Implementado y probado
|