diff --git a/index.js b/index.js index beb2a48..90d0c08 100644 --- a/index.js +++ b/index.js @@ -37,7 +37,7 @@ let discordClient = new Discord.Client({ Discord.GatewayIntentBits.GuildWebhooks, Discord.GatewayIntentBits.GuildInvites, Discord.GatewayIntentBits.GuildVoiceStates, - Discord.GatewayIntentBits.GuildPresences, + //Discord.GatewayIntentBits.GuildPresences, Discord.GatewayIntentBits.GuildMessages, Discord.GatewayIntentBits.GuildMessageReactions, //Discord.GatewayIntentBits.GuildMessageTyping, @@ -153,7 +153,7 @@ database_pool.query('SELECT NOW();', (err, res) => { //These events are only used by the bot, users can't use these discordClient.on("guildCreate", async(guild)=>{ - database_pool.query("INSERT INTO servers (server_id, name) VALUES ($1, $2) ON CONFLICT DO NOTHING;", [guild.id, guild.name]) + database_pool.query("INSERT INTO servers (server_id) VALUES ($1) ON CONFLICT DO NOTHING;", [guild.id]) .then(()=>{ logger.info("Bot was added in a new server : "+guild.id+"("+guild.name+")"); logger.debug("Successfully added a new server to database !"); @@ -165,19 +165,6 @@ database_pool.query('SELECT NOW();', (err, res) => { logger.info("Bot was removed from a guild : "+guild.id+"("+guild.name+")"); }); - discordClient.on("guildUpdate", async(oldGuild, newGuild)=>{ - if(oldGuild.name===newGuild.name)return; - //This guild has a new name, we will save it in database - database_pool.query("UPDATE servers SET name = $1 WHERE server_id = $2;", [newGuild.name, newGuild.id]) - .then(async()=>{ - logger.debug("Saved a new name for guild "+newGuild.id); - }) - .catch((err)=>{ - logger.error("Error while saving the new name of guild "+newGuild.id+" : "+err); - }); - - }); - discordClient.on("interactionCreate", async(interaction) => {//See https://discordjs.guide/creating-your-bot/command-handling.html#executing-commands if (!interaction.isChatInputCommand()) return;//Do nothing here if not a chat command const command = interaction.client.commands.get(interaction.commandName); diff --git a/modules/data_storage_functions.js b/modules/data_storage_functions.js new file mode 100644 index 0000000..911fad3 --- /dev/null +++ b/modules/data_storage_functions.js @@ -0,0 +1,83 @@ +'use-strict'; + +//Functions used to manage saved data in database + +module.exports = { + + saveValueInStorage: async function(database_pool, logger, serverId, storageName, key, value){ + /* Save a new value in a server's storage */ + + //Key and value must be defined + if(!key || key=='' || value===undefined || value==='')return; + + //We will check that key and valud aren't bigger than 32 or 256 char + if(key.length > 32){ + key = key.slice(0, 32); + } + if(value.toString().length > 1024){ + logger.debug("Can't save data in data storage for server "+serverId+" : value length exceed limit"); + return; + } + + database_pool.query("SELECT f_insert_or_update_data($1, $2, $3, $4)", + [serverId, storageName, key, value.toString()]) + .catch((err)=>{ + logger.error("Error while saving data in data storage for server "+serverId+" : "+err); + }); + + }, + + getValueInStorage: async function(database_pool, logger, serverId, storageName, key){ + /* Get a value stored in a data storage from database */ + + //We will check that key isn't bigger than 32 char + if(key.length > 32){ + key = key.slice(0, 32); + } + + try{ + const row = (await database_pool.query("SELECT d.data, s.storage_is_int FROM data_storage s INNER JOIN stored_data d ON s.storage_id=d.storage_id WHERE s.server_id = $1 AND s.storage_name = $2 AND d.data_key = $3;", + [serverId, storageName, key])).rows[0]; + + if(row){ + return row.data; + }else if(storageName.startsWith('I')){ + return -1; + }else if(storageName.startsWith('S')){ + return 'undefined'; + }else{ + throw('Error : Invalid storage name "'+storageName+'" for server '+serverId); + } + + }catch(err){ + logger.error("Error while getting data from data storage for server "+serverId+" : "+err); + + if(storageName.startsWith('I')){ + return -1; + }else if(storageName.startsWith('S')){ + return 'undefined'; + }else{ + return null;//May cause errors in workspaces, so using this can be considered a bug + } + + } + }, + + deleteValueInStorage: async function(database_pool, logger, serverId, storageName, key){ + /* Get a value stored in a data storage from database */ + + //We will check that key isn't bigger than 32 char + if(key.length > 32){ + key = key.slice(0, 32); + } + + try{ + await database_pool.query("DELETE FROM stored_data WHERE data_id = (SELECT d.data_id FROM data_storage s INNER JOIN stored_data d ON s.storage_id=d.storage_id WHERE s.server_id = $1 AND s.storage_name = $2 AND d.data_key = $3);", + [serverId, storageName, key]); + + }catch(err){ + logger.error("Error while deleting data from data storage for server "+serverId+" : "+err); + } + }, + +} diff --git a/modules/event_functions.js b/modules/event_functions.js index 30c6251..2b08d7d 100644 --- a/modules/event_functions.js +++ b/modules/event_functions.js @@ -3,17 +3,11 @@ /* Functions executed on guilds events are defined here */ const {NodeVM} = require('vm2');//Sandbox -const get_sandbox = require('./init_sandbox.js').getSandbox;//Return a sandbox when called with object containing shared vars as arg +const run_code_in_sandbox = require('./sandbox.js').runCodeInSandbox;//Run code in a sandbox const get_help_embed = require('./help_embed.js');//Return an embed that explain how to use the bot +const data_storage_functions = require('./data_storage_functions.js');//Functions used to manage data saved in database const Discord = require('discord.js'); -//Alls these var must be declared when executing generated code. These var are created at code generation ( Blockly ) Functions used by blocks can also be added here -const globalVars = `let embedMessage,createdTextChannel,createdVoiceChannel,sentMessage,createdThreadOnMessage,createdRank;let temporaryStorage = {}; - /*Functions*/ function colourRandom() {let num = Math.floor(Math.random() * Math.pow(2, 24));return '#' + ('00000' + num.toString(16)).substr(-6);} - function mathRandomInt(min, max){return Math.floor(Math.random() * (max - min + 1) + min)}; - const sleep = ms => new Promise(r => {if(ms>5000){throw('Timeout too long !')}setTimeout(r, ms)}); - function strToInt(str){if(/^[0-9]{1,16}$/.test(str)){return(parseInt(str));}else{return(-1);}}`; - //SQL request to get code to execute, $n are defined when executing this request const sqlRequest = "SELECT code FROM server_code WHERE server_id = $1 AND action_type = $2 AND active = TRUE;"; @@ -38,7 +32,6 @@ async function didBotDidIt(guild, eventType){ return false;//An user did it } - module.exports = { interactionCreate: async(interaction, logger, database_pool)=>{ @@ -61,12 +54,10 @@ module.exports = { } logger.debug("Got SQL result for "+CURRENT_GUILD.id+", we found a command to run !"); - - const vm = get_sandbox({CURRENT_GUILD:CURRENT_GUILD, Discord:Discord, interaction:interaction});//A sandbox is created in module init_sandbox.js - //We will delay the answer and start the sandbox : await interaction.deferReply({ ephemeral: res.rows[0].ephemeral }); - vm.run(globalVars+"async function a(){"+res.rows[0].code+"};a();"); + run_code_in_sandbox({CURRENT_GUILD:CURRENT_GUILD, Discord:Discord, interaction:interaction}, + database_pool, logger, res.rows); }) .catch(err =>{//Got an error while getting data from database or while executing code @@ -106,10 +97,7 @@ module.exports = { logger.debug("Got SQL result for "+CURRENT_GUILD.id+", codes to execute : "+res.rows.length); - const vm = get_sandbox({CURRENT_GUILD:CURRENT_GUILD, Discord:Discord, eventMessage:eventMessage});//A sandbox is created in module init_sandbox.js - for(let i=0; i{//Got an error while getting data from database or while executing code @@ -136,10 +124,7 @@ module.exports = { logger.debug("Got SQL result for "+CURRENT_GUILD.id+", codes to execute : "+res.rows.length); - const vm = get_sandbox({CURRENT_GUILD:CURRENT_GUILD, Discord:Discord, eventMessage:eventMessage});//A sandbox is created in module init_sandbox.js - for(let i=0; i{//Got an error while getting data from database or while executing code @@ -166,10 +151,8 @@ module.exports = { logger.debug("Got SQL result for "+CURRENT_GUILD.id+", codes to execute : "+res.rows.length); - const vm = get_sandbox({CURRENT_GUILD:CURRENT_GUILD, Discord:Discord, eventOldMessage:eventOldMessage, eventNewMessage:eventNewMessage});//A sandbox is created in module init_sandbox.js - for(let i=0; i{//Got an error while getting data from database or while executing code @@ -191,10 +174,8 @@ module.exports = { logger.debug("Got SQL result for "+CURRENT_GUILD.id+", codes to execute : "+res.rows.length); - const vm = get_sandbox({CURRENT_GUILD:CURRENT_GUILD, Discord:Discord, eventUser:eventUser});//A sandbox is created in module init_sandbox.js - for(let i=0; i{//Got an error while getting data from database or while executing code @@ -216,10 +197,8 @@ module.exports = { logger.debug("Got SQL result for "+CURRENT_GUILD.id+", codes to execute : "+res.rows.length); - const vm = get_sandbox({CURRENT_GUILD:CURRENT_GUILD, Discord:Discord, eventUser:eventUser});//A sandbox is created in module init_sandbox.js - for(let i=0; i{//Got an error while getting data from database or while executing code @@ -243,10 +222,8 @@ module.exports = { logger.debug("Got SQL result for "+CURRENT_GUILD.id+", codes to execute : "+res.rows.length); - const vm = get_sandbox({CURRENT_GUILD:CURRENT_GUILD, Discord:Discord, eventOldUser:eventOldUser, eventNewUser:eventNewUser});//A sandbox is created in module init_sandbox.js - for(let i=0; i{//Got an error while getting data from database or while executing code @@ -284,10 +261,9 @@ module.exports = { logger.debug("Got SQL result for "+CURRENT_GUILD.id+", codes to execute : "+res.rows.length); - const vm = get_sandbox({CURRENT_GUILD:CURRENT_GUILD, Discord:Discord, eventVoiceChannel:eventVoiceChannel, eventTextChannel:eventTextChannel, eventThreadChannel:eventThreadChannel});//A sandbox is created in module init_sandbox.js - for(let i=0; i{//Got an error while getting data from database or while executing code @@ -323,10 +299,9 @@ module.exports = { logger.debug("Got SQL result for "+CURRENT_GUILD.id+", codes to execute : "+res.rows.length); - const vm = get_sandbox({CURRENT_GUILD:CURRENT_GUILD, Discord:Discord, eventVoiceChannel:eventVoiceChannel, eventTextChannel:eventTextChannel, eventThreadChannel:eventThreadChannel});//A sandbox is created in module init_sandbox.js - for(let i=0; i{//Got an error while getting data from database or while executing code @@ -374,12 +349,10 @@ module.exports = { logger.debug("Got SQL result for "+CURRENT_GUILD.id+", codes to execute : "+res.rows.length); - const vm = get_sandbox({CURRENT_GUILD:CURRENT_GUILD, Discord:Discord, + run_code_in_sandbox({CURRENT_GUILD:CURRENT_GUILD, Discord:Discord, eventOldVoiceChannel:eventOldVoiceChannel, eventNewVoiceChannel:eventNewVoiceChannel, eventOldTextChannel:eventOldTextChannel, - eventNewTextChannel:eventNewTextChannel, eventOldThreadChannel:eventOldThreadChannel, eventNewThreadChannel:eventNewThreadChannel});//A sandbox is created in module init_sandbox.js - for(let i=0; i{//Got an error while getting data from database or while executing code @@ -403,10 +376,8 @@ module.exports = { logger.debug("Got SQL result for "+CURRENT_GUILD.id+", codes to execute : "+res.rows.length); - const vm = get_sandbox({CURRENT_GUILD:CURRENT_GUILD, Discord:Discord, eventRole:eventRole});//A sandbox is created in module init_sandbox.js - for(let i=0; i{//Got an error while getting data from database or while executing code @@ -430,10 +401,8 @@ module.exports = { logger.debug("Got SQL result for "+CURRENT_GUILD.id+", codes to execute : "+res.rows.length); - const vm = get_sandbox({CURRENT_GUILD:CURRENT_GUILD, Discord:Discord, eventRole:eventRole});//A sandbox is created in module init_sandbox.js - for(let i=0; i{//Got an error while getting data from database or while executing code @@ -457,10 +426,8 @@ module.exports = { logger.debug("Got SQL result for "+CURRENT_GUILD.id+", codes to execute : "+res.rows.length); - const vm = get_sandbox({CURRENT_GUILD:CURRENT_GUILD, Discord:Discord, eventOldRole:eventOldRole, eventNewRole:eventNewRole});//A sandbox is created in module init_sandbox.js - for(let i=0; i{//Got an error while getting data from database or while executing code @@ -483,10 +450,8 @@ module.exports = { logger.debug("Got SQL result for "+CURRENT_GUILD.id+", codes to execute : "+res.rows.length); - const vm = get_sandbox({CURRENT_GUILD:CURRENT_GUILD, Discord:Discord, eventUser:eventUser});//A sandbox is created in module init_sandbox.js - for(let i=0; i{//Got an error while getting data from database or while executing code @@ -508,10 +473,8 @@ module.exports = { logger.debug("Got SQL result for "+CURRENT_GUILD.id+", codes to execute : "+res.rows.length); - const vm = get_sandbox({CURRENT_GUILD:CURRENT_GUILD, Discord:Discord, eventUser:eventUser});//A sandbox is created in module init_sandbox.js - for(let i=0; i{//Got an error while getting data from database or while executing code @@ -549,10 +512,9 @@ module.exports = { logger.debug("Got SQL result for "+CURRENT_GUILD.id+", codes to execute : "+res.rows.length); - const vm = get_sandbox({CURRENT_GUILD:CURRENT_GUILD, Discord:Discord, eventReaction:eventReaction, eventMessage:eventMessage, eventUser:eventUser});//A sandbox is created in module init_sandbox.js - for(let i=0; i{//Got an error while getting data from database or while executing code @@ -590,10 +552,9 @@ module.exports = { logger.debug("Got SQL result for "+CURRENT_GUILD.id+", codes to execute : "+res.rows.length); - const vm = get_sandbox({CURRENT_GUILD:CURRENT_GUILD, Discord:Discord, eventReaction:eventReaction, eventMessage:eventMessage, eventUser:eventUser});//A sandbox is created in module init_sandbox.js - for(let i=0; i{//Got an error while getting data from database or while executing code @@ -620,10 +581,9 @@ module.exports = { logger.debug("Got SQL result for "+CURRENT_GUILD.id+", codes to execute : "+res.rows.length); - const vm = get_sandbox({CURRENT_GUILD:CURRENT_GUILD, Discord:Discord, eventOldVoiceChannel:eventOldVoiceChannel, eventNewVoiceChannel:eventNewVoiceChannel, eventUser:eventUser});//A sandbox is created in module init_sandbox.js - for(let i=0; i{//Got an error while getting data from database or while executing code @@ -651,10 +611,8 @@ module.exports = { logger.debug("Got SQL result for "+CURRENT_GUILD.id+", codes to execute : "+res.rows.length); - const vm = get_sandbox({CURRENT_GUILD:CURRENT_GUILD, Discord:Discord, eventUser:eventUser, eventTextChannel:eventTextChannel});//A sandbox is created in module init_sandbox.js - for(let i=0; i{//Got an error while getting data from database or while executing code diff --git a/modules/help_embed.js b/modules/help_embed.js index 17ddc0e..090192a 100644 --- a/modules/help_embed.js +++ b/modules/help_embed.js @@ -15,5 +15,6 @@ module.exports = ()=>{ .addFields({name:'Disblock\'s dashboard', value:'You can configure Disblock [Here](https://disblock.xyz/panel). Login, and select a server to see the editor ! ', inline:true}) .addFields({name:'I need help !', value:'No problem, you can check the [docs](https://docs.disblock.xyz), or join the [support server](https://discord.gg/4b6j3UBKWp). Also, be sure to give the right permissions to the bot when creating an action flow !', inline:true}) .addFields({name:'How do I get started ?', value:'We have a page in the docs to answer this question ! Just read [this](https://docs.disblock.xyz/disblock/first-steps) and everything should be more clear !', inline:false}) + .addFields({name:'Useful links', value:'[Dashboard](https://disblock.xyz/panel) • [Support server](https://discord.gg/4b6j3UBKWp) • [Vote for Disblock](https://top.gg/bot/903324635108634654/vote) • [Leave a review](https://top.gg/bot/903324635108634654#reviews)', inline:false}) ) } diff --git a/modules/init_sandbox.js b/modules/init_sandbox.js deleted file mode 100644 index af15bbe..0000000 --- a/modules/init_sandbox.js +++ /dev/null @@ -1,22 +0,0 @@ -'use strict'; -const {NodeVM} = require('vm2');//Sandbox - -module.exports = { - - //Get the sandbox object for a vm and return the created vm - //https://github.com/patriksimek/vm2#nodevm - getSandbox: function(args){ - - return new NodeVM({ - //console: 'inherit', //Show console - console: 'off', - sandbox: args, - eval: false, - wasm: false, - nesting: false, - require: false, - strict: true - }); - } - -} diff --git a/modules/sandbox.js b/modules/sandbox.js new file mode 100644 index 0000000..b961040 --- /dev/null +++ b/modules/sandbox.js @@ -0,0 +1,54 @@ +'use strict'; +const {NodeVM} = require('vm2');//Sandbox +const data_storage_functions = require('./data_storage_functions.js');//Functions used to manage data saved in database + +//Alls these var must be declared when executing generated code. These var are created at code generation ( Blockly ) Functions used by blocks can also be added here +const globalVars = `let embedMessage,createdTextChannel,createdVoiceChannel,sentMessage,createdThreadOnMessage,createdRank;let temporaryStorage = {}; + /*Functions*/ function colourRandom() {let num = Math.floor(Math.random() * Math.pow(2, 24));return '#' + ('00000' + num.toString(16)).substr(-6);} + function mathRandomInt(min, max){return Math.floor(Math.random() * (max - min + 1) + min)}; + const sleep = ms => new Promise(r => {if(ms>5000){throw('Timeout too long !')}setTimeout(r, ms)}); + function strToInt(str){if(/^[0-9]{1,16}$/.test(str)){return(parseInt(str));}else{return(-1);}}`; + +//Function that will add the object that allow us to manage stored data in database to sandbox +function addDataStorageObject(vm, database_pool, logger, serverId){ + const dataStorage = { + saveValue: async function(storageName, key, value){//Pool, logger, and server_id shouldn't be editable in sandbox. + data_storage_functions.saveValueInStorage(database_pool, logger, serverId, storageName, key, value); + }, + getValue: async function(storageName, key){ + return await data_storage_functions.getValueInStorage(database_pool, logger, serverId, storageName, key); + }, + delValue: async function(storageName, key){ + return await data_storage_functions.deleteValueInStorage(database_pool, logger, serverId, storageName, key); + } + }; + + vm.freeze(dataStorage, 'dataStorage'); +} + +module.exports = { + + //Create the sandbox, add neccessary variables in it, and run code + //https://github.com/patriksimek/vm2#nodevm + runCodeInSandbox: function(args, database_pool, logger, sqlRows){ + + let vm = new NodeVM({ + //console: 'inherit', //Show console + console: 'off', + sandbox: args,//Must at least contain CURRENT_GUILD, server that triggered an event + eval: false, + wasm: false, + nesting: false, + require: false, + strict: true + }); + + addDataStorageObject(vm, database_pool, logger, args.CURRENT_GUILD.id);//Used to manage data in database + + for(let i=0; i