Initial commit

This commit is contained in:
2023-11-03 21:12:55 +01:00
parent a4afe6cc85
commit 57362e7520
39 changed files with 3505 additions and 1 deletions
+40
View File
@@ -0,0 +1,40 @@
module.exports = {
name:"authenticate",
async function(req, res){
let username = req.body.username.trim()
let password = req.body.password
if(username == undefined || password == undefined || username == ""){
res.json({code:32})
return
}
if(username.length > 32 || username.length < 3){
res.json({code:32})
return
}
let user = await commands.get("query").function("SELECT dtPassword from tbl_users WHERE dtUsername = ?",[username])
if(user.length == 0){
res.json({code:32})
return
}
let valid = await bcrypt.compare(password, user[0].dtPassword)
if(!valid){
res.json({code:31})
return
}
// Yes, i am using bcrypt to make the hash key cause i m too lazy to implement md5 here
// I mean, afterall, it doesnt contain sensitive information, so, who cares what algorithm you use
// it looks fancy and does its job, so, cry about it
let apiKey = await bcrypt.hash(Math.random() * 100000000 * Math.random() + username,saltRounds)
commands.get("query").function("UPDATE tbl_users SET dtApiKey = ? WHERE dtUsername = ?",[apiKey, username]).then(resp => {
res.json({code:30,key:apiKey})
}).catch(err => {
console.log(err);
res.json({code:33})
})
}
}
+37
View File
@@ -0,0 +1,37 @@
module.exports = {
name:"codeList",
async function(req, res){
let apiKey = req.headers.auth
if(apiKey == undefined){
res.json({code:51})
return
}
var userid
await commands.get("validate").check(apiKey).then(resp => {
userid = resp
}).catch(err => {
switch(err){
case 1: res.json({code:51}); break;
case 2: res.json({code:52}); break;
}
return
})
let output = {
code:50,
shortcodes:[]
}
let codes = await commands.get("query").function("SELECT idShortcode, dtOriginal, tbl_urls.dtTimestamp from tbl_urls, tbl_users where fiUser = idUser AND dtApiKey = ?",[apiKey])
for (let i = 0; i < codes.length; i++) {
output.shortcodes.push({
"shortcode": codes[i].idShortcode,
"destination": codes[i].dtOriginal,
"timestamp": codes[i].dtTimestamp
})
}
res.json(output)
}
}
+49
View File
@@ -0,0 +1,49 @@
module.exports = {
name:"createCode",
async function(req, res){
let apiKey = req.headers.auth
let url = req.body.url
if(apiKey == undefined){
res.json({code:41})
return
}
var userid
await commands.get("validate").check(apiKey).then(resp => {
userid = resp
}).catch(err => {
switch(err){
case 1: res.json({code:41}); break;
case 2: res.json({code:42}); break;
}
return
})
let dupes = await commands.get("query").function("SELECT idShortcode FROM tbl_urls, tbl_users WHERE fiUser = idUser AND dtApiKey = ? AND dtOriginal = ?",[apiKey,url])
if(dupes.length != 0){
let urls = []
config.baseUrl.forEach(el => {
urls.push(`${el}/${dupes[0].idShortcode}`)
});
res.json({code:44,shortcode:dupes[0].idShortcode,full_url:urls})
return
}
let hashData = new Date().getTime()+""
hashData = parseInt(hashData.slice(6)) + Math.floor((Math.random()*1000)-500)
let hash = hashids.encode(hashData)
// console.log(a);
commands.get("query").function("INSERT INTO tbl_urls (idShortcode, dtOriginal, dtTimestamp, fiUser) VALUES (?,?,?,?)",[hash, url, new Date().getTime(), userid]).then(resp => {
let urls = []
config.baseUrl.forEach(el => {
urls.push(`${el}/${hash}`)
});
res.json({code:40,shortcode:hash,full_url:urls})
}).catch(err => {
res.json({code:43})
})
}
}
+34
View File
@@ -0,0 +1,34 @@
module.exports = {
name:"createUser",
async function(req, res){
let username = req.body.username.trim()
let password = req.body.password
if(username == undefined || passowrd == undefined || username == ""){
res.json({code:24})
return
}
if(username.length > 32 || username.length < 3){
res.json({code:23})
return
}
let user = await commands.get("query").function("SELECT idUser from tbl_users WHERE dtUsername = ?",[username])
if(user.length != 0){
res.json({code:21})
return
}
let hash = await bcrypt.hash(password, saltRounds)
commands.get("query").function("INSERT INTO tbl_users (dtUsername,dtPassword,dtTimestamp) VALUES (?,?,?)",[username,hash,new Date().getTime()],true).then(res => {
console.log(res);
if(res != false){
res.json({code:20})
}
})
.catch(err => {
res.json({code:22,error:err})
})
}
}
+35
View File
@@ -0,0 +1,35 @@
module.exports = {
name:"deleteCode",
async function(req, res){
let apiKey = req.headers.auth
let shortcode = req.body.shortcode
if(apiKey == undefined){
res.json({code:61})
return
}
var userid
await commands.get("validate").check(apiKey).then(resp => {
userid = resp
}).catch(err => {
switch(err){
case 1: res.json({code:61}); break;
case 2: res.json({code:62}); break;
}
return
})
let code = await commands.get("query").function("SELECT idShortcode FROM tbl_urls, tbl_users WHERE fiUser = idUser AND dtApiKey = ? AND idShortcode = ?",[apiKey,shortcode])
if(code.length == 0){
res.json({code:65})
return
}
commands.get("query").function("DELETE FROM tbl_urls WHERE idShortcode = ?",[shortcode]).then(resp => {
res.json({code:60})
}).catch(err => {
res.json({code:63})
})
}
}
+25
View File
@@ -0,0 +1,25 @@
module.exports = {
name:"info",
async function(req, res){
let query = await commands.get("query").function("SELECT * from tbl_urls, tbl_users WHERE idShortcode = ? AND fiUser = idUser",[req.params.shortcode])
if(query.length == 0){
res.json({code:11})
return
}
let query2 = await commands.get("query").function("SELECT COUNT(*) AS amount FROM tbl_access WHERE fiShortcode = ?",[req.params.shortcode])
let query3 = await commands.get("query").function("SELECT COUNT(*) AS amount FROM (SELECT * FROM tbl_access WHERE fiShortcode = ? GROUP BY dtIpHash) AS sq",[req.params.shortcode])
res.json({
code:10,
shortcode: req.params.shortcode,
redirect: query[0].dtOriginal,
creator: query[0].dtUsername,
creationTime: query[0].dtTimestamp,
clicked:{
total:query2[0].amount,
distinct_users:query3[0].amount
}
})
}
}
+22
View File
@@ -0,0 +1,22 @@
const crypto = require('crypto');
module.exports = {
name:"redirect",
async function(req, res){
if(req.params.shortcode == "")
return
if(shortcodes[req.params.shortcode]){
res.redirect(shortcodes[req.params.shortcode])
}else{
let url = await commands.get("query").function("SELECT dtOriginal from tbl_urls WHERE idShortcode = ?",[req.params.shortcode])
if(url.length == 0)
return
shortcodes[req.params.shortcode] = url[0].dtOriginal
res.redirect(shortcodes[req.params.shortcode])
}
// commands.get("query").function("UPDATE tbl_urls SET dtAccessed = dtAccessed + 1 WHERE idShortcode = ?",[req.params.shortcode])
let ipHash = req.headers["cf-connecting-ip"] == undefined ? "localhost" : crypto.createHash('md5').update(req.headers["cf-connecting-ip"]).digest('hex')
commands.get("query").function("INSERT INTO tbl_access (fiShortcode,dtIpHash,dtTimestamp) VALUES (?,?,?)",[req.params.shortcode, ipHash, new Date().getTime()])
}
}
+42
View File
@@ -0,0 +1,42 @@
module.exports = {
name:"Startup_function",
async function(msg, args){
setTimeout(async () => {
console.log("-------------------------------- Startup Function ------------------------------");
// Load all shortcodes with their redirects directly into memeory on startup
process.stdout.write("Loading all shortcodes into memory 🟥");
let url = await commands.get("query").function("SELECT idShortcode, dtOriginal from tbl_urls",[])
for (let i = 0; i < url.length; i++) {
shortcodes[url[i].idShortcode] = url[i].dtOriginal
}
process.stdout.cursorTo(40)
process.stdout.write(`🟩 (${url.length})\n`)
// Load all bans into memory
process.stdout.write("Loading all bans into memory 🟥");
let bans = await commands.get("query").function("SELECT dtIpHash from tbl_bans",[])
for (let i = 0; i < bans.length; i++) {
ignorelist[bans[i].dtIpHash] = bans[i].dtIpHash
}
process.stdout.cursorTo(40)
process.stdout.write(`🟩 (${bans.length})\n`)
// Ratelimit hit cleanup
if(config.ratelimit.resetHits){
setInterval(() => {
for(hash in ratelimit){
if(ratelimit[hash][1] > 0)
ratelimit[hash][1] = ratelimit[hash][1]-1
}
}, 60000* config.ratelimit.resetTimeframe); // Timeframe value in minutes
}
console.log("--------------------------------------------------------------------------------");
}, 500);
}
}
+30
View File
@@ -0,0 +1,30 @@
const crypto = require('crypto');
module.exports = {
name:"banHandler",
check: async function(req){
return new Promise(async (resolve,reject) => {
let hash = req.headers["cf-connecting-ip"] == undefined ? crypto.createHash('md5').update("localhost").digest('hex') : crypto.createHash('md5').update(req.headers["cf-connecting-ip"]).digest('hex')
let ban = await commands.get("query").function("SELECT idBan from tbl_bans WHERE dtIpHash = ?",[hash])
if(ban.length == 0){
resolve()
return
}else{
reject()
return
}
})
},
ban: async function(req){
if(req.headers["cf-connecting-ip"] != undefined){
if(config.banhandler.whitelisted.includes(req.headers["cf-connecting-ip"]))
return
}
let hash = req.headers["cf-connecting-ip"] == undefined ? crypto.createHash('md5').update("localhost").digest('hex') : crypto.createHash('md5').update(req.headers["cf-connecting-ip"]).digest('hex')
await commands.get("query").function("INSERT INTO tbl_bans (dtIpHash,dtTimestamp) VALUES (?,?)",[hash, new Date().getTime()])
ignorelist[hash] = hash
},
unban: async function(hash){
await commands.get("query").function("DELETE FROM tbl_bans WHERE dtIpHash = ?",[hash])
delete ignorelist[hash]
}
}
+17
View File
@@ -0,0 +1,17 @@
module.exports = {
name:"log",
async function(message,status){
switch(status){
case "good":
console.log(`${new Date()} : ${message}`.green)
break;
case "warn":
console.log(`${new Date()} : ${message}`.yellow)
break;
case "bad":
console.log(`${new Date()} : ${message}`.red)
break;
}
}
}
+47
View File
@@ -0,0 +1,47 @@
// const included = require("../../requires")
pool = mysql.createPool({
connectionLimit : 10,
host: config.database.host,
port: config.database.port,
user: config.database.username,
password: config.database.password,
database: config.database.database,
charset : 'utf8mb4'
});
module.exports = {
name: "query",
async function(query, values, verbose){
// if(values == undefined){
// values = query
// query = msg
// }
return new Promise((resolve, reject) => {
// connection.query(query, values, function (error, results, fields) {
// if (error) throw error;
// resolve(results)
// });
pool.getConnection(function(err, connection) {
if (err) throw err; // not connected!
// Use the connection
connection.query(query, values, function (error, results, fields) {
// When done with the connection, release it.
connection.release();
// Handle error after the release.
if (error){
// console.log(error) //-------------------------------------------------------------------------- DEBUGGING
if(verbose){
reject(error.sqlMessage);
}
resolve(false)
}
resolve(results)
// Don't use the connection here, it has been returned to the pool.
});
});
})
}
}
+48
View File
@@ -0,0 +1,48 @@
const crypto = require('crypto');
module.exports = {
name:"ratelimit",
async function(req){
return new Promise(async (resolve,reject) => {
// If developer key has been sent, skip ratelimiter
if(req.headers.devkey){if(req.headers.devkey == config.ratelimit.devKey){resolve();return}}
// If user is banned already, reject with code 3 (ignore)
let bh = false
await commands.get("banHandler").check(req).catch(err => {reject(3);bh=true})
if(bh){return}
if(!config.ratelimit.enabled){
resolve()
return
}
let hash = req.headers["cf-connecting-ip"] == undefined ? crypto.createHash('md5').update("localhost").digest('hex') : crypto.createHash('md5').update(req.headers["cf-connecting-ip"]).digest('hex')
if(ratelimit[hash] == undefined){
// Everything is fine
ratelimit[hash] = [new Date().getTime()+1000,0]
resolve()
return
}
else{
if(ratelimit[hash][0] > new Date().getTime()){
ratelimit[hash][1] = ratelimit[hash][1] + 1
if(ratelimit[hash][1] >= config.ratelimit.hitsUntilBan){
// User gets banned now, reject with code 2 (tell user about the ban)
commands.get("banHandler").ban(req)
reject(2)
console.log(`${new Date()}: Banning ${hash}`);
return
}
// User hits ratelimit, reject with code 1 (tell user about the hit)
reject(1)
// console.log(`Rate Limiting ${hash}`);
return
}else{
// Everything is fine
ratelimit[hash][0] = new Date().getTime()+1000
resolve()
return
}
}
})
}
}
+38
View File
@@ -0,0 +1,38 @@
module.exports = {
name:"readableTime",
async timeframe(seconds){
return new Promise(resolve => {
seconds = Math.floor(Number(seconds)/1000);
var d = Math.floor(seconds / (3600*24));
var h = Math.floor(seconds % (3600*24) / 3600);
var m = Math.floor(seconds % 3600 / 60);
var s = Math.floor(seconds % 60);
var dDisplay = d > 0 ? d + (d == 1 ? " day, " : " days, ") : "";
var hDisplay = h > 0 ? h + (h == 1 ? " hour, " : " hours, ") : "";
var mDisplay = m > 0 ? m + (m == 1 ? " minute, " : " minutes, ") : "";
var sDisplay = s > 0 ? s + (s == 1 ? " second" : " seconds") : "";
resolve(dDisplay + hDisplay + mDisplay + sDisplay);
})
},
async timestamp(timestamp=new Date()){
return new Promise(resolve => {
let vals = {
yyyy: timestamp.getFullYear(),
m: timestamp.getMonth()+1,
d: timestamp.getDate(),
h: timestamp.getHours(),
mi: timestamp.getMinutes(),
s: timestamp.getSeconds(),
ms: timestamp.getMilliseconds()
};
// console.log(`${vals.yyyy}/${vals.m}/${vals.d} ${vals.h}:${vals.mi}:${vals.s}`);
resolve(`${vals.yyyy}/${vals.m}/${vals.d} ${vals.h}:${vals.mi}:${vals.s}`)
})
}
}
+71
View File
@@ -0,0 +1,71 @@
// require("../../requires")
module.exports = {
name: "registerCommands",
async function(global, guild){
return new Promise(resolve => {
const { SlashCommandBuilder } = require('@discordjs/builders');
const { REST } = require('@discordjs/rest');
const { Routes } = require('discord-api-types/v9');
const token = config.token
const commandsList = []
var commandstopush = "| "
commands.forEach(element => {
if(element.slashcommand != undefined){
if(global){
if(element.slashcommandGlobal){
commandstopush += `${element.name} | `
commandsList.push(element.slashcommand)
}
}else{
commandstopush += `${element.name} | `
commandsList.push(element.slashcommand)
if(element.permissions){
commandsList[commandsList.length-1].default_member_permissions = element.permissions
}
}
// commandsList.push(element.slashcommand)
}
});
console.log(commandstopush);
const rest = new REST({ version: '9' }).setToken(token);
const clientId = client.user.id;
const guildId = '929749429156724807';
(async () => {
try {
if(!global){
await rest.put(
Routes.applicationGuildCommands(clientId, guildId),
{ body: commandsList },
);
}else{
if(guild == undefined){
await rest.put(
Routes.applicationCommands(clientId),
{ body: commandsList },
);
}else{
await rest.put(
Routes.applicationGuildCommands(clientId, guild.id),
{ body: commandsList },
);
}
}
console.log('Successfully registered application commands.');
resolve()
} catch (error) {
console.error(error);
resolve()
}
})();
})
}
}
+29
View File
@@ -0,0 +1,29 @@
const included = require("../../requires")
// Here you can add functions that will be run at each startup of the bot
module.exports = {
name:"reloadCommands",
async function(msg, args){
commands.clear()
var path = `${__dirname}/../../functions`
var folders = fs.readdirSync(path).filter(function (file) {
return fs.statSync(path+'/'+file).isDirectory();
});
folders.forEach(element => {
var commandFiles = fs.readdirSync(`${path}/${element}`).filter(file => file.endsWith('.js') && !file.startsWith("index"));
for (const file of commandFiles) {
delete require.cache[require.resolve(`${path}/${element}/${file}`)];
try {
const command = require(`${path}/${element}/${file}`);
commands.set(command.name, command);
} catch (error) {
console.log(error);
}
}
});
// commands.get("garbage_collector").function() // reset garbage collector
console.log(`Reloading ${commands.size} modules done`)
}
}
+20
View File
@@ -0,0 +1,20 @@
module.exports = {
name:"validate",
check: async function(apiKey){
return new Promise(async (resolve,reject) => {
if(apiKey == undefined){
reject(1)
}
let user = await commands.get("query").function("SELECT idUser from tbl_users WHERE dtApiKey = ?",[apiKey])
if(user.length == 1){
resolve(user[0].idUser)
}else{
// resolve(false)
reject(2)
}
})
}
}