forked from mtcontrib/3d_armor
		
	Fix item duplication vulnerability
This commit is contained in:
		@@ -68,6 +68,9 @@ armor_fire_protect = false
 | 
			
		||||
-- Enable punch damage effects.
 | 
			
		||||
armor_punch_damage = true
 | 
			
		||||
 | 
			
		||||
-- Enable migration of old armor inventories
 | 
			
		||||
armor_migrate_old_inventory = true
 | 
			
		||||
 | 
			
		||||
API
 | 
			
		||||
---
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -69,6 +69,7 @@ armor = {
 | 
			
		||||
		on_damage = {},
 | 
			
		||||
		on_destroy = {},
 | 
			
		||||
	},
 | 
			
		||||
	migrate_old_inventory = true,
 | 
			
		||||
	version = "0.4.9",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -177,7 +178,7 @@ armor.update_player_visuals = function(self, player)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
armor.set_player_armor = function(self, player)
 | 
			
		||||
	local name, player_inv = self:get_valid_player(player, "[set_player_armor]")
 | 
			
		||||
	local name, armor_inv = self:get_valid_player(player, "[set_player_armor]")
 | 
			
		||||
	if not name then
 | 
			
		||||
		return
 | 
			
		||||
	end
 | 
			
		||||
@@ -205,7 +206,10 @@ armor.set_player_armor = function(self, player)
 | 
			
		||||
		change[group] = 1
 | 
			
		||||
		levels[group] = 0
 | 
			
		||||
	end
 | 
			
		||||
	local list = player_inv:get_list("armor") or {}
 | 
			
		||||
	local list = armor_inv:get_list("armor")
 | 
			
		||||
	if type(list) ~= "table" then
 | 
			
		||||
		return
 | 
			
		||||
	end
 | 
			
		||||
	for i, stack in pairs(list) do
 | 
			
		||||
		if stack:get_count() == 1 then
 | 
			
		||||
			local def = stack:get_definition()
 | 
			
		||||
@@ -221,6 +225,7 @@ armor.set_player_armor = function(self, player)
 | 
			
		||||
						local level = def.groups["armor_"..element]
 | 
			
		||||
						levels["fleshy"] = levels["fleshy"] + level
 | 
			
		||||
					end
 | 
			
		||||
					break
 | 
			
		||||
				end
 | 
			
		||||
				-- DEPRECATED, use armor_groups instead
 | 
			
		||||
				if def.groups["armor_radiation"] and levels["radiation"] then
 | 
			
		||||
@@ -299,7 +304,7 @@ armor.set_player_armor = function(self, player)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
armor.punch = function(self, player, hitter, time_from_last_punch, tool_capabilities)
 | 
			
		||||
	local name, player_inv = self:get_valid_player(player, "[punch]")
 | 
			
		||||
	local name, armor_inv = self:get_valid_player(player, "[punch]")
 | 
			
		||||
	if not name then
 | 
			
		||||
		return
 | 
			
		||||
	end
 | 
			
		||||
@@ -307,7 +312,7 @@ armor.punch = function(self, player, hitter, time_from_last_punch, tool_capabili
 | 
			
		||||
	local count = 0
 | 
			
		||||
	local recip = true
 | 
			
		||||
	local default_groups = {cracky=3, snappy=3, choppy=3, crumbly=3, level=1}
 | 
			
		||||
	local list = player_inv:get_list("armor")
 | 
			
		||||
	local list = armor_inv:get_list("armor")
 | 
			
		||||
	for i, stack in pairs(list) do
 | 
			
		||||
		if stack:get_count() == 1 then
 | 
			
		||||
			local name = stack:get_name()
 | 
			
		||||
@@ -399,12 +404,64 @@ armor.get_armor_formspec = function(self, name, listring)
 | 
			
		||||
	for _, attr in pairs(self.attributes) do
 | 
			
		||||
		formspec = formspec:gsub("armor_attr_"..attr, armor.def[name][attr])
 | 
			
		||||
	end
 | 
			
		||||
	for _, group in pairs(self.attributes) do
 | 
			
		||||
		formspec = formspec:gsub("armor_group_"..group, armor.def[name][group])
 | 
			
		||||
	for group, _ in pairs(self.registered_groups) do
 | 
			
		||||
		formspec = formspec:gsub("armor_group_"..group,
 | 
			
		||||
			armor.def[name].groups[group])
 | 
			
		||||
	end
 | 
			
		||||
	return formspec
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
armor.serialize_inventory_list = function(self, list)
 | 
			
		||||
	local list_table = {}
 | 
			
		||||
	for _, stack in ipairs(list) do
 | 
			
		||||
		table.insert(list_table, stack:to_string())
 | 
			
		||||
	end
 | 
			
		||||
	return minetest.serialize(list_table)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
armor.deserialize_inventory_list = function(self, list_string)
 | 
			
		||||
	local list_table = minetest.deserialize(list_string)
 | 
			
		||||
	local list = {}
 | 
			
		||||
	for _, stack in ipairs(list_table or {}) do
 | 
			
		||||
		table.insert(list, ItemStack(stack))
 | 
			
		||||
	end
 | 
			
		||||
	return list
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
armor.load_armor_inventory = function(self, player)
 | 
			
		||||
	local msg = "[load_armor_inventory]"
 | 
			
		||||
	local name = player:get_player_name()
 | 
			
		||||
	if not name then
 | 
			
		||||
		minetest.log("warning", S("3d_armor: Player name is nil @1", msg))
 | 
			
		||||
		return
 | 
			
		||||
	end
 | 
			
		||||
	local armor_inv = minetest.get_inventory({type="detached", name=name.."_armor"})
 | 
			
		||||
	if not armor_inv then
 | 
			
		||||
		minetest.log("warning", S("3d_armor: Detached armor inventory is nil @1", msg))
 | 
			
		||||
		return
 | 
			
		||||
	end
 | 
			
		||||
	local armor_list_string = player:get_attribute("3d_armor_inventory")
 | 
			
		||||
	if armor_list_string then
 | 
			
		||||
		armor_inv:set_list("armor", self:deserialize_inventory_list(armor_list_string))
 | 
			
		||||
		return true
 | 
			
		||||
	end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
armor.save_armor_inventory = function(self, player)
 | 
			
		||||
	local msg = "[save_armor_inventory]"
 | 
			
		||||
	local name = player:get_player_name()
 | 
			
		||||
	if not name then
 | 
			
		||||
		minetest.log("warning", S("3d_armor: Player name is nil @1", msg))
 | 
			
		||||
		return
 | 
			
		||||
	end
 | 
			
		||||
	local armor_inv = minetest.get_inventory({type="detached", name=name.."_armor"})
 | 
			
		||||
	if not armor_inv then
 | 
			
		||||
		minetest.log("warning", S("3d_armor: Detached armor inventory is nil @1", msg))
 | 
			
		||||
		return
 | 
			
		||||
	end
 | 
			
		||||
	player:set_attribute("3d_armor_inventory", self:serialize_inventory_list(armor_inv:get_list("armor")))
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
armor.update_inventory = function(self, player)
 | 
			
		||||
	-- DEPRECATED: Legacy inventory support
 | 
			
		||||
end
 | 
			
		||||
@@ -416,17 +473,13 @@ armor.set_inventory_stack = function(self, player, i, stack)
 | 
			
		||||
		minetest.log("warning", "3d_armor: Player name is nil "..msg)
 | 
			
		||||
		return
 | 
			
		||||
	end
 | 
			
		||||
	local player_inv = player:get_inventory()
 | 
			
		||||
	local armor_inv = minetest.get_inventory({type="detached", name=name.."_armor"})
 | 
			
		||||
	if not player_inv then
 | 
			
		||||
		minetest.log("warning", "3d_armor: Player inventory is nil "..msg)
 | 
			
		||||
		return
 | 
			
		||||
	elseif not armor_inv then
 | 
			
		||||
		minetest.log("warning", "3d_armor: Detached armor inventory is nil "..msg)
 | 
			
		||||
	if not armor_inv then
 | 
			
		||||
		minetest.log("warning", S("3d_armor: Detached armor inventory is nil @1", msg))
 | 
			
		||||
		return
 | 
			
		||||
	end
 | 
			
		||||
	player_inv:set_stack("armor", i, stack)
 | 
			
		||||
	armor_inv:set_stack("armor", i, stack)
 | 
			
		||||
	self:save_armor_inventory(player)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
armor.get_valid_player = function(self, player, msg)
 | 
			
		||||
@@ -440,7 +493,7 @@ armor.get_valid_player = function(self, player, msg)
 | 
			
		||||
		minetest.log("warning", "3d_armor: Player name is nil "..msg)
 | 
			
		||||
		return
 | 
			
		||||
	end
 | 
			
		||||
	local inv = player:get_inventory()
 | 
			
		||||
	local inv = minetest.get_inventory({type="detached", name=name.."_armor"})
 | 
			
		||||
	if not inv then
 | 
			
		||||
		minetest.log("warning", "3d_armor: Player inventory is nil "..msg)
 | 
			
		||||
		return
 | 
			
		||||
 
 | 
			
		||||
@@ -101,27 +101,23 @@ end)
 | 
			
		||||
 | 
			
		||||
local function init_player_armor(player)
 | 
			
		||||
	local name = player:get_player_name()
 | 
			
		||||
	local player_inv = player:get_inventory()
 | 
			
		||||
	local pos = player:getpos()
 | 
			
		||||
	if not name or not player_inv or not pos then
 | 
			
		||||
	if not name or not pos then
 | 
			
		||||
		return false
 | 
			
		||||
	end
 | 
			
		||||
	local armor_inv = minetest.create_detached_inventory(name.."_armor", {
 | 
			
		||||
		on_put = function(inv, listname, index, stack, player)
 | 
			
		||||
			player:get_inventory():set_stack(listname, index, stack)
 | 
			
		||||
			armor:save_armor_inventory(player)
 | 
			
		||||
			armor:run_callbacks("on_equip", player, index, stack)
 | 
			
		||||
			armor:set_player_armor(player)
 | 
			
		||||
		end,
 | 
			
		||||
		on_take = function(inv, listname, index, stack, player)
 | 
			
		||||
			player:get_inventory():set_stack(listname, index, nil)
 | 
			
		||||
			armor:save_armor_inventory(player)
 | 
			
		||||
			armor:run_callbacks("on_unequip", player, index, stack)
 | 
			
		||||
			armor:set_player_armor(player)
 | 
			
		||||
		end,
 | 
			
		||||
		on_move = function(inv, from_list, from_index, to_list, to_index, count, player)
 | 
			
		||||
			local plaver_inv = player:get_inventory()
 | 
			
		||||
			local stack = inv:get_stack(to_list, to_index)
 | 
			
		||||
			player_inv:set_stack(to_list, to_index, stack)
 | 
			
		||||
			player_inv:set_stack(from_list, from_index, nil)
 | 
			
		||||
			armor:save_armor_inventory(player)
 | 
			
		||||
			armor:set_player_armor(player)
 | 
			
		||||
		end,
 | 
			
		||||
		allow_put = function(inv, listname, index, stack, player)
 | 
			
		||||
@@ -148,10 +144,18 @@ local function init_player_armor(player)
 | 
			
		||||
		end,
 | 
			
		||||
	}, name)
 | 
			
		||||
	armor_inv:set_size("armor", 6)
 | 
			
		||||
	player_inv:set_size("armor", 6)
 | 
			
		||||
	if not armor:load_armor_inventory(player) and armor.migrate_old_inventory then
 | 
			
		||||
		local player_inv = player:get_inventory()
 | 
			
		||||
		player_inv:set_size("armor", 6)
 | 
			
		||||
		for i=1, 6 do
 | 
			
		||||
			local stack = player_inv:get_stack("armor", i)
 | 
			
		||||
			armor_inv:set_stack("armor", i, stack)
 | 
			
		||||
		end
 | 
			
		||||
		armor:save_armor_inventory(player)
 | 
			
		||||
		player_inv:set_size("armor", 0)
 | 
			
		||||
	end
 | 
			
		||||
	for i=1, 6 do
 | 
			
		||||
		local stack = player_inv:get_stack("armor", i)
 | 
			
		||||
		armor_inv:set_stack("armor", i, stack)
 | 
			
		||||
		local stack = armor_inv:get_stack("armor", i)
 | 
			
		||||
		armor:run_callbacks("on_equip", player, i, stack)
 | 
			
		||||
	end
 | 
			
		||||
	armor.def[name] = {
 | 
			
		||||
@@ -220,13 +224,13 @@ end)
 | 
			
		||||
 | 
			
		||||
if armor.config.drop == true or armor.config.destroy == true then
 | 
			
		||||
	minetest.register_on_dieplayer(function(player)
 | 
			
		||||
		local name, player_inv = armor:get_valid_player(player, "[on_dieplayer]")
 | 
			
		||||
		local name, armor_inv = armor:get_valid_player(player, "[on_dieplayer]")
 | 
			
		||||
		if not name then
 | 
			
		||||
			return
 | 
			
		||||
		end
 | 
			
		||||
		local drop = {}
 | 
			
		||||
		for i=1, player_inv:get_size("armor") do
 | 
			
		||||
			local stack = player_inv:get_stack("armor", i)
 | 
			
		||||
		for i=1, armor_inv:get_size("armor") do
 | 
			
		||||
			local stack = armor_inv:get_stack("armor", i)
 | 
			
		||||
			if stack:get_count() > 0 then
 | 
			
		||||
				table.insert(drop, stack)
 | 
			
		||||
				armor:set_inventory_stack(player, i, nil)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user