359 lines
9.3 KiB
JavaScript
359 lines
9.3 KiB
JavaScript
console.log("Starting up...")
|
|
require("dotenv").config()
|
|
const funcs = require("./helpers.js");
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const colors = require("colors");
|
|
const Discord = require("discord.js");
|
|
const client = new Discord.Client({ intents: ["Guilds"] });
|
|
const {
|
|
REST,
|
|
Routes
|
|
} = require('discord.js');
|
|
const { title } = require("process");
|
|
const rest = new REST({
|
|
version: '10'
|
|
}).setToken(process.env.DISCORD_TOKEN);
|
|
|
|
ipBans = {}
|
|
idBans = {}
|
|
|
|
ipRaw = "";
|
|
idRaw = "";
|
|
|
|
|
|
// Setup
|
|
// if process.env.CONFIG_PATH is not set or it doesnt exist, exit 1
|
|
if (!process.env.CONFIG_PATH || !fs.existsSync(process.env.CONFIG_PATH)) {
|
|
console.error("CONFIG_PATH is not set or does not exist. Exiting.")
|
|
process.exit(1);
|
|
}
|
|
|
|
// if ./errors/ doesnt exist, create it
|
|
if (!fs.existsSync("errors")) {
|
|
fs.mkdirSync("errors")
|
|
}
|
|
|
|
|
|
const jsonfix = (json) => JSON.parse(JSON.stringify(json));
|
|
|
|
client.on('ready', async () => {
|
|
console.log(`${colors.cyan("[INFO]")} Logged in as ${colors.green(client.user.tag)}`);
|
|
const commands = [
|
|
{
|
|
name: "ban",
|
|
description: "Interact with SL server bans",
|
|
type: 1,
|
|
options: [
|
|
{
|
|
name: "lookup",
|
|
description: "Look up a ban",
|
|
type: 1,
|
|
options: [
|
|
{
|
|
name: "type",
|
|
description: "The type of ban to look up",
|
|
type: 3,
|
|
required: true,
|
|
choices: [
|
|
{
|
|
name: "IP",
|
|
value: "ip"
|
|
},
|
|
{
|
|
name: "ID",
|
|
value: "id"
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: "value",
|
|
description: "The value to look up (IP or ID)",
|
|
type: 3,
|
|
required: true
|
|
}
|
|
]
|
|
},
|
|
{
|
|
name: "pardon"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
|
|
await(async () => {
|
|
try {
|
|
console.log(`${colors.cyan("[INFO]")} Registering Commands...`)
|
|
//Global
|
|
await rest.put(Routes.applicationCommands(client.user.id), { body: commands })
|
|
console.log(`${colors.cyan("[INFO]")} Successfully registered commands. Took ${colors.green((Date.now() - startTime) / 1000)} seconds.`);
|
|
} catch (error) {
|
|
console.error(error);
|
|
}
|
|
})();
|
|
watchFiles();
|
|
});
|
|
|
|
client.on('interactionCreate', async interaction => {
|
|
if (!interaction.isCommand()) return;
|
|
switch (interaction.commandName) {
|
|
case "ban":
|
|
switch (interaction.options.getSubcommand()) {
|
|
case "lookup":
|
|
type = interaction.options.getString("type");
|
|
value = interaction.options.getString("value");
|
|
if (type == "ip") {
|
|
if (ipBans[value]) {
|
|
embed = {
|
|
fields: [
|
|
{
|
|
name: "Banned Username",
|
|
value: ipBans[value].banned_username,
|
|
inline: true
|
|
},
|
|
{
|
|
name: "Banned ID",
|
|
value: ipBans[value].banned_id,
|
|
inline: true
|
|
},
|
|
{
|
|
name: "Banned",
|
|
value: `<t:${new Date(ipBans[value].banned_timestamp) / 1000}:f> <t:${new Date(ipBans[value].banned_timestamp) / 1000}:R>`,
|
|
inline: true
|
|
},
|
|
{
|
|
name: "Expires",
|
|
value: `<t:${new Date(ipBans[value].expires) / 1000}:f> <t:${new Date(ipBans[value].expires) / 1000}:R>`,
|
|
inline: true
|
|
},
|
|
{
|
|
name: "Reason",
|
|
value: ipBans[value].reason,
|
|
inline: true
|
|
},
|
|
{
|
|
name: "Moderator",
|
|
value: ipBans[value].moderator,
|
|
inline: true
|
|
}
|
|
]
|
|
}
|
|
embed.title = "IP Ban Lookup"
|
|
embed.color = 0xffff00
|
|
interaction.reply({ embeds: [embed] })
|
|
} else {
|
|
interaction.reply("No ban found for that IP")
|
|
}
|
|
} else if (type == "id") {
|
|
if (idBans[value]) {
|
|
embed = {
|
|
fields: [
|
|
{
|
|
name: "Banned Username",
|
|
value: idBans[value].banned_username,
|
|
inline: true
|
|
},
|
|
{
|
|
name: "Banned ID",
|
|
value: idBans[value].banned_id,
|
|
inline: true
|
|
},
|
|
{
|
|
name: "Banned",
|
|
value: `<t:${new Date(idBans[value].banned_timestamp) / 1000}:f> <t:${new Date(idBans[value].banned_timestamp) / 1000}:R>`,
|
|
inline: true
|
|
},
|
|
{
|
|
name: "Expires",
|
|
value: `<t:${new Date(idBans[value].expires) / 1000}:f> <t:${new Date(idBans[value].expires) / 1000}:R>`,
|
|
inline: true
|
|
},
|
|
{
|
|
name: "Reason",
|
|
value: idBans[value].reason,
|
|
inline: true
|
|
},
|
|
{
|
|
name: "Moderator",
|
|
value: idBans[value].moderator,
|
|
inline: true
|
|
}
|
|
]
|
|
}
|
|
embed.title = "ID Ban Lookup"
|
|
embed.color = 0xffff00
|
|
interaction.reply({ embeds: [embed] })
|
|
} else {
|
|
interaction.reply("No ban found for that ID")
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
});
|
|
|
|
|
|
const sendMessages = async (data) => {
|
|
const channel = await client.channels.fetch(process.env.DISCORD_BANLOG_CHANNEL_ID);
|
|
for (const ban in data.added) {
|
|
thisBan = data.added[ban]
|
|
embed = {
|
|
fields: [
|
|
{
|
|
name: "Banned Username",
|
|
value: thisBan.banned_username,
|
|
inline: true
|
|
},
|
|
{
|
|
name: "Banned ID",
|
|
value: thisBan.banned_id,
|
|
inline: true
|
|
},
|
|
{
|
|
name: "Banned",
|
|
value: `<t:${new Date(thisBan.banned_timestamp) / 1000}:f> <t:${new Date(thisBan.banned_timestamp) / 1000}:R>`,
|
|
inline: true
|
|
},
|
|
{
|
|
name: "Expires",
|
|
value: `<t:${new Date(thisBan.expires) / 1000}:f> <t:${new Date(thisBan.expires) / 1000}:R>`,
|
|
inline: true
|
|
},
|
|
{
|
|
name: "Reason",
|
|
value: thisBan.reason,
|
|
inline: true
|
|
},
|
|
{
|
|
name: "Moderator",
|
|
value: thisBan.moderator,
|
|
inline: true
|
|
}
|
|
]
|
|
}
|
|
|
|
embed.title = "Ban Added"
|
|
embed.color = 0xff0000
|
|
channel.send({ embeds: [embed] })
|
|
}
|
|
|
|
|
|
for (const ban in data.removed) {
|
|
thisBan = data.removed[ban]
|
|
embed = {
|
|
fields: [
|
|
{
|
|
name: "Banned Username",
|
|
value: thisBan.banned_username,
|
|
inline: true
|
|
},
|
|
{
|
|
name: "Banned ID",
|
|
value: thisBan.banned_id,
|
|
inline: true
|
|
},
|
|
{
|
|
name: "Banned",
|
|
value: `<t:${new Date(thisBan.banned_timestamp) / 1000}:f> <t:${new Date(thisBan.banned_timestamp) / 1000}:R>`,
|
|
inline: true
|
|
},
|
|
{
|
|
name: "Expires",
|
|
value: `<t:${new Date(thisBan.expires) / 1000}:f> <t:${new Date(thisBan.expires) / 1000}:R>`,
|
|
inline: true
|
|
},
|
|
{
|
|
name: "Reason",
|
|
value: thisBan.reason,
|
|
inline: true
|
|
},
|
|
{
|
|
name: "Moderator",
|
|
value: thisBan.moderator,
|
|
inline: true
|
|
}
|
|
]
|
|
}
|
|
|
|
embed.title = "Ban Removed"
|
|
embed.color = 0x00ff00
|
|
channel.send({ embeds: [embed] })
|
|
};
|
|
}
|
|
|
|
|
|
fs.readdirSync(process.env.CONFIG_PATH).forEach(file => {
|
|
if (file.startsWith(".")) return; // Ignore hidden files
|
|
contents = fs.readFileSync(path.join(process.env.CONFIG_PATH, file)).toString()
|
|
switch (file) {
|
|
case "IpBans.txt":
|
|
ipRaw = String(contents);
|
|
lines = contents.split("\n");
|
|
ipBans = funcs.makeBansTable(contents)
|
|
break;
|
|
case "UserIdBans.txt":
|
|
idRaw = String(contents);
|
|
idBans = funcs.makeBansTable(contents)
|
|
break;
|
|
}
|
|
})
|
|
|
|
const watchFiles = () => {
|
|
fs.watch(process.env.CONFIG_PATH, (event, file) => {
|
|
if (file.startsWith(".")) return; // Ignore hidden files
|
|
setTimeout(() => {
|
|
tmp = {}
|
|
newContents = fs.readFileSync(path.join(process.env.CONFIG_PATH, file)).toString()
|
|
switch (file) {
|
|
case "IpBans.txt":
|
|
if (newContents == ipRaw) return; // File didnt change, ignore
|
|
tmp = funcs.makeBansTable(newContents)
|
|
// Do stuff
|
|
console.log(`IP Bans changed\nOld Length: ${Object.keys(ipBans).length}\nNew Length: ${Object.keys(tmp).length}`)
|
|
// if the number of adds or removes is over 40 ignore it
|
|
if (Object.keys(funcs.diff(ipBans, tmp).added).length > 40 || Object.keys(funcs.diff(ipBans, tmp).removed).length > 40) {
|
|
console.log("Too many changes, logging and ignoring")
|
|
fs.writeFileSync(`errors/changes-${Date.now()}.log`, JSON.stringify(funcs.diff(idBans, tmp), null, 2));
|
|
break;
|
|
}
|
|
sendMessages(funcs.diff(ipBans, tmp))
|
|
ipBans = jsonfix(tmp)
|
|
ipRaw = String(newContents)
|
|
break;
|
|
case "UserIdBans.txt":
|
|
if (newContents == idRaw) return; // File didnt change, ignore
|
|
tmp = funcs.makeBansTable(newContents)
|
|
// Do stuff
|
|
console.log(`ID Bans changed\nOld Length: ${Object.keys(idBans).length}\nNew Length: ${Object.keys(tmp).length}`)
|
|
// if the number of adds or removes is over 40 ignore it
|
|
if (Object.keys(funcs.diff(idBans, tmp).added).length > 40 || Object.keys(funcs.diff(idBans, tmp).removed).length > 40) {
|
|
console.log("Too many changes, logging and ignoring")
|
|
fs.writeFileSync(`errors/changes-${Date.now()}.log`, JSON.stringify(funcs.diff(idBans, tmp), null, 2));
|
|
break;
|
|
}
|
|
sendMessages(funcs.diff(idBans, tmp))
|
|
idBans = jsonfix(tmp)
|
|
idRaw = String(newContents)
|
|
break;
|
|
}
|
|
})
|
|
|
|
})
|
|
}
|
|
|
|
// Catch unhandled promise rejections and unhandled exceptions
|
|
process.on('unhandledRejection', (error) => {
|
|
console.error('Unhandled promise rejection:', error);
|
|
// save full stack to file in errors/timestamp.log
|
|
fs.writeFileSync(`errors/rejection-${Date.now()}.log`, error.stack);
|
|
});
|
|
|
|
process.on('uncaughtException', (error) => {
|
|
console.error('Uncaught exception:', error);
|
|
// save full stack to file in errors/timestamp.log
|
|
fs.writeFileSync(`errors/exception-${Date.now()}.log`, error.stack);
|
|
});
|
|
|
|
const startTime = new Date();
|
|
client.login(process.env.DISCORD_TOKEN) |