Progress is being made
This commit is contained in:
parent
65c6991a6a
commit
8d6aa4cbe7
24
commands.js
Normal file
24
commands.js
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// Command definitions
|
||||||
|
const Discord = require("discord.js")
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
global: [
|
||||||
|
// Use SlashCommandBuilder for command creation
|
||||||
|
new Discord.SlashCommandBuilder()
|
||||||
|
.setName("report")
|
||||||
|
.setDescription("Report a user.")
|
||||||
|
.addNumberOption(option => option.setName("roblox_id").setDescription("The Roblox ID of the user you're reporting.").setRequired(true))
|
||||||
|
.addStringOption(option => option.setName("reason").setDescription("The reason for the report. (Please be as descriptive as possible)").setRequired(true)),
|
||||||
|
],
|
||||||
|
admin: [
|
||||||
|
new Discord.SlashCommandBuilder()
|
||||||
|
.setName("ban")
|
||||||
|
.setDescription("Ban a user.")
|
||||||
|
.setDefaultMemberPermissions(0),
|
||||||
|
new Discord.SlashCommandBuilder()
|
||||||
|
.setName("unban")
|
||||||
|
.setDescription("Unban a user.")
|
||||||
|
.addNumberOption(option => option.setName("roblox_id").setDescription("The Roblox ID of the user you're unbanning.").setRequired(true))
|
||||||
|
.setDefaultMemberPermissions(0),
|
||||||
|
]
|
||||||
|
}
|
15
flags.js
15
flags.js
|
@ -70,6 +70,18 @@ function defineFlags(flagNames) {
|
||||||
}, {});
|
}, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the names of the flags that are set.
|
||||||
|
* @param {number} flags - The current set of flags.
|
||||||
|
* @param {Object} flagDefinitions - An object where keys are flag names and values are powers of 2.
|
||||||
|
* @returns {string[]} - An array of flag names that are set.
|
||||||
|
*/
|
||||||
|
function getSetFlags(flags, flagDefinitions) {
|
||||||
|
return Object.keys(flagDefinitions).filter(flagName =>
|
||||||
|
(flags & flagDefinitions[flagName]) !== 0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
addFlag,
|
addFlag,
|
||||||
|
@ -78,5 +90,6 @@ module.exports = {
|
||||||
toggleFlag,
|
toggleFlag,
|
||||||
hasAllFlags,
|
hasAllFlags,
|
||||||
hasAnyFlag,
|
hasAnyFlag,
|
||||||
defineFlags
|
defineFlags,
|
||||||
|
getSetFlags
|
||||||
}
|
}
|
93
index.js
93
index.js
|
@ -1,18 +1,25 @@
|
||||||
// Other stuff
|
// Other requires
|
||||||
const colors = require("colors");
|
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
const { execSync } = require('child_process');
|
||||||
const flags = require("./flags.js")
|
const flags = require("./flags.js")
|
||||||
|
const log = require("./log");
|
||||||
|
|
||||||
|
// Legal stuff
|
||||||
|
log.info(`UBS Server (${execSync("git rev-parse --short HEAD").toString().trim()}) on ${execSync("git rev-parse --abbrev-ref HEAD").toString().trim()}`)
|
||||||
|
log.info(`\u00A9 ${new Date().getFullYear()} RTECH Consortium.`)
|
||||||
|
log.info("This software is licensed under the GNU General Public License v3.0")
|
||||||
|
log.info("This software is provided as-is with no warranty or guarantee of support.")
|
||||||
|
log.info("This software is not affiliated with Roblox Corporation.")
|
||||||
|
|
||||||
// Color logs
|
|
||||||
const log = {
|
|
||||||
info(msg) {
|
|
||||||
console.log(`${colors.cyan.bold("[INFO]")} ${msg}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// dotenv
|
// dotenv
|
||||||
require("dotenv").config();
|
require("dotenv").config();
|
||||||
|
|
||||||
|
const noblox = require("noblox.js")
|
||||||
|
noblox.setCookie(process.env.ROBLOSECURITY)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Express
|
// Express
|
||||||
const express = require("express");
|
const express = require("express");
|
||||||
const app = new express();
|
const app = new express();
|
||||||
|
@ -27,11 +34,76 @@ app.use((req, res, next) => {
|
||||||
requestIp = req.headers["x-forwarded-for"];
|
requestIp = req.headers["x-forwarded-for"];
|
||||||
}
|
}
|
||||||
fs.appendFileSync(process.env.LOGFILE, `${requestIp} - ${req.method} ${req.protocol}://${req.get('host')}${req.originalUrl} - ${req.headers["user-agent"]}\n`)
|
fs.appendFileSync(process.env.LOGFILE, `${requestIp} - ${req.method} ${req.protocol}://${req.get('host')}${req.originalUrl} - ${req.headers["user-agent"]}\n`)
|
||||||
console.log(req.headers)
|
|
||||||
next()
|
next()
|
||||||
});
|
});
|
||||||
|
|
||||||
// Run migrations
|
// Flags
|
||||||
|
const reasonFlagTypes = [
|
||||||
|
"OTHER",
|
||||||
|
"LEAKER",
|
||||||
|
"TOXIC",
|
||||||
|
"SCAM",
|
||||||
|
"CHILD_SAFETY"
|
||||||
|
]
|
||||||
|
|
||||||
|
const reasonFlags = flags.defineFlags(reasonFlagTypes)
|
||||||
|
process.env.REASON_FLAGS = JSON.stringify(reasonFlags)
|
||||||
|
|
||||||
|
// Discord stuff
|
||||||
|
const Discord = require("discord.js");
|
||||||
|
const client = new Discord.Client({intents: ["Guilds", "GuildBans", "GuildMembers"]})
|
||||||
|
|
||||||
|
client.on("ready", async () => {
|
||||||
|
log.info(`Logged into Discord as ${client.user.displayName}`);
|
||||||
|
const commands = require("./commands")
|
||||||
|
// Command registration
|
||||||
|
await (async () => {
|
||||||
|
try {
|
||||||
|
const rest = new Discord.REST().setToken(client.token);
|
||||||
|
//Global
|
||||||
|
await rest.put(Discord.Routes.applicationGuildCommands(client.user.id, process.env.ADMIN_GUILD), { body: [] })
|
||||||
|
log.info(`Registering global commands`);
|
||||||
|
await rest.put(Discord.Routes.applicationCommands(client.user.id), { body: commands.global })
|
||||||
|
|
||||||
|
//Admin
|
||||||
|
log.info(`Registering admin commands`);
|
||||||
|
await rest.put(Discord.Routes.applicationGuildCommands(client.user.id, process.env.ADMIN_GUILD), { body: commands.admin })
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on("interactionCreate", async (interaction) => {
|
||||||
|
// Switch by type (either slash command or modal)
|
||||||
|
switch(interaction.type) {
|
||||||
|
// Slash Command Handler
|
||||||
|
case Discord.InteractionType.ApplicationCommand:
|
||||||
|
if (!interaction.isCommand()) return;
|
||||||
|
const command = interaction.commandName;
|
||||||
|
const args = interaction.options;
|
||||||
|
switch(command) {
|
||||||
|
// Report Command
|
||||||
|
case "report":
|
||||||
|
const robloxId = args.getNumber("roblox_id");
|
||||||
|
const reason = args.getString("reason");
|
||||||
|
// TODO: Report Command
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Modal Handler
|
||||||
|
case Discord.InteractionType.ModalSubmit:
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Startup
|
||||||
|
log.info("Starting up...")
|
||||||
|
|
||||||
|
|
||||||
require("./migrations")().then(() => {
|
require("./migrations")().then(() => {
|
||||||
// Load all route modules from the 'routes' folder
|
// Load all route modules from the 'routes' folder
|
||||||
const routesPath = path.join(__dirname, 'routes');
|
const routesPath = path.join(__dirname, 'routes');
|
||||||
|
@ -45,4 +117,5 @@ require("./migrations")().then(() => {
|
||||||
app.listen(port, () => {
|
app.listen(port, () => {
|
||||||
log.info(`Listening on ${port}`)
|
log.info(`Listening on ${port}`)
|
||||||
})
|
})
|
||||||
|
client.login(process.env.DISCORD_TOKEN);
|
||||||
});
|
});
|
9
log.js
Normal file
9
log.js
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
const colors = require("colors");
|
||||||
|
module.exports = {
|
||||||
|
info(msg) {
|
||||||
|
console.log(`${colors.cyan.bold("[INFO]")} ${msg}`);
|
||||||
|
},
|
||||||
|
error(msg) {
|
||||||
|
console.log(`${colors.red.bold("[ERROR]")} ${msg}`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,8 @@ const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const util = require("util")
|
const util = require("util")
|
||||||
require("dotenv").config()
|
require("dotenv").config()
|
||||||
|
const log = require("./log");
|
||||||
|
|
||||||
|
|
||||||
// Create a MariaDB connection pool
|
// Create a MariaDB connection pool
|
||||||
const pool = mariadb.createPool({
|
const pool = mariadb.createPool({
|
||||||
|
@ -45,7 +47,7 @@ function runMigrations() {
|
||||||
[migrationName]
|
[migrationName]
|
||||||
).then(([rows]) => {
|
).then(([rows]) => {
|
||||||
if (Object.keys(rows || {}).length > 0) {
|
if (Object.keys(rows || {}).length > 0) {
|
||||||
console.log(`Skipping already applied migration: ${migrationName}`);
|
//log.info(`Skipping already applied migration: ${migrationName}`);
|
||||||
return; // Skip this migration
|
return; // Skip this migration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,7 +60,7 @@ function runMigrations() {
|
||||||
'INSERT INTO migrations (name) VALUES (?)',
|
'INSERT INTO migrations (name) VALUES (?)',
|
||||||
[migrationName]
|
[migrationName]
|
||||||
).then(() => {
|
).then(() => {
|
||||||
console.log(`Applied migration: ${migrationName}`);
|
log.info(`Applied migration: ${migrationName}`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -66,11 +68,11 @@ function runMigrations() {
|
||||||
}, Promise.resolve());
|
}, Promise.resolve());
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
console.log('All migrations applied successfully!');
|
log.info('All migrations applied successfully!');
|
||||||
resolve();
|
resolve();
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
console.error('Error running migrations:', err);
|
log.error('Error running migrations:', err);
|
||||||
reject(err);
|
reject(err);
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
CREATE TABLE bans (
|
CREATE TABLE bans (
|
||||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
id CHAR(36) DEFAULT (UUID()) PRIMARY KEY,
|
||||||
robloxId INT,
|
robloxId VARCHAR(16),
|
||||||
discordId INT,
|
discordId VARCHAR(24),
|
||||||
robloxUsername VARCHAR(255),
|
robloxUsername VARCHAR(255),
|
||||||
discordUsername VARCHAR(255),
|
discordUsername VARCHAR(255),
|
||||||
reasonShort VARCHAR(255),
|
reasonShort VARCHAR(255),
|
||||||
|
|
12
migrations/002_init_guilds_table.sql
Normal file
12
migrations/002_init_guilds_table.sql
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
CREATE TABLE guilds (
|
||||||
|
id VARCHAR(24) NOT NULL PRIMARY KEY,
|
||||||
|
robloxId VARCHAR(16),
|
||||||
|
discordId VARCHAR(24),
|
||||||
|
robloxUsername VARCHAR(255),
|
||||||
|
discordUsername VARCHAR(255),
|
||||||
|
reasonShort VARCHAR(255),
|
||||||
|
reasonLong VARCHAR(2048),
|
||||||
|
reasonsFlag INT,
|
||||||
|
banTimestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
expiresTimestamp TIMESTAMP DEFAULT NULL
|
||||||
|
);
|
1
migrations/999_insert_test_bans.sql
Normal file
1
migrations/999_insert_test_bans.sql
Normal file
|
@ -0,0 +1 @@
|
||||||
|
INSERT INTO ubs.bans (robloxId,discordId,robloxUsername,discordUsername,reasonShort,reasonLong,reasonsFlag) VALUES (999999999,123456789,'testuser','testuser', "Example Short", "Example Long", 20);
|
990
package-lock.json
generated
990
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -14,6 +14,7 @@
|
||||||
"discord.js": "^14.16.3",
|
"discord.js": "^14.16.3",
|
||||||
"dotenv": "^16.4.7",
|
"dotenv": "^16.4.7",
|
||||||
"express": "^4.21.1",
|
"express": "^4.21.1",
|
||||||
"mariadb": "^3.4.0"
|
"mariadb": "^3.4.0",
|
||||||
|
"noblox.js": "^6.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const mariadb = require('mariadb');
|
const mariadb = require('mariadb');
|
||||||
|
const reasonFlags = JSON.parse(process.env.REASON_FLAGS)
|
||||||
|
|
||||||
|
const { execSync } = require('child_process');
|
||||||
|
|
||||||
// Create a MariaDB connection pool
|
// Create a MariaDB connection pool
|
||||||
const pool = mariadb.createPool({
|
const pool = mariadb.createPool({
|
||||||
|
@ -60,4 +63,35 @@ router.get("/v1/ban/roblox/:uid", async (req, res) => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
router.get("/v1/ban/discord/:uid", async (req, res) => {
|
||||||
|
if (!req.params.uid) return res.status(400).json({error: "Specify user ID!"});
|
||||||
|
try {
|
||||||
|
// Get a connection from the pool
|
||||||
|
const connection = await pool.getConnection();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Execute the query to fetch all rows from the `bans` table
|
||||||
|
const rows = await connection.query('SELECT * FROM bans WHERE discordId = ?', [req.params.uid]);
|
||||||
|
|
||||||
|
// Send the results as a JSON response
|
||||||
|
res.json(rows);
|
||||||
|
} finally {
|
||||||
|
// Release the connection back to the pool
|
||||||
|
connection.release();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error fetching bans:', err);
|
||||||
|
|
||||||
|
// Respond with a 500 Internal Server Error status if something goes wrong
|
||||||
|
res.status(500).json({ error: 'An error occurred while fetching the bans.' });
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
router.get("/v1/info", (req,res) => {
|
||||||
|
res.json({
|
||||||
|
commit_hash: execSync('git rev-parse HEAD').toString().trim(),
|
||||||
|
reasonFlags
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
Loading…
Reference in a new issue