AeThex-Bot-Master/aethex-bot/commands/federation.js
sirpiglr 76cad00dd9 Enhance bot with federation protection and new command features
Introduces federation protection listener, expands federation commands, adds federation API endpoints to web server, and updates bot status to 'Protecting the Federation'.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: aed2e46d-25bb-4b73-81a1-bb9e8437c261
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
Replit-Commit-Event-Id: d254ee4b-e69e-44a5-b1be-b89c088a485a
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/3bdfff67-975a-46ad-9845-fbb6b4a4c4b5/aed2e46d-25bb-4b73-81a1-bb9e8437c261/FUs0R2K
Replit-Helium-Checkpoint-Created: true
2025-12-10 01:41:25 +00:00

696 lines
26 KiB
JavaScript

const { SlashCommandBuilder, EmbedBuilder, PermissionFlagsBits, ActionRowBuilder, ButtonBuilder, ButtonStyle } = require('discord.js');
const { getServerMode, EMBED_COLORS } = require('../utils/modeHelper');
module.exports = {
data: new SlashCommandBuilder()
.setName('federation')
.setDescription('AeThex Federation - Global protection & cross-server network')
.addSubcommandGroup(group =>
group
.setName('roles')
.setDescription('Manage cross-server role synchronization')
.addSubcommand(sub => sub.setName('link').setDescription('Link a role for cross-server sync')
.addRoleOption(opt => opt.setName('role').setDescription('Role to sync').setRequired(true)))
.addSubcommand(sub => sub.setName('unlink').setDescription('Remove a role from sync')
.addRoleOption(opt => opt.setName('role').setDescription('Role to remove').setRequired(true)))
.addSubcommand(sub => sub.setName('list').setDescription('List all linked roles'))
)
.addSubcommandGroup(group =>
group
.setName('bans')
.setDescription('Global Ban List - Protect the network')
.addSubcommand(sub => sub.setName('add').setDescription('Add user to global ban list')
.addUserOption(opt => opt.setName('user').setDescription('User to ban').setRequired(true))
.addStringOption(opt => opt.setName('reason').setDescription('Reason for ban').setRequired(true))
.addStringOption(opt => opt.setName('severity').setDescription('Severity level')
.addChoices(
{ name: 'Low - Minor offense', value: 'low' },
{ name: 'Medium - Moderate offense', value: 'medium' },
{ name: 'High - Serious offense', value: 'high' },
{ name: 'Critical - Nuker/Scammer', value: 'critical' }
)))
.addSubcommand(sub => sub.setName('lookup').setDescription('Check if user is on global ban list')
.addUserOption(opt => opt.setName('user').setDescription('User to lookup').setRequired(true)))
.addSubcommand(sub => sub.setName('list').setDescription('View recent global bans'))
.addSubcommand(sub => sub.setName('remove').setDescription('Remove user from global ban list')
.addUserOption(opt => opt.setName('user').setDescription('User to remove').setRequired(true)))
)
.addSubcommandGroup(group =>
group
.setName('servers')
.setDescription('Federation Server Directory')
.addSubcommand(sub => sub.setName('directory').setDescription('Browse all federation servers'))
.addSubcommand(sub => sub.setName('info').setDescription('View a specific server')
.addStringOption(opt => opt.setName('server').setDescription('Server name or ID').setRequired(true)))
.addSubcommand(sub => sub.setName('featured').setDescription('View featured servers'))
)
.addSubcommandGroup(group =>
group
.setName('membership')
.setDescription('Join or manage federation membership')
.addSubcommand(sub => sub.setName('apply').setDescription('Apply to join the federation')
.addStringOption(opt => opt.setName('category').setDescription('Server category')
.addChoices(
{ name: 'Gaming', value: 'gaming' },
{ name: 'Creative', value: 'creative' },
{ name: 'Development', value: 'development' },
{ name: 'Education', value: 'education' },
{ name: 'Community', value: 'community' },
{ name: 'Business', value: 'business' }
).setRequired(true))
.addStringOption(opt => opt.setName('description').setDescription('Brief description of your server').setRequired(true)))
.addSubcommand(sub => sub.setName('status').setDescription('Check your server\'s federation status'))
.addSubcommand(sub => sub.setName('treaty').setDescription('View the Federation Treaty'))
)
.addSubcommandGroup(group =>
group
.setName('scouts')
.setDescription('Talent Scout - Cross-server reputation')
.addSubcommand(sub => sub.setName('leaderboard').setDescription('View global reputation leaderboard'))
.addSubcommand(sub => sub.setName('profile').setDescription('View cross-server profile')
.addUserOption(opt => opt.setName('user').setDescription('User to lookup')))
),
async execute(interaction, supabase, client) {
const mode = await getServerMode(supabase, interaction.guildId);
const group = interaction.options.getSubcommandGroup();
const subcommand = interaction.options.getSubcommand();
if (mode === 'standalone' && group !== 'membership') {
const embed = new EmbedBuilder()
.setColor(EMBED_COLORS.standalone)
.setTitle('Standalone Mode')
.setDescription('Federation features are disabled in standalone mode.\n\nUse `/federation membership apply` to join the network, or `/config mode` to switch to federated mode.');
return interaction.reply({ embeds: [embed], ephemeral: true });
}
if (group === 'roles') {
await handleRoles(interaction, supabase, client, subcommand);
} else if (group === 'bans') {
await handleBans(interaction, supabase, client, subcommand);
} else if (group === 'servers') {
await handleServers(interaction, supabase, client, subcommand);
} else if (group === 'membership') {
await handleMembership(interaction, supabase, client, subcommand);
} else if (group === 'scouts') {
await handleScouts(interaction, supabase, client, subcommand);
}
},
};
async function handleRoles(interaction, supabase, client, subcommand) {
if (subcommand === 'link') {
if (!interaction.member.permissions.has(PermissionFlagsBits.ManageRoles)) {
return interaction.reply({ content: 'You need Manage Roles permission.', ephemeral: true });
}
const role = interaction.options.getRole('role');
const mappingData = {
name: role.name,
guildId: interaction.guildId,
guildName: interaction.guild.name,
linkedAt: Date.now(),
};
client.federationMappings.set(role.id, mappingData);
if (client.saveFederationMapping) {
await client.saveFederationMapping(role.id, mappingData);
}
const embed = new EmbedBuilder()
.setColor(0x00ff00)
.setTitle('Role Linked')
.setDescription(`${role} is now linked for federation sync.`)
.addFields(
{ name: 'Role ID', value: role.id, inline: true },
{ name: 'Server', value: interaction.guild.name, inline: true }
)
.setTimestamp();
await interaction.reply({ embeds: [embed] });
}
if (subcommand === 'unlink') {
if (!interaction.member.permissions.has(PermissionFlagsBits.ManageRoles)) {
return interaction.reply({ content: 'You need Manage Roles permission.', ephemeral: true });
}
const role = interaction.options.getRole('role');
if (client.federationMappings.has(role.id)) {
client.federationMappings.delete(role.id);
if (client.deleteFederationMapping) {
await client.deleteFederationMapping(role.id);
}
const embed = new EmbedBuilder()
.setColor(0xff6600)
.setTitle('Role Unlinked')
.setDescription(`${role} has been removed from federation sync.`)
.setTimestamp();
await interaction.reply({ embeds: [embed] });
} else {
await interaction.reply({ content: `${role} is not currently linked.`, ephemeral: true });
}
}
if (subcommand === 'list') {
const mappings = [...client.federationMappings.entries()];
if (mappings.length === 0) {
const embed = new EmbedBuilder()
.setColor(0x7c3aed)
.setTitle('Federation Roles')
.setDescription('No roles are currently linked.\nUse `/federation roles link` to add roles.')
.setTimestamp();
return interaction.reply({ embeds: [embed] });
}
const roleList = mappings.map(([roleId, data]) =>
`<@&${roleId}> - ${data.guildName}`
).join('\n');
const embed = new EmbedBuilder()
.setColor(0x7c3aed)
.setTitle('Federation Roles')
.setDescription(roleList)
.setFooter({ text: `${mappings.length} role(s) linked` })
.setTimestamp();
await interaction.reply({ embeds: [embed] });
}
}
async function handleBans(interaction, supabase, client, subcommand) {
if (!supabase) {
return interaction.reply({ content: 'Database not available.', ephemeral: true });
}
if (subcommand === 'add') {
if (!interaction.member.permissions.has(PermissionFlagsBits.BanMembers)) {
return interaction.reply({ content: 'You need Ban Members permission.', ephemeral: true });
}
const user = interaction.options.getUser('user');
const reason = interaction.options.getString('reason');
const severity = interaction.options.getString('severity') || 'medium';
const { data: existing } = await supabase
.from('federation_bans')
.select('id')
.eq('user_id', user.id)
.eq('active', true)
.maybeSingle();
if (existing) {
return interaction.reply({ content: `${user.tag} is already on the global ban list.`, ephemeral: true });
}
const { error } = await supabase.from('federation_bans').insert({
user_id: user.id,
username: user.tag,
reason,
severity,
banned_by_guild_id: interaction.guildId,
banned_by_user_id: interaction.user.id,
});
if (error) {
console.error('Federation ban error:', error);
return interaction.reply({ content: 'Failed to add ban.', ephemeral: true });
}
const severityColors = { low: 0xffff00, medium: 0xff9900, high: 0xff3300, critical: 0xff0000 };
const severityEmojis = { low: '⚠️', medium: '🔶', high: '🔴', critical: '☠️' };
const embed = new EmbedBuilder()
.setColor(severityColors[severity])
.setTitle(`${severityEmojis[severity]} Global Ban Added`)
.setThumbnail(user.displayAvatarURL())
.addFields(
{ name: 'User', value: `${user.tag}\n\`${user.id}\``, inline: true },
{ name: 'Severity', value: severity.toUpperCase(), inline: true },
{ name: 'Reason', value: reason }
)
.setFooter({ text: `Added by ${interaction.user.tag}` })
.setTimestamp();
await interaction.reply({ embeds: [embed] });
await createBanAlerts(supabase, client, user.id, severity);
}
if (subcommand === 'lookup') {
const user = interaction.options.getUser('user');
const { data: ban } = await supabase
.from('federation_bans')
.select('*')
.eq('user_id', user.id)
.eq('active', true)
.maybeSingle();
if (!ban) {
const embed = new EmbedBuilder()
.setColor(0x00ff00)
.setTitle('User Clear')
.setThumbnail(user.displayAvatarURL())
.setDescription(`${user.tag} is **not** on the global ban list.`)
.setTimestamp();
return interaction.reply({ embeds: [embed] });
}
const severityColors = { low: 0xffff00, medium: 0xff9900, high: 0xff3300, critical: 0xff0000 };
const embed = new EmbedBuilder()
.setColor(severityColors[ban.severity])
.setTitle('User Flagged')
.setThumbnail(user.displayAvatarURL())
.addFields(
{ name: 'User', value: `${user.tag}\n\`${user.id}\``, inline: true },
{ name: 'Severity', value: ban.severity.toUpperCase(), inline: true },
{ name: 'Reason', value: ban.reason },
{ name: 'Banned On', value: new Date(ban.created_at).toLocaleDateString(), inline: true }
)
.setTimestamp();
await interaction.reply({ embeds: [embed] });
}
if (subcommand === 'list') {
const { data: bans } = await supabase
.from('federation_bans')
.select('*')
.eq('active', true)
.order('created_at', { ascending: false })
.limit(10);
if (!bans || bans.length === 0) {
return interaction.reply({ content: 'No active global bans.', ephemeral: true });
}
const severityEmojis = { low: '⚠️', medium: '🔶', high: '🔴', critical: '☠️' };
const banList = bans.map(b =>
`${severityEmojis[b.severity]} **${b.username || b.user_id}** - ${b.reason.substring(0, 50)}${b.reason.length > 50 ? '...' : ''}`
).join('\n');
const embed = new EmbedBuilder()
.setColor(0xff0000)
.setTitle('Global Ban List')
.setDescription(banList)
.setFooter({ text: `Showing ${bans.length} most recent bans` })
.setTimestamp();
await interaction.reply({ embeds: [embed] });
}
if (subcommand === 'remove') {
if (!interaction.member.permissions.has(PermissionFlagsBits.Administrator)) {
return interaction.reply({ content: 'You need Administrator permission.', ephemeral: true });
}
const user = interaction.options.getUser('user');
const { error } = await supabase
.from('federation_bans')
.update({ active: false, updated_at: new Date().toISOString() })
.eq('user_id', user.id)
.eq('active', true);
if (error) {
return interaction.reply({ content: 'Failed to remove ban.', ephemeral: true });
}
const embed = new EmbedBuilder()
.setColor(0x00ff00)
.setTitle('Ban Removed')
.setDescription(`${user.tag} has been removed from the global ban list.`)
.setTimestamp();
await interaction.reply({ embeds: [embed] });
}
}
async function handleServers(interaction, supabase, client, subcommand) {
if (!supabase) {
return interaction.reply({ content: 'Database not available.', ephemeral: true });
}
if (subcommand === 'directory') {
const { data: servers } = await supabase
.from('federation_servers')
.select('*')
.eq('status', 'approved')
.order('member_count', { ascending: false })
.limit(15);
if (!servers || servers.length === 0) {
const embed = new EmbedBuilder()
.setColor(0x7c3aed)
.setTitle('Federation Directory')
.setDescription('No servers in the federation yet.\nUse `/federation membership apply` to be the first!')
.setTimestamp();
return interaction.reply({ embeds: [embed] });
}
const categoryEmojis = { gaming: '🎮', creative: '🎨', development: '💻', education: '📚', community: '👥', business: '🏢' };
const serverList = servers.map((s, i) => {
const emoji = categoryEmojis[s.category] || '🌐';
const featured = s.featured ? '⭐' : '';
return `${i + 1}. ${emoji} **${s.guild_name}** ${featured}\n ${s.member_count?.toLocaleString() || '?'} members • ${s.category || 'general'}`;
}).join('\n\n');
const embed = new EmbedBuilder()
.setColor(0x7c3aed)
.setTitle('Federation Directory')
.setDescription(serverList)
.setFooter({ text: `${servers.length} servers in the federation` })
.setTimestamp();
await interaction.reply({ embeds: [embed] });
}
if (subcommand === 'info') {
const serverQuery = interaction.options.getString('server');
const { data: server } = await supabase
.from('federation_servers')
.select('*')
.or(`guild_id.eq.${serverQuery},guild_name.ilike.%${serverQuery}%`)
.eq('status', 'approved')
.maybeSingle();
if (!server) {
return interaction.reply({ content: 'Server not found in the federation.', ephemeral: true });
}
const embed = new EmbedBuilder()
.setColor(0x7c3aed)
.setTitle(server.guild_name)
.setDescription(server.description || 'No description provided.')
.addFields(
{ name: 'Members', value: server.member_count?.toLocaleString() || 'Unknown', inline: true },
{ name: 'Category', value: server.category || 'General', inline: true },
{ name: 'Tier', value: server.tier?.toUpperCase() || 'FREE', inline: true },
{ name: 'Joined Federation', value: new Date(server.joined_at).toLocaleDateString(), inline: true }
)
.setTimestamp();
if (server.guild_icon) {
embed.setThumbnail(`https://cdn.discordapp.com/icons/${server.guild_id}/${server.guild_icon}.png`);
}
await interaction.reply({ embeds: [embed] });
}
if (subcommand === 'featured') {
const { data: featured } = await supabase
.from('federation_servers')
.select('*')
.eq('featured', true)
.eq('status', 'approved');
if (!featured || featured.length === 0) {
return interaction.reply({ content: 'No featured servers at this time.', ephemeral: true });
}
const serverList = featured.map(s =>
`⭐ **${s.guild_name}**\n${s.description?.substring(0, 100) || 'No description'}${s.description?.length > 100 ? '...' : ''}`
).join('\n\n');
const embed = new EmbedBuilder()
.setColor(0xffd700)
.setTitle('Featured Servers')
.setDescription(serverList)
.setTimestamp();
await interaction.reply({ embeds: [embed] });
}
}
async function handleMembership(interaction, supabase, client, subcommand) {
if (!supabase) {
return interaction.reply({ content: 'Database not available.', ephemeral: true });
}
if (subcommand === 'apply') {
if (!interaction.member.permissions.has(PermissionFlagsBits.Administrator)) {
return interaction.reply({ content: 'Only administrators can apply to the federation.', ephemeral: true });
}
const { data: existing } = await supabase
.from('federation_servers')
.select('status')
.eq('guild_id', interaction.guildId)
.maybeSingle();
if (existing) {
return interaction.reply({ content: `Your server is already ${existing.status} in the federation.`, ephemeral: true });
}
const { data: pendingApp } = await supabase
.from('federation_applications')
.select('status')
.eq('guild_id', interaction.guildId)
.maybeSingle();
if (pendingApp) {
return interaction.reply({ content: `Application already ${pendingApp.status}. Use /federation membership status to check.`, ephemeral: true });
}
const category = interaction.options.getString('category');
const description = interaction.options.getString('description');
const { error } = await supabase.from('federation_applications').insert({
guild_id: interaction.guildId,
guild_name: interaction.guild.name,
guild_icon: interaction.guild.icon,
member_count: interaction.guild.memberCount,
category,
description,
admin_id: interaction.user.id,
admin_username: interaction.user.tag,
treaty_agreed: true,
});
if (error) {
console.error('Federation application error:', error);
return interaction.reply({ content: 'Failed to submit application.', ephemeral: true });
}
const embed = new EmbedBuilder()
.setColor(0x00ff00)
.setTitle('Application Submitted')
.setDescription('Your server has been submitted for federation membership!')
.addFields(
{ name: 'Server', value: interaction.guild.name, inline: true },
{ name: 'Category', value: category, inline: true },
{ name: 'Status', value: 'Pending Review', inline: true }
)
.setFooter({ text: 'You will be notified when your application is reviewed.' })
.setTimestamp();
await interaction.reply({ embeds: [embed] });
}
if (subcommand === 'status') {
const { data: server } = await supabase
.from('federation_servers')
.select('*')
.eq('guild_id', interaction.guildId)
.maybeSingle();
if (server) {
const embed = new EmbedBuilder()
.setColor(0x00ff00)
.setTitle('Federation Member')
.addFields(
{ name: 'Status', value: server.status.toUpperCase(), inline: true },
{ name: 'Tier', value: server.tier?.toUpperCase() || 'FREE', inline: true },
{ name: 'Joined', value: new Date(server.joined_at).toLocaleDateString(), inline: true }
)
.setTimestamp();
return interaction.reply({ embeds: [embed] });
}
const { data: application } = await supabase
.from('federation_applications')
.select('*')
.eq('guild_id', interaction.guildId)
.maybeSingle();
if (application) {
const statusColors = { pending: 0xffff00, approved: 0x00ff00, rejected: 0xff0000 };
const embed = new EmbedBuilder()
.setColor(statusColors[application.status] || 0x7c3aed)
.setTitle('Application Status')
.addFields(
{ name: 'Status', value: application.status.toUpperCase(), inline: true },
{ name: 'Submitted', value: new Date(application.created_at).toLocaleDateString(), inline: true }
)
.setTimestamp();
if (application.rejection_reason) {
embed.addFields({ name: 'Reason', value: application.rejection_reason });
}
return interaction.reply({ embeds: [embed] });
}
const embed = new EmbedBuilder()
.setColor(0x7c3aed)
.setTitle('Not a Member')
.setDescription('This server is not in the federation.\nUse `/federation membership apply` to join!')
.setTimestamp();
await interaction.reply({ embeds: [embed] });
}
if (subcommand === 'treaty') {
const embed = new EmbedBuilder()
.setColor(0x7c3aed)
.setTitle('The AeThex Federation Treaty')
.setDescription('By joining the Federation, your server agrees to:')
.addFields(
{ name: '1. Contribute to Global Safety', value: 'Report nukers, scammers, and bad actors to the Global Ban List.' },
{ name: '2. Maintain Standards', value: 'Uphold basic moderation and community guidelines.' },
{ name: '3. Respect the Network', value: 'Do not exploit federation features or share protected data.' },
{ name: '4. Display Membership', value: 'Optionally display Federation badge to verify authenticity.' }
)
.setFooter({ text: 'Together, we are untouchable.' })
.setTimestamp();
const row = new ActionRowBuilder()
.addComponents(
new ButtonBuilder()
.setCustomId('federation_agree_treaty')
.setLabel('I Agree')
.setStyle(ButtonStyle.Success),
new ButtonBuilder()
.setLabel('Learn More')
.setStyle(ButtonStyle.Link)
.setURL('https://aethex.dev/federation')
);
await interaction.reply({ embeds: [embed], components: [row] });
}
}
async function handleScouts(interaction, supabase, client, subcommand) {
if (!supabase) {
return interaction.reply({ content: 'Database not available.', ephemeral: true });
}
if (subcommand === 'leaderboard') {
const { data: leaders } = await supabase
.from('federation_reputation')
.select('*')
.order('reputation_score', { ascending: false })
.limit(15);
if (!leaders || leaders.length === 0) {
const embed = new EmbedBuilder()
.setColor(0x7c3aed)
.setTitle('Federation Leaderboard')
.setDescription('No reputation data yet. Be active across federation servers to appear here!')
.setTimestamp();
return interaction.reply({ embeds: [embed] });
}
const tierEmojis = { newcomer: '🌱', member: '⭐', veteran: '🏆', elite: '💎', legend: '👑' };
const leaderList = leaders.map((l, i) => {
const emoji = tierEmojis[l.rank_tier] || '🌱';
const medal = i === 0 ? '🥇' : i === 1 ? '🥈' : i === 2 ? '🥉' : `${i + 1}.`;
return `${medal} ${emoji} <@${l.discord_id}> - **${l.reputation_score?.toLocaleString() || 0}** rep`;
}).join('\n');
const embed = new EmbedBuilder()
.setColor(0xffd700)
.setTitle('Federation Leaderboard')
.setDescription(leaderList)
.setFooter({ text: 'Reputation earned across all federation servers' })
.setTimestamp();
await interaction.reply({ embeds: [embed] });
}
if (subcommand === 'profile') {
const user = interaction.options.getUser('user') || interaction.user;
const { data: rep } = await supabase
.from('federation_reputation')
.select('*')
.eq('discord_id', user.id)
.maybeSingle();
if (!rep) {
const embed = new EmbedBuilder()
.setColor(0x7c3aed)
.setTitle('No Federation Profile')
.setDescription(`${user.tag} doesn't have a federation profile yet.\nBe active across federation servers to build reputation!`)
.setTimestamp();
return interaction.reply({ embeds: [embed] });
}
const tierEmojis = { newcomer: '🌱', member: '⭐', veteran: '🏆', elite: '💎', legend: '👑' };
const embed = new EmbedBuilder()
.setColor(0x7c3aed)
.setTitle(`${user.tag}'s Federation Profile`)
.setThumbnail(user.displayAvatarURL())
.addFields(
{ name: 'Reputation', value: rep.reputation_score?.toLocaleString() || '0', inline: true },
{ name: 'Rank', value: `${tierEmojis[rep.rank_tier] || '🌱'} ${rep.rank_tier?.toUpperCase() || 'NEWCOMER'}`, inline: true },
{ name: 'Active In', value: `${rep.servers_active_in || 0} servers`, inline: true },
{ name: 'Total XP', value: rep.total_xp?.toLocaleString() || '0', inline: true },
{ name: 'Highest Level', value: `${rep.highest_level || 0}`, inline: true },
{ name: 'Prestige', value: `${rep.prestige_total || 0}`, inline: true }
)
.setFooter({ text: `Last active: ${rep.last_active ? new Date(rep.last_active).toLocaleDateString() : 'Unknown'}` })
.setTimestamp();
if (rep.badges && rep.badges.length > 0) {
embed.addFields({ name: 'Badges', value: rep.badges.join(' ') });
}
await interaction.reply({ embeds: [embed] });
}
}
async function createBanAlerts(supabase, client, userId, severity) {
try {
const { data: servers } = await supabase
.from('federation_servers')
.select('guild_id, tier')
.eq('status', 'approved');
if (!servers) return;
const alerts = servers
.filter(s => severity === 'critical' || s.tier === 'premium')
.map(s => ({
guild_id: s.guild_id,
alert_type: 'new_ban',
}));
if (alerts.length > 0) {
const { data: ban } = await supabase
.from('federation_bans')
.select('id')
.eq('user_id', userId)
.eq('active', true)
.maybeSingle();
if (ban) {
const alertsWithBanId = alerts.map(a => ({ ...a, ban_id: ban.id }));
await supabase.from('federation_alerts').insert(alertsWithBanId);
}
}
} catch (err) {
console.error('Error creating ban alerts:', err);
}
}