From 2c09355b75a23968a7062f67816932a6ee261673 Mon Sep 17 00:00:00 2001 From: SX Date: Sat, 23 May 2020 02:28:44 +0300 Subject: [PATCH 1/3] Allow per node protection bypass / protection override #11 #9 --- README.md | 16 +++++++++- metatool/api.lua | 79 ++++++++++++++++++++++++++++++++++++------------ 2 files changed, 74 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index ae0b4ef..3b8d01d 100644 --- a/README.md +++ b/README.md @@ -103,6 +103,20 @@ Example definition: end, ``` +Parameter `protection_bypass_read = { "mytool_copy" }` +Bypass all read protection checks when using tool if player has listed privs. + +Parameter `protection_bypass_write = { "mytool_admin" }` +Bypass all write protection checks when using tool if player has listed privs. + +Callback `allowed = before_read(nodedef, pos, player)` +Executed before node reading is called, this method can override all protection checks. +Above protection_bypass_read parameters might not work if this is overridden. + +Callback `allowed = before_write(nodedef, pos, player)` +Executed before node reading is called, this method can override all protection checks. +Above protection_bypass_write parameters might not work if this is overridden. + ### Metatool API methods (commonly used) `mytool = metatool:register_tool(name, definition)` @@ -111,7 +125,7 @@ Example definition: ### Metatool API methods (for special needs) -`node, pos = metatool:get_node(tool, player, pointed_thing)` +`node, pos, nodedef = metatool:get_node(tool, player, pointed_thing)` `metatool.write_data(itemstack, data, description)` diff --git a/metatool/api.lua b/metatool/api.lua index 98b53ce..641363f 100644 --- a/metatool/api.lua +++ b/metatool/api.lua @@ -75,11 +75,45 @@ local validate_tool_definition = function(definition) return F('on_read_node') and F('on_write_node') and T('recipe') end +local get_privs = function(privs) + if privs and #privs > 0 then + -- return privs if length > 0 + return privs + end +end + --luacheck: ignore unused argument self metatool = { -- Metatool registered tools tools = {}, + is_protected = function(pos, player, privs) + local name = player:get_player_name() + if minetest.is_protected(pos, name) then + local bypass = privs and minetest.check_player_privs(player, privs) or false + -- node is protected record violation even with bypass priv + minetest.record_protection_violation(pos, name) + return not bypass + end + return false + end, + + before_read = function(nodedef, pos, player) + local privs = get_privs(nodedef.protection_bypass_read) + if metatool.is_protected(pos, player, privs) then + return false + end + return true + end, + + before_write = function(nodedef, pos, player) + local privs = get_privs(nodedef.protection_bypass_write) + if metatool.is_protected(pos, player, privs) then + return false + end + return true + end, + -- Called when registered tool is used on_use = function(self, toolname, itemstack, player, pointed_thing) if not player or type(player) == 'table' then @@ -88,26 +122,31 @@ metatool = { local tooldef = self.tools[toolname] - local node, pos = metatool:get_node(tooldef, player, pointed_thing) + local node, pos, nodedef = metatool:get_node(tooldef, player, pointed_thing) if not node then return end local controls = player:get_player_control() + if controls.aux1 or controls.sneak then - -- Execute on_read_node when tool is used on node and special or sneak is held - local data, group, description = tooldef.itemdef.on_read_node(tooldef, player, pointed_thing, node, pos) - metatool.write_data(itemstack, {data=data,group=group}, description) + if nodedef.before_read(nodedef, pos, player) then + -- Execute on_read_node when tool is used on node and special or sneak is held + local data, group, description = tooldef.itemdef.on_read_node(tooldef, player, pointed_thing, node, pos) + metatool.write_data(itemstack, {data=data,group=group}, description) + end else - local data = metatool.read_data(itemstack) - if type(data) == 'table' then - -- Execute on_write_node when tool is used on node and tool contains data - tooldef.itemdef.on_write_node(tooldef, data.data, data.group, player, pointed_thing, node, pos) - else - minetest.chat_send_player( - player:get_player_name(), - 'no data stored in this wand, sneak+use or special+use to record data.' - ) + if nodedef.before_write(nodedef, pos, player) then + local data = metatool.read_data(itemstack) + if type(data) == 'table' then + -- Execute on_write_node when tool is used on node and tool contains data + tooldef.itemdef.on_write_node(tooldef, data.data, data.group, player, pointed_thing, node, pos) + else + minetest.chat_send_player( + player:get_player_name(), + 'no data stored in this wand, sneak+use or special+use to record data.' + ) + end end end @@ -188,6 +227,12 @@ metatool = { elseif not minetest.registered_nodes[name] then print(S('metatool:register_node node %s not registered for minetest, skipping registration.', name)) elseif type(definition.copy) == 'function' and type(definition.paste) == 'function' then + if type(definition.before_read) ~= 'function' then + definition.before_read = metatool.before_read + end + if type(definition.before_write) ~= 'function' then + definition.before_write = metatool.before_write + end tooldef.nodes[name] = definition print(S('metatool:register_node registered %s for tool %s with group %s.', name, tool, definition.group)) else @@ -223,12 +268,6 @@ metatool = { return end - if minetest.is_protected(pos, name) then - -- node is protected - minetest.record_protection_violation(pos, name) - return - end - local definition = tool.nodes[node.name] if not definition then -- node is not registered for metatool @@ -236,7 +275,7 @@ metatool = { return end - return node, pos + return node, pos, definition end, -- Save data for tool and update tool description From 138518e9948057a5915d3443b7c4890ab3590e59 Mon Sep 17 00:00:00 2001 From: SX Date: Sat, 23 May 2020 03:24:11 +0300 Subject: [PATCH 2/3] Bypass protection check completely if bypass privs present --- metatool/api.lua | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/metatool/api.lua b/metatool/api.lua index 641363f..9827dfd 100644 --- a/metatool/api.lua +++ b/metatool/api.lua @@ -89,11 +89,13 @@ metatool = { is_protected = function(pos, player, privs) local name = player:get_player_name() - if minetest.is_protected(pos, name) then - local bypass = privs and minetest.check_player_privs(player, privs) or false - -- node is protected record violation even with bypass priv + if privs and minetest.check_player_privs(player, privs) then + -- player is allowed to bypass protection checks + return false + elseif minetest.is_protected(pos, name) then + -- node is protected record violation minetest.record_protection_violation(pos, name) - return not bypass + return true end return false end, From 5c4248daf371becd9c40ff073a19ce389ce92539 Mon Sep 17 00:00:00 2001 From: SX Date: Sat, 23 May 2020 04:13:53 +0300 Subject: [PATCH 3/3] Simplify overcomplicated privilege check --- metatool/api.lua | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/metatool/api.lua b/metatool/api.lua index 9827dfd..dce0345 100644 --- a/metatool/api.lua +++ b/metatool/api.lua @@ -75,24 +75,19 @@ local validate_tool_definition = function(definition) return F('on_read_node') and F('on_write_node') and T('recipe') end -local get_privs = function(privs) - if privs and #privs > 0 then - -- return privs if length > 0 - return privs - end -end - ---luacheck: ignore unused argument self metatool = { + --luacheck: ignore unused argument self + -- Metatool registered tools tools = {}, is_protected = function(pos, player, privs) - local name = player:get_player_name() - if privs and minetest.check_player_privs(player, privs) then + if privs and (minetest.check_player_privs(player, privs)) then -- player is allowed to bypass protection checks return false - elseif minetest.is_protected(pos, name) then + end + local name = player:get_player_name() + if minetest.is_protected(pos, name) then -- node is protected record violation minetest.record_protection_violation(pos, name) return true @@ -101,16 +96,14 @@ metatool = { end, before_read = function(nodedef, pos, player) - local privs = get_privs(nodedef.protection_bypass_read) - if metatool.is_protected(pos, player, privs) then + if metatool.is_protected(pos, player, nodedef.protection_bypass_read) then return false end return true end, before_write = function(nodedef, pos, player) - local privs = get_privs(nodedef.protection_bypass_write) - if metatool.is_protected(pos, player, privs) then + if metatool.is_protected(pos, player, nodedef.protection_bypass_write) then return false end return true @@ -219,8 +212,8 @@ metatool = { end end, - register_node = function(self, tool, name, definition, override) - local tooldef = self.tools[tool] + register_node = function(self, toolname, name, definition, override) + local tooldef = self.tools[toolname] if override or not tooldef.nodes[name] then if type(definition) ~= 'table' then print(S('metatool:register_node invalid definition, must be table but was %s', type(definition))) @@ -236,7 +229,7 @@ metatool = { definition.before_write = metatool.before_write end tooldef.nodes[name] = definition - print(S('metatool:register_node registered %s for tool %s with group %s.', name, tool, definition.group)) + print(S('metatool:register_node registered %s for tool %s with group %s.', name, toolname, definition.group)) else print(S('metatool:register_node invalid definition for %s: copy or paste function not defined.', name)) end