From 9ee0d376d4e4679be074ed3a27e9700169aecea3 Mon Sep 17 00:00:00 2001
From: PilzAdam <pilzadam@minetest.net>
Date: Sat, 24 Oct 2015 22:31:54 +0200
Subject: [PATCH] Don't allow games or mods to add secure. settings

---
 builtin/mainmenu/tab_settings.lua | 321 ++++++++++++++++--------------
 1 file changed, 169 insertions(+), 152 deletions(-)

diff --git a/builtin/mainmenu/tab_settings.lua b/builtin/mainmenu/tab_settings.lua
index e96fa1c4d..e6d6c6dd7 100644
--- a/builtin/mainmenu/tab_settings.lua
+++ b/builtin/mainmenu/tab_settings.lua
@@ -26,11 +26,25 @@ local CHAR_CLASSES = {
 }
 
 -- returns error message, or nil
-local function parse_setting_line(settings, line, read_all, base_level)
+local function parse_setting_line(settings, line, read_all, base_level, allow_secure)
+	-- comment
+	local comment = line:match("^#" .. CHAR_CLASSES.SPACE .. "*(.*)$")
+	if comment then
+		if settings.current_comment == "" then
+			settings.current_comment = comment
+		else
+			settings.current_comment = settings.current_comment .. "\n" .. comment
+		end
+		return
+	end
+
+	-- clear current_comment so only comments directly above a setting are bound to it
+	-- but keep a local reference to it for variables in the current line
+	local current_comment = settings.current_comment
+	settings.current_comment = ""
+
 	-- empty lines
 	if line:match("^" .. CHAR_CLASSES.SPACE .. "*$") then
-		-- clear current_comment so only comments directly above a setting are bound to it
-		settings.current_comment = ""
 		return
 	end
 
@@ -45,19 +59,6 @@ local function parse_setting_line(settings, line, read_all, base_level)
 		return
 	end
 
-	-- comment
-	local comment = line:match("^#" .. CHAR_CLASSES.SPACE .. "*(.*)$")
-	if comment then
-		if settings.current_comment == "" then
-			settings.current_comment = comment
-		else
-			settings.current_comment = settings.current_comment .. "\n" .. comment
-		end
-		return
-	end
-
-	local error_msg
-
 	-- settings
 	local first_part, name, readable_name, setting_type = line:match("^"
 			-- this first capture group matches the whole first part,
@@ -71,158 +72,174 @@ local function parse_setting_line(settings, line, read_all, base_level)
 				.. CHAR_CLASSES.SPACE .. "?"
 			.. ")")
 
-	if first_part then
-		if readable_name == "" then
-			readable_name = nil
+	if not first_part then
+		return "Invalid line"
+	end
+
+	if name:match("secure%.[.]*") and not allow_secure then
+		return "Tried to add \"secure.\" setting"
+	end
+
+	if readable_name == "" then
+		readable_name = nil
+	end
+	local remaining_line = line:sub(first_part:len() + 1)
+
+	if setting_type == "int" then
+		local default, min, max = remaining_line:match("^"
+				-- first int is required, the last 2 are optional
+				.. "(" .. CHAR_CLASSES.INTEGER .. "+)" .. CHAR_CLASSES.SPACE .. "?"
+				.. "(" .. CHAR_CLASSES.INTEGER .. "*)" .. CHAR_CLASSES.SPACE .. "?"
+				.. "(" .. CHAR_CLASSES.INTEGER .. "*)"
+				.. "$")
+
+		if not default or not tonumber(default) then
+			return "Invalid integer setting"
 		end
-		local remaining_line = line:sub(first_part:len() + 1)
-
-		if setting_type == "int" then
-			local default, min, max = remaining_line:match("^"
-					-- first int is required, the last 2 are optional
-					.. "(" .. CHAR_CLASSES.INTEGER .. "+)" .. CHAR_CLASSES.SPACE .. "?"
-					.. "(" .. CHAR_CLASSES.INTEGER .. "*)" .. CHAR_CLASSES.SPACE .. "?"
-					.. "(" .. CHAR_CLASSES.INTEGER .. "*)"
-					.. "$")
-			if default and tonumber(default) then
-				min = tonumber(min)
-				max = tonumber(max)
-				table.insert(settings, {
-					name = name,
-					readable_name = readable_name,
-					type = "int",
-					default = default,
-					min = min,
-					max = max,
-					comment = settings.current_comment,
-				})
-			else
-				error_msg = "Invalid integer setting"
-			end
 
-		elseif setting_type == "string" or setting_type == "noise_params"
-				or setting_type == "key" then
-			local default = remaining_line:match("^(.*)$")
-			if default then
-				if setting_type ~= "key" or read_all then -- ignore key type if read_all is false
-					table.insert(settings, {
-						name = name,
-						readable_name = readable_name,
-						type = setting_type,
-						default = default,
-						comment = settings.current_comment,
-					})
-				end
-			else
-				error_msg =  "Invalid string setting"
-			end
+		min = tonumber(min)
+		max = tonumber(max)
+		table.insert(settings, {
+			name = name,
+			readable_name = readable_name,
+			type = "int",
+			default = default,
+			min = min,
+			max = max,
+			comment = settings.current_comment,
+		})
+		return
+	end
 
-		elseif setting_type == "bool" then
-			if remaining_line == "false" or remaining_line == "true" then
-				table.insert(settings, {
-					name = name,
-					readable_name = readable_name,
-					type = "bool",
-					default = remaining_line,
-					comment = settings.current_comment,
-				})
-			else
-				error_msg =  "Invalid boolean setting"
-			end
+	if setting_type == "string" or setting_type == "noise_params"
+			or setting_type == "key" then
+		local default = remaining_line:match("^(.*)$")
 
-		elseif setting_type == "float" then
-			local default, min, max = remaining_line:match("^"
-					-- first float is required, the last 2 are optional
-					.. "(" .. CHAR_CLASSES.FLOAT .. "+)" .. CHAR_CLASSES.SPACE .. "?"
-					.. "(" .. CHAR_CLASSES.FLOAT .. "*)" .. CHAR_CLASSES.SPACE .. "?"
-					.. "(" .. CHAR_CLASSES.FLOAT .. "*)"
-					.."$")
-			if default and tonumber(default) then
-				min = tonumber(min)
-				max = tonumber(max)
-				table.insert(settings, {
-					name = name,
-					readable_name = readable_name,
-					type = "float",
-					default = default,
-					min = min,
-					max = max,
-					comment = settings.current_comment,
-				})
-			else
-				error_msg =  "Invalid float setting"
-			end
+		if not default then
+			return "Invalid string setting"
+		end
+		if setting_type == "key" and not read_all then
+			-- ignore key type if read_all is false
+			return
+		end
 
-		elseif setting_type == "enum" then
-			local default, values = remaining_line:match("^(.+)" .. CHAR_CLASSES.SPACE .. "(.+)$")
-			if default and values ~= "" then
-				table.insert(settings, {
-					name = name,
-					readable_name = readable_name,
-					type = "enum",
-					default = default,
-					values = values:split(",", true),
-					comment = settings.current_comment,
-				})
-			else
-				error_msg =  "Invalid enum setting"
-			end
+		table.insert(settings, {
+			name = name,
+			readable_name = readable_name,
+			type = setting_type,
+			default = default,
+			comment = settings.current_comment,
+		})
+		return
+	end
 
-		elseif setting_type == "path" then
-			local default = remaining_line:match("^(.*)$")
-			if default then
-				table.insert(settings, {
-					name = name,
-					readable_name = readable_name,
-					type = "path",
-					default = default,
-					comment = settings.current_comment,
-				})
-			else
-				error_msg =  "Invalid path setting"
-			end
+	if setting_type == "bool" then
+		if remaining_line ~= "false" and remaining_line ~= "true" then
+			return "Invalid boolean setting"
+		end
 
-		elseif setting_type == "flags" then
-			local default, possible = remaining_line:match("^"
-					.. "(" .. CHAR_CLASSES.FLAGS .. "+)" .. CHAR_CLASSES.SPACE .. ""
-					.. "(" .. CHAR_CLASSES.FLAGS .. "+)"
-					.. "$")
-			if default and possible then
-				table.insert(settings, {
-					name = name,
-					readable_name = readable_name,
-					type = "flags",
-					default = default,
-					possible = possible,
-					comment = settings.current_comment,
-				})
-			else
-				error_msg =  "Invalid flags setting"
-			end
+		table.insert(settings, {
+			name = name,
+			readable_name = readable_name,
+			type = "bool",
+			default = remaining_line,
+			comment = settings.current_comment,
+		})
+		return
+	end
 
-		-- TODO: flags, noise_params (, struct)
+	if setting_type == "float" then
+		local default, min, max = remaining_line:match("^"
+				-- first float is required, the last 2 are optional
+				.. "(" .. CHAR_CLASSES.FLOAT .. "+)" .. CHAR_CLASSES.SPACE .. "?"
+				.. "(" .. CHAR_CLASSES.FLOAT .. "*)" .. CHAR_CLASSES.SPACE .. "?"
+				.. "(" .. CHAR_CLASSES.FLOAT .. "*)"
+				.."$")
 
-		else
-			error_msg =  "Invalid setting type \"" .. type .. "\""
+		if not default or not tonumber(default) then
+			return "Invalid float setting"
 		end
-	else
-		error_msg =  "Invalid line"
+
+		min = tonumber(min)
+		max = tonumber(max)
+		table.insert(settings, {
+			name = name,
+			readable_name = readable_name,
+			type = "float",
+			default = default,
+			min = min,
+			max = max,
+			comment = settings.current_comment,
+		})
+		return
+	end
+
+	if setting_type == "enum" then
+		local default, values = remaining_line:match("^(.+)" .. CHAR_CLASSES.SPACE .. "(.+)$")
+
+		if not default or values == "" then
+			return "Invalid enum setting"
+		end
+
+		table.insert(settings, {
+			name = name,
+			readable_name = readable_name,
+			type = "enum",
+			default = default,
+			values = values:split(",", true),
+			comment = settings.current_comment,
+		})
+		return
+	end
+
+	if setting_type == "path" then
+		local default = remaining_line:match("^(.*)$")
+
+		if not default then
+			return "Invalid path setting"
+		end
+
+		table.insert(settings, {
+			name = name,
+			readable_name = readable_name,
+			type = "path",
+			default = default,
+			comment = settings.current_comment,
+		})
+		return
+	end
+
+	if setting_type == "flags" then
+		local default, possible = remaining_line:match("^"
+				.. "(" .. CHAR_CLASSES.FLAGS .. "+)" .. CHAR_CLASSES.SPACE .. ""
+				.. "(" .. CHAR_CLASSES.FLAGS .. "+)"
+				.. "$")
+
+		if not default or not possible then
+			return "Invalid flags setting"
+		end
+
+		table.insert(settings, {
+			name = name,
+			readable_name = readable_name,
+			type = "flags",
+			default = default,
+			possible = possible,
+			comment = settings.current_comment,
+		})
+		return
 	end
-	-- clear current_comment since we just used it
-	-- if we not just used it, then clear it since we only want comments
-	--  directly above the setting to be bound to it
-	settings.current_comment = ""
 
-	return error_msg
+	return "Invalid setting type \"" .. setting_type .. "\""
 end
 
-local function parse_single_file(file, filepath, read_all, result, base_level)
+local function parse_single_file(file, filepath, read_all, result, base_level, allow_secure)
 	-- store this helper variable in the table so it's easier to pass to parse_setting_line()
 	result.current_comment = ""
 
 	local line = file:read("*line")
 	while line do
-		local error_msg = parse_setting_line(result, line, read_all, base_level)
+		local error_msg = parse_setting_line(result, line, read_all, base_level, allow_secure)
 		if error_msg then
 			core.log("error", error_msg .. " in " .. filepath .. " \"" .. line .. "\"")
 		end
@@ -243,7 +260,7 @@ local function parse_config_file(read_all, parse_mods)
 		return settings
 	end
 
-	parse_single_file(file, builtin_path, read_all, settings, 0)
+	parse_single_file(file, builtin_path, read_all, settings, 0, true)
 
 	file:close()
 
@@ -272,7 +289,7 @@ local function parse_config_file(read_all, parse_mods)
 					type = "category",
 				})
 
-				parse_single_file(file, path, read_all, settings, 2)
+				parse_single_file(file, path, read_all, settings, 2, false)
 
 				file:close()
 			end
@@ -305,7 +322,7 @@ local function parse_config_file(read_all, parse_mods)
 					type = "category",
 				})
 
-				parse_single_file(file, path, read_all, settings, 2)
+				parse_single_file(file, path, read_all, settings, 2, false)
 
 				file:close()
 			end
-- 
GitLab