2017-11-05 07:37:49 +03:00
|
|
|
|
|
|
|
--[[
|
|
|
|
|
2018-02-02 22:08:04 +03:00
|
|
|
Copyright 2017-8 Auke Kok <sofar@foo-projects.org>
|
|
|
|
Copyright 2018 rubenwardy <rw@rubenwardy.com>
|
2017-11-05 07:37:49 +03:00
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
|
|
a copy of this software and associated documentation files (the
|
|
|
|
"Software"), to deal in the Software without restriction, including
|
|
|
|
without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
distribute, sublicense, and/or sell copies of the Software, and to
|
|
|
|
permit persons to whom the Software is furnished to do so, subject
|
|
|
|
to the following conditions:
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included
|
|
|
|
in all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
|
|
|
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
|
|
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
|
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
|
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
|
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
|
|
]]--
|
|
|
|
|
2024-11-07 13:59:13 +03:00
|
|
|
local S = minetest.get_translator("filter")
|
|
|
|
|
2018-02-02 22:16:48 +03:00
|
|
|
filter = { registered_on_violations = {} }
|
2024-11-07 16:53:35 +03:00
|
|
|
local utf8 = require 'lua-utf8'
|
2018-02-02 20:07:41 +03:00
|
|
|
local words = {}
|
|
|
|
local muted = {}
|
|
|
|
local violations = {}
|
2017-11-05 07:37:49 +03:00
|
|
|
local s = minetest.get_mod_storage()
|
|
|
|
|
2018-02-02 20:07:41 +03:00
|
|
|
function filter.init()
|
|
|
|
local sw = s:get_string("words")
|
|
|
|
if sw and sw ~= "" then
|
|
|
|
words = minetest.parse_json(sw)
|
|
|
|
end
|
2017-11-05 07:37:49 +03:00
|
|
|
|
2018-02-02 20:07:41 +03:00
|
|
|
if #words == 0 then
|
|
|
|
filter.import_file(minetest.get_modpath("filter") .. "/words.txt")
|
|
|
|
end
|
2017-11-05 07:37:49 +03:00
|
|
|
end
|
|
|
|
|
2018-02-02 20:07:41 +03:00
|
|
|
function filter.import_file(filepath)
|
|
|
|
local file = io.open(filepath, "r")
|
|
|
|
if file then
|
|
|
|
for line in file:lines() do
|
|
|
|
line = line:trim()
|
|
|
|
if line ~= "" then
|
|
|
|
words[#words + 1] = line:trim()
|
|
|
|
end
|
|
|
|
end
|
2017-11-05 07:37:49 +03:00
|
|
|
return true
|
2018-02-02 20:07:41 +03:00
|
|
|
else
|
|
|
|
return false
|
2017-11-05 07:37:49 +03:00
|
|
|
end
|
2018-02-02 20:07:41 +03:00
|
|
|
end
|
2017-11-05 07:37:49 +03:00
|
|
|
|
2018-02-02 22:16:48 +03:00
|
|
|
function filter.register_on_violation(func)
|
|
|
|
table.insert(filter.registered_on_violations, func)
|
|
|
|
end
|
|
|
|
|
2018-02-02 20:07:41 +03:00
|
|
|
function filter.check_message(name, message)
|
2017-11-05 07:37:49 +03:00
|
|
|
for _, w in ipairs(words) do
|
2024-11-12 10:35:55 +03:00
|
|
|
if utf8.find(utf8.lower(message), "%f[%a]" .. w .. "%f[%A]") then
|
2018-02-02 20:07:41 +03:00
|
|
|
return false
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
|
2018-02-02 21:23:04 +03:00
|
|
|
function filter.mute(name, duration)
|
|
|
|
do
|
|
|
|
local privs = minetest.get_player_privs(name)
|
|
|
|
privs.shout = nil
|
|
|
|
minetest.set_player_privs(name, privs)
|
|
|
|
end
|
2018-02-02 22:29:45 +03:00
|
|
|
|
2024-11-07 13:59:13 +03:00
|
|
|
minetest.chat_send_player(name, S("Watch your language! You have been temporarily muted"))
|
2018-02-02 21:23:04 +03:00
|
|
|
|
|
|
|
muted[name] = true
|
|
|
|
|
|
|
|
minetest.after(duration * 60, function()
|
2023-02-14 22:22:44 +03:00
|
|
|
local privs = minetest.get_player_privs(name)
|
2018-04-26 05:37:00 +03:00
|
|
|
if privs.shout == true then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2018-02-02 21:23:04 +03:00
|
|
|
muted[name] = nil
|
2024-11-07 13:59:13 +03:00
|
|
|
minetest.chat_send_player(name, S("Chat privilege reinstated. Please do not abuse chat."))
|
2018-02-02 21:23:04 +03:00
|
|
|
|
|
|
|
privs.shout = true
|
|
|
|
minetest.set_player_privs(name, privs)
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
2018-02-02 22:08:04 +03:00
|
|
|
function filter.show_warning_formspec(name)
|
2023-02-14 22:21:31 +03:00
|
|
|
local formspec = "size[7,3]bgcolor[#080808BB;true]" .. [[
|
2018-02-02 22:08:04 +03:00
|
|
|
image[0,0;2,2;filter_warning.png]
|
2024-11-07 13:59:13 +03:00
|
|
|
label[2.3,0.5;]] .. S("Please watch your language!") .. "]"
|
2018-02-02 22:08:04 +03:00
|
|
|
|
|
|
|
if minetest.global_exists("rules") and rules.show then
|
|
|
|
formspec = formspec .. [[
|
|
|
|
button[0.5,2.1;3,1;rules;Show Rules]
|
|
|
|
button_exit[3.5,2.1;3,1;close;Okay]
|
|
|
|
]]
|
|
|
|
else
|
|
|
|
formspec = formspec .. [[
|
|
|
|
button_exit[2,2.1;3,1;close;Okay]
|
|
|
|
]]
|
|
|
|
end
|
|
|
|
minetest.show_formspec(name, "filter:warning", formspec)
|
|
|
|
end
|
|
|
|
|
2018-02-02 20:07:41 +03:00
|
|
|
function filter.on_violation(name, message)
|
|
|
|
violations[name] = (violations[name] or 0) + 1
|
|
|
|
|
|
|
|
local resolution
|
|
|
|
|
2018-02-02 22:16:48 +03:00
|
|
|
for _, cb in pairs(filter.registered_on_violations) do
|
|
|
|
if cb(name, message, violations) then
|
|
|
|
resolution = "custom"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if not resolution then
|
|
|
|
if violations[name] == 1 and minetest.get_player_by_name(name) then
|
|
|
|
resolution = "warned"
|
|
|
|
filter.show_warning_formspec(name)
|
|
|
|
elseif violations[name] <= 3 then
|
|
|
|
resolution = "muted"
|
|
|
|
filter.mute(name, 1)
|
|
|
|
else
|
|
|
|
resolution = "kicked"
|
2024-11-07 13:59:13 +03:00
|
|
|
minetest.kick_player(name, S("Please mind your language!"))
|
2018-02-02 22:16:48 +03:00
|
|
|
end
|
2018-02-02 20:07:41 +03:00
|
|
|
end
|
2017-11-05 07:37:49 +03:00
|
|
|
|
2018-02-03 00:00:09 +03:00
|
|
|
local logmsg = "VIOLATION (" .. resolution .. "): <" .. name .. "> ".. message
|
|
|
|
minetest.log("action", logmsg)
|
|
|
|
|
|
|
|
local email_to = minetest.settings:get("filter.email_to")
|
|
|
|
if email_to and minetest.global_exists("email") then
|
|
|
|
email.send_mail(name, email_to, logmsg)
|
|
|
|
end
|
2018-02-02 20:07:41 +03:00
|
|
|
end
|
2017-11-05 07:37:49 +03:00
|
|
|
|
2018-02-02 20:07:41 +03:00
|
|
|
table.insert(minetest.registered_on_chat_messages, 1, function(name, message)
|
2018-02-03 06:37:21 +03:00
|
|
|
if message:sub(1, 1) == "/" then
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2018-02-02 20:07:41 +03:00
|
|
|
local privs = minetest.get_player_privs(name)
|
|
|
|
if not privs.shout and muted[name] then
|
2024-11-07 13:59:13 +03:00
|
|
|
minetest.chat_send_player(name, S("You are temporarily muted."))
|
2018-02-02 20:07:41 +03:00
|
|
|
return true
|
2017-11-05 07:37:49 +03:00
|
|
|
end
|
|
|
|
|
2018-02-02 20:07:41 +03:00
|
|
|
if not filter.check_message(name, message) then
|
|
|
|
filter.on_violation(name, message)
|
|
|
|
return true
|
|
|
|
end
|
2017-11-05 07:37:49 +03:00
|
|
|
end)
|
|
|
|
|
2018-02-03 06:37:21 +03:00
|
|
|
|
|
|
|
local function make_checker(old_func)
|
|
|
|
return function(name, param)
|
|
|
|
if not filter.check_message(name, param) then
|
|
|
|
filter.on_violation(name, param)
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
|
|
|
return old_func(name, param)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
for name, def in pairs(minetest.registered_chatcommands) do
|
|
|
|
if def.privs and def.privs.shout then
|
|
|
|
def.func = make_checker(def.func)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local old_register_chatcommand = minetest.register_chatcommand
|
|
|
|
function minetest.register_chatcommand(name, def)
|
|
|
|
if def.privs and def.privs.shout then
|
|
|
|
def.func = make_checker(def.func)
|
|
|
|
end
|
|
|
|
return old_register_chatcommand(name, def)
|
|
|
|
end
|
|
|
|
|
|
|
|
|
2018-02-02 20:07:41 +03:00
|
|
|
local function step()
|
|
|
|
for name, v in pairs(violations) do
|
|
|
|
violations[name] = math.floor(v * 0.5)
|
|
|
|
if violations[name] < 1 then
|
|
|
|
violations[name] = nil
|
|
|
|
end
|
|
|
|
end
|
2018-02-02 22:16:48 +03:00
|
|
|
minetest.after(10*60, step)
|
2018-02-02 20:07:41 +03:00
|
|
|
end
|
2018-02-02 22:16:48 +03:00
|
|
|
minetest.after(10*60, step)
|
2018-02-02 20:07:41 +03:00
|
|
|
|
2017-11-05 07:37:49 +03:00
|
|
|
minetest.register_chatcommand("filter", {
|
2024-11-07 13:59:13 +03:00
|
|
|
params = S("filter server"),
|
|
|
|
description = S("manage swear word filter"),
|
2024-11-07 16:59:29 +03:00
|
|
|
privs = {mute = true},
|
2017-11-05 07:37:49 +03:00
|
|
|
func = function(name, param)
|
|
|
|
local cmd, val = param:match("(%w+) (.+)")
|
|
|
|
if param == "list" then
|
2024-11-07 13:59:13 +03:00
|
|
|
return true, #words .. S(" words: ") .. table.concat(words, ", ")
|
2017-11-05 07:37:49 +03:00
|
|
|
elseif cmd == "add" then
|
|
|
|
table.insert(words, val)
|
|
|
|
s:set_string("words", minetest.write_json(words))
|
2024-11-07 13:59:13 +03:00
|
|
|
return true, S("Added \"") .. val .. "\"."
|
2017-11-05 07:37:49 +03:00
|
|
|
elseif cmd == "remove" then
|
|
|
|
for i, w in ipairs(words) do
|
|
|
|
if w == val then
|
|
|
|
table.remove(words, i)
|
|
|
|
s:set_string("words", minetest.write_json(words))
|
2024-11-07 13:59:13 +03:00
|
|
|
return true, S("Removed \"") .. val .. "\"."
|
2017-11-05 07:37:49 +03:00
|
|
|
end
|
|
|
|
end
|
|
|
|
return true, "\"" .. val .. "\" not found in list."
|
|
|
|
else
|
2024-11-07 13:59:13 +03:00
|
|
|
return true, S("I know ") .. #words .. S(" words.\nUsage: /filter <add|remove|list> [<word>]")
|
2017-11-05 07:37:49 +03:00
|
|
|
end
|
|
|
|
end,
|
|
|
|
})
|
2018-02-02 20:07:41 +03:00
|
|
|
|
2018-02-02 22:08:04 +03:00
|
|
|
if minetest.global_exists("rules") and rules.show then
|
|
|
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|
|
|
if formname == "filter:warning" and fields.rules then
|
|
|
|
rules.show(player)
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
end
|
|
|
|
|
2018-02-02 22:29:45 +03:00
|
|
|
minetest.register_on_shutdown(function()
|
|
|
|
for name, _ in pairs(muted) do
|
|
|
|
local privs = minetest.get_player_privs(name)
|
|
|
|
privs.shout = true
|
|
|
|
minetest.set_player_privs(name, privs)
|
|
|
|
end
|
|
|
|
end)
|
|
|
|
|
2018-02-02 20:07:41 +03:00
|
|
|
filter.init()
|