import express from 'express'; import axios from 'axios'; import { TelegramUseLog } from '../lib/all.js'; import { Database } from '../database/database.js'; import { authenticateApiKey, apiLimiter } from '../middleware/midware.js'; import { Federation } from '../models.js'; const FedsRoutes = express.Router(); const dbClient = new Database("AkenoXJs"); const db = dbClient.collection("api_keys"); async function updateIP(apiKey, newIP) { await db.updateOne( { key: apiKey }, { $addToSet: { ip_addresses: newIP } } ); } /** * @swagger * /api/v2/federation/newfed: * post: * summary: Create a new federation * tags: [Federation] * description: Creates a new federation with a unique name and owner. * security: * - apiKeyAuth: [] * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * name: * type: string * description: The unique name of the federation. * owner: * type: integer * description: The user ID of the federation owner. * parameters: * - in: header * name: x-api-key * required: true * description: API key for authentication. * schema: * type: string * responses: * 200: * description: Federation created successfully. * content: * application/json: * schema: * type: object * properties: * message: * type: string * example: Federation created successfully * federation: * type: object * properties: * name: * type: string * owner: * type: integer * banned_users: * type: array * items: * type: integer * sub_federations: * type: array * items: * type: string * 400: * description: Federation already exists or missing parameters. * 500: * description: Internal server error. */ FedsRoutes.post("/api/v2/federation/newfed", authenticateApiKey, apiLimiter, async (req, res) => { try { const apiKey = req.headers['x-api-key']; const userAgent = req.headers['user-agent']; const xForwardedFor = req.headers['x-forwarded-for']; const xRealIP = req.headers['x-real-ip']; const cfConnectingIP = req.headers['cf-connecting-ip']; let realIP = req.ip; if (xForwardedFor) { realIP = xForwardedFor.split(',')[0].trim(); } else if (xRealIP) { realIP = xRealIP; } else if (cfConnectingIP) { realIP = cfConnectingIP; } req.realIP = realIP; console.log(`🔍 Captured IPs:`, { xForwardedFor, xRealIP, cfConnectingIP, realIP }); const keyDoc = await db.findOne({ key: apiKey }); if (!keyDoc) { return res.status(403).json({ error: "Invalid API Key." }); } const { name, owner } = req.body; const existing = await Federation.findOne({ name }); if (existing) return res.status(200).json({ error: "Federation already exists" }); await updateIP(apiKey, realIP); await TelegramUseLog( keyDoc.owner, keyDoc.key, `Accessed: ${req.path}\nRealIP: ${realIP}\nUser-Agent: ${userAgent}` ); const federation = new Federation({ name, owner, banned_users: [], sub_federations: [] }); await federation.save(); res.json({ message: "Federation created successfully", federation }); } catch (err) { console.log(err.message); res.status(500).json({ error: err.message }); } }); /** * @swagger * /api/v2/federation/subfed: * post: * summary: Add a sub-federation * tags: [Federation] * description: Adds a federation as a sub-federation under a parent federation. * security: * - apiKeyAuth: [] * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * parent_uuid: * type: string * description: UUID of the parent federation. * child_uuid: * type: string * description: UUID of the child federation to be added as a sub-federation. * parameters: * - in: header * name: x-api-key * required: true * description: API key for authentication. * schema: * type: string * responses: * 200: * description: Sub-federation added successfully. * content: * application/json: * schema: * type: object * properties: * message: * type: string * example: "Federation ChildName is now a sub-federation of ParentName" * 404: * description: Parent or child federation not found. * 500: * description: Internal server error. */ FedsRoutes.post("/api/v2/federation/subfed", authenticateApiKey, apiLimiter, async (req, res) => { try { const apiKey = req.headers['x-api-key']; const userAgent = req.headers['user-agent']; const xForwardedFor = req.headers['x-forwarded-for']; const xRealIP = req.headers['x-real-ip']; const cfConnectingIP = req.headers['cf-connecting-ip']; let realIP = req.ip; if (xForwardedFor) { realIP = xForwardedFor.split(',')[0].trim(); } else if (xRealIP) { realIP = xRealIP; } else if (cfConnectingIP) { realIP = cfConnectingIP; } req.realIP = realIP; console.log(`🔍 Captured IPs:`, { xForwardedFor, xRealIP, cfConnectingIP, realIP }); const keyDoc = await db.findOne({ key: apiKey }); if (!keyDoc) { return res.status(403).json({ error: "Invalid API Key." }); } const { parent_uuid, child_uuid } = req.body; const parent = await Federation.findOne({ uuid: parent_uuid }); const child = await Federation.findOne({ uuid: child_uuid }); if (!parent || !child) return res.status(404).json({ error: "Federation not found" }); if (!parent.sub_federations.includes(child.uuid)) { parent.sub_federations.push(child.uuid); await parent.save(); } await updateIP(apiKey, realIP); await TelegramUseLog( keyDoc.owner, keyDoc.key, `Accessed: ${req.path}\nRealIP: ${realIP}\nUser-Agent: ${userAgent}` ); res.json({ message: `Federation ${child.name} is now a sub-federation of ${parent.name}` }); } catch (err) { res.status(500).json({ error: err.message }); } }); /** * @swagger * /api/v2/federation/getfed/{uuid}: * get: * summary: Check Federation Info * tags: [Federation] * parameters: * - in: path * name: uuid * required: true * description: Check uuid to info * schema: * type: string * - in: header * name: x-api-key * required: true * description: API key for authentication * schema: * type: string * responses: * 200: * description: Returns */ FedsRoutes.get("/api/v2/federation/getfed/:uuid", authenticateApiKey, apiLimiter, async (req, res) => { try { const apiKey = req.headers['x-api-key']; const userAgent = req.headers['user-agent']; const xForwardedFor = req.headers['x-forwarded-for']; const xRealIP = req.headers['x-real-ip']; const cfConnectingIP = req.headers['cf-connecting-ip']; let realIP = req.ip; if (xForwardedFor) { realIP = xForwardedFor.split(',')[0].trim(); } else if (xRealIP) { realIP = xRealIP; } else if (cfConnectingIP) { realIP = cfConnectingIP; } req.realIP = realIP; console.log(`🔍 Captured IPs:`, { xForwardedFor, xRealIP, cfConnectingIP, realIP }); const keyDoc = await db.findOne({ key: apiKey }); if (!keyDoc) { return res.status(403).json({ error: "Invalid API Key." }); } const federation = await Federation.findOne({ uuid: req.params.uuid }); if (!federation) return res.status(404).json({ error: "Federation not found" }); const subFeds = await Federation.find({ uuid: { $in: federation.sub_federations } }); await updateIP(apiKey, realIP); await TelegramUseLog( keyDoc.owner, keyDoc.key, `Accessed: ${req.path}\nRealIP: ${realIP}\nUser-Agent: ${userAgent}` ); res.json({ federation, sub_federations: subFeds }); } catch (err) { res.status(500).json({ error: err.message }); } }); /** * @swagger * /api/v2/federation/unban: * post: * summary: Unban a user in a federation * tags: [Federation] * description: Removes a user from the banned list of a specified federation. * security: * - apiKeyAuth: [] * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * name: * type: string * description: Name of the federation where the user will be unbanned. * user_id: * type: integer * description: User ID to be unbanned. * parameters: * - in: header * name: x-api-key * required: true * description: API key for authentication. * schema: * type: string * responses: * 200: * description: User unbanned successfully. * content: * application/json: * schema: * type: object * properties: * success: * type: boolean * example: true * message: * type: string * example: "User 12345 unbanned from federation FederationName." * 400: * description: Missing federation name or user ID. * 404: * description: Federation not found. * 500: * description: Internal server error. */ FedsRoutes.post('/api/v2/federation/unban', authenticateApiKey, async (req, res) => { try { const apiKey = req.headers['x-api-key']; const userAgent = req.headers['user-agent']; const xForwardedFor = req.headers['x-forwarded-for']; const xRealIP = req.headers['x-real-ip']; const cfConnectingIP = req.headers['cf-connecting-ip']; let realIP = req.ip; if (xForwardedFor) { realIP = xForwardedFor.split(',')[0].trim(); } else if (xRealIP) { realIP = xRealIP; } else if (cfConnectingIP) { realIP = cfConnectingIP; } req.realIP = realIP; console.log(`🔍 Captured IPs:`, { xForwardedFor, xRealIP, cfConnectingIP, realIP }); const keyDoc = await db.findOne({ key: apiKey }); if (!keyDoc) { return res.status(403).json({ error: "Invalid API Key." }); } const { name, user_id } = req.body; if (!name || !user_id || isNaN(user_id)) { return res.status(400).json({ error: "Federation name and valid user ID required" }); } const federation = await Federation.findOne({ name }); if (!federation) { return res.status(404).json({ error: "Federation not found." }); } federation.banned_users = federation.banned_users.filter(id => Number(id) !== Number(user_id)); await federation.save(); await Federation.updateMany( { uuid: { $in: federation.sub_federations } }, { $pull: { banned_users: Number(user_id) } } ); await updateIP(apiKey, realIP); await TelegramUseLog( keyDoc.owner, keyDoc.key, `Accessed: ${req.path}\nRealIP: ${realIP}\nUser-Agent: ${userAgent}` ); res.json({ success: true, message: `User ${user_id} unbanned from ${name} and its sub-federations.` }); } catch (error) { res.status(500).json({ error: `Failed to unban user: ${error.message}` }); } }); /** * @swagger * /api/v2/federation/ban: * post: * summary: Ban a user in a federation * tags: [Federation] * description: Bans a user in the specified federation and all its sub-federations. * security: * - apiKeyAuth: [] * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * federation_uuid: * type: string * description: UUID of the federation where the user will be banned. * user_id: * type: integer * description: User ID to be banned. * parameters: * - in: header * name: x-api-key * required: true * description: API key for authentication. * schema: * type: string * responses: * 200: * description: User banned successfully. * content: * application/json: * schema: * type: object * properties: * message: * type: string * example: "User 12345 banned in FederationName and all its sub-federations" * 404: * description: Federation not found. * 500: * description: Internal server error. */ FedsRoutes.post("/api/v2/federation/ban", authenticateApiKey, apiLimiter, async (req, res) => { try { const apiKey = req.headers['x-api-key']; const userAgent = req.headers['user-agent']; const xForwardedFor = req.headers['x-forwarded-for']; const xRealIP = req.headers['x-real-ip']; const cfConnectingIP = req.headers['cf-connecting-ip']; let realIP = req.ip; if (xForwardedFor) { realIP = xForwardedFor.split(',')[0].trim(); } else if (xRealIP) { realIP = xRealIP; } else if (cfConnectingIP) { realIP = cfConnectingIP; } req.realIP = realIP; console.log(`🔍 Captured IPs:`, { xForwardedFor, xRealIP, cfConnectingIP, realIP }); const keyDoc = await db.findOne({ key: apiKey }); if (!keyDoc) { return res.status(403).json({ error: "Invalid API Key." }); } const { federation_uuid, user_id } = req.body; if (!federation_uuid || !user_id || isNaN(user_id)) { return res.status(400).json({ error: "Federation UUID and valid user ID required" }); } const federation = await Federation.findOne({ uuid: federation_uuid }); if (!federation) return res.status(404).json({ error: "Federation not found" }); if (!federation.banned_users.includes(Number(user_id))) { federation.banned_users.push(Number(user_id)); await federation.save(); } await Federation.updateMany( { uuid: { $in: federation.sub_federations } }, { $addToSet: { banned_users: Number(user_id) } } ); await updateIP(apiKey, realIP); await TelegramUseLog( keyDoc.owner, keyDoc.key, `Accessed: ${req.path}\nRealIP: ${realIP}\nUser-Agent: ${userAgent}` ); res.json({ message: `User ${user_id} banned in ${federation.name} and all its sub-federations.` }); console.log(user_id); } catch (err) { res.status(500).json({ error: err.message }); } }); /** * @swagger * /api/v2/federation/ban-check: * post: * summary: Check if a user is banned in a federation * tags: [Federation] * description: Checks whether a user is banned in a specific federation using UUID and user ID. * security: * - apiKeyAuth: [] * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * federation_uuid: * type: string * description: UUID of the federation. * user_id: * type: integer * description: User ID to check. * parameters: * - in: header * name: x-api-key * required: true * description: API key for authentication. * schema: * type: string * responses: * 200: * description: Ban status of the user in the federation. * content: * application/json: * schema: * type: object * properties: * federation: * type: string * example: "AkenoX Federation" * user_id: * type: integer * example: 12345 * is_banned: * type: boolean * example: true * 400: * description: Missing federation UUID or invalid user ID. * 404: * description: Federation not found. * 500: * description: Internal server error. */ FedsRoutes.post("/api/v2/federation/ban-check", authenticateApiKey, async (req, res) => { try { const apiKey = req.headers['x-api-key']; const userAgent = req.headers['user-agent']; const xForwardedFor = req.headers['x-forwarded-for']; const xRealIP = req.headers['x-real-ip']; const cfConnectingIP = req.headers['cf-connecting-ip']; let realIP = req.ip; if (xForwardedFor) { realIP = xForwardedFor.split(',')[0].trim(); } else if (xRealIP) { realIP = xRealIP; } else if (cfConnectingIP) { realIP = cfConnectingIP; } req.realIP = realIP; console.log(`🔍 Captured IPs:`, { xForwardedFor, xRealIP, cfConnectingIP, realIP }); const keyDoc = await db.findOne({ key: apiKey }); if (!keyDoc) { return res.status(403).json({ error: "Invalid API Key." }); } const { federation_uuid, user_id } = req.body; if (!federation_uuid || !user_id || isNaN(user_id)) { return res.status(400).json({ error: "Federation UUID and valid user ID required." }); } const federation = await Federation.findOne({ uuid: federation_uuid }); if (!federation) { return res.status(404).json({ error: "Federation not found." }); } const isBanned = federation.banned_users.includes(user_id); await updateIP(apiKey, realIP); await TelegramUseLog( keyDoc.owner, keyDoc.key, `Accessed: ${req.path}\nRealIP: ${realIP}\nUser-Agent: ${userAgent}` ); res.json({ federation: federation.name, user_id, is_banned: isBanned }); } catch (error) { res.status(500).json({ error: `Failed to check ban status: ${error.message}` }); } }); /** * @swagger * /api/v2/federation/fedstats: * get: * summary: Get Federation Statistics * tags: [Federation] * description: Retrieve the statistics of a federation, including total banned users and sub-federations. * parameters: * - in: query * name: uuid * required: true * description: UUID of the federation to check stats for. * schema: * type: string * - in: header * name: x-api-key * required: true * description: API key for authentication. * schema: * type: string * responses: * 200: * description: Federation statistics retrieved successfully. * content: * application/json: * schema: * type: object * properties: * success: * type: boolean * example: true * stats: * type: object * properties: * federation_name: * type: string * example: "Example Federation" * total_banned_users: * type: integer * example: 10 * total_sub_federations: * type: integer * example: 3 * owner: * type: number * example: 123456789 * 400: * description: Missing or invalid federation UUID. * 404: * description: Federation not found. * 500: * description: Internal server error. */ FedsRoutes.get("/api/v2/federation/fedstats", authenticateApiKey, async (req, res) => { try { const apiKey = req.headers['x-api-key']; const userAgent = req.headers['user-agent']; const xForwardedFor = req.headers['x-forwarded-for']; const xRealIP = req.headers['x-real-ip']; const cfConnectingIP = req.headers['cf-connecting-ip']; let realIP = req.ip; if (xForwardedFor) { realIP = xForwardedFor.split(',')[0].trim(); } else if (xRealIP) { realIP = xRealIP; } else if (cfConnectingIP) { realIP = cfConnectingIP; } req.realIP = realIP; console.log(`🔍 Captured IPs:`, { xForwardedFor, xRealIP, cfConnectingIP, realIP }); const keyDoc = await db.findOne({ key: apiKey }); if (!keyDoc) { return res.status(403).json({ error: "Invalid API Key." }); } const { uuid } = req.query; if (!uuid) { return res.status(400).json({ error: "Federation UUID is required" }); } const federation = await Federation.findOne({ uuid }); if (!federation) { return res.status(404).json({ error: "Federation not found" }); } const stats = { federation_name: federation.name, total_banned_users: federation.banned_users.length, total_sub_federations: federation.sub_federations.length, owner: federation.owner, }; await updateIP(apiKey, realIP); await TelegramUseLog( keyDoc.owner, keyDoc.key, `Accessed: ${req.path}\nRealIP: ${realIP}\nUser-Agent: ${userAgent}` ); res.json({ success: true, stats }); } catch (error) { res.status(500).json({ error: `Failed to fetch federation stats: ${error.message}` }); } }); /** * @swagger * /api/v2/federation/unsubfed: * post: * summary: Unsubscribe a Sub-Federation * tags: [Federation] * description: Remove a sub-federation from a parent federation. * security: * - apiKeyAuth: [] * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * parent_uuid: * type: string * description: UUID of the parent federation. * child_uuid: * type: string * description: UUID of the sub-federation to be removed. * parameters: * - in: header * name: x-api-key * required: true * description: API key for authentication. * schema: * type: string * responses: * 200: * description: Sub-federation successfully removed. * content: * application/json: * schema: * type: object * properties: * message: * type: string * example: "Federation SubFed has been unsubscribed from ParentFed." * 400: * description: Missing or invalid federation UUIDs. * 404: * description: Federation not found. * 500: * description: Internal server error. */ FedsRoutes.post("/api/v2/federation/unsubfed", authenticateApiKey, apiLimiter, async (req, res) => { try { const apiKey = req.headers['x-api-key']; const userAgent = req.headers['user-agent']; const xForwardedFor = req.headers['x-forwarded-for']; const xRealIP = req.headers['x-real-ip']; const cfConnectingIP = req.headers['cf-connecting-ip']; let realIP = req.ip; if (xForwardedFor) { realIP = xForwardedFor.split(',')[0].trim(); } else if (xRealIP) { realIP = xRealIP; } else if (cfConnectingIP) { realIP = cfConnectingIP; } req.realIP = realIP; console.log(`🔍 Captured IPs:`, { xForwardedFor, xRealIP, cfConnectingIP, realIP }); const keyDoc = await db.findOne({ key: apiKey }); if (!keyDoc) { return res.status(403).json({ error: "Invalid API Key." }); } const { parent_uuid, child_uuid } = req.body; if (!parent_uuid || !child_uuid) { return res.status(400).json({ error: "Both parent and child federation UUIDs are required." }); } const parent = await Federation.findOne({ uuid: parent_uuid }); const child = await Federation.findOne({ uuid: child_uuid }); if (!parent || !child) { return res.status(404).json({ error: "Federation not found." }); } parent.sub_federations = parent.sub_federations.filter(uuid => uuid !== child_uuid); await parent.save(); await updateIP(apiKey, realIP); await TelegramUseLog( keyDoc.owner, keyDoc.key, `Accessed: ${req.path}\nRealIP: ${realIP}\nUser-Agent: ${userAgent}` ); res.json({ message: `Federation ${child.name} has been unsubscribed from ${parent.name}` }); } catch (error) { res.status(500).json({ error: `Failed to unsubscribe sub-federation: ${error.message}` }); } }); /** * @swagger * /api/v2/federation/renamefed: * post: * summary: Rename a Federation * tags: [Federation] * description: Change the name of an existing federation. * requestBody: * required: true * content: * application/json: * schema: * type: object * properties: * federation_uuid: * type: string * description: UUID of the federation to be renamed. * new_name: * type: string * description: The new name for the federation. * parameters: * - in: header * name: x-api-key * required: true * description: API key for authentication. * schema: * type: string * responses: * 200: * description: Federation successfully renamed. * content: * application/json: * schema: * type: object * properties: * message: * type: string * example: "Federation renamed to NewFedName successfully." * 400: * description: Missing parameters or federation name already exists. * 404: * description: Federation not found. * 500: * description: Internal server error. */ FedsRoutes.post("/api/v2/federation/renamefed", authenticateApiKey, apiLimiter, async (req, res) => { try { const apiKey = req.headers['x-api-key']; const userAgent = req.headers['user-agent']; const xForwardedFor = req.headers['x-forwarded-for']; const xRealIP = req.headers['x-real-ip']; const cfConnectingIP = req.headers['cf-connecting-ip']; let realIP = req.ip; if (xForwardedFor) { realIP = xForwardedFor.split(',')[0].trim(); } else if (xRealIP) { realIP = xRealIP; } else if (cfConnectingIP) { realIP = cfConnectingIP; } req.realIP = realIP; console.log(`🔍 Captured IPs:`, { xForwardedFor, xRealIP, cfConnectingIP, realIP }); const keyDoc = await db.findOne({ key: apiKey }); if (!keyDoc) { return res.status(403).json({ error: "Invalid API Key." }); } const { federation_uuid, new_name } = req.body; if (!federation_uuid || !new_name) { return res.status(400).json({ error: "Federation UUID and new name are required." }); } const federation = await Federation.findOne({ uuid: federation_uuid }); if (!federation) { return res.status(404).json({ error: "Federation not found." }); } const existingFederation = await Federation.findOne({ name: new_name }); if (existingFederation) { return res.status(400).json({ error: "Federation name already exists." }); } federation.name = new_name; await federation.save(); await updateIP(apiKey, realIP); await TelegramUseLog( keyDoc.owner, keyDoc.key, `Accessed: ${req.path}\nRealIP: ${realIP}\nUser-Agent: ${userAgent}` ); res.json({ message: `Federation renamed to ${new_name} successfully.` }); } catch (error) { res.status(500).json({ error: `Failed to rename federation: ${error.message}` }); } }); export { FedsRoutes };