From 931d740c563d9dbf329aa1a6167917021a8df93b Mon Sep 17 00:00:00 2001 From: giuseppe marino Date: Sat, 4 Feb 2017 18:08:01 +0100 Subject: [PATCH 01/42] Cats More cats --- plugins/httpcat.lua | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 plugins/httpcat.lua diff --git a/plugins/httpcat.lua b/plugins/httpcat.lua new file mode 100644 index 0000000..f327856 --- /dev/null +++ b/plugins/httpcat.lua @@ -0,0 +1,26 @@ +local function run(msg, matches) + local receiver = get_receiver(msg) + local res, code = https.request("https://http.cat/" .. matches[1]) + if code == 404 then + send_msg(receiver, "Oops where is the cat?!!", ok_cb, nil) + send_photo_from_url_callback({receiver = receiver, url = "https://http.cat/404"}) + return nil + end + if code ~= 200 then + return "There was an error downloading the image" + else + local file = io.open("tmp.jpg", "w+") + file:write(res) + file:close() + send_photo(receiver, "tmp.jpg", rmtmp_cb, {file_path="tmp.jpg"}) + end +end +return{ + patterns = { + "^!httpcat (%d+)$" + }, + run = run, + usage = { + "!httpcat : gives an image from http.cat" + } +} \ No newline at end of file From 5205823825dc5e5b1eca6bdc7f7eb0a25009e070 Mon Sep 17 00:00:00 2001 From: giuseppe marino Date: Sat, 4 Feb 2017 21:06:20 +0100 Subject: [PATCH 02/42] Fixed config generator --- bot/bot.lua | 43 +++++++++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 12 deletions(-) diff --git a/bot/bot.lua b/bot/bot.lua index a0523a8..9d0f633 100644 --- a/bot/bot.lua +++ b/bot/bot.lua @@ -240,26 +240,45 @@ function create_config( ) -- A simple config with basic plugins and ourselves as privileged user config = { enabled_plugins = { - "echo", - "get", - "google", "groupmanager", "help", - "id", - "images", - "img_google", "location", - "media", "plugins", - "channels", - "set", "stats", "time", "version", - "weather", - "youtube", "media_handler", - "moderation"}, + "moderation", + "sudo", + "9gag", + "xkcd", + "wiki", + "danbooru", + "imdb", + "boobs", + "banhammer", + "meme", + "weather", + "pokedex", + "rss", + "roll", + "join", + "eur", + "isup", + "torrent_search", + "music", + "hello", + "invite_sudo", + "id", + "antispam", + "delmsg", + "anti-flood", + "expand", + "tex", + "webshot", + "translate", + "mute" + }, sudo_users = {our_id}, disabled_channels = {}, moderation = {data = 'data/moderation.json'} From 85237e3850e349561695079e8605345d6fba448d Mon Sep 17 00:00:00 2001 From: giuseppe marino Date: Thu, 2 Mar 2017 18:36:03 +0100 Subject: [PATCH 03/42] Improved stats --- plugins/stats.lua | 55 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 53 insertions(+), 2 deletions(-) diff --git a/plugins/stats.lua b/plugins/stats.lua index adb44fc..795b0b8 100644 --- a/plugins/stats.lua +++ b/plugins/stats.lua @@ -127,11 +127,43 @@ do hash = 'chat:*:users' r = redis:eval(redis_scan, 1, hash) text = text..'\nChats: '..r + hash = 'banned:*' + r = redis:eval(redis_scan, 1, hash) + text = text .. '\nBans: ' ..r + hash = 'superbanned:*' + r = redis:eval(redis_scan, 1, hash) + text = text .. '\nSuperbans: ' ..r + hash = 'blocklist:*' + r = redis:eval(redis_scan, 1, hash) + text = text .. '\nBlocklist: ' ..r return text end + local function superban_stats() + local hash = 'superbanned:*' + local r = redis:keys(hash) + if not r then + return "No ids superbanned" + end + local text = 'List of superbanned ids:\n\n---------' + for k, v in pairs(r) do + text = text .. "\n " .. k .. ". " .. v:gsub("superbanned:", "") + end + return text + end + + local function blocklist_stats() + local hash = 'blocklist:*' + local r = redis:keys(hash) + local text = 'blocklist ids:\n\n---------' + for k, v in pairs(r) do + text = text .. "\n " .. k .. ". " .. v:gsub("blocklist:", "") + end + return text + end + local function run(msg, matches) if matches[1]:lower() == "stats" then @@ -159,6 +191,23 @@ do return chat_stats(matches[3]) end end + + if matches[2] == "superban" then + if not is_admin(msg) then + return "This command require privileged user" + else + return superban_stats() + end + end + + if matches[2] == "blocklist" then + if not is_blocklistadm(msg) then + return "This command require privileged user" + else + return blocklist_stats() + end + end + end end @@ -172,8 +221,10 @@ do }, patterns = { "^!([Ss]tats)$", - "^!([Ss]tats) (chat) (%d+)", - "^!([Ss]tats) (bot)" + "^!([Ss]tats) (chat) (%d+)$", + "^!([Ss]tats) (bot)$", + "^!([Ss]tats) (superban)s?$", + "^!([Ss]tats) (blocklist)" }, run = run, pre_process = pre_process From 94dacf9fc3904e31c0d5ccd8e5594d0745c2628a Mon Sep 17 00:00:00 2001 From: giuseppeM99 Date: Fri, 7 Apr 2017 19:35:31 +0200 Subject: [PATCH 04/42] Preventing bot flood Signed-off-by: giuseppeM99 --- plugins/anti-flood.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/anti-flood.lua b/plugins/anti-flood.lua index f1c7311..ce356d7 100644 --- a/plugins/anti-flood.lua +++ b/plugins/anti-flood.lua @@ -149,7 +149,7 @@ local function kick_user(user_id, chat_id) local hash = 'anti-flood:'..msg.from.id..':'..msg.to.id..':msg-num' local msgs = tonumber(redis:get(hash) or 0) - if msgs > NUM_MSG_MAX then + if msgs > NUM_MSG_MAX and msgs < NUM_MSG_MAX + 3 then local receiver = get_receiver(msg) local user = msg.from.id local text = str2emoji(":exclamation:")..' User ' From c2893effdcc02f88e9de3063699a341d10ede9f5 Mon Sep 17 00:00:00 2001 From: giuseppeM99 Date: Sat, 8 Jul 2017 16:01:05 +0200 Subject: [PATCH 05/42] Plugins updates. Moving to madeline --- .gitmodules | 6 +++--- Madeline_lua_shim | 1 + tg | 1 - 3 files changed, 4 insertions(+), 4 deletions(-) create mode 160000 Madeline_lua_shim delete mode 160000 tg diff --git a/.gitmodules b/.gitmodules index f033e96..edd35df 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ -[submodule "tg"] - path = tg - url = https://github.com/LucentW/tg.git +[submodule "Madeline_lua_shim"] + path = Madeline_lua_shim + url = https://github.com/giuseppeM99/Madeline_lua_shim diff --git a/Madeline_lua_shim b/Madeline_lua_shim new file mode 160000 index 0000000..f2a1b6b --- /dev/null +++ b/Madeline_lua_shim @@ -0,0 +1 @@ +Subproject commit f2a1b6b9c661ea2d98dd8e96bce050723aec7e47 diff --git a/tg b/tg deleted file mode 160000 index 3e03c12..0000000 --- a/tg +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3e03c12f66701df0c63ca540e09861664a37c923 From 98b6773e55276b04ada6a931c3918718b3ba530c Mon Sep 17 00:00:00 2001 From: giuseppeM99 Date: Sat, 8 Jul 2017 16:04:51 +0200 Subject: [PATCH 06/42] Real updates --- .gitignore | 4 + launch.sh | 48 +++++----- madeline.php | 45 ++++++++++ plugins/banhammer.lua | 37 +++++--- plugins/groupmanager.lua | 30 +++++-- plugins/moderation.lua | 17 ++-- plugins/warn.lua | 183 +++++++++++++++++++++++++++++++++++++++ start.lua | 45 ++++++++++ 8 files changed, 367 insertions(+), 42 deletions(-) create mode 100644 madeline.php create mode 100644 plugins/warn.lua create mode 100644 start.lua diff --git a/.gitignore b/.gitignore index 46109bb..3661006 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,10 @@ luac.out *.hex +composer.lock +*.madeline +data/config.lua + # ========================= # Operating System Files # ========================= diff --git a/launch.sh b/launch.sh index a5d4ba8..002d060 100755 --- a/launch.sh +++ b/launch.sh @@ -107,42 +107,50 @@ install_rocks() { install() { git pull git submodule update --init --recursive - cd tg && ./configure && make + cd Madeline_lua_shim && composer update + cd .. +} - RET=$?; if [ $RET -ne 0 ]; then - echo "Trying without Python..."; - ./configure --disable-python && make - RET=$? +botlogin() { + if [ ! -f ./Madeline_lua_shim/vendor/autoload.php ]; then + echo "MadelineProto not found, installing..." + install fi + cd Madeline_lua_shim + php botlogin.php + cp bot.madeline ../bot.madeline + cd .. +} - if [ $RET -ne 0 ]; then - echo "Error. Exiting."; exit $RET; +login() { + if [ ! -f ./Madeline_lua_shim/vendor/autoload.php ]; then + echo "MadelineProto not found, installing..." + install fi + cd Madeline_lua_shim + php userlogin.php + cp bot.madeline ../bot.madeline cd .. - install_luarocks - install_rocks } if [ "$1" = "install" ]; then install elif [ "$1" = "update" ]; then update +elif [ "$1" = "login"]; then + login +elif [ "$1" = "botlogin" ]; then + botlogin else - if [ ! -f ./tg/telegram.h ]; then - echo "tg not found" + if [ ! -f ./Madeline_lua_shim/vendor/autoload.php ]; then + echo "MadelineProto not found" echo "Run $0 install" exit 1 fi - if [ ! -f ./tg/bin/telegram-cli ]; then - echo "tg binary not found" - echo "Run $0 install" + if [ ! -e "bot.madeline" ]; then + echo "Login file not found" + echo "Run $0 login or $0 botlogin" exit 1 fi - - if [ ! -e "bot_mode" ]; then - ./tg/bin/telegram-cli -k ./tg/tg-server.pub -s ./bot/bot.lua -l 1 -E - else - ./tg/bin/telegram-cli -k ./tg/tg-server.pub -s ./bot/bot.lua -l 1 -E -b - fi fi diff --git a/madeline.php b/madeline.php new file mode 100644 index 0000000..2f777d7 --- /dev/null +++ b/madeline.php @@ -0,0 +1,45 @@ +#!/usr/bin/env php +. +*/ + +//See https://github.com/danog/MadelineProto/blob/master/lua/madeline.php + +require 'vendor/autoload.php'; +$settings = ['app_info' => ['api_id' => 6, 'api_hash' => 'eb06d4abfb49dc3eeb1aeb98ae0f581e'], 'logger' => ['loglevel' => \danog\MadelineProto\Logger::ERROR]]; +$Lua = false; + +try { + $Lua = new \danog\MadelineProto\Lua('start.lua', \danog\MadelineProto\Serialization::deserialize('bot.madeline')); +} catch (\danog\MadelineProto\Exception $e) { + die($e->getMessage().PHP_EOL); +} + +$Lua->MadelineProto->lua = true; +foreach ($Lua->MadelineProto->get_methods_namespaced() as $method => $namespace) { + $Lua->MadelineProto->{$namespace}->lua = true; +} + +$offset = 0; +while (true) { + + $updates = $Lua->MadelineProto->API->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]) + + foreach ($updates as $update) { + $offset = $update['update_id'] + 1; + $Lua->madeline_update_callback($update['update']); + echo PHP_EOL; + } + + $Lua->doCrons(); + \danog\MadelineProto\Serialization::serialize('bot.madeline', $Lua->MadelineProto); + +} diff --git a/plugins/banhammer.lua b/plugins/banhammer.lua index fc3ef7a..95e7b40 100644 --- a/plugins/banhammer.lua +++ b/plugins/banhammer.lua @@ -195,19 +195,34 @@ local function is_blocklisted(user_id, chat_id) return blocklisted and is_chat_blocklist_ok end +local function check_ban_all(chat, users, is_chan) + for _, user in ipairs(users) do + print('Checking invited user '..user_id) + local user_id = user.id + local superbanned = is_super_banned2(user_id, chat) + local banned = is_banned(user_id, chat) + local blocklisted = is_blocklisted(user_id, chat) + if superbanned or banned or blocklisted then + print('User is banned!') + if not is_chan_msg(msg) then + kick_user(user_id, chat, "chat#id" .. chat) + else + kick_chan_user(user_id, chat, "channel#id" .. chat) + end + end + end +end + local function pre_process(msg) -- SERVICE MESSAGE if msg.action and msg.action.type then local action = msg.action.type -- Check if banned user joins chat - if action == 'chat_add_user' or action == 'chat_add_user_link' then - local user_id - if msg.action.link_issuer then - user_id = msg.from.id - else - user_id = msg.action.user.id - end + if action == 'chat_add_user' then + check_ban_all(msg.to.id, users, is_chan_msg(msg)) + elseif action == 'chat_add_user_link' then + local user_id = msg.from.id print('Checking invited user '..user_id) local superbanned = is_super_banned2(user_id, msg.to.id) local banned = is_banned(user_id, msg.to.id) @@ -479,12 +494,12 @@ local function run(msg, matches) return str2emoji(':information_source:')..' Superbans are now enforced on group '..string.gsub(msg.to.print_name, '_', ' ')..' ['..msg.to.id..'].' end end - + --Only admin can superban if not is_admin(msg) then return nil end ---Superban via reply +--Superban via reply if msg.reply_id then get_message(msg.reply_id, superban_by_reply, {is_chan=is_chan_msg(msg),receiver=get_receiver(msg)}) return nil @@ -542,7 +557,7 @@ local function run(msg, matches) resolve_username(member, resolved_username, {get_cmd=get_cmd, receiver=receiver, chat_id=chat_id, member=member, is_chan=is_chan_msg(msg)}) end end - + --Enable/Disable Blocklist in chat if matches[2] == 'enable' then local hash = 'blocklistok:'..msg.to.id @@ -635,7 +650,7 @@ local function run(msg, matches) redis:del(hash) return str2emoji(':information_source:')..' Chat '..msg.to.print_name..' ['..msg.to.id..'] removed from whitelist' end - + --Enable/Disable modonly if matches[2] == 'modonly' and matches[3] == 'enable' and is_momod(msg) then local hash = 'whitelist:modonly:'..msg.to.id diff --git a/plugins/groupmanager.lua b/plugins/groupmanager.lua index 9c85b08..0376b23 100644 --- a/plugins/groupmanager.lua +++ b/plugins/groupmanager.lua @@ -213,6 +213,20 @@ do return text end + local function ban_all(chat, users, is_chan, bots_only) + if is_chan then + for _, user in ipairs(users) do + if not bots_only or bots_only and is_bot(user) then + channel_kick(chat, "user#id" .. user.id, ok_cb, nil) + end + end + else + if not bots_only or bots_only and is_bot(user) then + chat_del_user(chat, "user#id" .. user.id, ok_cb, nil) + end + end + end + function run(msg, matches) --vardump(msg) if matches[1] == 'creategroup' and matches[2] then @@ -334,23 +348,27 @@ do if not is_chan_msg(msg) then chat = 'chat#id'..msg.to.id if group_member_lock == 'yes' then - chat_del_user(chat, user, ok_cb, true) + --chat_del_user(chat, user, ok_cb, true) + ban_all(chat, msg.action.users, false, false) end if group_bots_lock == 'yes' then - if is_bot(userobj) then + --[[if is_bot(userobj) then chat_del_user(chat, user, ok_cb, true) - end + end--]] + ban_all(chat, msg.action.users, false, true) end return nil else chat = 'channel#id'..msg.to.id if group_member_lock == 'yes' then - channel_kick(chat, user, ok_cb, true) + --channel_kick(chat, user, ok_cb, true) + ban_all(chat, msg.action.users, true, false) end if group_bots_lock == 'yes' then - if is_bot(userobj) then + --[[if is_bot(userobj) then channel_kick(chat, user, ok_cb, true) - end + end--]] + ban_all(chat, msg.action.users, true, true) end return nil end diff --git a/plugins/moderation.lua b/plugins/moderation.lua index 91eb6fc..521e549 100644 --- a/plugins/moderation.lua +++ b/plugins/moderation.lua @@ -216,7 +216,7 @@ do return send_large_msg(receiver, 'Blocklist admin '..member_username..' has been demoted.') end - + local function syncmods(cb_extra, success, result) local receiver = cb_extra @@ -227,14 +227,14 @@ do return send_large_msg(receiver, 'Group is not added.') end data[group]['moderators'] = {} - + for _,cur_user in pairs(result) do if cur_user.peer_id ~= our_id then data[group]['moderators'][tostring(cur_user.peer_id)] = cur_user.username end end save_data(_config.moderation.data, data) - + send_large_msg(receiver, "Moderators synced successfully.") end @@ -489,8 +489,15 @@ do end return blocklistadm_list(msg) end - if matches[1] == 'chat_add_user' and msg.action.user.id == our_id then - return automodadd(msg) + if matches[1] == 'chat_add_user' then + print("Check for automodadd") + for _, user in ipairs(msg.action.users) do + print("The for is working") + if user.id == our_id then + print("Hello, it's me") + return automodadd(msg) + end + end end if matches[1] == 'chat_created' and msg.from.id == 0 then return automodadd(msg) diff --git a/plugins/warn.lua b/plugins/warn.lua new file mode 100644 index 0000000..93db0ae --- /dev/null +++ b/plugins/warn.lua @@ -0,0 +1,183 @@ +local MAX_WARN = 3 + +local function ban_user(user_id, chat_id) + local chat = 'chat#id'..chat_id + local user = 'user#id'..user_id + local hash = 'banned:'..chat_id..':'..user_id + redis:set(hash, true) + chat_del_user(chat, user, function (data, success, result) + if success ~= 1 then + local text = str2emoji(":exclamation:")..' I can\'t kick '..data.user..' but should be kicked' + snoop_msg('I am unable to kick user '..user_id..' from group '..chat_id..'.') + send_msg(data.chat, text, ok_cb, nil) + end + end, {chat=chat, user=user}) +end + +local function ban_chan_user(user_id, chat_id) + local chat = 'channel#id'..chat_id + local user = 'user#id'..user_id + local hash = 'banned:'..chat_id..':'..user_id + redis:set(hash, true) + channel_kick(chat, user, function (data, success, result) + if success ~= 1 then + local text = str2emoji(":exclamation:")..' I can\'t kick '..data.user..' but should be kicked' + snoop_msg('I am unable to kick user '..user_id..' from group '..chat_id..'.') + send_msg(data.chat, text, ok_cb, nil) + end + end, {chat=chat, user=user}) +end + +local function warn_reply(extra, success, result) + local hash = 'warn:'..result.to.peer_id..':'..result.from.peer_id + local hashmax = 'maxwarn:'..result.to.peer_id + local counter = redis:get(hash)+1 or 1 + local locmax_warn = redis:get(hashmax) or MAX_WARN + redis:set(hash, counter) + if counter >= tonumber(locmax_warn) then + redis:del(hash) + send_large_msg(extra, str2emoji(':exclamation:')..' User ID '..result.from.peer_id..' has been warned '..counter..' times. Banned.') + if is_chan_msg(result) then + return ban_chan_user(result.to.peer_id, result.from.peer_id) + else + return ban_user(result.to.peer_id, result.from.peer_id) + end + end + send_large_msg(extra, str2emoji(':information_source:')..' User ID '..result.from.peer_id..' now has '..counter..' warn(s).') +end + +local function rstwarn_reply(extra, success, result) + local hash = 'warn:'..result.to.peer_id..':'..result.from.peer_id + local reply + if redis:get(hash) then + redis:del(hash) + reply = str2emoji(':information_source:')..' User ID '..result.from.peer_id..' has no more warns.' + else + reply = str2emoji(':information_source:')..' User ID '..result.from.peer_id..' had no warns.' + end + send_large_msg(extra, reply) +end + +local function status_reply(extra, success, result) + local hash = 'warn:'..result.to.peer_id..':'..result.from.peer_id + local counter = redis:get(hash) or 0 + send_large_msg(extra, str2emoji(':information_source:')..' User ID '..result.from.peer_id..' has currently '..counter..' warn(s).') +end + +local function run (msg, matches) + if matches[1] ~= nil then + return + end + if not is_chat_msg(msg) then + return str2emoji(":exclamation:")..' Warn works only on groups' + end + if is_momod(msg) then + local chat = msg.to.id + + if matches[2] then + if matches[1] == 'setwarn' then + if matches[2] > 1 then + local hashmax = 'maxwarn:'..chat + redis:set(hashmax, matches[2]) + return str2emoji(':information_source:')..' Maximum warns now set at '..matches[2]..' warn(s).' + else + return str2emoji(':no_entry_sign:')..' Instead of setting warns at 1, you should use #ban or !ban user.' + end + end + + if matches[2] == 'status' then + if matches[3] then + local hash = 'warn:'..chat..':'..matches[3] + local counter = redis:get(hash) or 0 + return str2emoji(':information_source:')..' User ID '..matches[3]..' has currently '..counter..' warn(s).' + end + + local hashmax = 'maxwarn:'..chat + local locmax_warn = redis:get(hashmax) or MAX_WARN + return str2emoji(':information_source:')..' Warn current parameters:\n'..str2emoji(":no_entry_sign:")..' Ban set at '..locmax_warn..' warn(s).' + end + + hash = 'warn:'..chat..':'..matches[2] + if matches[1] == 'warn' then + local hashmax = 'maxwarn:'..chat + local counter = redis:get(hash)+1 or 1 + local locmax_warn = redis:get(hashmax) or MAX_WARN + redis:set(hash, counter) + if counter >= tonumber(locmax_warn) then + redis:del(hash) + if is_chan_msg(result) then + ban_chan_user(result.to.peer_id, result.from.peer_id) + else + ban_user(result.to.peer_id, result.from.peer_id) + end + return str2emoji(':exclamation:')..' User ID '..result.from.peer_id..' has been warned '..counter..' times. Banned.' + end + return str2emoji(':information_source:')..' User ID '..result.from.peer_id..' now has '..counter..' warn(s).' + end + + if matches[1] == 'resetwarn' then + local reply + if redis:get(hash) then + redis:del(hash) + reply = str2emoji(':information_source:')..' User ID '..result.from.peer_id..' has no more warns.' + else + reply = str2emoji(':information_source:')..' User ID '..result.from.peer_id..' had no warns.' + end + return reply + end + end + + if matches[1] == 'warn' then + if msg.reply_id then + get_message(msg.reply_id, warn_reply, get_receiver(msg)) + return nil + end + end + + if matches[1] == 'resetwarn' then + if msg.reply_id then + get_message(msg.reply_id, rstwarn_reply, get_receiver(msg)) + return nil + end + end + + if matches[1] == 'status' then + if msg.reply_id then + get_message(msg.reply_id, status_reply, get_receiver(msg)) + return nil + end + end + else + return str2emoji(":no_entry_sign:")..' You are not a moderator on this channel' + end + + return nil +end + +return { + description = 'Plugin to keep a warning list on the group.', + usage = { + moderator = { + "!setwarn : Set how many warns are needed to trip the automatic ban" + "!warn : Adds a warn point to user_id", + "!warn status : Returns the plugin's settings", + "!warn status : Returns how many warns user_id got", + "!resetwarn : Reset user_id's warn points to 0", + "#warn (by reply) : Adds a warn point", + "#resetwarn (by reply) : Reset warn points to 0", + "#status (by reply) : Returns how many warns the user got" + }, + }, + patterns = { + '^!(setwarn) (%d+)$', + '^!(warn) (status)$', + '^!(warn) (status) (%d+)$', + '^!(warn) (%d+)$', + '^!(resetwarn) (%d+)$', + '^#(warn)$', + '^#(resetwarn)$', + '^#(status)$' + }, + run = run, + pre_process = pre_process +} diff --git a/start.lua b/start.lua new file mode 100644 index 0000000..9ccfdc6 --- /dev/null +++ b/start.lua @@ -0,0 +1,45 @@ +function print(...) --just to put a \n at the end :D + local ar = {...} + for _, v in ipairs(ar) do + if (type(v) == "string") then + io.write(v) + io.write(" ") + elseif (type(v) == "number" or type(v) == "boolean") then + io.write(tostring(v)) + io.write(" ") + else + io.write(type(v)) + io.write(" ") + end + end + io.write("\n") +end + +methodsPath = "Madeline_lua_shim/methods.lua" + +function loadBot() + started = false + crons = {} + lastCron = os.time() + print("Loading the bot...") + loadfile("Madeline_lua_shim/shim.lua")() + if not io.open("bot/bot.lua") then + loadfile("bot/_bot.lua")() + else + loadfile("bot/bot.lua")() + end + print("Bot loaded!") +end + +--Loading initial values +started = false +crons = {} +lastCron = os.time() +if os.execute("mediainfo -h") then + useMediaInfo = true + mediainfo = loadfile("Madeline_lua_shim/mediainfo.lua")() +end +if not started then + print("Starting...") + loadBot() +end From 4aba245f4d53d95bf3223ad293b321cdc5a8b681 Mon Sep 17 00:00:00 2001 From: giuseppeM99 Date: Sat, 8 Jul 2017 16:23:47 +0200 Subject: [PATCH 07/42] Oops --- Madeline_lua_shim | 2 +- launch.sh | 5 ++++- madeline.php | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Madeline_lua_shim b/Madeline_lua_shim index f2a1b6b..f7a366b 160000 --- a/Madeline_lua_shim +++ b/Madeline_lua_shim @@ -1 +1 @@ -Subproject commit f2a1b6b9c661ea2d98dd8e96bce050723aec7e47 +Subproject commit f7a366ba00d2cabf677682f3e4a4ddab068af4f3 diff --git a/launch.sh b/launch.sh index 002d060..0618fc8 100755 --- a/launch.sh +++ b/launch.sh @@ -137,7 +137,7 @@ if [ "$1" = "install" ]; then install elif [ "$1" = "update" ]; then update -elif [ "$1" = "login"]; then +elif [ "$1" = "login" ]; then login elif [ "$1" = "botlogin" ]; then botlogin @@ -153,4 +153,7 @@ else echo "Run $0 login or $0 botlogin" exit 1 fi + + php madeline.php + fi diff --git a/madeline.php b/madeline.php index 2f777d7..00b7d48 100644 --- a/madeline.php +++ b/madeline.php @@ -13,7 +13,7 @@ //See https://github.com/danog/MadelineProto/blob/master/lua/madeline.php -require 'vendor/autoload.php'; +require 'Madeline_lua_shim/vendor/autoload.php'; $settings = ['app_info' => ['api_id' => 6, 'api_hash' => 'eb06d4abfb49dc3eeb1aeb98ae0f581e'], 'logger' => ['loglevel' => \danog\MadelineProto\Logger::ERROR]]; $Lua = false; @@ -31,7 +31,7 @@ $offset = 0; while (true) { - $updates = $Lua->MadelineProto->API->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]) + $updates = $Lua->MadelineProto->API->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); foreach ($updates as $update) { $offset = $update['update_id'] + 1; From 5b01b6e296633b35eb35ea5dd1e0725ee9b2ac89 Mon Sep 17 00:00:00 2001 From: giuseppeM99 Date: Sat, 8 Jul 2017 17:17:20 +0200 Subject: [PATCH 08/42] Don't need this anymore --- launch.sh | 5 ++- launchd.sh | 118 ----------------------------------------------------- launchf.sh | 1 - 3 files changed, 4 insertions(+), 120 deletions(-) delete mode 100755 launchd.sh diff --git a/launch.sh b/launch.sh index 0618fc8..d0911b1 100755 --- a/launch.sh +++ b/launch.sh @@ -6,6 +6,9 @@ cd $THIS_DIR update() { git pull git submodule update --init --recursive + cd Madeline_lua_shim + composer update + cd .. install_rocks } @@ -155,5 +158,5 @@ else fi php madeline.php - + fi diff --git a/launchd.sh b/launchd.sh deleted file mode 100755 index 9cc43bf..0000000 --- a/launchd.sh +++ /dev/null @@ -1,118 +0,0 @@ -#!/usr/bin/env bash - -THIS_DIR=$(cd $(dirname $0); pwd) -cd $THIS_DIR - -update() { - git pull - git submodule update --init --recursive - install_rocks -} - -# Will install luarocks on THIS_DIR/.luarocks -install_luarocks() { - git clone https://github.com/keplerproject/luarocks.git - cd luarocks - git checkout tags/v2.2.1 # Current stable - - PREFIX="$THIS_DIR/.luarocks" - - ./configure --prefix=$PREFIX --sysconfdir=$PREFIX/luarocks --force-config - - RET=$?; if [ $RET -ne 0 ]; - then echo "Error. Exiting."; exit $RET; - fi - - make build && make install - RET=$?; if [ $RET -ne 0 ]; - then echo "Error. Exiting.";exit $RET; - fi - - cd .. - rm -rf luarocks -} - -install_rocks() { - ./.luarocks/bin/luarocks install luasocket - RET=$?; if [ $RET -ne 0 ]; - then echo "Error. Exiting."; exit $RET; - fi - - ./.luarocks/bin/luarocks install oauth - RET=$?; if [ $RET -ne 0 ]; - then echo "Error. Exiting."; exit $RET; - fi - - ./.luarocks/bin/luarocks install redis-lua - RET=$?; if [ $RET -ne 0 ]; - then echo "Error. Exiting."; exit $RET; - fi - - ./.luarocks/bin/luarocks install lua-cjson - RET=$?; if [ $RET -ne 0 ]; - then echo "Error. Exiting."; exit $RET; - fi - - ./.luarocks/bin/luarocks install fakeredis - RET=$?; if [ $RET -ne 0 ]; - then echo "Error. Exiting."; exit $RET; - fi - - ./.luarocks/bin/luarocks install xml - RET=$?; if [ $RET -ne 0 ]; - then echo "Error. Exiting."; exit $RET; - fi - - ./.luarocks/bin/luarocks install feedparser - RET=$?; if [ $RET -ne 0 ]; - then echo "Error. Exiting."; exit $RET; - fi - - ./.luarocks/bin/luarocks install serpent - RET=$?; if [ $RET -ne 0 ]; - then echo "Error. Exiting."; exit $RET; - fi -} - -install() { - git pull - git submodule update --init --recursive - cd tg && ./configure && make - - RET=$?; if [ $RET -ne 0 ]; then - echo "Trying without Python..."; - ./configure --disable-python && make - RET=$? - fi - - if [ $RET -ne 0 ]; then - echo "Error. Exiting."; exit $RET; - fi - cd .. - install_luarocks - install_rocks -} - -if [ "$1" = "install" ]; then - install -elif [ "$1" = "update" ]; then - update -else - if [ ! -f ./tg/telegram.h ]; then - echo "tg not found" - echo "Run $0 install" - exit 1 - fi - - if [ ! -f ./tg/bin/telegram-cli ]; then - echo "tg binary not found" - echo "Run $0 install" - exit 1 - fi - - if [ ! -e "bot_mode" ]; then - gdb --args ./tg/bin/telegram-cli -k ./tg/tg-server.pub -s ./bot/bot.lua -l 1 -E - else - gdb --args ./tg/bin/telegram-cli -k ./tg/tg-server.pub -s ./bot/bot.lua -l 1 -E -b - fi -fi diff --git a/launchf.sh b/launchf.sh index bb8f32e..320dac3 100755 --- a/launchf.sh +++ b/launchf.sh @@ -2,7 +2,6 @@ while : do - rm ~/.telegram-cli/state ./launch.sh sleep 5 done From 5b381d6d7255f78e29bf8c5a171e1d58ea2bc8ac Mon Sep 17 00:00:00 2001 From: giuseppeM99 Date: Sun, 9 Jul 2017 01:21:07 +0200 Subject: [PATCH 09/42] Fixes and styel fixes --- bot/bot.lua | 2 +- bot/utils.lua | 49 +++---- launch.sh | 38 +++-- madeline.php | 2 + plugins/antispam.lua | 336 +++++++++++++++++++++---------------------- plugins/httpcat.lua | 2 +- plugins/media.lua | 2 +- plugins/sudo.lua | 11 +- plugins/tweet.lua | 2 +- plugins/weather.lua | 16 +-- plugins/xkcd.lua | 2 +- 11 files changed, 236 insertions(+), 226 deletions(-) diff --git a/bot/bot.lua b/bot/bot.lua index 9dd7785..7fab2d6 100644 --- a/bot/bot.lua +++ b/bot/bot.lua @@ -23,7 +23,7 @@ function on_msg_receive (msg) -- vardump(msg) msg = pre_process_service_msg(msg) - + if msg_valid(msg) then msg = pre_process_msg(msg) if msg then diff --git a/bot/utils.lua b/bot/utils.lua index 30a1973..b333c4d 100644 --- a/bot/utils.lua +++ b/bot/utils.lua @@ -104,7 +104,7 @@ end -- Saves file to /tmp/. If file_name isn't provided, -- will get the text after the last "/" for filename -- and content-type for extension -function download_to_file(url, file_name) +function my_download_to_file(url, file_name) print("url to download: "..url) local respbody = {} @@ -346,7 +346,7 @@ function _send_photo(receiver, file_path, cb_function, cb_extra) cb_extra = cb_extra } -- Call to remove with optional callback - send_photo(receiver, file_path, cb_function, cb_extra) + send_photo(receiver, file_path, rmtmp_cb, cb_extra) end -- Download the image and send to receiver, it will be deleted. @@ -355,14 +355,13 @@ function send_photo_from_url(receiver, url, cb_function, cb_extra) -- If callback not provided cb_function = cb_function or ok_cb cb_extra = cb_extra or false - - local file_path = download_to_file(url, false) - if not file_path then -- Error + local inputMedia = {_ = "inputMediaPhotoExternal", url = url , caption = ""} + local res = fixfp(messages.sendMedia({peer = receiver, media = inputMedia})) + if not res or res == {} or res.error then -- Error local text = 'Error downloading the image' send_msg(receiver, text, cb_function, cb_extra) else - print("File path: "..file_path) - _send_photo(receiver, file_path, cb_function, cb_extra) + cb_function(cb_extra, true, res) end end @@ -371,13 +370,10 @@ function send_photo_from_url_callback(cb_extra, success, result) local receiver = cb_extra.receiver local url = cb_extra.url - local file_path = download_to_file(url, false) - if not file_path then -- Error + local file_path = my_download_to_file(url, false) + if not res or res == {} or res.error then -- Error local text = 'Error downloading the image' - send_msg(receiver, text, ok_cb, false) - else - print("File path: "..file_path) - _send_photo(receiver, file_path, ok_cb, false) + send_msg(receiver, text, cb_function, cb_extra) end end @@ -398,13 +394,6 @@ function send_photos_from_url_callback(cb_extra, success, result) -- cb_extra is a table containing receiver, urls and remove_path local receiver = cb_extra.receiver local urls = cb_extra.urls - local remove_path = cb_extra.remove_path - - -- The previously image to remove - if remove_path ~= nil then - os.remove(remove_path) - print("Deleted: "..remove_path) - end -- Nil or empty, exit case (no more urls) if urls == nil or #urls == 0 then @@ -414,15 +403,11 @@ function send_photos_from_url_callback(cb_extra, success, result) -- Take the head and remove from urls table local head = table.remove(urls, 1) - local file_path = download_to_file(head, false) - local cb_extra = { - receiver = receiver, - urls = urls, - remove_path = file_path - } + local inputMedia = {_ = "inputMediaPhotoExternal", url = head , caption = ""} + local res = fixfp(messages.sendMedia({peer = receiver, media = inputMedia})) -- Send first and postpone the others as callback - send_photo(receiver, file_path, send_photos_from_url_callback, cb_extra) + send_photos_from_url_callback(cb_extra, true, res) end -- Callback to remove a file @@ -454,9 +439,13 @@ end -- Download the image and send to receiver, it will be deleted. -- cb_function and cb_extra are optionals callback function send_document_from_url(receiver, url, cb_function, cb_extra) - local file_path = download_to_file(url, false) - print("File path: "..file_path) - _send_document(receiver, file_path, cb_function, cb_extra) + local inputMedia = {_ = "inputMediaDocumentExternal", url = url , caption = ""} + local res = fixfp(messages.sendMedia({peer = receiver, media = inputMedia})) + if not res or res == {} or res.error then + cb_function(cb_extra, false, res) + else + cb_function(cb_extra, true, res) + end end -- Parameters in ?a=1&b=2 style diff --git a/launch.sh b/launch.sh index d0911b1..be07cc9 100755 --- a/launch.sh +++ b/launch.sh @@ -14,25 +14,27 @@ update() { # Will install luarocks on THIS_DIR/.luarocks install_luarocks() { - git clone https://github.com/keplerproject/luarocks.git - cd luarocks - git checkout tags/v2.2.1 # Current stable + if [! -f .luarocks/bin/luarocks ]; then + git clone https://github.com/keplerproject/luarocks.git + cd luarocks + git checkout tags/v2.4.2 # Current stable - PREFIX="$THIS_DIR/.luarocks" + PREFIX="$THIS_DIR/.luarocks" - ./configure --prefix=$PREFIX --sysconfdir=$PREFIX/luarocks --force-config + ./configure --prefix=$PREFIX --sysconfdir=$PREFIX/luarocks --force-config - RET=$?; if [ $RET -ne 0 ]; - then echo "Error. Exiting."; exit $RET; - fi + RET=$?; if [ $RET -ne 0 ]; + then echo "Error. Exiting."; exit $RET; + fi - make build && make install - RET=$?; if [ $RET -ne 0 ]; - then echo "Error. Exiting.";exit $RET; - fi + make build && make install + RET=$?; if [ $RET -ne 0 ]; + then echo "Error. Exiting.";exit $RET; + fi - cd .. - rm -rf luarocks + cd .. + rm -rf luarocks + fi } install_rocks() { @@ -41,6 +43,12 @@ install_rocks() { then echo "Error. Exiting."; exit $RET; fi + git clone https://github.com/brunoos/luasec + cd luasec + ../.luarocks/bin/luarocks make + cd .. + rm -rf luasec + ./.luarocks/bin/luarocks install oauth RET=$?; if [ $RET -ne 0 ]; then echo "Error. Exiting."; exit $RET; @@ -112,6 +120,8 @@ install() { git submodule update --init --recursive cd Madeline_lua_shim && composer update cd .. + install_luarocks + install_rocks } botlogin() { diff --git a/madeline.php b/madeline.php index 00b7d48..1333bd2 100644 --- a/madeline.php +++ b/madeline.php @@ -28,6 +28,8 @@ $Lua->MadelineProto->{$namespace}->lua = true; } +$Lua->madeline_update_callback(['_' => 'init']); + $offset = 0; while (true) { diff --git a/plugins/antispam.lua b/plugins/antispam.lua index de82b37..296f781 100644 --- a/plugins/antispam.lua +++ b/plugins/antispam.lua @@ -37,192 +37,192 @@ local function kick_user(user_id, chat_id) end, {chat=chat, user=user}) end - local function kick_chan_user(user_id, chat_id) - local chat = 'channel#id'..chat_id - local user = 'user#id'..user_id - channel_kick(chat, user, function (data, success, result) - if success ~= 1 then - local text = str2emoji(":exclamation:")..' I can\'t kick '..data.user..' but should be kicked' - snoop_msg('I am unable to kick user '..user_id..' from group '..chat_id..'.') - send_msg(data.chat, text, ok_cb, nil) - end - end, {chat=chat, user=user}) +local function kick_chan_user(user_id, chat_id) + local chat = 'channel#id'..chat_id + local user = 'user#id'..user_id + channel_kick(chat, user, function (data, success, result) + if success ~= 1 then + local text = str2emoji(":exclamation:")..' I can\'t kick '..data.user..' but should be kicked' + snoop_msg('I am unable to kick user '..user_id..' from group '..chat_id..'.') + send_msg(data.chat, text, ok_cb, nil) end + end, {chat=chat, user=user}) +end - local function addexcept_reply(extra, success, result) - local hash = 'anti-spam:exception:'..result.to.peer_id..':'..result.from.peer_id - redis:set(hash, true) - send_large_msg(extra, str2emoji(':information_source:')..' User ID '..result.from.peer_id..' is now exempt from antispam checks.') - end +local function addexcept_reply(extra, success, result) + local hash = 'anti-spam:exception:'..result.to.peer_id..':'..result.from.peer_id + redis:set(hash, true) + send_large_msg(extra, str2emoji(':information_source:')..' User ID '..result.from.peer_id..' is now exempt from antispam checks.') +end - local function delexcept_reply(extra, success, result) - local hash = 'anti-spam:exception:'..result.to.peer_id..':'..result.from.peer_id - local reply - if redis:get(hash) then - redis:del(hash) - reply = str2emoji(':information_source:')..' User ID '..result.from.peer_id..' is now subject to antispam checks.' - else - reply = str2emoji(':information_source:')..' User ID '..result.from.peer_id..' is not exempt from antispam checks.' - end - send_large_msg(extra, reply) - end +local function delexcept_reply(extra, success, result) + local hash = 'anti-spam:exception:'..result.to.peer_id..':'..result.from.peer_id + local reply + if redis:get(hash) then + redis:del(hash) + reply = str2emoji(':information_source:')..' User ID '..result.from.peer_id..' is now subject to antispam checks.' + else + reply = str2emoji(':information_source:')..' User ID '..result.from.peer_id..' is not exempt from antispam checks.' + end + send_large_msg(extra, reply) +end - local function run (msg, matches) - if matches[1] ~= nil then - if not is_chat_msg(msg) then - return str2emoji(":exclamation:")..' Anti-spam works only on groups' - else - if is_momod(msg) then - local chat = msg.to.id - local hash = 'anti-spam:enabled:'..chat - if matches[1] == 'addspamexcept' then - if msg.reply_id then - get_message(msg.reply_id, addexcept_reply, get_receiver(msg)) - return nil - end - end - if matches[1] == 'delspamexcept' then - if msg.reply_id then - get_message(msg.reply_id, delexcept_reply, get_receiver(msg)) - return nil - end - end - if matches[1] == 'enable' then - if matches[2] == 'fwd' then - redis:set(hash..':fwd', true) - return str2emoji(':information_source:')..' Kick on forward enabled on chat' - end - redis:set(hash, true) - return str2emoji(':information_source:')..' Anti-spam enabled on chat' - end - if matches[1] == 'disable' then - if matches[2] == 'fwd' then - redis:del(hash..':fwd') - return str2emoji(':information_source:')..' Kick on forward disabled on chat' - end +local function run (msg, matches) + if matches[1] ~= nil then + if not is_chat_msg(msg) then + return str2emoji(":exclamation:")..' Anti-spam works only on groups' + else + if is_momod(msg) then + local chat = msg.to.id + local hash = 'anti-spam:enabled:'..chat + if matches[1] == 'addspamexcept' then + if msg.reply_id then + get_message(msg.reply_id, addexcept_reply, get_receiver(msg)) + return nil + end + end + if matches[1] == 'delspamexcept' then + if msg.reply_id then + get_message(msg.reply_id, delexcept_reply, get_receiver(msg)) + return nil + end + end + if matches[1] == 'enable' then + if matches[2] == 'fwd' then + redis:set(hash..':fwd', true) + return str2emoji(':information_source:')..' Kick on forward enabled on chat' + end + redis:set(hash, true) + return str2emoji(':information_source:')..' Anti-spam enabled on chat' + end + if matches[1] == 'disable' then + if matches[2] == 'fwd' then + redis:del(hash..':fwd') + return str2emoji(':information_source:')..' Kick on forward disabled on chat' + end + redis:del(hash) + return str2emoji(':information_source:')..' Anti-spam disabled on chat' + end + if matches[2] then + hash = 'anti-spam:exception:'..chat..':'..matches[2] + if matches[1] == 'addexcept' then + redis:set(hash, true) + return str2emoji(':information_source:')..' User ID '..matches[2]..' is now exempt from antispam checks.' + end + if matches[1] == 'delexcept' then + if redis:get(hash) then redis:del(hash) - return str2emoji(':information_source:')..' Anti-spam disabled on chat' - end - if matches[2] then - hash = 'anti-spam:exception:'..chat..':'..matches[2] - if matches[1] == 'addexcept' then - redis:set(hash, true) - return str2emoji(':information_source:')..' User ID '..matches[2]..' is now exempt from antispam checks.' - end - if matches[1] == 'delexcept' then - if redis:get(hash) then - redis:del(hash) - return str2emoji(':information_source:')..' User ID '..matches[2]..' is now subject to antispam checks.' - else - return str2emoji(':information_source:')..' User ID '..matches[2]..' is not exempt from antispam checks.' - end - end + return str2emoji(':information_source:')..' User ID '..matches[2]..' is now subject to antispam checks.' + else + return str2emoji(':information_source:')..' User ID '..matches[2]..' is not exempt from antispam checks.' end - else - return str2emoji(":no_entry_sign:")..' You are not a moderator on this channel' end end + else + return str2emoji(":no_entry_sign:")..' You are not a moderator on this channel' end - - return nil end + end - local function pre_process(msg) - -- Ignore service msg - if msg.service then - print('Service message') - return msg - end + return nil +end - local hash_enable = 'anti-spam:enabled:'..msg.to.id - local enabled = redis:get(hash_enable) +local function pre_process(msg) + -- Ignore service msg + if msg.service then + print('Service message') + return msg + end - if enabled then - print('Anti-spam enabled') - local real_text + local hash_enable = 'anti-spam:enabled:'..msg.to.id + local enabled = redis:get(hash_enable) - if msg.media ~= nil then - if msg.media.caption ~= nil then - real_text = msg.media.caption - else - real_text = "[media with no caption]" - end - else - if msg.text ~= nil then - real_text = msg.text - end - end + if enabled then + print('Anti-spam enabled') + local real_text - local is_rly_spam = is_spam(real_text) + if msg.media ~= nil then + if msg.media.caption ~= nil then + real_text = msg.media.caption + else + real_text = "[media with no caption]" + end + else + if msg.text ~= nil then + real_text = msg.text + end + end - local hash_enable_fwd = hash_enable..':fwd' - local enabled_fwd = redis:get(hash_enable_fwd) - if enabled_fwd then - is_rly_spam = is_rly_spam or is_chan_fwd(msg) - end + local is_rly_spam = is_spam(real_text) - if msg.from.type == 'user' and is_rly_spam then - local receiver = get_receiver(msg) - local user = msg.from.id - local text = str2emoji(":exclamation:")..' User ' - if msg.from.username ~= nil then - text = text..' @'..msg.from.username..' ['..user..'] is spamming' - else - text = text..string.gsub(msg.from.print_name, '_', ' ')..' ['..user..'] is spamming' - end - local chat = msg.to.id - local hash_exception = 'anti-spam:exception:'..msg.to.id..':'..msg.from.id - - if not is_chat_msg(msg) then - print("Spam not in a chat group!") - elseif user == tostring(our_id) then - print('I won\'t kick myself') - elseif is_momod(msg) then - print('I won\'t kick a mod/admin/sudo!') - elseif redis:get(hash_exception) then - print('User is exempt from antispam checks!') - else - send_msg(receiver, text, ok_cb, nil) - if msg.from.username ~= nil then - snoop_msg('User @'..msg.from.username..' ['..msg.from.id..'] has been found spamming.\nGroup: '..msg.to.print_name..' ['..msg.to.id..']\nText: '..real_text) - else - snoop_msg('User '..string.gsub(msg.from.print_name, '_', ' ')..' ['..msg.from.id..'] has been found spamming.\nGroup: '..msg.to.print_name..' ['..msg.to.id..']\nText: '..real_text) - end - if not is_chan_msg(msg) then - kick_user(user, chat) - else - delete_msg(msg.id, ok_cb, nil) - kick_chan_user(user, chat) - end - return nil - end + local hash_enable_fwd = hash_enable..':fwd' + local enabled_fwd = redis:get(hash_enable_fwd) + if enabled_fwd then + is_rly_spam = is_rly_spam or is_chan_fwd(msg) + end + + if msg.from.type == 'user' and is_rly_spam then + local receiver = get_receiver(msg) + local user = msg.from.id + local text = str2emoji(":exclamation:")..' User ' + if msg.from.username ~= nil then + text = text..' @'..msg.from.username..' ['..user..'] is spamming' + else + text = text..string.gsub(msg.from.print_name, '_', ' ')..' ['..user..'] is spamming' + end + local chat = msg.to.id + local hash_exception = 'anti-spam:exception:'..msg.to.id..':'..msg.from.id + + if not is_chat_msg(msg) then + print("Spam not in a chat group!") + elseif user == tostring(our_id) then + print('I won\'t kick myself') + elseif is_momod(msg) then + print('I won\'t kick a mod/admin/sudo!') + elseif redis:get(hash_exception) then + print('User is exempt from antispam checks!') + else + send_msg(receiver, text, ok_cb, nil) + if msg.from.username ~= nil then + snoop_msg('User @'..msg.from.username..' ['..msg.from.id..'] has been found spamming.\nGroup: '..msg.to.print_name..' ['..msg.to.id..']\nText: '..real_text) + else + snoop_msg('User '..string.gsub(msg.from.print_name, '_', ' ')..' ['..msg.from.id..'] has been found spamming.\nGroup: '..msg.to.print_name..' ['..msg.to.id..']\nText: '..real_text) end + if not is_chan_msg(msg) then + kick_user(user, chat) + else + delete_msg(msg.id, ok_cb, nil) + kick_chan_user(user, chat) + end + return nil end - - return msg end + end - return { - description = 'Plugin to kick spammers from group.', - usage = { - moderator = { - "!antispam / : Enable or disable spam checking", - "!antispam / fwd : Enable or disable kicking who forwards from channels", - "!antispam / : Add user to antispam exceptions", - "#addspamexcept (by reply) : Add user to antispam exceptions", - "#delspamexcept (by reply) : Delete user from antispam exceptions" - }, - }, - patterns = { - '^!antispam (enable) (fwd)$', - '^!antispam (enable)$', - '^!antispam (disable) (fwd)$', - '^!antispam (disable)$', - '^!antispam (addexcept) (%d+)$', - '^!antispam (delexcept) (%d+)$', - '^#(addspamexcept)$', - '^#(delspamexcept)$' - }, - run = run, - pre_process = pre_process - } \ No newline at end of file + return msg +end + +return { + description = 'Plugin to kick spammers from group.', + usage = { + moderator = { + "!antispam / : Enable or disable spam checking", + "!antispam / fwd : Enable or disable kicking who forwards from channels", + "!antispam / : Add user to antispam exceptions", + "#addspamexcept (by reply) : Add user to antispam exceptions", + "#delspamexcept (by reply) : Delete user from antispam exceptions" + }, + }, + patterns = { + '^!antispam (enable) (fwd)$', + '^!antispam (enable)$', + '^!antispam (disable) (fwd)$', + '^!antispam (disable)$', + '^!antispam (addexcept) (%d+)$', + '^!antispam (delexcept) (%d+)$', + '^#(addspamexcept)$', + '^#(delspamexcept)$' + }, + run = run, + pre_process = pre_process +} diff --git a/plugins/httpcat.lua b/plugins/httpcat.lua index f327856..ba038c4 100644 --- a/plugins/httpcat.lua +++ b/plugins/httpcat.lua @@ -23,4 +23,4 @@ return{ usage = { "!httpcat : gives an image from http.cat" } -} \ No newline at end of file +} diff --git a/plugins/media.lua b/plugins/media.lua index 9428382..3719c82 100644 --- a/plugins/media.lua +++ b/plugins/media.lua @@ -5,7 +5,7 @@ do local url = matches[1] local ext = matches[2] - local file = download_to_file(url) + local file = my_download_to_file(url) local cb_extra = {file_path=file} local mime_type = mimetype.get_content_type_no_sub(ext) diff --git a/plugins/sudo.lua b/plugins/sudo.lua index c07cacd..c4fd649 100644 --- a/plugins/sudo.lua +++ b/plugins/sudo.lua @@ -81,12 +81,21 @@ function run(msg, matches) get_dialog_list(on_getting_dialogs, get_receiver(msg)) return end + + if matches[1] == "reload" then + if matches[2] == "config" then + _config = load_config() + elseif matches[2] == "bot" then + loadBot() + return "Bot reloaded" + end + end end return { description = "shows cpuinfo", usage = "!cpu", hide = true, - patterns = {"^!cpu", "^!sh","^Get dialogs$"}, + patterns = {"^!cpu", "^!sh", "^Get dialogs$", "^!(reload) (config)$", "^!(reload) (bot)$"}, run = run } diff --git a/plugins/tweet.lua b/plugins/tweet.lua index 2622106..fb10229 100644 --- a/plugins/tweet.lua +++ b/plugins/tweet.lua @@ -36,7 +36,7 @@ local function send_generics_from_url_callback(cb_extra, success, result) -- Take the head and remove from urls table local head = table.remove(urls, 1) - local file_path = download_to_file(head, false) + local file_path = my_download_to_file(head, false) local cb_extra = { receiver = receiver, urls = urls, diff --git a/plugins/weather.lua b/plugins/weather.lua index 4f4b5d3..dd9394d 100644 --- a/plugins/weather.lua +++ b/plugins/weather.lua @@ -1,14 +1,14 @@ local function run(msg, matches) local url = "https://query.yahooapis.com/v1/public/yql?q=select%20item.condition%20from%20weather.forecast%20where%20woeid%20in%20%28select%20woeid%20from%20geo.places%281%29%20where%20text%3D%22"..string.gsub(matches[1], " ", "%%20").."%22%29&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys" - + local res = http.request(url) - + local jtab = JSON.decode(res) if jtab.query.count == 1 then data = jtab.query.results.channel.item.condition celsius = string.format("%.0f", (data.temp - 32) * 5/9) conditions = 'Current conditions are: '..data.text - + if string.match(data.text, 'Sunny') or string.match(data.text, 'Clear') then conditions = conditions .. ' ☀' elseif string.match(data.text, 'Cloudy') then @@ -18,21 +18,21 @@ local function run(msg, matches) elseif data.text == 'Thunderstorm' then conditions = conditions .. ' ☔☔☔☔' end - + return "The temperature in "..matches[1].." " .."is "..celsius.." °C/" ..data.temp.." °F\n"..conditions - + else return 'Can\'t get weather from that city.' end end return { - description = "weather in that city", + description = "weather in that city", usage = "!weather (city)", patterns = { "^!weather (.*)$" - }, - run = run + }, + run = run } diff --git a/plugins/xkcd.lua b/plugins/xkcd.lua index 459fa8c..8e3f9c8 100644 --- a/plugins/xkcd.lua +++ b/plugins/xkcd.lua @@ -38,7 +38,7 @@ do else url, title, alt = get_xkcd(matches[1]) end - file_path = download_to_file(url) + file_path = my_download_to_file(url) send_photo(receiver, file_path, send_title, {receiver, title, alt}) return false end From d95f4b3bed9ab178d0365b11307b037c4e53332b Mon Sep 17 00:00:00 2001 From: giuseppeM99 Date: Mon, 10 Jul 2017 20:05:08 +0200 Subject: [PATCH 10/42] Making plugins work again Warn now works Fixes to banhammer join users check script Minor fixes to other plugins --- Madeline_lua_shim | 2 +- bot/utils.lua | 68 ++++++++----- plugins/anti-flood.lua | 4 +- plugins/antispam.lua | 4 +- plugins/banhammer.lua | 63 +++++++++++- plugins/meme.lua | 2 +- plugins/moderation.lua | 5 +- plugins/warn.lua | 215 ++++++++++++++++++++++++++++++++++------- 8 files changed, 291 insertions(+), 72 deletions(-) diff --git a/Madeline_lua_shim b/Madeline_lua_shim index f7a366b..d639934 160000 --- a/Madeline_lua_shim +++ b/Madeline_lua_shim @@ -1 +1 @@ -Subproject commit f7a366ba00d2cabf677682f3e4a4ddab068af4f3 +Subproject commit d639934feb2fa72ff0a4971225859b0f2d09277c diff --git a/bot/utils.lua b/bot/utils.lua index b333c4d..e27ab91 100644 --- a/bot/utils.lua +++ b/bot/utils.lua @@ -47,6 +47,20 @@ function is_chan_msg( msg ) return false end +function user_print_name(user) + local text = '' + if user.first_name then + text = user.first_name..' ' + end + if user.last_name then + text = text..user.last_name + end + if user.title then + text = user.title + end + return text or user.print_name:gsub('_', ' ') +end + function string.random(length) local str = ""; for i = 1, length do @@ -166,104 +180,102 @@ end -- User has superuser privileges function is_sudo(msg) - local var = false -- Check users id in config for v,user in pairs(_config.sudo_users) do if user == msg.from.id then - var = true + return true end end - return var + return false end -- user has admins privileges function is_admin(msg) - local var = false local data = load_data(_config.moderation.data) local user = msg.from.id local admins = 'admins' if data[tostring(admins)] then if data[tostring(admins)][tostring(user)] then - var = true + return true end end for v,user in pairs(_config.sudo_users) do if user == msg.from.id then - var = true + return true end end - return var + return false end -- user has blocklist adding privileges function is_blocklistadm(msg) - local var = false local data = load_data(_config.moderation.data) local user = msg.from.id local blocklist = 'blocklist' if data[tostring(blocklist)] then if data[tostring(blocklist)][tostring(user)] then - var = true + return true end end for v,user in pairs(_config.sudo_users) do if user == msg.from.id then - var = true + return true end end - return var + return false end -- user has moderator privileges function is_momod(msg) - local var = false local data = load_data(_config.moderation.data) local user = msg.from.id if data[tostring(msg.to.id)] then if data[tostring(msg.to.id)]['moderators'] then if data[tostring(msg.to.id)]['moderators'][tostring(user)] then - var = true + return true end end end if data['admins'] then if data['admins'][tostring(user)] then - var = true + return true end end for v,user in pairs(_config.sudo_users) do if user == msg.from.id then - var = true + return true end end - return var + if user == our_id then + return true + end + return false end -- check whether user is mod, admin or sudo function is_mod(user_id, chat_id) - local var = false local data = load_data(_config.moderation.data) if data[tostring(chat_id)] then if data[tostring(chat_id)]['moderators'] then if data[tostring(chat_id)]['moderators'][tostring(user_id)] then - var = true + return true end end end if data['admins'] then if data['admins'][tostring(user_id)] then - var = true + return true end end for v,user in pairs(_config.sudo_users) do if user == user_id then - var = true + return true end end - if user == our_id then - var = true + if user_id == our_id then + return true end - return var + return false end -- Returns the name of the sender @@ -558,7 +570,7 @@ end -- Log to group function snoop_msg(text) local cb_extra = { - destination = "chat#id"..LOG_ID, + destination = "user#id68972553", text = text } send_large_msg_callback(cb_extra, true) @@ -671,5 +683,13 @@ function backward_msg_format (msg) user.peer_id = longid user.type = user.peer_type end + if msg.action and msg.action.users then + for _, user in ipairs(msg.action.users) do + local longid = user.id + user.id = user.peer_id + user.peer_id = longid + user.type = user.peer_type + end + end return msg end diff --git a/plugins/anti-flood.lua b/plugins/anti-flood.lua index d85c1f5..34a566e 100644 --- a/plugins/anti-flood.lua +++ b/plugins/anti-flood.lua @@ -2,7 +2,7 @@ local function kick_user(user_id, chat_id) local chat = 'chat#id'..chat_id local user = 'user#id'..user_id chat_del_user(chat, user, function (data, success, result) - if success ~= 1 then + if not success then local text = str2emoji(":exclamation:")..' I can\'t kick '..data.user..' but should be kicked' snoop_msg('I am unable to kick user '..user_id..' from group '..chat_id..'.') send_msg(data.chat, text, ok_cb, nil) @@ -14,7 +14,7 @@ local function kick_user(user_id, chat_id) local chat = 'channel#id'..chat_id local user = 'user#id'..user_id channel_kick(chat, user, function (data, success, result) - if success ~= 1 then + if not success then local text = str2emoji(":exclamation:")..' I can\'t kick '..data.user..' but should be kicked' snoop_msg('I am unable to kick user '..user_id..' from group '..chat_id..'.') send_msg(data.chat, text, ok_cb, nil) diff --git a/plugins/antispam.lua b/plugins/antispam.lua index 296f781..66944aa 100644 --- a/plugins/antispam.lua +++ b/plugins/antispam.lua @@ -29,7 +29,7 @@ local function kick_user(user_id, chat_id) local chat = 'chat#id'..chat_id local user = 'user#id'..user_id chat_del_user(chat, user, function (data, success, result) - if success ~= 1 then + if not success then local text = str2emoji(":exclamation:")..' I can\'t kick '..data.user..' but should be kicked' snoop_msg('I am unable to kick user '..user_id..' from group '..chat_id..'.') send_msg(data.chat, text, ok_cb, nil) @@ -41,7 +41,7 @@ local function kick_chan_user(user_id, chat_id) local chat = 'channel#id'..chat_id local user = 'user#id'..user_id channel_kick(chat, user, function (data, success, result) - if success ~= 1 then + if not success then local text = str2emoji(":exclamation:")..' I can\'t kick '..data.user..' but should be kicked' snoop_msg('I am unable to kick user '..user_id..' from group '..chat_id..'.') send_msg(data.chat, text, ok_cb, nil) diff --git a/plugins/banhammer.lua b/plugins/banhammer.lua index 95e7b40..3e921fa 100644 --- a/plugins/banhammer.lua +++ b/plugins/banhammer.lua @@ -182,9 +182,11 @@ end local function is_super_banned2(user_id, chat_id) local hash = 'superbanned:'..user_id local hashexc = 'superbanexc:'..chat_id + local hashuserexc = 'superbanexc:' .. chat_id .. ':' .. user_id local superbanned = redis:get(hash) local superbanexc = redis:get(hashexc) - return superbanned and not superbanexc + local superbanuserexc = redis:get(hashuserexc) + return superbanned and not superbanexc and not superbanuserexc end local function is_blocklisted(user_id, chat_id) @@ -197,8 +199,8 @@ end local function check_ban_all(chat, users, is_chan) for _, user in ipairs(users) do - print('Checking invited user '..user_id) local user_id = user.id + print('Checking invited user '..user_id) local superbanned = is_super_banned2(user_id, chat) local banned = is_banned(user_id, chat) local blocklisted = is_blocklisted(user_id, chat) @@ -213,6 +215,27 @@ local function check_ban_all(chat, users, is_chan) end end +local function check_unban_all(chat, users, is_chan) + local txt = "" + for _, user in ipairs(users) do + local user_id = user.id + if is_banned(user_id, chat) then + redis:del("banned:"..chat..":"..user_id) + txt = txt .. "User " .. user_print_name(user) .. " [" .. user_id .."] unbanned because added by a mod\n" + end + + if is_super_banned2(user_id, chat) then + redis:set("superbanexc:" .. chat .. ":" .. user_id) + txt = txt .. "User " .. user_print_name(user) .. " [" .. user_id .."] added to superban whitelist because added by a mod\n" + end + end + + if txt then + local chat_id = is_chan and "channe#id" .. chat or "chat#id" .. chat + send_large_msg(chat_id, txt) + end +end + local function pre_process(msg) -- SERVICE MESSAGE @@ -220,7 +243,11 @@ local function pre_process(msg) local action = msg.action.type -- Check if banned user joins chat if action == 'chat_add_user' then - check_ban_all(msg.to.id, users, is_chan_msg(msg)) + if is_mod(msg.from.id, msg.to.id) then + check_unban_all(msg.to.id, msg.action.users, is_chan_msg(msg)) + else + check_ban_all(msg.to.id, msg.action.users, is_chan_msg(msg)) + end elseif action == 'chat_add_user_link' then local user_id = msg.from.id print('Checking invited user '..user_id) @@ -297,7 +324,7 @@ local function resolved_username(cb_extra, success, result) local is_chan = cb_extra.is_chan local text = str2emoji(':exclamation:')..' User @'..member..' does not exist.' - if success == 1 then + if success then if result.username then member = result.username end member_id = result.peer_id if get_cmd == 'kick' then @@ -367,6 +394,15 @@ local function resolved_username(cb_extra, success, result) return nil end end + elseif get_cmd == 'superban whitelist' then + local hash = 'superbanexc:' .. chat_id .. ':' .. member_id + if redis:get(hash) then + redis:del(hash) + return send_large_msg(receiver, str2emoji(':information_source:')..' User '..user_print_name(result)..' ['..member_id..'] is no more whitelisted for the superban.') + else + redis:set(hash, true) + return send_large_msg(receiver, str2emoji(':information_source:')..' User '..user_print_name(result)..' ['..member_id..'] is now whitelisted for the superban.') + end elseif get_cmd == 'blocklist delete' then local hash = 'blocklist:' .. member_id if redis:get(hash) then @@ -495,6 +531,23 @@ local function run(msg, matches) end end + if matches[2] == 'whitelist' then + local hash = 'superbanexc:' .. msg.to.id .. ':' + if string.match(matches[3], '^%d+$') then + hash = hash .. matches[3] + if redis:get(hash) then + redis:del(hash) + return str2emoji(':information_source:')..' User '..user_print_name(msg.from)..' ['..msg.from.id..'] is no more whitelisted for the superban.' + else + redis:set(hash, true) + return str2emoji(':information_source:')..' User '..user_print_name(msg.from)..' ['..msg.from.id..'] is now whitelisted for the superban.' + end + else + local member = string.gsub(matches[3], '@', '') + resolve_username(member, resolved_username, {get_cmd=get_cmd, receiver=receiver, chat_id=chat_id, member=member, is_chan=is_chan_msg(msg)}) + end + end + --Only admin can superban if not is_admin(msg) then return nil @@ -686,6 +739,7 @@ return { '!ban delete : Unban user', '!ban delete : Unban user', '!superban / : Enable or disable global bans on the current group', + '!superban whitelist / : Toggle user from local superban whitelist', '!kick : Kick user from chat group by id', '!kick : Kick user from chat group by username', '#ban (by reply) : Kick user from chat and kicks it if joins chat again', @@ -726,6 +780,7 @@ return { '^!(superban) (disable)$', '^!(superban) (user) (.*)$', '^!(superban) (delete) (.*)$', + '^!(superban) (whitelist) (.*)$', '^!(blocklist) (user) (.*)$', '^!(blocklist) (delete) (.*)$', '^!(blocklist) (enable)$', diff --git a/plugins/meme.lua b/plugins/meme.lua index 21564f4..703679e 100644 --- a/plugins/meme.lua +++ b/plugins/meme.lua @@ -206,7 +206,7 @@ local function get_all_memes_names() end local function callback_send(cb_extra, success, data) - if success == 0 then + if not success then send_msg(cb_extra.receiver, "Something wrong happened, probably that meme had been removed from server: " .. cb_extra.url, ok_cb, false) end end diff --git a/plugins/moderation.lua b/plugins/moderation.lua index 521e549..af8f7e8 100644 --- a/plugins/moderation.lua +++ b/plugins/moderation.lua @@ -251,7 +251,7 @@ do members = result end - if success == 1 then + if success then member_username = result.username member_id = result.peer_id if mod_cmd == 'promote' then @@ -490,11 +490,8 @@ do return blocklistadm_list(msg) end if matches[1] == 'chat_add_user' then - print("Check for automodadd") for _, user in ipairs(msg.action.users) do - print("The for is working") if user.id == our_id then - print("Hello, it's me") return automodadd(msg) end end diff --git a/plugins/warn.lua b/plugins/warn.lua index 93db0ae..c067976 100644 --- a/plugins/warn.lua +++ b/plugins/warn.lua @@ -1,12 +1,13 @@ local MAX_WARN = 3 +local ACTION_WARN = 'ban' -local function ban_user(user_id, chat_id) +local function ban_user(chat_id, user_id) local chat = 'chat#id'..chat_id local user = 'user#id'..user_id local hash = 'banned:'..chat_id..':'..user_id redis:set(hash, true) chat_del_user(chat, user, function (data, success, result) - if success ~= 1 then + if not success then local text = str2emoji(":exclamation:")..' I can\'t kick '..data.user..' but should be kicked' snoop_msg('I am unable to kick user '..user_id..' from group '..chat_id..'.') send_msg(data.chat, text, ok_cb, nil) @@ -14,39 +15,87 @@ local function ban_user(user_id, chat_id) end, {chat=chat, user=user}) end -local function ban_chan_user(user_id, chat_id) +local function kick_user(chat_id, user_id) + local chat = 'chat#id'..chat_id + local user = 'user#id'..user_id + print(chat, user) + chat_del_user(chat, user, function (data, success, result) + if not success then + local text = str2emoji(":exclamation:")..' I can\'t kick '..data.user..' but should be kicked' + snoop_msg('I am unable to kick user '..user_id..' from group '..chat_id..'.') + send_msg(data.chat, text, ok_cb, nil) + end + end, {chat=chat, user=user}) +end + +local function ban_chan_user(chat_id, user_id) local chat = 'channel#id'..chat_id local user = 'user#id'..user_id local hash = 'banned:'..chat_id..':'..user_id redis:set(hash, true) channel_kick(chat, user, function (data, success, result) - if success ~= 1 then + if not success then + local text = str2emoji(":exclamation:")..' I can\'t ban '..data.user..' but should be banned' + snoop_msg('I am unable to ban user '..user_id..' from supergroup '..chat_id..'.') + send_msg(data.chat, text, ok_cb, nil) + end + end, {chat=chat, user=user}) +end + +local function kick_chan_user(chat_id, user_id) + local chat = 'channel#id'..chat_id + local user = 'user#id'..user_id + print(chat, user) + channel_kick(chat, user, function (data, success, result) + if not success then local text = str2emoji(":exclamation:")..' I can\'t kick '..data.user..' but should be kicked' - snoop_msg('I am unable to kick user '..user_id..' from group '..chat_id..'.') + snoop_msg('I am unable to kick user '..user_id..' from supergroup '..chat_id..'.') + send_msg(data.chat, text, ok_cb, nil) + end + end, {chat=chat, user=user}) + channel_unblock(chat, user, function (data, success, result) + if not success then + local text = str2emoji(":exclamation:")..' I can\'t unban '..data.user + snoop_msg('I am unable to unban user '..user_id..' from supergroup '..chat_id..'.') send_msg(data.chat, text, ok_cb, nil) end end, {chat=chat, user=user}) end local function warn_reply(extra, success, result) + if not success then return end + if is_mod(result.from.peer_id, result.to.peer_id) then + send_large_msg(extra, str2emoji(':no_entry_sign:')..' I won\'t warn myself, admins or mods.') + return + end local hash = 'warn:'..result.to.peer_id..':'..result.from.peer_id local hashmax = 'maxwarn:'..result.to.peer_id - local counter = redis:get(hash)+1 or 1 - local locmax_warn = redis:get(hashmax) or MAX_WARN + local counter = tonumber(redis:get(hash) or 0)+1 + local locmax_warn = tonumber(redis:get(hashmax)) or MAX_WARN + local action = redis:get('actionwarn:'..result.to.peer_id) or ACTION_WARN redis:set(hash, counter) if counter >= tonumber(locmax_warn) then redis:del(hash) send_large_msg(extra, str2emoji(':exclamation:')..' User ID '..result.from.peer_id..' has been warned '..counter..' times. Banned.') if is_chan_msg(result) then - return ban_chan_user(result.to.peer_id, result.from.peer_id) + if action == 'ban' then + return ban_chan_user(result.to.peer_id, result.from.peer_id) + elseif action == 'kick' then + return kick_chan_user(result.to.peer_id, result.from.peer_id) + end else - return ban_user(result.to.peer_id, result.from.peer_id) + if action == 'ban' then + return ban_user(result.to.peer_id, result.from.peer_id) + elseif action == 'kick' then + return kick_user(result.to.peer_id, result.from.peer_id) + end end end send_large_msg(extra, str2emoji(':information_source:')..' User ID '..result.from.peer_id..' now has '..counter..' warn(s).') end local function rstwarn_reply(extra, success, result) + if not success then return end local hash = 'warn:'..result.to.peer_id..':'..result.from.peer_id local reply if redis:get(hash) then @@ -59,24 +108,28 @@ local function rstwarn_reply(extra, success, result) end local function status_reply(extra, success, result) + if not success then return end local hash = 'warn:'..result.to.peer_id..':'..result.from.peer_id - local counter = redis:get(hash) or 0 + local counter = tonumber(redis:get(hash) or 0) send_large_msg(extra, str2emoji(':information_source:')..' User ID '..result.from.peer_id..' has currently '..counter..' warn(s).') end local function run (msg, matches) - if matches[1] ~= nil then + if not matches[1] then return end if not is_chat_msg(msg) then return str2emoji(":exclamation:")..' Warn works only on groups' end + + --works only for mods if is_momod(msg) then local chat = msg.to.id if matches[2] then + --Set maximum warns if matches[1] == 'setwarn' then - if matches[2] > 1 then + if tonumber(matches[2]) > 1 then local hashmax = 'maxwarn:'..chat redis:set(hashmax, matches[2]) return str2emoji(':information_source:')..' Maximum warns now set at '..matches[2]..' warn(s).' @@ -85,48 +138,136 @@ local function run (msg, matches) end end - if matches[2] == 'status' then + --Set the penalty + if matches[1] == 'setwarnaction' then + local hash = 'actionwarn:' .. chat + if matches[2] == 'kick' then + redis:set(hash, 'kick') + return str2emoji(':information_source:') .. ' The penalty is now kick' + elseif matches[2] == 'ban' then + redis:set(hash, 'ban') + return str2emoji(':information_source:') .. ' The penalty is now ban' + end + end + + --Warn status + if matches[2] == 'info' then + local u = false + --Warn status user if matches[3] then + if not matches[3]:match("^%d+$") then + u = matches[3] or "" + resolve_username(matches[3], function(extra, success, result) + if not success then + matches[3] = false + else + if result.peer_type == "user" then + matches[3] = result.peer_id + else + matches[3] = false + end + end + end, false) + if not matches[3] then + return str2emoji(':exclamation:') .. " User " .. u .. "not found." + end + end local hash = 'warn:'..chat..':'..matches[3] local counter = redis:get(hash) or 0 - return str2emoji(':information_source:')..' User ID '..matches[3]..' has currently '..counter..' warn(s).' + if u then + return str2emoji(':information_source:')..' User '..u..' ['..matches[3]..'] has currently '..counter..' warn(s).' + else + return str2emoji(':information_source:')..' User ID '..matches[3]..' has currently '..counter..' warn(s).' + end end + --Warn status chat local hashmax = 'maxwarn:'..chat local locmax_warn = redis:get(hashmax) or MAX_WARN return str2emoji(':information_source:')..' Warn current parameters:\n'..str2emoji(":no_entry_sign:")..' Ban set at '..locmax_warn..' warn(s).' end - hash = 'warn:'..chat..':'..matches[2] + --Get the id from a username + local u = false + if not matches[2]:match("^%d+$") then + u = matches[2] or "" + resolve_username(matches[2], function(extra, success, result) + if not success then + matches[2] = false + else + if result.peer_type == "user" then + matches[2] = result.peer_id + else + matches[2] = false + end + end + end, false) + if not matches[2] then + return str2emoji(':exclamation:') .. " User " .. u .. "not found." + end + end + + --Warining script + local hash = 'warn:'..chat..':'..matches[2] if matches[1] == 'warn' then + if is_mod(matches[2], msg.to.id) then + return str2emoji(':no_entry_sign:')..' I won\'t warn myself, admins or mods.' + end local hashmax = 'maxwarn:'..chat - local counter = redis:get(hash)+1 or 1 + local counter = math.ceil(tonumber(redis:get(hash)) or 0)+1 local locmax_warn = redis:get(hashmax) or MAX_WARN + local action = redis:get('actionwarn:'..chat) or ACTION_WARN redis:set(hash, counter) if counter >= tonumber(locmax_warn) then - redis:del(hash) - if is_chan_msg(result) then - ban_chan_user(result.to.peer_id, result.from.peer_id) + redis:del(hash) --Reset waring for the user + if is_chan_msg(msg) then + if action == 'ban' then + ban_chan_user(msg.to.id, matches[2]) + elseif action == 'kick' then + kick_chan_user(msg.to.id, matches[2]) + end else - ban_user(result.to.peer_id, result.from.peer_id) + if action == 'ban' then + ban_user(msg.to.id, matches[2]) + elseif action == 'kick' then + kick_user(msg.to.id, matches[2]) + end end - return str2emoji(':exclamation:')..' User ID '..result.from.peer_id..' has been warned '..counter..' times. Banned.' + if u then + return str2emoji(':exclamation:')..' User '..u..' ['..matches[2]..'] has been warned '..counter..' times. Banned.' + else + return str2emoji(':exclamation:')..' User ID '..matches[2]..' has been warned '..counter..' times. Banned.' + end + end + if u then + return str2emoji(':information_source:')..' User ' .. u .. ' ['..matches[2]..'] now has '..counter..' warn(s).' + else + return str2emoji(':information_source:')..' User ID '..matches[2]..' now has '..counter..' warn(s).' end - return str2emoji(':information_source:')..' User ID '..result.from.peer_id..' now has '..counter..' warn(s).' end + --Reset warning if matches[1] == 'resetwarn' then local reply if redis:get(hash) then redis:del(hash) - reply = str2emoji(':information_source:')..' User ID '..result.from.peer_id..' has no more warns.' + if u then + reply = str2emoji(':information_source:')..' User '..u..' ['..matches[2]..'] has no more warns.' + else + reply = str2emoji(':information_source:')..' User ID '..matches[2]..' has no more warns.' + end else - reply = str2emoji(':information_source:')..' User ID '..result.from.peer_id..' had no warns.' + if u then + + else + reply = str2emoji(':information_source:')..' User '..u..' ['..matches[2]..'] had no warns.' + end end return reply end end + --Reply commands if matches[1] == 'warn' then if msg.reply_id then get_message(msg.reply_id, warn_reply, get_receiver(msg)) @@ -141,7 +282,7 @@ local function run (msg, matches) end end - if matches[1] == 'status' then + if matches[1] == 'warninfo' then if msg.reply_id then get_message(msg.reply_id, status_reply, get_receiver(msg)) return nil @@ -158,25 +299,31 @@ return { description = 'Plugin to keep a warning list on the group.', usage = { moderator = { - "!setwarn : Set how many warns are needed to trip the automatic ban" - "!warn : Adds a warn point to user_id", - "!warn status : Returns the plugin's settings", - "!warn status : Returns how many warns user_id got", - "!resetwarn : Reset user_id's warn points to 0", + "!setwarn : Set how many warns are needed to trip the automatic ban", + "!warn : Adds a warn point to user_id", + "!warn info : Returns the plugin's settings", + "!warn info : Returns how many warns user_id got", + "!resetwarn : Reset user_id's warn points to 0", + "!setwarnaction Date: Mon, 10 Jul 2017 20:14:38 +0200 Subject: [PATCH 11/42] That shouldn't be there --- bot/utils.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bot/utils.lua b/bot/utils.lua index e27ab91..7f64272 100644 --- a/bot/utils.lua +++ b/bot/utils.lua @@ -13,7 +13,7 @@ JSON = (loadfile "./libs/dkjson.lua")() http.TIMEOUT = 10 -- insert snoop group ID -local LOG_ID = 0 +local LOG_ID = "chat#id0" function get_receiver(msg) if msg.to.type == 'user' then @@ -570,7 +570,7 @@ end -- Log to group function snoop_msg(text) local cb_extra = { - destination = "user#id68972553", + destination = LOG_ID, text = text } send_large_msg_callback(cb_extra, true) From ed595f6c31dc46c3826771fbdb2f8fbff20f8f65 Mon Sep 17 00:00:00 2001 From: CapacitorSet Date: Mon, 21 Aug 2017 21:30:23 +0200 Subject: [PATCH 12/42] Add basic test suite Implements a basic test suite with Busted, and makes small changes to s-uzzbot in order to output useful data. --- bot/bot.lua | 58 ++++++++++++++++++++++++++++++--------------------- bot/utils.lua | 28 ++++++++++++------------- 2 files changed, 48 insertions(+), 38 deletions(-) diff --git a/bot/bot.lua b/bot/bot.lua index 9dd7785..f030768 100644 --- a/bot/bot.lua +++ b/bot/bot.lua @@ -7,6 +7,10 @@ require("./bot/emoji") VERSION = '0.2' +function _print (arg) + if (not quiet) then print(arg) end +end + -- This function is called when tg receive a msg function on_msg_receive (msg) if not started then @@ -30,7 +34,7 @@ function on_msg_receive (msg) if not whitelistmod or (whitelistmod and is_momod(msg)) then match_plugins(msg) else - print('Message ignored -- '..chat_id..' has modonly wl enabled') + _print('Message ignored -- '..chat_id..' has modonly wl enabled') end -- Commented out since it is a cosmetic feature. @@ -51,53 +55,56 @@ function on_binlog_replay_end() -- See plugins/isup.lua as an example for cron - _config = load_config() + -- You can optionally pass a pre-existing configuration. Used in tests. + if (not _config) then + _config = load_config() + end -- load plugins plugins = {} - load_plugins() + return load_plugins() end function msg_valid(msg) -- Don't process outgoing messages if msg.out then - print('\27[36mNot valid: msg from us\27[39m') + _print('\27[36mNot valid: msg from us\27[39m') return false end -- Before bot was started if msg.date < now then - print('\27[36mNot valid: old msg\27[39m') + _print('\27[36mNot valid: old msg\27[39m') return false end if msg.unread == 0 then - print('\27[36mNot valid: read\27[39m') + _print('\27[36mNot valid: read\27[39m') return false end if not msg.to.id then - print('\27[36mNot valid: To id not provided\27[39m') + _print('\27[36mNot valid: To id not provided\27[39m') return false end if not msg.from.id then - print('\27[36mNot valid: From id not provided\27[39m') + _print('\27[36mNot valid: From id not provided\27[39m') return false end if msg.from.id == our_id then - print('\27[36mNot valid: Msg from our id\27[39m') + _print('\27[36mNot valid: Msg from our id\27[39m') return false end if msg.to.type == 'encr_chat' then - print('\27[36mNot valid: Encrypted chat\27[39m') + _print('\27[36mNot valid: Encrypted chat\27[39m') return false end if msg.from.id == 777000 then - print('\27[36mNot valid: Telegram message\27[39m') + _print('\27[36mNot valid: Telegram message\27[39m') return false end @@ -126,7 +133,7 @@ end function pre_process_msg(msg) for name,plugin in pairs(plugins) do if plugin.pre_process and msg then - print('Preprocess', name) + _print('Preprocess', name) msg = plugin.pre_process(msg) end end @@ -150,10 +157,10 @@ local function is_plugin_disabled_on_chat(plugin_name, receiver) for disabled_plugin,disabled in pairs(disabled_chats[receiver]) do if disabled_plugin == plugin_name and disabled then if plugins[disabled_plugin].hidden then - print('Plugin '..disabled_plugin..' is disabled on this chat') + _print('Plugin '..disabled_plugin..' is disabled on this chat') else local warning = 'Plugin '..disabled_plugin..' is disabled on this chat' - print(warning) + _print(warning) send_msg(receiver, warning, ok_cb, false) end return true @@ -180,7 +187,7 @@ function match_plugin(plugin, plugin_name, msg) for k, pattern in pairs(plugin.patterns) do local matches = match_pattern(pattern, msg.text) if matches then - print("msg matches: ", pattern) + _print("msg matches: ", pattern) if not is_sudo(msg) then if is_plugin_disabled_on_chat(plugin_name, receiver) then @@ -215,7 +222,7 @@ end -- Save the content of _config to config.lua function save_config( ) serialize_to_file(_config, './data/config.lua') - print ('saved config into ./data/config.lua') + _print ('saved config into ./data/config.lua') end -- Returns the config from config.lua file. @@ -224,14 +231,14 @@ function load_config( ) local f = io.open('./data/config.lua', "r") -- If config.lua doesn't exist if not f then - print ("Created new config file: data/config.lua") + _print ("Created new config file: data/config.lua") create_config() else f:close() end local config = loadfile ("./data/config.lua")() for v,user in pairs(config.sudo_users) do - print("Allowed user: " .. user) + _print("Allowed user: " .. user) end return config end @@ -288,8 +295,8 @@ function create_config( ) moderation = {data = 'data/moderation.json'} } serialize_to_file(config, './data/config.lua') - print ('Saved clean configuration into ./data/config.lua') - print ('Make sure to edit sudo_users and add your ID.') + _print ('Saved clean configuration into ./data/config.lua') + _print ('Make sure to edit sudo_users and add your ID.') end function on_our_id (id) @@ -317,8 +324,9 @@ end -- Enable plugins in config.json function load_plugins() + local success = true for k, v in pairs(_config.enabled_plugins) do - print("Loading plugin", v) + _print("Loading plugin " .. v) local ok, err = pcall(function() local t = loadfile("plugins/"..v..'.lua')() @@ -326,11 +334,13 @@ function load_plugins() end) if not ok then - print('\27[31mError loading plugin '..v..'\27[39m') - print('\27[31m'..err..'\27[39m') + success = false + _print('\27[31mError loading plugin '..v..'\27[39m') + _print('\27[31m'..err..'\27[39m') end - end + + return success end -- custom add diff --git a/bot/utils.lua b/bot/utils.lua index 30a1973..41a4842 100644 --- a/bot/utils.lua +++ b/bot/utils.lua @@ -26,7 +26,7 @@ function get_receiver(msg) return 'channel#id'..msg.to.id end if msg.to.type == 'encr_chat' then - return msg.to.print_name + return msg.to._print_name end end @@ -65,7 +65,7 @@ end -- DEPRECATED function string.trim(s) - print("string.trim(s) is DEPRECATED use string:trim() instead") + _print("string.trim(s) is DEPRECATED use string:trim() instead") return s:gsub("^%s*(.-)%s*$", "%1") end @@ -105,7 +105,7 @@ end -- will get the text after the last "/" for filename -- and content-type for extension function download_to_file(url, file_name) - print("url to download: "..url) + _print("url to download: "..url) local respbody = {} local options = { @@ -133,7 +133,7 @@ function download_to_file(url, file_name) file_name = file_name or get_http_file_name(url, headers) local file_path = "/tmp/"..file_name - print("Saved to: "..file_path) + _print("Saved to: "..file_path) file = io.open(file_path, "w+") file:write(table.concat(respbody)) @@ -143,7 +143,7 @@ function download_to_file(url, file_name) end function vardump(value) - print(serpent.block(value, {comment=false})) + _print(serpent.block(value, {comment=false})) end -- taken from http://stackoverflow.com/a/11130774/3163199 @@ -328,7 +328,7 @@ end -- DEPRECATED!!!!! function string.starts(String, Start) - print("string.starts(String, Start) is DEPRECATED use string:starts(text) instead") + _print("string.starts(String, Start) is DEPRECATED use string:starts(text) instead") return Start == string.sub(String,1,string.len(Start)) end @@ -361,7 +361,7 @@ function send_photo_from_url(receiver, url, cb_function, cb_extra) local text = 'Error downloading the image' send_msg(receiver, text, cb_function, cb_extra) else - print("File path: "..file_path) + _print("File path: "..file_path) _send_photo(receiver, file_path, cb_function, cb_extra) end end @@ -376,7 +376,7 @@ function send_photo_from_url_callback(cb_extra, success, result) local text = 'Error downloading the image' send_msg(receiver, text, ok_cb, false) else - print("File path: "..file_path) + _print("File path: "..file_path) _send_photo(receiver, file_path, ok_cb, false) end end @@ -403,7 +403,7 @@ function send_photos_from_url_callback(cb_extra, success, result) -- The previously image to remove if remove_path ~= nil then os.remove(remove_path) - print("Deleted: "..remove_path) + _print("Deleted: "..remove_path) end -- Nil or empty, exit case (no more urls) @@ -433,7 +433,7 @@ function rmtmp_cb(cb_extra, success, result) if file_path ~= nil then os.remove(file_path) - print("Deleted: "..file_path) + _print("Deleted: "..file_path) end -- Finally call the callback cb_function(cb_extra, success, result) @@ -455,7 +455,7 @@ end -- cb_function and cb_extra are optionals callback function send_document_from_url(receiver, url, cb_function, cb_extra) local file_path = download_to_file(url, false) - print("File path: "..file_path) + _print("File path: "..file_path) _send_document(receiver, file_path, cb_function, cb_extra) end @@ -522,7 +522,7 @@ function send_order_msg_callback(cb_extra, success, result) local file_path = cb_extra.file_path if file_path ~= nil then os.remove(file_path) - print("Deleted: " .. file_path) + _print("Deleted: " .. file_path) end if type(msgs) == 'string' then send_large_msg(destination, msgs) @@ -638,9 +638,9 @@ function load_from_file(file, default_data) -- Create a new empty table default_data = default_data or {} serialize_to_file(default_data, file) - print ('Created file', file) + _print ('Created file ' .. file) else - print ('Data loaded from file', file) + _print ('Data loaded from file ' .. file) f:close() end return loadfile (file)() From 9556f61430500e8ea3d6df7b8d437af64d1ffc20 Mon Sep 17 00:00:00 2001 From: CapacitorSet Date: Mon, 21 Aug 2017 21:39:27 +0200 Subject: [PATCH 13/42] Fix incorrect replacement in earlier commit --- bot/utils.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bot/utils.lua b/bot/utils.lua index 41a4842..a680165 100644 --- a/bot/utils.lua +++ b/bot/utils.lua @@ -26,7 +26,7 @@ function get_receiver(msg) return 'channel#id'..msg.to.id end if msg.to.type == 'encr_chat' then - return msg.to._print_name + return msg.to.print_name end end From 7dfa64417678033ccdb6a2c2ef04865bef586658 Mon Sep 17 00:00:00 2001 From: CapacitorSet Date: Mon, 21 Aug 2017 22:01:54 +0200 Subject: [PATCH 14/42] Implement custom logger --- bot/bot.lua | 53 +++++++++++++++++++++++++++++---------------------- bot/utils.lua | 26 ++++++++++++------------- 2 files changed, 43 insertions(+), 36 deletions(-) diff --git a/bot/bot.lua b/bot/bot.lua index f030768..dcbeff3 100644 --- a/bot/bot.lua +++ b/bot/bot.lua @@ -7,8 +7,14 @@ require("./bot/emoji") VERSION = '0.2' -function _print (arg) - if (not quiet) then print(arg) end +-- Let's leave space for backwards-compatible new levels +LOGLEVEL_DEBUG = 0 +LOGLEVEL_INFO = 10 +LOGLEVEL_WARN = 20 +LOGLEVEL_ERROR = 30 +if (not loglevel) then loglevel = LOGLEVEL_INFO end +function log(level, message) + if (level >= loglevel) then print(message) end end -- This function is called when tg receive a msg @@ -34,7 +40,7 @@ function on_msg_receive (msg) if not whitelistmod or (whitelistmod and is_momod(msg)) then match_plugins(msg) else - _print('Message ignored -- '..chat_id..' has modonly wl enabled') + log(LOGLEVEL_INFO, 'Message ignored -- '..chat_id..' has modonly wl enabled') end -- Commented out since it is a cosmetic feature. @@ -68,43 +74,43 @@ end function msg_valid(msg) -- Don't process outgoing messages if msg.out then - _print('\27[36mNot valid: msg from us\27[39m') + log(LOGLEVEL_INFO, '\27[36mNot valid: msg from us\27[39m') return false end -- Before bot was started if msg.date < now then - _print('\27[36mNot valid: old msg\27[39m') + log(LOGLEVEL_INFO, '\27[36mNot valid: old msg\27[39m') return false end if msg.unread == 0 then - _print('\27[36mNot valid: read\27[39m') + log(LOGLEVEL_INFO, '\27[36mNot valid: read\27[39m') return false end if not msg.to.id then - _print('\27[36mNot valid: To id not provided\27[39m') + log(LOGLEVEL_INFO, '\27[36mNot valid: To id not provided\27[39m') return false end if not msg.from.id then - _print('\27[36mNot valid: From id not provided\27[39m') + log(LOGLEVEL_INFO, '\27[36mNot valid: From id not provided\27[39m') return false end if msg.from.id == our_id then - _print('\27[36mNot valid: Msg from our id\27[39m') + log(LOGLEVEL_INFO, '\27[36mNot valid: Msg from our id\27[39m') return false end if msg.to.type == 'encr_chat' then - _print('\27[36mNot valid: Encrypted chat\27[39m') + log(LOGLEVEL_INFO, '\27[36mNot valid: Encrypted chat\27[39m') return false end if msg.from.id == 777000 then - _print('\27[36mNot valid: Telegram message\27[39m') + log(LOGLEVEL_INFO, '\27[36mNot valid: Telegram message\27[39m') return false end @@ -133,7 +139,7 @@ end function pre_process_msg(msg) for name,plugin in pairs(plugins) do if plugin.pre_process and msg then - _print('Preprocess', name) + log(LOGLEVEL_INFO, 'Preprocess', name) msg = plugin.pre_process(msg) end end @@ -157,10 +163,10 @@ local function is_plugin_disabled_on_chat(plugin_name, receiver) for disabled_plugin,disabled in pairs(disabled_chats[receiver]) do if disabled_plugin == plugin_name and disabled then if plugins[disabled_plugin].hidden then - _print('Plugin '..disabled_plugin..' is disabled on this chat') + log(LOGLEVEL_INFO, 'Plugin '..disabled_plugin..' is disabled on this chat') else local warning = 'Plugin '..disabled_plugin..' is disabled on this chat' - _print(warning) + log(LOGLEVEL_INFO, warning) send_msg(receiver, warning, ok_cb, false) end return true @@ -187,7 +193,7 @@ function match_plugin(plugin, plugin_name, msg) for k, pattern in pairs(plugin.patterns) do local matches = match_pattern(pattern, msg.text) if matches then - _print("msg matches: ", pattern) + log(LOGLEVEL_INFO, "msg matches: ", pattern) if not is_sudo(msg) then if is_plugin_disabled_on_chat(plugin_name, receiver) then @@ -222,7 +228,7 @@ end -- Save the content of _config to config.lua function save_config( ) serialize_to_file(_config, './data/config.lua') - _print ('saved config into ./data/config.lua') + log(LOGLEVEL_INFO, 'saved config into ./data/config.lua') end -- Returns the config from config.lua file. @@ -231,14 +237,14 @@ function load_config( ) local f = io.open('./data/config.lua', "r") -- If config.lua doesn't exist if not f then - _print ("Created new config file: data/config.lua") + log(LOGLEVEL_INFO, "Created new config file: data/config.lua") create_config() else f:close() end local config = loadfile ("./data/config.lua")() for v,user in pairs(config.sudo_users) do - _print("Allowed user: " .. user) + log(LOGLEVEL_INFO, "Allowed user: " .. user) end return config end @@ -295,8 +301,8 @@ function create_config( ) moderation = {data = 'data/moderation.json'} } serialize_to_file(config, './data/config.lua') - _print ('Saved clean configuration into ./data/config.lua') - _print ('Make sure to edit sudo_users and add your ID.') + log(LOGLEVEL_INFO, 'Saved clean configuration into ./data/config.lua') + log(LOGLEVEL_INFO, 'Make sure to edit sudo_users and add your ID.') end function on_our_id (id) @@ -326,7 +332,7 @@ end function load_plugins() local success = true for k, v in pairs(_config.enabled_plugins) do - _print("Loading plugin " .. v) + log(LOGLEVEL_INFO, "Loading plugin " .. v) local ok, err = pcall(function() local t = loadfile("plugins/"..v..'.lua')() @@ -335,8 +341,8 @@ function load_plugins() if not ok then success = false - _print('\27[31mError loading plugin '..v..'\27[39m') - _print('\27[31m'..err..'\27[39m') + log(LOGLEVEL_WARN, '\27[31mError loading plugin '..v..'\27[39m') + log(LOGLEVEL_WARN, '\27[31m'..err..'\27[39m') end end @@ -381,6 +387,7 @@ function cron_plugins() postpone (cron_plugins, false, 5*60.0) end + -- Start and load values our_id = 0 now = os.time() diff --git a/bot/utils.lua b/bot/utils.lua index a680165..cab3415 100644 --- a/bot/utils.lua +++ b/bot/utils.lua @@ -65,7 +65,7 @@ end -- DEPRECATED function string.trim(s) - _print("string.trim(s) is DEPRECATED use string:trim() instead") + log(LOGLEVEL_WARN, "string.trim(s) is DEPRECATED use string:trim() instead") return s:gsub("^%s*(.-)%s*$", "%1") end @@ -105,7 +105,7 @@ end -- will get the text after the last "/" for filename -- and content-type for extension function download_to_file(url, file_name) - _print("url to download: "..url) + log(LOGLEVEL_INFO, "url to download: "..url) local respbody = {} local options = { @@ -133,7 +133,7 @@ function download_to_file(url, file_name) file_name = file_name or get_http_file_name(url, headers) local file_path = "/tmp/"..file_name - _print("Saved to: "..file_path) + log(LOGLEVEL_INFO, "Saved to: "..file_path) file = io.open(file_path, "w+") file:write(table.concat(respbody)) @@ -143,7 +143,7 @@ function download_to_file(url, file_name) end function vardump(value) - _print(serpent.block(value, {comment=false})) + log(LOGLEVEL_INFO, serpent.block(value, {comment=false})) end -- taken from http://stackoverflow.com/a/11130774/3163199 @@ -328,7 +328,7 @@ end -- DEPRECATED!!!!! function string.starts(String, Start) - _print("string.starts(String, Start) is DEPRECATED use string:starts(text) instead") + log(LOGLEVEL_INFO, "string.starts(String, Start) is DEPRECATED use string:starts(text) instead") return Start == string.sub(String,1,string.len(Start)) end @@ -361,7 +361,7 @@ function send_photo_from_url(receiver, url, cb_function, cb_extra) local text = 'Error downloading the image' send_msg(receiver, text, cb_function, cb_extra) else - _print("File path: "..file_path) + log(LOGLEVEL_INFO, "File path: "..file_path) _send_photo(receiver, file_path, cb_function, cb_extra) end end @@ -376,7 +376,7 @@ function send_photo_from_url_callback(cb_extra, success, result) local text = 'Error downloading the image' send_msg(receiver, text, ok_cb, false) else - _print("File path: "..file_path) + log(LOGLEVEL_INFO, "File path: "..file_path) _send_photo(receiver, file_path, ok_cb, false) end end @@ -403,7 +403,7 @@ function send_photos_from_url_callback(cb_extra, success, result) -- The previously image to remove if remove_path ~= nil then os.remove(remove_path) - _print("Deleted: "..remove_path) + log(LOGLEVEL_INFO, "Deleted: "..remove_path) end -- Nil or empty, exit case (no more urls) @@ -433,7 +433,7 @@ function rmtmp_cb(cb_extra, success, result) if file_path ~= nil then os.remove(file_path) - _print("Deleted: "..file_path) + log(LOGLEVEL_INFO, "Deleted: "..file_path) end -- Finally call the callback cb_function(cb_extra, success, result) @@ -455,7 +455,7 @@ end -- cb_function and cb_extra are optionals callback function send_document_from_url(receiver, url, cb_function, cb_extra) local file_path = download_to_file(url, false) - _print("File path: "..file_path) + log(LOGLEVEL_INFO, "File path: "..file_path) _send_document(receiver, file_path, cb_function, cb_extra) end @@ -522,7 +522,7 @@ function send_order_msg_callback(cb_extra, success, result) local file_path = cb_extra.file_path if file_path ~= nil then os.remove(file_path) - _print("Deleted: " .. file_path) + log(LOGLEVEL_INFO, "Deleted: " .. file_path) end if type(msgs) == 'string' then send_large_msg(destination, msgs) @@ -638,9 +638,9 @@ function load_from_file(file, default_data) -- Create a new empty table default_data = default_data or {} serialize_to_file(default_data, file) - _print ('Created file ' .. file) + log(LOGLEVEL_INFO, 'Created file ' .. file) else - _print ('Data loaded from file ' .. file) + log(LOGLEVEL_INFO, 'Data loaded from file ' .. file) f:close() end return loadfile (file)() From ce60157ae47eeb4719b2fac8d444e8b114debbc6 Mon Sep 17 00:00:00 2001 From: CapacitorSet Date: Mon, 21 Aug 2017 23:10:19 +0200 Subject: [PATCH 15/42] Add test/, whoops. --- bot/bot.lua | 15 +++++--- test/README.md | 3 ++ test/test.lua | 96 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 5 deletions(-) create mode 100644 test/README.md create mode 100644 test/test.lua diff --git a/bot/bot.lua b/bot/bot.lua index dcbeff3..94f9b68 100644 --- a/bot/bot.lua +++ b/bot/bot.lua @@ -17,7 +17,8 @@ function log(level, message) if (level >= loglevel) then print(message) end end --- This function is called when tg receive a msg +-- This function is called when tg receives a msg +-- Returns false if the message was ignored, true otherwise function on_msg_receive (msg) if not started then return @@ -39,6 +40,7 @@ function on_msg_receive (msg) if msg then if not whitelistmod or (whitelistmod and is_momod(msg)) then match_plugins(msg) + return true else log(LOGLEVEL_INFO, 'Message ignored -- '..chat_id..' has modonly wl enabled') end @@ -50,6 +52,7 @@ function on_msg_receive (msg) end end + return false end function ok_cb(extra, success, result) @@ -193,14 +196,14 @@ function match_plugin(plugin, plugin_name, msg) for k, pattern in pairs(plugin.patterns) do local matches = match_pattern(pattern, msg.text) if matches then - log(LOGLEVEL_INFO, "msg matches: ", pattern) + print("msg matches: ", pattern) if not is_sudo(msg) then if is_plugin_disabled_on_chat(plugin_name, receiver) then - return nil + goto continue end if plugin.nsfw and is_nsfw_disabled_on_chat(receiver) then - return nil + goto continue end end @@ -215,8 +218,9 @@ function match_plugin(plugin, plugin_name, msg) end end -- One patterns matches - return + goto continue end + ::continue:: end end @@ -329,6 +333,7 @@ function on_get_difference_end () end -- Enable plugins in config.json +-- Returns true if all the plugins were loaded correctly, false otherwise function load_plugins() local success = true for k, v in pairs(_config.enabled_plugins) do diff --git a/test/README.md b/test/README.md new file mode 100644 index 0000000..32f37f3 --- /dev/null +++ b/test/README.md @@ -0,0 +1,3 @@ +Requires Busted: `luarocks install busted` + +Run with `busted test/test.lua` from the project folder. \ No newline at end of file diff --git a/test/test.lua b/test/test.lua new file mode 100644 index 0000000..b711e20 --- /dev/null +++ b/test/test.lua @@ -0,0 +1,96 @@ +describe("Bot", function() + it("initializes", function() + _G.postpone = function() end + _G._config = { + disabled_channels = {}, + enabled_plugins = { + }, + moderation = { + data = "data/moderation.json" + }, + sudo_users = { + 0 + } + } + require("bot/bot") + _G.loglevel = LOGLEVEL_WARN + local initialized_correctly = on_binlog_replay_end() + assert.is_true(initialized_correctly) + end) + it("loads ping", function() + _config.enabled_plugins = {"ping"} + local plugins_loaded_correctly = load_plugins() + assert.is_true(plugins_loaded_correctly) + end) + it("responds to pings", function() + -- Create a stub in advance + _G.send_msg = spy.new(function(destination, text) end) + + local was_message_received = on_msg_receive({ + date = 1/0, -- a date infinitely in the future + flags = 257, + from = { + access_hash = -1.11111111111111+18, + bot = false, + first_name = "TARS", + flags = 196609, + id = "$010000000be6840443e616f4ce4780c0", + peer_id = 75818507, + peer_type = "user", + phone = "11111111111", + print_name = "TARS", + username = "rTARS" + }, + id = "020000006466ef0024923a00000000000000000000000000", + out = false, + service = false, + temp_id = 2, + text = "!ping", + to = { + flags = 65537, + id = "$020000006466ef000000000000000000", + members_num = 100, + peer_id = 15689316, + peer_type = "chat", + print_name = "Group name here", + title = "Group name here" + }, + unread = true + }) + assert.is_true(was_message_received) + assert.spy(_G.send_msg).was.called() + end) +end) + +-- Typical message: +-- { +-- date = 1503346812, +-- flags = 257, +-- from = { +-- access_hash = -1.11111111111111+18, +-- bot = false, +-- first_name = "User", +-- flags = 196609, +-- id = "$010000000be6840443e616f4ce4780c0", +-- peer_id = 75818507, +-- peer_type = "user", +-- phone = "11111111111", +-- print_name = "User", +-- username = "username" +-- }, +-- id = "020000006466ef0024923a00000000000000000000000000", +-- out = false, +-- service = false, +-- temp_id = 2, +-- text = "test", +-- to = { +-- flags = 65537, +-- id = "$020000006466ef000000000000000000", +-- members_num = 100, +-- peer_id = 15689316, +-- peer_type = "chat", +-- print_name = "Group name here", +-- title = "Group name here" +-- }, +-- unread = true +-- } \ No newline at end of file From bce595bf5a5bf7eb31491c45944d68c27d2710c9 Mon Sep 17 00:00:00 2001 From: CapacitorSet Date: Tue, 22 Aug 2017 22:38:27 +0200 Subject: [PATCH 16/42] Make utils more readable (early return) --- bot/utils.lua | 58 +++++++++++++++++++++++---------------------------- 1 file changed, 26 insertions(+), 32 deletions(-) diff --git a/bot/utils.lua b/bot/utils.lua index cab3415..bef0801 100644 --- a/bot/utils.lua +++ b/bot/utils.lua @@ -166,77 +166,73 @@ end -- User has superuser privileges function is_sudo(msg) - local var = false -- Check users id in config for v,user in pairs(_config.sudo_users) do if user == msg.from.id then - var = true + return true end end - return var + return false end -- user has admins privileges function is_admin(msg) - local var = false local data = load_data(_config.moderation.data) local user = msg.from.id local admins = 'admins' if data[tostring(admins)] then if data[tostring(admins)][tostring(user)] then - var = true + return true end end for v,user in pairs(_config.sudo_users) do if user == msg.from.id then - var = true + return true end end - return var + return false end -- user has blocklist adding privileges function is_blocklistadm(msg) - local var = false local data = load_data(_config.moderation.data) local user = msg.from.id local blocklist = 'blocklist' if data[tostring(blocklist)] then if data[tostring(blocklist)][tostring(user)] then - var = true + return true end end for v,user in pairs(_config.sudo_users) do if user == msg.from.id then - var = true + return true end end - return var + return false end -- user has moderator privileges function is_momod(msg) - local var = false local data = load_data(_config.moderation.data) local user = msg.from.id if data[tostring(msg.to.id)] then if data[tostring(msg.to.id)]['moderators'] then if data[tostring(msg.to.id)]['moderators'][tostring(user)] then - var = true + return true end end end if data['admins'] then if data['admins'][tostring(user)] then - var = true + return true end end for v,user in pairs(_config.sudo_users) do if user == msg.from.id then - var = true + return true end end - return var + return false end -- check whether user is mod, admin or sudo @@ -246,24 +242,24 @@ function is_mod(user_id, chat_id) if data[tostring(chat_id)] then if data[tostring(chat_id)]['moderators'] then if data[tostring(chat_id)]['moderators'][tostring(user_id)] then - var = true + return true end end end if data['admins'] then if data['admins'][tostring(user_id)] then - var = true + return true end end for v,user in pairs(_config.sudo_users) do if user == user_id then - var = true + return true end end if user == our_id then - var = true + return true end - return var + return false end -- Returns the name of the sender @@ -616,18 +612,16 @@ end -- Returns a table with matches or nil function match_pattern(pattern, text, lower_case) - if text then - local matches = {} - if lower_case then - matches = { string.match(text:lower(), pattern) } - else - matches = { string.match(text, pattern) } - end - if next(matches) then - return matches - end + if not text then return nil end + local matches = {} + if lower_case then + matches = { string.match(text:lower(), pattern) } + else + matches = { string.match(text, pattern) } + end + if next(matches) then + return matches end - -- nil end -- Function to read data from files From e86d5032cdfa64e0b558281d333c6ac1c3d9d45c Mon Sep 17 00:00:00 2001 From: CapacitorSet Date: Tue, 22 Aug 2017 22:38:47 +0200 Subject: [PATCH 17/42] Format anti-flood plugin, use early return --- plugins/anti-flood.lua | 425 ++++++++++++++++++++--------------------- 1 file changed, 212 insertions(+), 213 deletions(-) diff --git a/plugins/anti-flood.lua b/plugins/anti-flood.lua index 34a566e..4b07b81 100644 --- a/plugins/anti-flood.lua +++ b/plugins/anti-flood.lua @@ -2,238 +2,237 @@ local function kick_user(user_id, chat_id) local chat = 'chat#id'..chat_id local user = 'user#id'..user_id chat_del_user(chat, user, function (data, success, result) - if not success then - local text = str2emoji(":exclamation:")..' I can\'t kick '..data.user..' but should be kicked' - snoop_msg('I am unable to kick user '..user_id..' from group '..chat_id..'.') - send_msg(data.chat, text, ok_cb, nil) - end - end, {chat=chat, user=user}) + if not success then + local text = str2emoji(":exclamation:")..' I can\'t kick '..data.user..' but should be kicked' + snoop_msg('I am unable to kick user '..user_id..' from group '..chat_id..'.') + send_msg(data.chat, text, ok_cb, nil) end + end, {chat=chat, user=user}) +end - local function kick_chan_user(user_id, chat_id) - local chat = 'channel#id'..chat_id - local user = 'user#id'..user_id - channel_kick(chat, user, function (data, success, result) - if not success then - local text = str2emoji(":exclamation:")..' I can\'t kick '..data.user..' but should be kicked' - snoop_msg('I am unable to kick user '..user_id..' from group '..chat_id..'.') - send_msg(data.chat, text, ok_cb, nil) - end - end, {chat=chat, user=user}) +local function kick_chan_user(user_id, chat_id) + local chat = 'channel#id'..chat_id + local user = 'user#id'..user_id + channel_kick(chat, user, function (data, success, result) + if not success then + local text = str2emoji(":exclamation:")..' I can\'t kick '..data.user..' but should be kicked' + snoop_msg('I am unable to kick user '..user_id..' from group '..chat_id..'.') + send_msg(data.chat, text, ok_cb, nil) + end + end, {chat=chat, user=user}) +end + +local function addexcept_reply(extra, success, result) + local hash = 'anti-flood:exception:'..result.to.peer_id..':'..result.from.peer_id + redis:set(hash, true) + send_large_msg(extra, str2emoji(':information_source:')..' User ID '..result.from.peer_id..' is now exempt from antiflood checks.') +end + +local function delexcept_reply(extra, success, result) + local hash = 'anti-flood:exception:'..result.to.peer_id..':'..result.from.peer_id + local reply + if redis:get(hash) then + redis:del(hash) + reply = str2emoji(':information_source:')..' User ID '..result.from.peer_id..' is now subject to antiflood checks.' + else + reply = str2emoji(':information_source:')..' User ID '..result.from.peer_id..' is not exempt from antiflood checks.' + end + send_large_msg(extra, reply) +end + +local function run (msg, matches) + if not is_chat_msg(msg) then + return str2emoji(":exclamation:")..' Anti-flood works only on groups' + end + if not is_momod(msg) then + return str2emoji(":no_entry_sign:")..' You are not a moderator on this channel' + end + + local chat = msg.to.id + local hash = 'anti-flood:enabled:'..chat + if matches[1] == 'addexcept' then + if msg.reply_id then + get_message(msg.reply_id, addexcept_reply, get_receiver(msg)) + return nil + end + end + if matches[1] == 'delexcept' then + if msg.reply_id then + get_message(msg.reply_id, delexcept_reply, get_receiver(msg)) + return nil + end + end + if matches[1] == 'enable' then + redis:set(hash, true) + return str2emoji(':information_source:')..' Anti-flood enabled on chat' + end + if matches[1] == 'disable' then + redis:del(hash) + return str2emoji(':information_source:')..' Anti-flood disabled on chat' + end + if matches[1] == 'status' then + local hash_enable = 'anti-flood:enabled:'..msg.to.id + local enabled = redis:get(hash_enable) + + if enabled then + local hash_maxmsg = 'anti-flood:maxmsg:'..msg.to.id + local hash_timeframe = 'anti-flood:timeframe:'..msg.to.id + + -- Max number of messages per TIME_CHECK seconds + local NUM_MSG_MAX = tonumber(redis:get(hash_maxmsg) or 5) + local TIME_CHECK = tonumber(redis:get(hash_timeframe) or 5) + + return str2emoji(':information_source:')..' Anti-flood current parameters:\n'..str2emoji(":no_entry_sign:")..' Kick set at '..NUM_MSG_MAX..' messages over '..TIME_CHECK..' seconds.' + else + return str2emoji(':information_source:')..' Anti-flood is disabled on this chat.\n'..str2emoji(":point_right:")..' Enable it with !antiflood enable.' + end + end + if matches[2] then + local hash_maxmsg = 'anti-flood:maxmsg:'..msg.to.id + local hash_timeframe = 'anti-flood:timeframe:'..msg.to.id + + local parameter_mt = tonumber(matches[2]) + if matches[1] == 'maxmsg' then + if parameter_mt > 4 then + redis:set(hash_maxmsg, parameter_mt) + return str2emoji(':information_source:')..' Now the number of messages needed to trip the antiflood is '..matches[2]..'.' + end + return str2emoji(":exclamation:")..' The limit should be higher than 4.' + end + if matches[1] == 'timeframe' then + if parameter_mt > 4 then + redis:set(hash_timeframe, parameter_mt) + return 'Now the timeframe in which the antiflood will take its samples is '..matches[2].. ' seconds.' + end + return str2emoji(":exclamation:")..' The time frame should be higher than 4.' end - local function addexcept_reply(extra, success, result) - local hash = 'anti-flood:exception:'..result.to.peer_id..':'..result.from.peer_id + hash = 'anti-flood:exception:'..chat..':'..matches[2] + if matches[1] == 'addexcept' then redis:set(hash, true) - send_large_msg(extra, str2emoji(':information_source:')..' User ID '..result.from.peer_id..' is now exempt from antiflood checks.') + return str2emoji(':information_source:')..' User ID '..matches[2]..' is now exempt from antiflood checks.' end - - local function delexcept_reply(extra, success, result) - local hash = 'anti-flood:exception:'..result.to.peer_id..':'..result.from.peer_id - local reply + if matches[1] == 'delexcept' then if redis:get(hash) then redis:del(hash) - reply = str2emoji(':information_source:')..' User ID '..result.from.peer_id..' is now subject to antiflood checks.' + return str2emoji(':information_source:')..' User ID '..matches[2]..' is now subject to antiflood checks.' else - reply = str2emoji(':information_source:')..' User ID '..result.from.peer_id..' is not exempt from antiflood checks.' + return str2emoji(':information_source:')..' User ID '..matches[2]..' is not exempt from antiflood checks.' end - send_large_msg(extra, reply) end + end +end - local function run (msg, matches) - if not is_chat_msg(msg) then - return str2emoji(":exclamation:")..' Anti-flood works only on groups' - else - if is_momod(msg) then - local chat = msg.to.id - local hash = 'anti-flood:enabled:'..chat - if matches[1] == 'addexcept' then - if msg.reply_id then - get_message(msg.reply_id, addexcept_reply, get_receiver(msg)) - return nil - end - end - if matches[1] == 'delexcept' then - if msg.reply_id then - get_message(msg.reply_id, delexcept_reply, get_receiver(msg)) - return nil - end - end - if matches[1] == 'enable' then - redis:set(hash, true) - return str2emoji(':information_source:')..' Anti-flood enabled on chat' - end - if matches[1] == 'disable' then - redis:del(hash) - return str2emoji(':information_source:')..' Anti-flood disabled on chat' - end - if matches[1] == 'status' then - local hash_enable = 'anti-flood:enabled:'..msg.to.id - local enabled = redis:get(hash_enable) - - if enabled then - local hash_maxmsg = 'anti-flood:maxmsg:'..msg.to.id - local hash_timeframe = 'anti-flood:timeframe:'..msg.to.id - - -- Max number of messages per TIME_CHECK seconds - local NUM_MSG_MAX = tonumber(redis:get(hash_maxmsg) or 5) - local TIME_CHECK = tonumber(redis:get(hash_timeframe) or 5) - - return str2emoji(':information_source:')..' Anti-flood current parameters:\n'..str2emoji(":no_entry_sign:")..' Kick set at '..NUM_MSG_MAX..' messages over '..TIME_CHECK..' seconds.' - else - return str2emoji(':information_source:')..' Anti-flood is disabled on this chat.\n'..str2emoji(":point_right:")..' Enable it with !antiflood enable.' - end - end - if matches[2] then - local hash_maxmsg = 'anti-flood:maxmsg:'..msg.to.id - local hash_timeframe = 'anti-flood:timeframe:'..msg.to.id - - local parameter_mt = tonumber(matches[2]) - if matches[1] == 'maxmsg' then - if parameter_mt > 4 then - redis:set(hash_maxmsg, parameter_mt) - return str2emoji(':information_source:')..' Now the number of messages needed to trip the antiflood is '..matches[2]..'.' - end - return str2emoji(":exclamation:")..' The limit should be higher than 4.' - end - if matches[1] == 'timeframe' then - if parameter_mt > 4 then - redis:set(hash_timeframe, parameter_mt) - return 'Now the timeframe in which the antiflood will take its samples is '..matches[2].. ' seconds.' - end - return str2emoji(":exclamation:")..' The time frame should be higher than 4.' - end +local function pre_process (msg) + -- Ignore service msg + if msg.service then + print('Service message') + return msg + end - hash = 'anti-flood:exception:'..chat..':'..matches[2] - if matches[1] == 'addexcept' then - redis:set(hash, true) - return str2emoji(':information_source:')..' User ID '..matches[2]..' is now exempt from antiflood checks.' - end - if matches[1] == 'delexcept' then - if redis:get(hash) then - redis:del(hash) - return str2emoji(':information_source:')..' User ID '..matches[2]..' is now subject to antiflood checks.' - else - return str2emoji(':information_source:')..' User ID '..matches[2]..' is not exempt from antiflood checks.' - end - end - end + local hash_enable = 'anti-flood:enabled:'..msg.to.id + local enabled = redis:get(hash_enable) + + if enabled then + print('anti-flood enabled') + -- Check flood + if msg.from.type == 'user' then + local hash_maxmsg = 'anti-flood:maxmsg:'..msg.to.id + local hash_timeframe = 'anti-flood:timeframe:'..msg.to.id + + -- Max number of messages per TIME_CHECK seconds + local NUM_MSG_MAX = tonumber(redis:get(hash_maxmsg) or 5) + local TIME_CHECK = tonumber(redis:get(hash_timeframe) or 5) + + -- Increase the number of messages from the user on the chat + local hash = 'anti-flood:'..msg.from.id..':'..msg.to.id..':msg-num' + local hash_warned = 'anti-flood:'..msg.from.id..':'..msg.to.id..':msg-num' + local msgs = tonumber(redis:get(hash) or 0) + local warned = redis:get(hash_warned) or false + + if msgs > NUM_MSG_MAX and not warned then + local receiver = get_receiver(msg) + local user = msg.from.id + local text = str2emoji(":exclamation:")..' User ' + if msg.from.username ~= nil then + text = text..' @'..msg.from.username..' ['..user..'] is flooding' else - return str2emoji(":no_entry_sign:")..' You are not a moderator on this channel' + text = text..string.gsub(msg.from.print_name, '_', ' ')..' ['..user..'] is flooding' end - end - end - - local function pre_process (msg) - -- Ignore service msg - if msg.service then - print('Service message') - return msg - end - - local hash_enable = 'anti-flood:enabled:'..msg.to.id - local enabled = redis:get(hash_enable) - - if enabled then - print('anti-flood enabled') - -- Check flood - if msg.from.type == 'user' then - local hash_maxmsg = 'anti-flood:maxmsg:'..msg.to.id - local hash_timeframe = 'anti-flood:timeframe:'..msg.to.id - - -- Max number of messages per TIME_CHECK seconds - local NUM_MSG_MAX = tonumber(redis:get(hash_maxmsg) or 5) - local TIME_CHECK = tonumber(redis:get(hash_timeframe) or 5) - - -- Increase the number of messages from the user on the chat - local hash = 'anti-flood:'..msg.from.id..':'..msg.to.id..':msg-num' - local hash_warned = 'anti-flood:'..msg.from.id..':'..msg.to.id..':msg-num' - local msgs = tonumber(redis:get(hash) or 0) - local warned = redis:get(hash_warned) or false - - if msgs > NUM_MSG_MAX and not warned then - local receiver = get_receiver(msg) - local user = msg.from.id - local text = str2emoji(":exclamation:")..' User ' - if msg.from.username ~= nil then - text = text..' @'..msg.from.username..' ['..user..'] is flooding' + local chat = msg.to.id + local hash_exception = 'anti-flood:exception:'..msg.to.id..':'..msg.from.id + + if not is_chat_msg(msg) then + print("Flood in not a chat group!") + msg = nil + elseif user == tostring(our_id) then + print('I won\'t kick myself') + msg = nil + elseif is_momod(msg) then + print('I won\'t kick a mod/admin/sudo!') + msg = nil + elseif redis:get(hash_exception) then + print('User is exempt from antiflood checks!') + msg = nil + else + local real_text + if msg.media ~= nil then + if msg.media.caption ~= nil then + real_text = msg.media.caption else - text = text..string.gsub(msg.from.print_name, '_', ' ')..' ['..user..'] is flooding' + real_text = "[media with no caption]" end - local chat = msg.to.id - local hash_exception = 'anti-flood:exception:'..msg.to.id..':'..msg.from.id - - if not is_chat_msg(msg) then - print("Flood in not a chat group!") - msg = nil - elseif user == tostring(our_id) then - print('I won\'t kick myself') - msg = nil - elseif is_momod(msg) then - print('I won\'t kick a mod/admin/sudo!') - msg = nil - elseif redis:get(hash_exception) then - print('User is exempt from antiflood checks!') - msg = nil - else - local real_text - if msg.media ~= nil then - if msg.media.caption ~= nil then - real_text = msg.media.caption - else - real_text = "[media with no caption]" - end - else - if msg.text ~= nil then - real_text = msg.text - end - end - - if msg.from.username ~= nil then - snoop_msg('User @'..msg.from.username..' ['..msg.from.id..'] has been found flooding.\nGroup: '..msg.to.print_name..' ['..msg.to.id..']\nText: '..real_text) - else - snoop_msg('User '..string.gsub(msg.from.print_name, '_', ' ')..' ['..msg.from.id..'] has been found flooding.\nGroup: '..msg.to.print_name..' ['..msg.to.id..']\nText: '..real_text) - end - send_msg(receiver, text, ok_cb, nil) - redis:set(hash_warned, true) - if not is_chan_msg(msg) then - kick_user(user, chat) - else - kick_chan_user(user, chat) - end - msg = nil + else + if msg.text ~= nil then + real_text = msg.text end end - redis:setex(hash, TIME_CHECK, msgs+1) + + if msg.from.username ~= nil then + snoop_msg('User @'..msg.from.username..' ['..msg.from.id..'] has been found flooding.\nGroup: '..msg.to.print_name..' ['..msg.to.id..']\nText: '..real_text) + else + snoop_msg('User '..string.gsub(msg.from.print_name, '_', ' ')..' ['..msg.from.id..'] has been found flooding.\nGroup: '..msg.to.print_name..' ['..msg.to.id..']\nText: '..real_text) + end + send_msg(receiver, text, ok_cb, nil) + redis:set(hash_warned, true) + if not is_chan_msg(msg) then + kick_user(user, chat) + else + kick_chan_user(user, chat) + end + msg = nil end end - return msg + redis:setex(hash, TIME_CHECK, msgs+1) end - - return { - description = 'Plugin to kick flooders from group.', - usage = { - moderator = { - "!antiflood enable/disable : Enable or disable flood checking", - "!antiflood addexcept/delexcept : Add user to antiflood exceptions", - "!antiflood status : Get current antiflood parameters", - "!antiflood maxmsg : Set number of messages/time needed to trip the antiflood", - "!antiflood timeframe : Set the antiflood's sample time frame", - "#addexcept (by reply) : Add user to antiflood exceptions", - "#delexcept (by reply) : Delete user from antiflood exceptions" - }, - }, - patterns = { - '^!antiflood (enable)$', - '^!antiflood (disable)$', - '^!antiflood (addexcept) (%d+)$', - '^!antiflood (delexcept) (%d+)$', - '^!antiflood (maxmsg) (%d+)$', - '^!antiflood (timeframe) (%d+)$', - '^!antiflood (status)$', - '^#(addexcept)$', - '^#(delexcept)$' - }, - run = run, - pre_process = pre_process - } + end + return msg +end + +return { + description = 'Plugin to kick flooders from group.', + usage = { + moderator = { + "!antiflood enable/disable : Enable or disable flood checking", + "!antiflood addexcept/delexcept : Add user to antiflood exceptions", + "!antiflood status : Get current antiflood parameters", + "!antiflood maxmsg : Set number of messages/time needed to trip the antiflood", + "!antiflood timeframe : Set the antiflood's sample time frame", + "#addexcept (by reply) : Add user to antiflood exceptions", + "#delexcept (by reply) : Delete user from antiflood exceptions" + }, + }, + patterns = { + '^!antiflood (enable)$', + '^!antiflood (disable)$', + '^!antiflood (addexcept) (%d+)$', + '^!antiflood (delexcept) (%d+)$', + '^!antiflood (maxmsg) (%d+)$', + '^!antiflood (timeframe) (%d+)$', + '^!antiflood (status)$', + '^#(addexcept)$', + '^#(delexcept)$' + }, + run = run, + pre_process = pre_process +} From de440ec898b07008069969766aae8a36c87b08b6 Mon Sep 17 00:00:00 2001 From: CapacitorSet Date: Tue, 22 Aug 2017 23:08:08 +0200 Subject: [PATCH 18/42] Make anti-flood compatible with FakeRedis --- plugins/anti-flood.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/anti-flood.lua b/plugins/anti-flood.lua index 4b07b81..71c0564 100644 --- a/plugins/anti-flood.lua +++ b/plugins/anti-flood.lua @@ -24,7 +24,7 @@ end local function addexcept_reply(extra, success, result) local hash = 'anti-flood:exception:'..result.to.peer_id..':'..result.from.peer_id - redis:set(hash, true) + redis:set(hash, 1) send_large_msg(extra, str2emoji(':information_source:')..' User ID '..result.from.peer_id..' is now exempt from antiflood checks.') end @@ -63,7 +63,7 @@ local function run (msg, matches) end end if matches[1] == 'enable' then - redis:set(hash, true) + redis:set(hash, 1) return str2emoji(':information_source:')..' Anti-flood enabled on chat' end if matches[1] == 'disable' then @@ -109,7 +109,7 @@ local function run (msg, matches) hash = 'anti-flood:exception:'..chat..':'..matches[2] if matches[1] == 'addexcept' then - redis:set(hash, true) + redis:set(hash, 1) return str2emoji(':information_source:')..' User ID '..matches[2]..' is now exempt from antiflood checks.' end if matches[1] == 'delexcept' then @@ -194,7 +194,7 @@ local function pre_process (msg) snoop_msg('User '..string.gsub(msg.from.print_name, '_', ' ')..' ['..msg.from.id..'] has been found flooding.\nGroup: '..msg.to.print_name..' ['..msg.to.id..']\nText: '..real_text) end send_msg(receiver, text, ok_cb, nil) - redis:set(hash_warned, true) + redis:set(hash_warned, 1) if not is_chan_msg(msg) then kick_user(user, chat) else From b9356f5dc5240bec338cb6458bfce8f98a0b94e8 Mon Sep 17 00:00:00 2001 From: CapacitorSet Date: Tue, 22 Aug 2017 23:22:06 +0200 Subject: [PATCH 19/42] Make bot.lua more readable (early return) --- bot/bot.lua | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/bot/bot.lua b/bot/bot.lua index 94f9b68..cd8a2dc 100644 --- a/bot/bot.lua +++ b/bot/bot.lua @@ -21,6 +21,7 @@ end -- Returns false if the message was ignored, true otherwise function on_msg_receive (msg) if not started then + log(LOGLEVEL_DEBUG, "not started") return end @@ -35,24 +36,29 @@ function on_msg_receive (msg) -- vardump(msg) msg = pre_process_service_msg(msg) - if msg_valid(msg) then - msg = pre_process_msg(msg) - if msg then - if not whitelistmod or (whitelistmod and is_momod(msg)) then - match_plugins(msg) - return true - else - log(LOGLEVEL_INFO, 'Message ignored -- '..chat_id..' has modonly wl enabled') - end + if not msg_valid(msg) then + log(LOGLEVEL_DEBUG, "msg not valid") + return false + end + + msg = pre_process_msg(msg) + if not msg then + log(LOGLEVEL_DEBUG, "preprocess failed") + return false + end -- Commented out since it is a cosmetic feature. -- Also breaks UX on groups since on standard mode it marks the message -- as read for everybody. -- mark_read(receiver, ok_cb, false) - end + if not (not whitelistmod or (whitelistmod and is_momod(msg))) then + log(LOGLEVEL_INFO, 'Message ignored -- '..chat_id..' has modonly wl enabled') + return false end - return false + + match_plugins(msg) + return true end function ok_cb(extra, success, result) @@ -142,7 +148,7 @@ end function pre_process_msg(msg) for name,plugin in pairs(plugins) do if plugin.pre_process and msg then - log(LOGLEVEL_INFO, 'Preprocess', name) + log(LOGLEVEL_INFO, 'Preprocess ' .. name) msg = plugin.pre_process(msg) end end From 0d4174f8e1753f244b15a3091bb85a7245c7f84d Mon Sep 17 00:00:00 2001 From: CapacitorSet Date: Tue, 22 Aug 2017 23:22:37 +0200 Subject: [PATCH 20/42] Add basic test suite for antiflood --- plugins/anti-flood.lua | 6 +++++ test/test.lua | 50 +++++++++++++++++++++++++++++++++++++++++- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/plugins/anti-flood.lua b/plugins/anti-flood.lua index 71c0564..6da77b6 100644 --- a/plugins/anti-flood.lua +++ b/plugins/anti-flood.lua @@ -209,6 +209,12 @@ local function pre_process (msg) return msg end +-- Public function, used in test suite +function is_antiflood_enabled(msg) + -- ugly cast to boolean + return not not redis:get('anti-flood:enabled:'..msg.to.id) +end + return { description = 'Plugin to kick flooders from group.', usage = { diff --git a/test/test.lua b/test/test.lua index b711e20..b40a8ff 100644 --- a/test/test.lua +++ b/test/test.lua @@ -1,3 +1,4 @@ +SUDO_USER_ID = 12345 describe("Bot", function() it("initializes", function() _G.postpone = function() end @@ -9,7 +10,8 @@ describe("Bot", function() data = "data/moderation.json" }, sudo_users = { - 0 + 0, + SUDO_USER_ID } } require("bot/bot") @@ -62,6 +64,52 @@ describe("Bot", function() end) end) +describe("Antiflood", function() + it("Can be enabled", function() + _G.send_msg = spy.new(function(destination, text) + print(text) + end) + _config.enabled_plugins = {"anti-flood"} + local plugins_loaded_correctly = load_plugins() + assert.is_true(plugins_loaded_correctly) + local msg = { + date = 1/0, -- a date infinitely in the future + flags = 257, + from = { + access_hash = -1.11111111111111+18, + bot = false, + first_name = "Admin", + flags = 196609, + id = "$010000000be6840443e616f4ce4780c0", + peer_id = SUDO_USER_ID, + peer_type = "user", + phone = "11111111111", + print_name = "Admin", + username = "Admin" + }, + id = "020000006466ef0024923a00000000000000000000000000", + out = false, + service = false, + temp_id = 2, + text = "!antiflood enable", + to = { + flags = 65537, + id = "$020000006466ef000000000000000000", + members_num = 100, + peer_id = 15689316, + peer_type = "chat", + print_name = "Group name here", + title = "Group name here" + }, + unread = true + } + local was_message_received = on_msg_receive(msg) + assert.is_true(was_message_received) + assert.spy(_G.send_msg).was.called() + assert.is_true(is_antiflood_enabled(msg)) + end) +end) + -- Typical message: -- { -- date = 1503346812, From 77e18de9aaafdd41d9dcf0f1634f7fee2edef7c8 Mon Sep 17 00:00:00 2001 From: CapacitorSet Date: Tue, 22 Aug 2017 23:28:38 +0200 Subject: [PATCH 21/42] Remove useless messages in tests --- bot/bot.lua | 2 +- libs/redis.lua | 1 + test/test.lua | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/bot/bot.lua b/bot/bot.lua index cd8a2dc..122a6bc 100644 --- a/bot/bot.lua +++ b/bot/bot.lua @@ -202,7 +202,7 @@ function match_plugin(plugin, plugin_name, msg) for k, pattern in pairs(plugin.patterns) do local matches = match_pattern(pattern, msg.text) if matches then - print("msg matches: ", pattern) + log(LOGLEVEL_INFO, "msg matches: ", pattern) if not is_sudo(msg) then if is_plugin_disabled_on_chat(plugin_name, receiver) then diff --git a/libs/redis.lua b/libs/redis.lua index eca0185..8f69926 100644 --- a/libs/redis.lua +++ b/libs/redis.lua @@ -27,6 +27,7 @@ end) if not ok then local fake_func = function() + if IS_TEST_ENVIRONMENT then return end print('\27[31mCan\'t connect with Redis, install/configure it!\27[39m') end fake_func() diff --git a/test/test.lua b/test/test.lua index b40a8ff..43286cd 100644 --- a/test/test.lua +++ b/test/test.lua @@ -1,4 +1,5 @@ SUDO_USER_ID = 12345 +_G.IS_TEST_ENVIRONMENT = true describe("Bot", function() it("initializes", function() _G.postpone = function() end @@ -67,7 +68,6 @@ end) describe("Antiflood", function() it("Can be enabled", function() _G.send_msg = spy.new(function(destination, text) - print(text) end) _config.enabled_plugins = {"anti-flood"} local plugins_loaded_correctly = load_plugins() From 9a8e2cca7a58db565641725e595b2f974a14ecfb Mon Sep 17 00:00:00 2001 From: CapacitorSet Date: Tue, 22 Aug 2017 23:53:53 +0200 Subject: [PATCH 22/42] Reduce duplication in tests --- test/test.lua | 153 ++++++++++++++++++++++++-------------------------- 1 file changed, 72 insertions(+), 81 deletions(-) diff --git a/test/test.lua b/test/test.lua index 43286cd..51e71b4 100644 --- a/test/test.lua +++ b/test/test.lua @@ -1,19 +1,79 @@ SUDO_USER_ID = 12345 _G.IS_TEST_ENVIRONMENT = true +_G.postpone = function() end + +-- Return a fake message. +-- isRoot: whether it comes from an admin +function test_craft_message(text, isRoot) + local _peer_id + local _username + if isRoot then + _peer_id = SUDO_USER_ID + _username = "root" + else + _peer_id = 100 + _username = "johndoe" + end + return { + date = 1/0, -- a date infinitely in the future + flags = 257, + from = { + access_hash = -1.11111111111111+18, + bot = false, + first_name = "John", + flags = 196609, + id = "$010000000be6840443e616f4ce4780c0", + peer_id = _peer_id, + peer_type = "user", + phone = "11111111111", + print_name = "John Doe", + username = _username + }, + id = "020000006466ef0024923a00000000000000000000000000", + out = false, + service = false, + temp_id = 2, + text = text, + to = { + flags = 65537, + id = "$020000006466ef000000000000000000", + members_num = 100, + peer_id = 15689316, + peer_type = "chat", + print_name = "Group name here", + title = "Group name here" + }, + unread = true + } +end + +-- Make the bot see a new message. +-- isRoot: whether the message comes from an admin +-- doNotAcknowledge: whether we must check that the message was not dropped, eg. during preprocessing or because it is invalid +function test_receive_message(text, isRoot, doNotAcknowledge) + local msg = test_craft_message(text, isRoot) + local was_message_received = on_msg_receive(msg) + if not doNotAcknowledge then + assert.is_true(was_message_received) + end + return msg -- can be useful later +end + +-- Load the given list of plugins. +function test_load_plugins(plugins) + _G._config.enabled_plugins = plugins + local plugins_loaded_correctly = load_plugins() +end + describe("Bot", function() it("initializes", function() - _G.postpone = function() end _G._config = { disabled_channels = {}, - enabled_plugins = { - }, + enabled_plugins = {}, moderation = { data = "data/moderation.json" }, - sudo_users = { - 0, - SUDO_USER_ID - } + sudo_users = {0, SUDO_USER_ID} } require("bot/bot") _G.loglevel = LOGLEVEL_WARN @@ -21,91 +81,22 @@ describe("Bot", function() assert.is_true(initialized_correctly) end) it("loads ping", function() - _config.enabled_plugins = {"ping"} - local plugins_loaded_correctly = load_plugins() - assert.is_true(plugins_loaded_correctly) + test_load_plugins({"ping"}) end) it("responds to pings", function() -- Create a stub in advance _G.send_msg = spy.new(function(destination, text) end) - local was_message_received = on_msg_receive({ - date = 1/0, -- a date infinitely in the future - flags = 257, - from = { - access_hash = -1.11111111111111+18, - bot = false, - first_name = "TARS", - flags = 196609, - id = "$010000000be6840443e616f4ce4780c0", - peer_id = 75818507, - peer_type = "user", - phone = "11111111111", - print_name = "TARS", - username = "rTARS" - }, - id = "020000006466ef0024923a00000000000000000000000000", - out = false, - service = false, - temp_id = 2, - text = "!ping", - to = { - flags = 65537, - id = "$020000006466ef000000000000000000", - members_num = 100, - peer_id = 15689316, - peer_type = "chat", - print_name = "Group name here", - title = "Group name here" - }, - unread = true - }) - assert.is_true(was_message_received) + test_load_plugins({"ping"}) + test_receive_message("!ping") assert.spy(_G.send_msg).was.called() end) end) describe("Antiflood", function() it("Can be enabled", function() - _G.send_msg = spy.new(function(destination, text) - end) - _config.enabled_plugins = {"anti-flood"} - local plugins_loaded_correctly = load_plugins() - assert.is_true(plugins_loaded_correctly) - local msg = { - date = 1/0, -- a date infinitely in the future - flags = 257, - from = { - access_hash = -1.11111111111111+18, - bot = false, - first_name = "Admin", - flags = 196609, - id = "$010000000be6840443e616f4ce4780c0", - peer_id = SUDO_USER_ID, - peer_type = "user", - phone = "11111111111", - print_name = "Admin", - username = "Admin" - }, - id = "020000006466ef0024923a00000000000000000000000000", - out = false, - service = false, - temp_id = 2, - text = "!antiflood enable", - to = { - flags = 65537, - id = "$020000006466ef000000000000000000", - members_num = 100, - peer_id = 15689316, - peer_type = "chat", - print_name = "Group name here", - title = "Group name here" - }, - unread = true - } - local was_message_received = on_msg_receive(msg) - assert.is_true(was_message_received) - assert.spy(_G.send_msg).was.called() + test_load_plugins({"anti-flood", "ping"}) + local msg = test_receive_message("!antiflood enable", true) assert.is_true(is_antiflood_enabled(msg)) end) end) From ec72b13dd843b25782141e44e3db31199d38caf6 Mon Sep 17 00:00:00 2001 From: CapacitorSet Date: Wed, 23 Aug 2017 00:41:45 +0200 Subject: [PATCH 23/42] Use correct log level in anti-flood --- plugins/anti-flood.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/anti-flood.lua b/plugins/anti-flood.lua index 6da77b6..9eb251f 100644 --- a/plugins/anti-flood.lua +++ b/plugins/anti-flood.lua @@ -134,7 +134,7 @@ local function pre_process (msg) local enabled = redis:get(hash_enable) if enabled then - print('anti-flood enabled') + log(LOGLEVEL_INFO, 'anti-flood enabled') -- Check flood if msg.from.type == 'user' then local hash_maxmsg = 'anti-flood:maxmsg:'..msg.to.id From c2d30db470e1d56b33f53d07f1081b67f24a80bb Mon Sep 17 00:00:00 2001 From: CapacitorSet Date: Wed, 23 Aug 2017 00:42:25 +0200 Subject: [PATCH 24/42] Make tests require Redis --- libs/redis.lua | 15 ++++++++++++--- test/README.md | 2 ++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/libs/redis.lua b/libs/redis.lua index 8f69926..1769e70 100644 --- a/libs/redis.lua +++ b/libs/redis.lua @@ -5,10 +5,15 @@ local params = { host = '127.0.0.1', port = 6379, db = 0 - --- for multiple instances on the same machine - --- change db = 0 with a number from 0 to 15 + -- For multiple instances on the same machine + -- change db = 0 with a number from 0 to 15. + -- Note that db #15 is used for tests. } +if IS_TEST_ENVIRONMENT then + params.db = 15 +end + -- Overwrite HGETALL Redis.commands.hgetall = Redis.command('hgetall', { response = function(reply, command, ...) @@ -26,8 +31,12 @@ local ok = pcall(function() end) if not ok then + if IS_TEST_ENVIRONMENT then + print("Couldn't connect to Redis, can't run tests without it.") + os.exit() + end + local fake_func = function() - if IS_TEST_ENVIRONMENT then return end print('\27[31mCan\'t connect with Redis, install/configure it!\27[39m') end fake_func() diff --git a/test/README.md b/test/README.md index 32f37f3..3d0d431 100644 --- a/test/README.md +++ b/test/README.md @@ -1,3 +1,5 @@ Requires Busted: `luarocks install busted` +Requires a working Redis server (FakeRedis isn't supported). + Run with `busted test/test.lua` from the project folder. \ No newline at end of file From 3770a0996ec04f58140cb552495038b05001172f Mon Sep 17 00:00:00 2001 From: CapacitorSet Date: Wed, 23 Aug 2017 01:07:49 +0200 Subject: [PATCH 25/42] Fix 'warned' bug in anti-flood.lua --- plugins/anti-flood.lua | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/plugins/anti-flood.lua b/plugins/anti-flood.lua index 9eb251f..f080d68 100644 --- a/plugins/anti-flood.lua +++ b/plugins/anti-flood.lua @@ -150,7 +150,7 @@ local function pre_process (msg) local msgs = tonumber(redis:get(hash) or 0) local warned = redis:get(hash_warned) or false - if msgs > NUM_MSG_MAX and not warned then + if msgs > NUM_MSG_MAX then local receiver = get_receiver(msg) local user = msg.from.id local text = str2emoji(":exclamation:")..' User ' @@ -188,13 +188,17 @@ local function pre_process (msg) end end - if msg.from.username ~= nil then - snoop_msg('User @'..msg.from.username..' ['..msg.from.id..'] has been found flooding.\nGroup: '..msg.to.print_name..' ['..msg.to.id..']\nText: '..real_text) - else - snoop_msg('User '..string.gsub(msg.from.print_name, '_', ' ')..' ['..msg.from.id..'] has been found flooding.\nGroup: '..msg.to.print_name..' ['..msg.to.id..']\nText: '..real_text) + -- Cooldown: avoid sending more than one message in TIME_CHECK seconds + if not warned then + if msg.from.username ~= nil then + snoop_msg('User @'..msg.from.username..' ['..msg.from.id..'] has been found flooding.\nGroup: '..msg.to.print_name..' ['..msg.to.id..']\nText: '..real_text) + else + snoop_msg('User '..string.gsub(msg.from.print_name, '_', ' ')..' ['..msg.from.id..'] has been found flooding.\nGroup: '..msg.to.print_name..' ['..msg.to.id..']\nText: '..real_text) + end + send_msg(receiver, text, ok_cb, nil) end - send_msg(receiver, text, ok_cb, nil) - redis:set(hash_warned, 1) + redis:setex(hash_warned, TIME_CHECK, 1) + if not is_chan_msg(msg) then kick_user(user, chat) else From 06e0216c79cd4f085567e7014790ceda8f6e7801 Mon Sep 17 00:00:00 2001 From: CapacitorSet Date: Wed, 23 Aug 2017 01:33:09 +0200 Subject: [PATCH 26/42] Add tests for anti-flood.lua --- test/test.lua | 64 +++++++++++++++++++++------------------------------ 1 file changed, 26 insertions(+), 38 deletions(-) diff --git a/test/test.lua b/test/test.lua index 51e71b4..9e2ec5a 100644 --- a/test/test.lua +++ b/test/test.lua @@ -84,9 +84,8 @@ describe("Bot", function() test_load_plugins({"ping"}) end) it("responds to pings", function() - -- Create a stub in advance _G.send_msg = spy.new(function(destination, text) end) - + test_load_plugins({"ping"}) test_receive_message("!ping") assert.spy(_G.send_msg).was.called() @@ -94,42 +93,31 @@ describe("Bot", function() end) describe("Antiflood", function() - it("Can be enabled", function() - test_load_plugins({"anti-flood", "ping"}) + local limit = 5 + it("Can be enabled and configured", function() + test_load_plugins({"anti-flood", "echo"}) local msg = test_receive_message("!antiflood enable", true) + local msg = test_receive_message("!antiflood maxmsg " .. limit, true) assert.is_true(is_antiflood_enabled(msg)) end) -end) - --- Typical message: --- { --- date = 1503346812, --- flags = 257, --- from = { --- access_hash = -1.11111111111111+18, --- bot = false, --- first_name = "User", --- flags = 196609, --- id = "$010000000be6840443e616f4ce4780c0", --- peer_id = 75818507, --- peer_type = "user", --- phone = "11111111111", --- print_name = "User", --- username = "username" --- }, --- id = "020000006466ef0024923a00000000000000000000000000", --- out = false, --- service = false, --- temp_id = 2, --- text = "test", --- to = { --- flags = 65537, --- id = "$020000006466ef000000000000000000", --- members_num = 100, --- peer_id = 15689316, --- peer_type = "chat", --- print_name = "Group name here", --- title = "Group name here" --- }, --- unread = true --- } \ No newline at end of file + it("Blocks floods", function() + local num_replies = 0 + local kicked = false + _G.send_msg = function(destination, text) + if text == "spam" then + num_replies = num_replies + 1 + end + end + _G.chat_del_user = function(chat, user, cb) + kicked = true + cb(nil, true) + end + for i = 1, 100 do + test_receive_message("!echo spam", false, true) + if kicked then break end + end + assert.is_true(kicked) + assert.are.equal(limit, num_replies) + --assert.spy(_G.send_msg).was.called(5) + end) +end) \ No newline at end of file From 8e5316fc22195dff1c35839950e9054111b0bfda Mon Sep 17 00:00:00 2001 From: CapacitorSet Date: Wed, 23 Aug 2017 01:40:07 +0200 Subject: [PATCH 27/42] Fix off-by-one error in anti-flood.lua --- plugins/anti-flood.lua | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/anti-flood.lua b/plugins/anti-flood.lua index f080d68..3556838 100644 --- a/plugins/anti-flood.lua +++ b/plugins/anti-flood.lua @@ -150,6 +150,8 @@ local function pre_process (msg) local msgs = tonumber(redis:get(hash) or 0) local warned = redis:get(hash_warned) or false + msgs = msgs + 1 + redis:setex(hash, TIME_CHECK, msgs) if msgs > NUM_MSG_MAX then local receiver = get_receiver(msg) local user = msg.from.id @@ -207,7 +209,6 @@ local function pre_process (msg) msg = nil end end - redis:setex(hash, TIME_CHECK, msgs+1) end end return msg From 2d390c2d8e4032de7b78167e2479e5060ae7e4a0 Mon Sep 17 00:00:00 2001 From: CapacitorSet Date: Wed, 23 Aug 2017 01:59:26 +0200 Subject: [PATCH 28/42] Improve error message for plugins with syntax errors --- bot/bot.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bot/bot.lua b/bot/bot.lua index 122a6bc..803709b 100644 --- a/bot/bot.lua +++ b/bot/bot.lua @@ -202,7 +202,7 @@ function match_plugin(plugin, plugin_name, msg) for k, pattern in pairs(plugin.patterns) do local matches = match_pattern(pattern, msg.text) if matches then - log(LOGLEVEL_INFO, "msg matches: ", pattern) + log(LOGLEVEL_INFO, "msg matches: " .. pattern) if not is_sudo(msg) then if is_plugin_disabled_on_chat(plugin_name, receiver) then @@ -346,7 +346,7 @@ function load_plugins() log(LOGLEVEL_INFO, "Loading plugin " .. v) local ok, err = pcall(function() - local t = loadfile("plugins/"..v..'.lua')() + local t = assert(loadfile("plugins/"..v..'.lua'))() plugins[v] = t end) From 880ed633b6e35db871055246204e62b013f0c93f Mon Sep 17 00:00:00 2001 From: CapacitorSet Date: Wed, 23 Aug 2017 02:00:28 +0200 Subject: [PATCH 29/42] Test that anti-flood ignores root --- test/test.lua | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/test/test.lua b/test/test.lua index 9e2ec5a..2f98236 100644 --- a/test/test.lua +++ b/test/test.lua @@ -63,6 +63,7 @@ end function test_load_plugins(plugins) _G._config.enabled_plugins = plugins local plugins_loaded_correctly = load_plugins() + assert.is_true(plugins_loaded_correctly) end describe("Bot", function() @@ -85,7 +86,7 @@ describe("Bot", function() end) it("responds to pings", function() _G.send_msg = spy.new(function(destination, text) end) - + test_load_plugins({"ping"}) test_receive_message("!ping") assert.spy(_G.send_msg).was.called() @@ -118,6 +119,25 @@ describe("Antiflood", function() end assert.is_true(kicked) assert.are.equal(limit, num_replies) - --assert.spy(_G.send_msg).was.called(5) + end) + it("Doesn't block floods from root", function() + local num_replies = 0 + local kicked = false + _G.send_msg = function(destination, text) + if text == "spam" then + num_replies = num_replies + 1 + end + end + _G.chat_del_user = function(chat, user, cb) + kicked = true + cb(nil, true) + end + for i = 1, 100 do + -- Note that in this case we do ask for acknowledgement (doNotAcknowledge is false). + test_receive_message("!echo spam", true, false) + if kicked then break end + end + assert.is_false(kicked) + assert.are.equal(100, num_replies) end) end) \ No newline at end of file From f0b7023180d1b768e8ee1e5e8f1edc24ce92e997 Mon Sep 17 00:00:00 2001 From: CapacitorSet Date: Wed, 23 Aug 2017 02:00:42 +0200 Subject: [PATCH 30/42] Fix anti-flood not ignoring root --- plugins/anti-flood.lua | 150 ++++++++++++++++++++--------------------- 1 file changed, 74 insertions(+), 76 deletions(-) diff --git a/plugins/anti-flood.lua b/plugins/anti-flood.lua index 3556838..355e39f 100644 --- a/plugins/anti-flood.lua +++ b/plugins/anti-flood.lua @@ -126,92 +126,90 @@ end local function pre_process (msg) -- Ignore service msg if msg.service then - print('Service message') + log(LOGLEVEL_INFO, 'Service message') return msg end local hash_enable = 'anti-flood:enabled:'..msg.to.id local enabled = redis:get(hash_enable) - if enabled then - log(LOGLEVEL_INFO, 'anti-flood enabled') - -- Check flood - if msg.from.type == 'user' then - local hash_maxmsg = 'anti-flood:maxmsg:'..msg.to.id - local hash_timeframe = 'anti-flood:timeframe:'..msg.to.id + if not enabled then return msg end + log(LOGLEVEL_INFO, 'anti-flood enabled') + + -- Check flood + if msg.from.type ~= 'user' then return msg end + local hash_maxmsg = 'anti-flood:maxmsg:'..msg.to.id + local hash_timeframe = 'anti-flood:timeframe:'..msg.to.id + + -- Max number of messages per TIME_CHECK seconds + local NUM_MSG_MAX = tonumber(redis:get(hash_maxmsg) or 5) + local TIME_CHECK = tonumber(redis:get(hash_timeframe) or 5) + + -- Increase the number of messages from the user on the chat + local hash = 'anti-flood:'..msg.from.id..':'..msg.to.id..':msg-num' + local hash_warned = 'anti-flood:'..msg.from.id..':'..msg.to.id..':msg-num' + local msgs = tonumber(redis:get(hash) or 0) + local warned = redis:get(hash_warned) or false + + msgs = msgs + 1 + redis:setex(hash, TIME_CHECK, msgs) + if msgs <= NUM_MSG_MAX then return msg end + + local receiver = get_receiver(msg) + local user = msg.from.id + local text = str2emoji(":exclamation:")..' User ' + if msg.from.username ~= nil then + text = text..' @'..msg.from.username..' ['..user..'] is flooding' + else + text = text..string.gsub(msg.from.print_name, '_', ' ')..' ['..user..'] is flooding' + end + local chat = msg.to.id + local hash_exception = 'anti-flood:exception:'..msg.to.id..':'..msg.from.id - -- Max number of messages per TIME_CHECK seconds - local NUM_MSG_MAX = tonumber(redis:get(hash_maxmsg) or 5) - local TIME_CHECK = tonumber(redis:get(hash_timeframe) or 5) + if not is_chat_msg(msg) then + log(LOGLEVEL_INFO, "Flood in not a chat group!") + return msg + elseif user == tostring(our_id) then + log(LOGLEVEL_INFO, 'I won\'t kick myself') + return msg + elseif is_momod(msg) then + log(LOGLEVEL_INFO, 'I won\'t kick a mod/admin/sudo!') + return msg + elseif redis:get(hash_exception) then + log(LOGLEVEL_INFO, 'User is exempt from antiflood checks!') + return msg + end - -- Increase the number of messages from the user on the chat - local hash = 'anti-flood:'..msg.from.id..':'..msg.to.id..':msg-num' - local hash_warned = 'anti-flood:'..msg.from.id..':'..msg.to.id..':msg-num' - local msgs = tonumber(redis:get(hash) or 0) - local warned = redis:get(hash_warned) or false - - msgs = msgs + 1 - redis:setex(hash, TIME_CHECK, msgs) - if msgs > NUM_MSG_MAX then - local receiver = get_receiver(msg) - local user = msg.from.id - local text = str2emoji(":exclamation:")..' User ' - if msg.from.username ~= nil then - text = text..' @'..msg.from.username..' ['..user..'] is flooding' - else - text = text..string.gsub(msg.from.print_name, '_', ' ')..' ['..user..'] is flooding' - end - local chat = msg.to.id - local hash_exception = 'anti-flood:exception:'..msg.to.id..':'..msg.from.id - - if not is_chat_msg(msg) then - print("Flood in not a chat group!") - msg = nil - elseif user == tostring(our_id) then - print('I won\'t kick myself') - msg = nil - elseif is_momod(msg) then - print('I won\'t kick a mod/admin/sudo!') - msg = nil - elseif redis:get(hash_exception) then - print('User is exempt from antiflood checks!') - msg = nil - else - local real_text - if msg.media ~= nil then - if msg.media.caption ~= nil then - real_text = msg.media.caption - else - real_text = "[media with no caption]" - end - else - if msg.text ~= nil then - real_text = msg.text - end - end - - -- Cooldown: avoid sending more than one message in TIME_CHECK seconds - if not warned then - if msg.from.username ~= nil then - snoop_msg('User @'..msg.from.username..' ['..msg.from.id..'] has been found flooding.\nGroup: '..msg.to.print_name..' ['..msg.to.id..']\nText: '..real_text) - else - snoop_msg('User '..string.gsub(msg.from.print_name, '_', ' ')..' ['..msg.from.id..'] has been found flooding.\nGroup: '..msg.to.print_name..' ['..msg.to.id..']\nText: '..real_text) - end - send_msg(receiver, text, ok_cb, nil) - end - redis:setex(hash_warned, TIME_CHECK, 1) - - if not is_chan_msg(msg) then - kick_user(user, chat) - else - kick_chan_user(user, chat) - end - msg = nil - end - end + local real_text + if msg.media ~= nil then + if msg.media.caption ~= nil then + real_text = msg.media.caption + else + real_text = "[media with no caption]" + end + else + if msg.text ~= nil then + real_text = msg.text + end + end + + -- Cooldown: avoid sending more than one message in TIME_CHECK seconds + if not warned then + if msg.from.username ~= nil then + snoop_msg('User @'..msg.from.username..' ['..msg.from.id..'] has been found flooding.\nGroup: '..msg.to.print_name..' ['..msg.to.id..']\nText: '..real_text) + else + snoop_msg('User '..string.gsub(msg.from.print_name, '_', ' ')..' ['..msg.from.id..'] has been found flooding.\nGroup: '..msg.to.print_name..' ['..msg.to.id..']\nText: '..real_text) end + send_msg(receiver, text, ok_cb, nil) + end + redis:setex(hash_warned, TIME_CHECK, 1) + + if not is_chan_msg(msg) then + kick_user(user, chat) + else + kick_chan_user(user, chat) end - return msg + return nil end -- Public function, used in test suite From 3e3bfbd8304b882555a132e9129dab6da59adaf9 Mon Sep 17 00:00:00 2001 From: CapacitorSet Date: Wed, 23 Aug 2017 02:20:37 +0200 Subject: [PATCH 31/42] Test antiflood addexcept (currently failing) --- test/test.lua | 73 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 58 insertions(+), 15 deletions(-) diff --git a/test/test.lua b/test/test.lua index 2f98236..6d770d5 100644 --- a/test/test.lua +++ b/test/test.lua @@ -3,16 +3,16 @@ _G.IS_TEST_ENVIRONMENT = true _G.postpone = function() end -- Return a fake message. --- isRoot: whether it comes from an admin -function test_craft_message(text, isRoot) +-- is_root: whether it comes from an admin +function test_craft_message(text, is_root, custom_id, custom_username) local _peer_id local _username - if isRoot then + if is_root then _peer_id = SUDO_USER_ID _username = "root" else - _peer_id = 100 - _username = "johndoe" + _peer_id = custom_id or 100 + _username = custom_username or "johndoe" end return { date = 1/0, -- a date infinitely in the future @@ -20,13 +20,13 @@ function test_craft_message(text, isRoot) from = { access_hash = -1.11111111111111+18, bot = false, - first_name = "John", + first_name = _username, flags = 196609, id = "$010000000be6840443e616f4ce4780c0", peer_id = _peer_id, peer_type = "user", phone = "11111111111", - print_name = "John Doe", + print_name = _username, username = _username }, id = "020000006466ef0024923a00000000000000000000000000", @@ -48,14 +48,18 @@ function test_craft_message(text, isRoot) end -- Make the bot see a new message. --- isRoot: whether the message comes from an admin +-- is_root: whether the message comes from an admin -- doNotAcknowledge: whether we must check that the message was not dropped, eg. during preprocessing or because it is invalid -function test_receive_message(text, isRoot, doNotAcknowledge) - local msg = test_craft_message(text, isRoot) +function test_receive_message(msg, doNotAcknowledge) local was_message_received = on_msg_receive(msg) if not doNotAcknowledge then assert.is_true(was_message_received) end +end + +function test_receive_text(text, is_root, doNotAcknowledge) + local msg = test_craft_message(text, is_root) + test_receive_message(msg, doNotAcknowledge) return msg -- can be useful later end @@ -88,7 +92,7 @@ describe("Bot", function() _G.send_msg = spy.new(function(destination, text) end) test_load_plugins({"ping"}) - test_receive_message("!ping") + test_receive_text("!ping") assert.spy(_G.send_msg).was.called() end) end) @@ -97,8 +101,8 @@ describe("Antiflood", function() local limit = 5 it("Can be enabled and configured", function() test_load_plugins({"anti-flood", "echo"}) - local msg = test_receive_message("!antiflood enable", true) - local msg = test_receive_message("!antiflood maxmsg " .. limit, true) + local msg = test_receive_text("!antiflood enable", true) + local msg = test_receive_text("!antiflood maxmsg " .. limit, true) assert.is_true(is_antiflood_enabled(msg)) end) it("Blocks floods", function() @@ -114,7 +118,7 @@ describe("Antiflood", function() cb(nil, true) end for i = 1, 100 do - test_receive_message("!echo spam", false, true) + test_receive_text("!echo spam", false, true) if kicked then break end end assert.is_true(kicked) @@ -134,10 +138,49 @@ describe("Antiflood", function() end for i = 1, 100 do -- Note that in this case we do ask for acknowledgement (doNotAcknowledge is false). - test_receive_message("!echo spam", true, false) + test_receive_text("!echo spam", true, false) if kicked then break end end assert.is_false(kicked) assert.are.equal(100, num_replies) end) + it("Honours exceptions", function() + test_receive_text("!antiflood addexcept 1234", true) + + local ham_replies = 0 + local spam_replies = 0 + _G.send_msg = function(destination, text) + if text == "I'm ham!" then + ham_replies = ham_replies + 1 + elseif text == "I'm spam!" then + spam_replies = spam_replies + 1 + end + end + local ham_kicked = false + local spam_kicked = false + _G.chat_del_user = function(chat, user, cb) + if user == "user#id1234" then + ham_kicked = true + elseif user == "user#id4321" then + spam_kicked = true + else + error("Kicking unknown user: " .. user) + end + cb(nil, true) + end + + -- Note: we'll use custom IDs, because the default user has supposedly been kicked for flooding + local ham_msg = test_craft_message("!echo I'm ham!", false, 1234, "hamsender") + local spam_msg = test_craft_message("!echo I'm spam!", false, 4321, "spamsender") + + for i = 1, 100 do + if not spam_kicked then test_receive_message(spam_msg, true) end + if not ham_kicked then test_receive_message(ham_msg) end -- Ask for acknowledgment + end + + assert.is_false(ham_kicked) + assert.is_true(spam_kicked) + assert.are.equal(100, ham_replies) + assert.are.equal(limit, spam_replies) + end) end) \ No newline at end of file From cdc1ddf5a802998eb9fa4369ae94c5a6cffbd4a7 Mon Sep 17 00:00:00 2001 From: CapacitorSet Date: Thu, 24 Aug 2017 01:16:45 +0200 Subject: [PATCH 32/42] Fix tests due to id/peer_id swapping --- test/test.lua | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/test.lua b/test/test.lua index 6d770d5..a28c80e 100644 --- a/test/test.lua +++ b/test/test.lua @@ -169,11 +169,12 @@ describe("Antiflood", function() cb(nil, true) end - -- Note: we'll use custom IDs, because the default user has supposedly been kicked for flooding - local ham_msg = test_craft_message("!echo I'm ham!", false, 1234, "hamsender") - local spam_msg = test_craft_message("!echo I'm spam!", false, 4321, "spamsender") - for i = 1, 100 do + -- Note: we'll use custom IDs, because the default user has supposedly been kicked for flooding + -- Also, the variables must be re-initialized every time, because s-uzzbot swaps id and peer_id + local ham_msg = test_craft_message("!echo I'm ham!", false, 1234, "hamsender") + local spam_msg = test_craft_message("!echo I'm spam!", false, 4321, "spamsender") + if not spam_kicked then test_receive_message(spam_msg, true) end if not ham_kicked then test_receive_message(ham_msg) end -- Ask for acknowledgment end From 0db1e32f700664afcb0320d976f502a9bf5a1f25 Mon Sep 17 00:00:00 2001 From: giuseppeM99 Date: Sat, 26 Aug 2017 13:00:54 +0200 Subject: [PATCH 33/42] Update --- .gitignore | 1 + Madeline_lua_shim | 2 +- bot/utils.lua | 4 ++++ madeline.php | 24 +++++++++++++++--------- plugins/sudo.lua | 13 ++++++++++++- 5 files changed, 33 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 3661006..89411f1 100644 --- a/.gitignore +++ b/.gitignore @@ -44,6 +44,7 @@ luac.out composer.lock *.madeline +*.madeline.lock data/config.lua # ========================= diff --git a/Madeline_lua_shim b/Madeline_lua_shim index d639934..fb1d501 160000 --- a/Madeline_lua_shim +++ b/Madeline_lua_shim @@ -1 +1 @@ -Subproject commit d639934feb2fa72ff0a4971225859b0f2d09277c +Subproject commit fb1d5019c9bde06ccab51589659d691facf351ee diff --git a/bot/utils.lua b/bot/utils.lua index 7f64272..6f80907 100644 --- a/bot/utils.lua +++ b/bot/utils.lua @@ -589,6 +589,10 @@ function send_large_msg_callback(cb_extra, success, result) end local text_len + if type(text) == "number" then + text = tostring(text) + end + if type(text) ~= "boolean" then text_len = string.len(text) or 0 else diff --git a/madeline.php b/madeline.php index 1333bd2..11fe44c 100644 --- a/madeline.php +++ b/madeline.php @@ -14,7 +14,6 @@ //See https://github.com/danog/MadelineProto/blob/master/lua/madeline.php require 'Madeline_lua_shim/vendor/autoload.php'; -$settings = ['app_info' => ['api_id' => 6, 'api_hash' => 'eb06d4abfb49dc3eeb1aeb98ae0f581e'], 'logger' => ['loglevel' => \danog\MadelineProto\Logger::ERROR]]; $Lua = false; try { @@ -23,18 +22,23 @@ die($e->getMessage().PHP_EOL); } -$Lua->MadelineProto->lua = true; -foreach ($Lua->MadelineProto->get_methods_namespaced() as $method => $namespace) { - $Lua->MadelineProto->{$namespace}->lua = true; +function ser() +{ + global $Lua; + $Lua->MadelineProto->serialize('bot.madeline'); } -$Lua->madeline_update_callback(['_' => 'init']); +$Lua->registerCallback('serialize', 'ser'); + +if (!file_exists('download')) { + mkdir('download'); +} +$Lua->madeline_update_callback(['_' => 'init']); $offset = 0; +$lastSer = time(); while (true) { - $updates = $Lua->MadelineProto->API->get_updates(['offset' => $offset, 'limit' => 50, 'timeout' => 0]); - foreach ($updates as $update) { $offset = $update['update_id'] + 1; $Lua->madeline_update_callback($update['update']); @@ -42,6 +46,8 @@ } $Lua->doCrons(); - \danog\MadelineProto\Serialization::serialize('bot.madeline', $Lua->MadelineProto); - + if (time()-60 >= $lastSer) { + ser(); + $lastSer = time(); + } } diff --git a/plugins/sudo.lua b/plugins/sudo.lua index c4fd649..986b3e3 100644 --- a/plugins/sudo.lua +++ b/plugins/sudo.lua @@ -1,3 +1,7 @@ +local function reply(cb_extra, success, result) + send_large_msg(cb_extra, serpent.block(result, {comment=false})) +end + function run_sh(msg) name = get_name(msg) text = '' @@ -90,12 +94,19 @@ function run(msg, matches) return "Bot reloaded" end end + + if matches[1] == "debug" then + if msg.reply_id then + get_message(msg.reply_id, reply, receiver) + end + return serpent.block(msg, {comment = false}) + end end return { description = "shows cpuinfo", usage = "!cpu", hide = true, - patterns = {"^!cpu", "^!sh", "^Get dialogs$", "^!(reload) (config)$", "^!(reload) (bot)$"}, + patterns = {"^!cpu", "^!sh", "^Get dialogs$", "^!(reload) (config)$", "^!(reload) (bot)$", "^!(debug)$"}, run = run } From a4974a3134574be9a4aa8d359bd525c8cb4333d9 Mon Sep 17 00:00:00 2001 From: giuseppeM99 Date: Sat, 26 Aug 2017 16:34:29 +0200 Subject: [PATCH 34/42] Fixes? --- Madeline_lua_shim | 2 +- bot/bot.lua | 10 ++++++---- launch.sh | 13 ++++++------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Madeline_lua_shim b/Madeline_lua_shim index fb1d501..b220f68 160000 --- a/Madeline_lua_shim +++ b/Madeline_lua_shim @@ -1 +1 @@ -Subproject commit fb1d5019c9bde06ccab51589659d691facf351ee +Subproject commit b220f68f5f6cb8f72d08bf9fb1a6a46b6f408512 diff --git a/bot/bot.lua b/bot/bot.lua index 7fab2d6..2d5191d 100644 --- a/bot/bot.lua +++ b/bot/bot.lua @@ -1,11 +1,13 @@ -package.path = package.path .. ';.luarocks/share/lua/5.2/?.lua' -..';.luarocks/share/lua/5.2/?/init.lua' -package.cpath = package.cpath .. ';.luarocks/lib/lua/5.2/?.so' +local _VERSION_NUM = _VERSION:match('(%d%.%d)$') + +package.path = package.path .. ';.luarocks/share/lua/'.._VERSION_NUM..'/?.lua' +..';.luarocks/share/lua/'.._VERSION_NUM..'/?/init.lua' +package.cpath = package.cpath .. ';.luarocks/lib/lua/'.._VERSION_NUM..'/?.so' require("./bot/utils") require("./bot/emoji") -VERSION = '0.2' +VERSION = '0.3' -- This function is called when tg receive a msg function on_msg_receive (msg) diff --git a/launch.sh b/launch.sh index be07cc9..365360f 100755 --- a/launch.sh +++ b/launch.sh @@ -14,7 +14,7 @@ update() { # Will install luarocks on THIS_DIR/.luarocks install_luarocks() { - if [! -f .luarocks/bin/luarocks ]; then + if [ ! -f .luarocks/bin/luarocks ]; then git clone https://github.com/keplerproject/luarocks.git cd luarocks git checkout tags/v2.4.2 # Current stable @@ -43,11 +43,10 @@ install_rocks() { then echo "Error. Exiting."; exit $RET; fi - git clone https://github.com/brunoos/luasec - cd luasec - ../.luarocks/bin/luarocks make - cd .. - rm -rf luasec + ./.luarocks/bin/luarocks install luasec + RET=$?; if [ $RET -ne 0 ]; + then echo "Error. Exiting."; exit $RET; + fi ./.luarocks/bin/luarocks install oauth RET=$?; if [ $RET -ne 0 ]; @@ -109,7 +108,7 @@ install_rocks() { then echo "Error. Exiting."; exit $RET; fi - ./.luarocks/bin/luarocks install htmlparser + ./.luarocks/bin/luarocks install htmlparser 0.3.2-1 RET=$?; if [ $RET -ne 0 ]; then echo "Error. Exiting."; exit $RET; fi From 555d172007a3ee33c487b7a4a7cb776f0f2f9f37 Mon Sep 17 00:00:00 2001 From: giuseppeM99 Date: Sat, 26 Aug 2017 16:59:02 +0200 Subject: [PATCH 35/42] oauth..... --- launch.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/launch.sh b/launch.sh index 365360f..70fd6d7 100755 --- a/launch.sh +++ b/launch.sh @@ -48,11 +48,10 @@ install_rocks() { then echo "Error. Exiting."; exit $RET; fi - ./.luarocks/bin/luarocks install oauth - RET=$?; if [ $RET -ne 0 ]; - then echo "Error. Exiting."; exit $RET; - fi - + git clone https://github.com/ignacio/LuaOAuth oauth + cp -a oauth .luarocks/share/lua/5.3/ + rm -rf oauth + ./.luarocks/bin/luarocks install redis-lua RET=$?; if [ $RET -ne 0 ]; then echo "Error. Exiting."; exit $RET; From e4539772e7296b942d8555edbc22173a52cf5104 Mon Sep 17 00:00:00 2001 From: giuseppeM99 Date: Sat, 26 Aug 2017 17:07:07 +0200 Subject: [PATCH 36/42] oauth... pt 2 --- launch.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/launch.sh b/launch.sh index 70fd6d7..33bc7f6 100755 --- a/launch.sh +++ b/launch.sh @@ -49,9 +49,9 @@ install_rocks() { fi git clone https://github.com/ignacio/LuaOAuth oauth - cp -a oauth .luarocks/share/lua/5.3/ + cp -a oauth/src .luarocks/share/lua/5.3/ rm -rf oauth - + ./.luarocks/bin/luarocks install redis-lua RET=$?; if [ $RET -ne 0 ]; then echo "Error. Exiting."; exit $RET; From f2e53e8c0459e2ac6d3b75957b06a494e0c810f0 Mon Sep 17 00:00:00 2001 From: giuseppeM99 Date: Sat, 26 Aug 2017 17:11:51 +0200 Subject: [PATCH 37/42] oauth.... pt3 --- launch.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launch.sh b/launch.sh index 33bc7f6..e959c0b 100755 --- a/launch.sh +++ b/launch.sh @@ -49,7 +49,7 @@ install_rocks() { fi git clone https://github.com/ignacio/LuaOAuth oauth - cp -a oauth/src .luarocks/share/lua/5.3/ + cp -a oauth/src/* .luarocks/share/lua/5.3/ rm -rf oauth ./.luarocks/bin/luarocks install redis-lua From 4de2a6be9d90cb17015f9378ff9e18aabf79b3ec Mon Sep 17 00:00:00 2001 From: giuseppeM99 Date: Sat, 26 Aug 2017 23:20:23 +0200 Subject: [PATCH 38/42] This works!!!! --- launch.sh | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/launch.sh b/launch.sh index e959c0b..58294b9 100755 --- a/launch.sh +++ b/launch.sh @@ -1,6 +1,7 @@ #!/usr/bin/env bash THIS_DIR=$(cd $(dirname $0); pwd) +LUA_DIR="$THIS_DIR/.lua" cd $THIS_DIR update() { @@ -12,6 +13,32 @@ update() { install_rocks } +install_lua() { + if [! -f $LUA_DIR]; then + mkdir $LUA_DIR + fi + curl -R -O http://www.lua.org/ftp/lua-5.3.4.tar.gz + tar zxf lua-5.3.4.tar.gz + cd lua-5.3.4 + sed -i 's/CFLAGS= -O2/CFLAGS= -fPIC -O2/g' src/Makefile + sed -i "s:/usr/local:$LUA_DIR:g" Makefile + make linux + make install + cd .. + rm -rf lua-5.3.4* +} + +install_php_lua() { + git clone https://github.com/giuseppem99/php-lua + cd php-lua + phpize + ./configure --with-lua=$LUA_DIR + make + cp modules/lua.so .. + cd .. + rm -rf php-lua +} + # Will install luarocks on THIS_DIR/.luarocks install_luarocks() { if [ ! -f .luarocks/bin/luarocks ]; then @@ -21,7 +48,7 @@ install_luarocks() { PREFIX="$THIS_DIR/.luarocks" - ./configure --prefix=$PREFIX --sysconfdir=$PREFIX/luarocks --force-config + ./configure --prefix=$PREFIX --sysconfdir=$PREFIX/luarocks --with-lua=$LUA_DIR --force-config RET=$?; if [ $RET -ne 0 ]; then echo "Error. Exiting."; exit $RET; @@ -118,6 +145,8 @@ install() { git submodule update --init --recursive cd Madeline_lua_shim && composer update cd .. + install_lua + install_php_lua install_luarocks install_rocks } @@ -165,6 +194,6 @@ else exit 1 fi - php madeline.php + php -d extension='./lua.so' madeline.php fi From 0c453efa91598fcd96fe3b569a85d48615d50e2b Mon Sep 17 00:00:00 2001 From: giuseppeM99 Date: Sun, 27 Aug 2017 22:35:13 +0200 Subject: [PATCH 39/42] Update submodule --- Madeline_lua_shim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Madeline_lua_shim b/Madeline_lua_shim index b220f68..82c0c4c 160000 --- a/Madeline_lua_shim +++ b/Madeline_lua_shim @@ -1 +1 @@ -Subproject commit b220f68f5f6cb8f72d08bf9fb1a6a46b6f408512 +Subproject commit 82c0c4cff25d868818d818addfd9e6e6e7c3630e From 2342c27de21e4a842fc95930476b7fdc79b0c5d7 Mon Sep 17 00:00:00 2001 From: giuseppeM99 Date: Sun, 27 Aug 2017 22:40:08 +0200 Subject: [PATCH 40/42] update update script --- launch.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/launch.sh b/launch.sh index 58294b9..ff19ff0 100755 --- a/launch.sh +++ b/launch.sh @@ -10,7 +10,6 @@ update() { cd Madeline_lua_shim composer update cd .. - install_rocks } install_lua() { From ff358e015d04ffb7754a9e4ae8a9d3f055f69011 Mon Sep 17 00:00:00 2001 From: giuseppeM99 Date: Thu, 31 Aug 2017 14:02:24 +0200 Subject: [PATCH 41/42] Update launch.sh --- launch.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launch.sh b/launch.sh index ff19ff0..77be257 100755 --- a/launch.sh +++ b/launch.sh @@ -13,7 +13,7 @@ update() { } install_lua() { - if [! -f $LUA_DIR]; then + if [ ! -f $LUA_DIR]; then mkdir $LUA_DIR fi curl -R -O http://www.lua.org/ftp/lua-5.3.4.tar.gz From d49463ea6d34d0373930b4a942bfa58b03125e16 Mon Sep 17 00:00:00 2001 From: giuseppeM99 Date: Thu, 7 Sep 2017 15:02:24 +0200 Subject: [PATCH 42/42] Update submodule --- Madeline_lua_shim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Madeline_lua_shim b/Madeline_lua_shim index 82c0c4c..f089f1a 160000 --- a/Madeline_lua_shim +++ b/Madeline_lua_shim @@ -1 +1 @@ -Subproject commit 82c0c4cff25d868818d818addfd9e6e6e7c3630e +Subproject commit f089f1ae45d5e0fc009342e2fb93c69d1f1dba17