Files first commit

master
Zughy 2020-09-15 21:21:00 +02:00
parent f90e4dad14
commit 2428dcadcb
10 changed files with 569 additions and 1 deletions

23
DOCS.md Normal file
View File

@ -0,0 +1,23 @@
# Whitelist Docs
## 1. How it works
Whitelisted players and whitelist status are both saved into the mod storage, and they're updated every time one of the core functions below succeeds. The end (?)
## 2. Functions
### 2.1 Core
> The `sender` field in here is optional. If specified, the sender will receive an output message
* `whitelist.enable(<sender>)`: enables the whitelist
* `whitelist.disable(<sender>)`: disables the whitelist
* `whitelist.add_player(p_name, <sender>)`: adds `p_name` to the whitelist
* `whitelist.remove_player(p_name, <sender>)`: removes `p_name` from the whitelist
### 2.2 Utils
* `whitelist.print_list(sender)`: prints a message to `sender` containing all the whitelisted players
* `whitelist.is_player_whitelisted(p_name)`: returns whether `p_name` is whitelisted, as a boolean
* `whitelist.is_whitelist_enabled()`: returns whether the whitelist is enabled, as a boolean
## 3. About the author
I'm Zughy (Marco), a professional Italian pixel artist who fights for FOSS and digital ethics. If this mod spared you some time and you want to support me somehow, please consider donating on [LiberaPay](https://liberapay.com/Zughy/)

View File

@ -1 +1,20 @@
# Whitelist
# Whitelist
Filter who can enter a Minetest server and who can't through a whitelist
<a href="https://liberapay.com/Zughy/"><img src="https://i.imgur.com/4B2PxjP.png" alt="Support my work"/></a>
### Commands
`/whitelist on`: enables the whitelist
`/whitelist off`: disables the whitelist
`/whitelist add <player>`: adds <player> to the whitelist
`/whitelist remove <player>`: removes <player> from the whitelist
`/whitelist who`: lists all the whitelisted players
### API
### Want to help?
Feel free to:
* open an [issue](https://gitlab.com/zughy-friends-minetest/whitelist/-/issues)
* submit a merge request. In this case, PLEASE, do follow milestones and my [coding guidelines](https://cryptpad.fr/pad/#/2/pad/view/-l75iHl3x54py20u2Y5OSAX4iruQBdeQXcO7PGTtGew/embed/). I won't merge features for milestones that are different from the upcoming one (if it's declared), nor messy code
* contact me on the [Minetest Forum](https://forum.minetest.net/memberlist.php?mode=viewprofile&u=26472)

137
api.lua Normal file
View File

@ -0,0 +1,137 @@
whitelist = {}
local S = minetest.get_translator("whitelist")
local storage = minetest.get_mod_storage()
----------------------------------------------
---------------DICHIARAZIONI------------------
----------------------------------------------
local is_whitelist_on = false
local whitelisted_players = {}
if storage:get_int("ENABLED") == 1 then
is_whitelist_on = true
end
if storage:get_string("PLAYERS") ~= "" then
whitelisted_players = minetest.deserialize(storage:get_string("PLAYERS"))
end
----------------------------------------------
--------------------CORE----------------------
----------------------------------------------
function whitelist.enable(sender)
sender = sender or ""
-- se è già abilitata
if is_whitelist_on then
minetest.chat_send_player(sender, minetest.colorize("#e6482e", S("[!] The whitelist is already enabled!")))
return end
whitelist.add_player(sender)
is_whitelist_on = true
storage:set_int("ENABLED", 1)
minetest.chat_send_player(sender, "[WHITELIST] " .. S("Whitelist successfully enabled"))
end
function whitelist.disable(sender)
sender = sender or ""
-- se è già disabilitata
if not is_whitelist_on then
minetest.chat_send_player(sender, minetest.colorize("#e6482e", S("[!] The whitelist is already disabled!")))
return end
is_whitelist_on = false
storage:set_int("ENABLED", 0)
minetest.chat_send_player(sender, "[WHITELIST] " .. S("Whitelist successfully disabled"))
end
function whitelist.add_player(p_name, sender)
sender = sender or ""
-- se già c'è
if whitelisted_players[p_name] then
minetest.chat_send_player(sender, minetest.colorize("#e6482e", S("[!] @1 is already whitelisted!", p_name)))
return end
whitelisted_players[p_name] = true
storage:set_string("PLAYERS", minetest.serialize(whitelisted_players))
minetest.chat_send_player(sender, "[WHITELIST] " .. minetest.colorize("#c8d692", "+ " .. p_name))
end
function whitelist.remove_player(p_name, sender)
sender = sender or ""
-- se già non c'è
if not whitelisted_players[p_name] then
minetest.chat_send_player(sender, minetest.colorize("#e6482e", S("[!] There is no player whitelisted with that name...")))
return end
-- se è lo stesso giocatore
if p_name == sender then
minetest.chat_send_player(sender, minetest.colorize("#e6482e", S("[!] You can't remove yourself!")))
return end
whitelisted_players[p_name] = nil
-- se si rimuove l'ultimo giocatore mentre è attiva
if not next(whitelisted_players) and is_whitelist_on then
minetest.chat_send_player(sender, minetest.colorize("#e6482e", S("[!] Whitelist can't be empty when enabled!")))
whitelisted_players[p_name] = true
return end
storage:set_string("PLAYERS", minetest.serialize(whitelisted_players))
minetest.chat_send_player(sender, "[WHITELIST] " .. minetest.colorize("#f16a54", "- " .. p_name))
end
----------------------------------------------
--------------------UTILS---------------------
----------------------------------------------
function whitelist.print_list(sender)
local msg = ""
for p_name, _ in pairs(whitelisted_players) do
msg = msg .. p_name .. ", "
end
minetest.chat_send_player(sender, "[WHITELIST] " .. minetest.colorize("#eea160", S("Whitelisted players: ")) .. minetest.colorize("#cfc6b8", msg:sub(1, -3)))
end
function whitelist.is_player_whitelisted(p_name)
return whitelisted_players[p_name] ~= nil
end
function whitelist.is_whitelist_enabled()
return is_whitelist_on
end

306
chatcmdbuilder.lua Normal file
View File

@ -0,0 +1,306 @@
ChatCmdBuilder = {}
function ChatCmdBuilder.new(name, func, def)
def = def or {}
local cmd = ChatCmdBuilder.build(func)
cmd.def = def
def.func = cmd.run
minetest.register_chatcommand(name, def)
return cmd
end
local STATE_READY = 1
local STATE_PARAM = 2
local STATE_PARAM_TYPE = 3
local bad_chars = {}
bad_chars["("] = true
bad_chars[")"] = true
bad_chars["."] = true
bad_chars["%"] = true
bad_chars["+"] = true
bad_chars["-"] = true
bad_chars["*"] = true
bad_chars["?"] = true
bad_chars["["] = true
bad_chars["^"] = true
bad_chars["$"] = true
local function escape(char)
if bad_chars[char] then
return "%" .. char
else
return char
end
end
local dprint = function() end
ChatCmdBuilder.types = {
pos = "%(? *(%-?[%d.]+) *, *(%-?[%d.]+) *, *(%-?[%d.]+) *%)?",
text = "(.+)",
number = "(%-?[%d.]+)",
int = "(%-?[%d]+)",
word = "([^ ]+)",
alpha = "([A-Za-z]+)",
modname = "([a-z0-9_]+)",
alphascore = "([A-Za-z_]+)",
alphanumeric = "([A-Za-z0-9]+)",
username = "([A-Za-z0-9-_]+)",
}
function ChatCmdBuilder.build(func)
local cmd = {
_subs = {}
}
function cmd:sub(route, func, def)
dprint("Parsing " .. route)
def = def or {}
if string.trim then
route = string.trim(route)
end
local sub = {
pattern = "^",
params = {},
func = func
}
-- End of param reached: add it to the pattern
local param = ""
local param_type = ""
local should_be_eos = false
local function finishParam()
if param ~= "" and param_type ~= "" then
dprint(" - Found param " .. param .. " type " .. param_type)
local pattern = ChatCmdBuilder.types[param_type]
if not pattern then
error("Unrecognised param_type=" .. param_type)
end
sub.pattern = sub.pattern .. pattern
table.insert(sub.params, param_type)
param = ""
param_type = ""
end
end
-- Iterate through the route to find params
local state = STATE_READY
local catching_space = false
local match_space = " " -- change to "%s" to also catch tabs and newlines
local catch_space = match_space.."+"
for i = 1, #route do
local c = route:sub(i, i)
if should_be_eos then
error("Should be end of string. Nothing is allowed after a param of type text.")
end
if state == STATE_READY then
if c == ":" then
dprint(" - Found :, entering param")
state = STATE_PARAM
param_type = "word"
catching_space = false
elseif c:match(match_space) then
print(" - Found space")
if not catching_space then
catching_space = true
sub.pattern = sub.pattern .. catch_space
end
else
catching_space = false
sub.pattern = sub.pattern .. escape(c)
end
elseif state == STATE_PARAM then
if c == ":" then
dprint(" - Found :, entering param type")
state = STATE_PARAM_TYPE
param_type = ""
elseif c:match(match_space) then
print(" - Found whitespace, leaving param")
state = STATE_READY
finishParam()
catching_space = true
sub.pattern = sub.pattern .. catch_space
elseif c:match("%W") then
dprint(" - Found nonalphanum, leaving param")
state = STATE_READY
finishParam()
sub.pattern = sub.pattern .. escape(c)
else
param = param .. c
end
elseif state == STATE_PARAM_TYPE then
if c:match(match_space) then
print(" - Found space, leaving param type")
state = STATE_READY
finishParam()
catching_space = true
sub.pattern = sub.pattern .. catch_space
elseif c:match("%W") then
dprint(" - Found nonalphanum, leaving param type")
state = STATE_READY
finishParam()
sub.pattern = sub.pattern .. escape(c)
else
param_type = param_type .. c
end
end
end
dprint(" - End of route")
finishParam()
sub.pattern = sub.pattern .. "$"
dprint("Pattern: " .. sub.pattern)
table.insert(self._subs, sub)
end
if func then
func(cmd)
end
cmd.run = function(name, param)
for i = 1, #cmd._subs do
local sub = cmd._subs[i]
local res = { string.match(param, sub.pattern) }
if #res > 0 then
local pointer = 1
local params = { name }
for j = 1, #sub.params do
local param = sub.params[j]
if param == "pos" then
local pos = {
x = tonumber(res[pointer]),
y = tonumber(res[pointer + 1]),
z = tonumber(res[pointer + 2])
}
table.insert(params, pos)
pointer = pointer + 3
elseif param == "number" or param == "int" then
table.insert(params, tonumber(res[pointer]))
pointer = pointer + 1
else
table.insert(params, res[pointer])
pointer = pointer + 1
end
end
if table.unpack then
-- lua 5.2 or later
return sub.func(table.unpack(params))
else
-- lua 5.1 or earlier
return sub.func(unpack(params))
end
end
end
return false, "Invalid command"
end
return cmd
end
local function run_tests()
if not (ChatCmdBuilder.build(function(cmd)
cmd:sub("bar :one and :two:word", function(name, one, two)
if name == "singleplayer" and one == "abc" and two == "def" then
return true
end
end)
end)).run("singleplayer", "bar abc and def") then
error("Test 1 failed")
end
local move = ChatCmdBuilder.build(function(cmd)
cmd:sub("move :target to :pos:pos", function(name, target, pos)
if name == "singleplayer" and target == "player1" and
pos.x == 0 and pos.y == 1 and pos.z == 2 then
return true
end
end)
end).run
if not move("singleplayer", "move player1 to 0,1,2") then
error("Test 2 failed")
end
if not move("singleplayer", "move player1 to (0,1,2)") then
error("Test 3 failed")
end
if not move("singleplayer", "move player1 to 0, 1,2") then
error("Test 4 failed")
end
if not move("singleplayer", "move player1 to 0 ,1, 2") then
error("Test 5 failed")
end
if not move("singleplayer", "move player1 to 0, 1, 2") then
error("Test 6 failed")
end
if not move("singleplayer", "move player1 to 0 ,1 ,2") then
error("Test 7 failed")
end
if not move("singleplayer", "move player1 to ( 0 ,1 ,2)") then
error("Test 8 failed")
end
if move("singleplayer", "move player1 to abc,def,sdosd") then
error("Test 9 failed")
end
if move("singleplayer", "move player1 to abc def sdosd") then
error("Test 10 failed")
end
if not (ChatCmdBuilder.build(function(cmd)
cmd:sub("does :one:int plus :two:int equal :three:int", function(name, one, two, three)
if name == "singleplayer" and one + two == three then
return true
end
end)
end)).run("singleplayer", "does 1 plus 2 equal 3") then
error("Test 11 failed")
end
local checknegint = ChatCmdBuilder.build(function(cmd)
cmd:sub("checknegint :x:int", function(name, x)
return x
end)
end).run
if checknegint("checker","checknegint -2") ~= -2 then
error("Test 12 failed")
end
local checknegnumber = ChatCmdBuilder.build(function(cmd)
cmd:sub("checknegnumber :x:number", function(name, x)
return x
end)
end).run
if checknegnumber("checker","checknegnumber -3.3") ~= -3.3 then
error("Test 13 failed")
end
local checknegpos = ChatCmdBuilder.build(function(cmd)
cmd:sub("checknegpos :pos:pos", function(name, pos)
return pos
end)
end).run
local negpos = checknegpos("checker","checknegpos (-13.3,-4.6,-1234.5)")
if negpos.x ~= -13.3 or negpos.y ~= -4.6 or negpos.z ~= -1234.5 then
error("Test 14 failed")
end
local checktypes = ChatCmdBuilder.build(function(cmd)
cmd:sub("checktypes :int:int :number:number :pos:pos :word:word :text:text", function(name, int, number, pos, word, text)
return int, number, pos.x, pos.y, pos.z, word, text
end)
end).run
local int, number, posx, posy, posz, word, text
int, number, posx, posy, posz, word, text = checktypes("checker","checktypes -1 -2.4 (-3,-5.3,6.12) some text to finish off with")
--dprint(int, number, posx, posy, posz, word, text)
if int ~= -1 or number ~= -2.4 or posx ~= -3 or posy ~= -5.3 or posz ~= 6.12 or word ~= "some" or text ~= "text to finish off with" then
error("Test 15 failed")
end
dprint("All tests passed")
end
if not minetest then
run_tests()
end

26
commands.lua Normal file
View File

@ -0,0 +1,26 @@
ChatCmdBuilder.new("whitelist", function(cmd)
cmd:sub("off", function(sender)
whitelist.disable(sender)
end)
cmd:sub("on", function(sender)
whitelist.enable(sender)
end)
cmd:sub("add :player:text", function(sender, p_name)
whitelist.add_player(p_name, sender)
end)
cmd:sub("remove :player:text", function(sender, p_name)
whitelist.remove_player(p_name, sender)
end)
cmd:sub("who", function(sender)
whitelist.print_list(sender)
end)
end, {
description = "whitelist commands",
privs = { server = true }
})

8
init.lua Normal file
View File

@ -0,0 +1,8 @@
local version = "1.0.0"
dofile(minetest.get_modpath("whitelist") .. "/api.lua")
dofile(minetest.get_modpath("whitelist") .. "/chatcmdbuilder.lua")
dofile(minetest.get_modpath("whitelist") .. "/commands.lua")
dofile(minetest.get_modpath("whitelist") .. "/player_manager.lua")
minetest.log("action", "[WHITELIST] Mod initialised, running version " .. version)

18
locale/template.txt Normal file
View File

@ -0,0 +1,18 @@
# version 1.0.0
# author(s):
# reviewer(s):
# textdomain: whitelist
# api.lua
[!] The whitelist is already enabled!=
Whitelist successfully enabled=
[!] The whitelist is already disabled!=
Whitelist successfully disabled=
[!] @1 is already whitelisted!=
[!] There is no player whitelisted with that name...=
[!] You can't remove yourself!=
[!] Whitelist can't be empty when enabled!=
Whitelisted players: =
#player_manager.lua
You're not whitelisted!=

18
locale/whitelist.it.tr Normal file
View File

@ -0,0 +1,18 @@
# version 1.0.0
# author(s): Zughy
# reviewer(s):
# textdomain: whitelist
# api.lua
[!] The whitelist is already enabled!=[!] La whitelist è già abilitata!
Whitelist successfully enabled=Whitelist abilitata con successo
[!] The whitelist is already disabled!=[!] La whitelist è già disabilitata!
Whitelist successfully disabled=Whitelist disabilitata con successo
[!] @1 is already whitelisted!=[!] @1 è già nella whitelist!
[!] There is no player whitelisted with that name...=[!] Nessun giocatore con quel nome è presente nella whitelist...
[!] You can't remove yourself!=[!] Non puoi rimuovere te stesso/a!
[!] Whitelist can't be empty when enabled!=[!] La whitelist non può essere vuota quand'è attiva!
Whitelisted players: =Giocatori in whitelist:
#player_manager.lua
You're not whitelisted!=Non sei in whitelist!

2
mod.conf Normal file
View File

@ -0,0 +1,2 @@
name = whitelist
description = manage who can and who can't enter in your server

11
player_manager.lua Normal file
View File

@ -0,0 +1,11 @@
local S = minetest.get_translator("whitelist")
minetest.register_on_prejoinplayer(function(name, ip)
if not whitelist.is_whitelist_enabled() then return end
if not whitelist.is_player_whitelisted(name) then
return S("You're not whitelisted!") -- this doesn't currently work
end
end)