AeThex-Bot-Master/sentinel-bot/src/modules/federation/FederationManager.ts
sirpiglr fbd203dcfc Add Aethex Sentinel bot with security and federation features
Initializes the Aethex Sentinel bot project, including package.json, Prisma schema, core client, configuration, health server, and event listeners for audit logs and member updates. Implements commands for federation management, sentinel security status, and ticket system.

Replit-Commit-Author: Agent
Replit-Commit-Session-Id: e72fc1b7-94bd-4d6c-801f-cbac2fae245c
Replit-Commit-Checkpoint-Type: intermediate_checkpoint
Replit-Commit-Event-Id: fc082e4d-cb52-4049-9c2e-69ba6c2e78d4
Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/3bdfff67-975a-46ad-9845-fbb6b4a4c4b5/e72fc1b7-94bd-4d6c-801f-cbac2fae245c/jW8PJKQ
Replit-Helium-Checkpoint-Created: true
2025-12-07 21:10:57 +00:00

124 lines
4.1 KiB
TypeScript

import { Guild, GuildMember, Role } from 'discord.js';
import { prisma } from '../../core/client';
import { config } from '../../core/config';
interface RoleMapping {
sourceGuild: string;
sourceRole: string;
targetGuild: string;
targetRole: string;
roleName: string;
}
export class FederationManager {
private roleMappings: RoleMapping[] = [];
async loadMappings(): Promise<void> {
this.roleMappings = await prisma.roleMapping.findMany();
console.log(`📋 Loaded ${this.roleMappings.length} role mappings`);
}
async addMapping(mapping: Omit<RoleMapping, 'id'>): Promise<void> {
await prisma.roleMapping.create({
data: mapping,
});
await this.loadMappings();
}
async syncRoleGrant(member: GuildMember, role: Role): Promise<void> {
const sourceGuildId = member.guild.id;
const mappings = this.roleMappings.filter(
m => m.sourceGuild === sourceGuildId && m.sourceRole === role.id
);
if (mappings.length === 0) return;
console.log(`🔄 Syncing role "${role.name}" for ${member.user.tag} to ${mappings.length} guild(s)`);
for (const mapping of mappings) {
try {
const targetGuild = member.client.guilds.cache.get(mapping.targetGuild);
if (!targetGuild) {
console.warn(`⚠️ Target guild ${mapping.targetGuild} not found`);
continue;
}
const targetMember = await targetGuild.members.fetch(member.id).catch(() => null);
if (!targetMember) {
console.warn(`⚠️ User ${member.user.tag} not in target guild ${targetGuild.name}`);
continue;
}
const targetRole = targetGuild.roles.cache.get(mapping.targetRole);
if (!targetRole) {
console.warn(`⚠️ Target role ${mapping.targetRole} not found in ${targetGuild.name}`);
continue;
}
if (!targetMember.roles.cache.has(targetRole.id)) {
await targetMember.roles.add(targetRole, `Federation sync from ${member.guild.name}`);
console.log(`✅ Granted "${targetRole.name}" to ${member.user.tag} in ${targetGuild.name}`);
}
} catch (error) {
console.error(`❌ Failed to sync role to guild ${mapping.targetGuild}:`, error);
}
}
await this.updateUserRoles(member.id);
}
async syncRoleRemove(member: GuildMember, role: Role): Promise<void> {
const sourceGuildId = member.guild.id;
const mappings = this.roleMappings.filter(
m => m.sourceGuild === sourceGuildId && m.sourceRole === role.id
);
if (mappings.length === 0) return;
console.log(`🔄 Removing synced role "${role.name}" for ${member.user.tag} from ${mappings.length} guild(s)`);
for (const mapping of mappings) {
try {
const targetGuild = member.client.guilds.cache.get(mapping.targetGuild);
if (!targetGuild) continue;
const targetMember = await targetGuild.members.fetch(member.id).catch(() => null);
if (!targetMember) continue;
const targetRole = targetGuild.roles.cache.get(mapping.targetRole);
if (!targetRole) continue;
if (targetMember.roles.cache.has(targetRole.id)) {
await targetMember.roles.remove(targetRole, `Federation sync removal from ${member.guild.name}`);
console.log(`✅ Removed "${targetRole.name}" from ${member.user.tag} in ${targetGuild.name}`);
}
} catch (error) {
console.error(`❌ Failed to remove synced role:`, error);
}
}
await this.updateUserRoles(member.id);
}
private async updateUserRoles(userId: string): Promise<void> {
const syncedRoles = this.roleMappings
.filter(m => m.sourceGuild === config.guilds.hub)
.map(m => m.roleName);
await prisma.user.upsert({
where: { id: userId },
update: { roles: syncedRoles },
create: { id: userId, roles: syncedRoles },
});
}
getGuildType(guildId: string): string | null {
const entries = Object.entries(config.guilds);
const found = entries.find(([, id]) => id === guildId);
return found ? found[0] : null;
}
}
export const federationManager = new FederationManager();