Initial commit
This commit is contained in:
@@ -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})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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})
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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()])
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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]
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
});
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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}`)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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()
|
||||
}
|
||||
})();
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -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`)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user