From 8a8d22416d50d5ed16f7cc96518fbb1e5c9146c6 Mon Sep 17 00:00:00 2001 From: rnd1 Date: Mon, 18 Dec 2017 11:19:05 +0100 Subject: [PATCH] - authlevel to set levels of access player has in robot sandbox (0 = ordinary, 1 = robot, 2 = puzzle, 3 = admin) - authlevel is stored in metadata of robot and digitally signed using server private password to prevent abuses - minor bugfixes - new giver and checker blocks for puzzle, can create locks and keys now --- commands.lua | 15 +++-- init.lua | 111 +++++++++++++++++++++++------------- scripts/sokoban_game.lua | 4 +- textures/puzzle_checker.png | Bin 0 -> 732 bytes textures/puzzle_giver.png | Bin 0 -> 762 bytes 5 files changed, 82 insertions(+), 48 deletions(-) create mode 100644 textures/puzzle_checker.png create mode 100644 textures/puzzle_giver.png diff --git a/commands.lua b/commands.lua index 87293aa..11d64da 100644 --- a/commands.lua +++ b/commands.lua @@ -49,7 +49,7 @@ local function pos_in_dir(obj, dir) -- position after we move in specified direc elseif dir == 13 then -- forward_up pos.y=pos.y+1 elseif dir == 14 then -- backward_up - yaw = yaw + pi; pos.y=pos.y-1 + yaw = yaw + pi; pos.y=pos.y+1 end if dir ~= 5 and dir ~= 6 then @@ -571,7 +571,7 @@ local register_robot_button = function(R,G,B,type) on_punch = function(pos, node, player) local name = player:get_player_name(); if name==nil then return end local round = math.floor; - local r = 32; local ry = 2*r; -- note: this is skyblock adjusted + local r = basic_robot.radius; local ry = 2*r; -- note: this is skyblock adjusted local ppos = {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry+1,z=round(pos.z/r+0.5)*r}; -- just on top of basic_protect:protector! local meta = minetest.get_meta(ppos); local name = meta:get_string("name"); @@ -595,7 +595,7 @@ minetest.register_node("basic_robot:button"..number, on_punch = function(pos, node, player) local name = player:get_player_name(); if name==nil then return end local round = math.floor; - local r = 32; local ry = 2*r; + local r = basic_robot.radius; local ry = 2*r; local ppos = {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry+1,z=round(pos.z/r+0.5)*r}; local meta = minetest.get_meta(ppos); local name = meta:get_string("name"); @@ -618,7 +618,7 @@ minetest.register_node("basic_robot:button_"..number, on_punch = function(pos, node, player) local name = player:get_player_name(); if name==nil then return end local round = math.floor; - local r = 32; local ry = 2*r; + local r = basic_robot.radius; local ry = 2*r; local ppos = {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry+1,z=round(pos.z/r+0.5)*r}; local meta = minetest.get_meta(ppos); local name = meta:get_string("name"); @@ -640,7 +640,7 @@ minetest.register_node("basic_robot:button_"..number, on_punch = function(pos, node, player) local name = player:get_player_name(); if name==nil then return end local round = math.floor; - local r = 32; local ry = 2*r; + local r = basic_robot.radius; local ry = 2*r; local ppos = {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry+1,z=round(pos.z/r+0.5)*r}; local meta = minetest.get_meta(ppos); local name = meta:get_string("name"); @@ -675,6 +675,9 @@ register_robot_button_custom(281,"puzzle_NOT") register_robot_button_custom(282,"puzzle_delayer") register_robot_button_custom(283,"puzzle_platform") +register_robot_button_custom(284,"puzzle_giver") +register_robot_button_custom(285,"puzzle_checker") + -- interactive button for robot: place robot on top of protector to intercept events @@ -1184,7 +1187,7 @@ basic_robot.commands.crypto = {encrypt = encrypt, decrypt = decrypt, scramble = local is_same_block = function(pos1,pos2) local round = math.floor; - local r = 32; local ry = 2*r; -- note: this is skyblock adjusted + local r = basic_robot.radius; local ry = 2*r; -- note: this is skyblock adjusted local ppos1 = {round(pos1.x/r+0.5)*r,round(pos1.y/ry+0.5)*ry,round(pos1.z/r+0.5)*r}; local ppos2 = {round(pos2.x/r+0.5)*r,round(pos2.y/ry+0.5)*ry,round(pos2.z/r+0.5)*r}; return ppos1[1]==ppos2[1] and ppos1[2]==ppos2[2] and ppos1[3] == ppos2[3] diff --git a/init.lua b/init.lua index 3526921..290ef65 100644 --- a/init.lua +++ b/init.lua @@ -6,9 +6,10 @@ basic_robot = {}; basic_robot.call_limit = 48; -- how many execution calls per script run allowed basic_robot.entry_count = 2 -- how many robot ordinary player can have basic_robot.advanced_count = 16 -- how many robots player with robot privs can have +basic_robot.radius = 32; -- divide whole world into blocks of this size - used for managing events like keyboard punches +basic_robot.password = "robot passw0rd"; -- IMPORTANT: change it before running mod, server private password used for authentifications - -basic_robot.bad_inventory_blocks = { -- disallow taking from these nodes inventories +basic_robot.bad_inventory_blocks = { -- disallow taking from these nodes inventories to prevent player abuses ["craft_guide:sign_wall"] = true, } basic_robot.maxoperations = 2; -- how many operations (dig, generate energy,..) available per run, 0 = unlimited @@ -17,14 +18,14 @@ basic_robot.dig_require_energy = true; -- does robot require energy to dig? basic_robot.http_api = minetest.request_http_api(); -basic_robot.version = "2017/10 /07a"; +basic_robot.version = "2017/12/18a"; basic_robot.data = {}; -- stores all robot data --[[ [name] = { sandbox= .., bytecode = ..., ram = ..., obj = robot object,spawnpos=...} robot object = object of entity, used to manipulate movements and more --]] -basic_robot.ids = {}; -- stores maxid for all players +basic_robot.ids = {}; -- stores maxid for each player --[name] = {id = .., maxid = .. }, current id, how many robot ids player can use basic_robot.data.listening = {}; -- which robots listen to chat @@ -38,6 +39,8 @@ local check_code, preprocess_code,is_inside_string; function getSandboxEnv (name) + local authlevel = basic_robot.data[name].authlevel or 0; + local commands = basic_robot.commands; local directions = {left = 1, right = 2, forward = 3, backward = 4, up = 5, down = 6, left_down = 7, right_down = 8, forward_down = 9, backward_down = 10, @@ -114,17 +117,6 @@ function getSandboxEnv (name) return sender,mail end, - read_form = function() - local fields = basic_robot.data[name].read_form; - local sender = basic_robot.data[name].form_sender; - basic_robot.data[name].read_form = nil; - basic_robot.data[name].form_sender = nil; - return sender,fields - end, - - show_form = function(playername, form) - commands.show_form(name, playername, form) - end, send_mail = function(target,mail) if not basic_robot.data[target] then return false end @@ -328,7 +320,7 @@ function getSandboxEnv (name) write = function(i,title,text) if i<=0 or i > 32 then return nil end local inv = minetest.get_meta(basic_robot.data[name].spawnpos):get_inventory(); - local stack = basic_robot.commands.write_book(name,title,text); + local stack = basic_robot.commands.write_book(basic_robot.data[name].owner,title,text); if stack then inv:set_stack("library", i, stack) end end }, @@ -346,7 +338,7 @@ function getSandboxEnv (name) end, run = function(script) - if basic_robot.data[name].isadmin ~= 1 then + if basic_robot.data[name].authlevel < 3 then local err = check_code(script); script = preprocess_code(script); if err then @@ -485,10 +477,23 @@ function getSandboxEnv (name) env.write_text[dir] = function(text) return commands.write_text(name, dir_id,text) end end - -- set up sandbox for puzzle + if authlevel>=1 then -- robot privs + env.self.read_form = function() + local fields = basic_robot.data[name].read_form; + local sender = basic_robot.data[name].form_sender; + basic_robot.data[name].read_form = nil; + basic_robot.data[name].form_sender = nil; + return sender,fields + end + + env.self.show_form = function(playername, form) + commands.show_form(name, playername, form) + end + end - local ispuzzle = basic_robot.data[name].ispuzzle; -- need puzzle privs - if ispuzzle == 1 then + -- set up sandbox for puzzle + + if authlevel>=2 then -- puzzle privs basic_robot.data[name].puzzle = {}; local data = basic_robot.data[name]; local pdata = data.puzzle; @@ -516,13 +521,13 @@ function getSandboxEnv (name) pdata = pdata, ItemStack = ItemStack, } + end + --special sandbox for admin - local isadmin=basic_robot.data[name].isadmin - - if isadmin~=1 then + if authlevel<3 then -- is admin? env._G = env; else env.minetest = minetest; @@ -675,7 +680,7 @@ end local function setCode( name, script ) -- to run script: 1. initSandbox 2. setCode 3. runSandbox local err; - if basic_robot.data[name].isadmin~=1 then + if basic_robot.data[name].authlevel<3 then -- not admin err = check_code(script); script = preprocess_code(script); end @@ -806,9 +811,7 @@ local function init_robot(obj) basic_robot.data[name].quiet_mode = false; -- can chat globally -- check if admin robot - if self.isadmin then basic_robot.data[name].isadmin = 1 end - -- can we do puzzles? - if self.ispuzzle then basic_robot.data[name].ispuzzle = 1 end + basic_robot.data[name].authlevel = self.authlevel or 0 --robot appearance,armor... obj:set_properties({infotext = "robot " .. name}); @@ -856,6 +859,8 @@ minetest.register_entity("basic_robot:robot",{ end self.owner = data.owner; + self.authlevel = data.authlevel; + self.spawnpos = {x=data.spawnpos.x,y=data.spawnpos.y,z=data.spawnpos.z}; init_robot(self.object); self.running = 1; @@ -985,7 +990,13 @@ local spawn_robot = function(pos,node,ttl) basic_robot.data[name] = {}; data = basic_robot.data[name]; meta:set_string("infotext",minetest.get_gametime().. " code changed ") data.owner = owner; - if meta:get_int("admin") == 1 then data.isadmin = 1 end + data.authlevel = meta:get_int("authlevel") + + local sec_hash = minetest.get_password_hash("",data.authlevel.. owner .. basic_robot.password) + if meta:get_string("sec_hash")~= sec_hash then + minetest.chat_send_all("#ROBOT: " .. name .. " is using fake auth level. dig and place again.") + return + end if not data.obj then --create virtual robot that reports position and other properties @@ -1007,8 +1018,8 @@ local spawn_robot = function(pos,node,ttl) if not data.bytecode then local script = meta:get_string("code"); - - if data.isadmin~=1 then + + if data.authlevel<3 then -- not admin err = check_code(script); script = preprocess_code(script); end @@ -1059,8 +1070,14 @@ local spawn_robot = function(pos,node,ttl) luaent.name = name; luaent.code = meta:get_string("code"); luaent.spawnpos = {x=pos.x,y=pos.y-1,z=pos.z}; - if meta:get_int("admin") == 1 then luaent.isadmin = 1 end - if meta:get_int("puzzle") == 1 then luaent.ispuzzle = 1 end + luaent.authlevel = meta:get_int("authlevel") + + local sec_hash = minetest.get_password_hash("",luaent.authlevel.. owner .. basic_robot.password) + if meta:get_string("sec_hash")~= sec_hash then + minetest.chat_send_all("#ROBOT: " .. name .. " is using fake auth level. dig and place again.") + obj:remove(); + return + end local data = basic_robot.data[name]; if data == nil then @@ -1720,10 +1737,24 @@ minetest.register_node("basic_robot:spawner", { alpha = 150, after_place_node = function(pos, placer) local meta = minetest.env:get_meta(pos) - meta:set_string("owner", placer:get_player_name()); + local owner = placer:get_player_name(); + meta:set_string("owner", owner); + local privs = minetest.get_player_privs(placer:get_player_name()); - if privs.privs then meta:set_int("admin",1) end - if privs.puzzle then meta:set_int("puzzle",1) end + local authlevel = 0; + if privs.privs then -- set auth level depending on privs + authlevel = 3 + elseif privs.puzzle then + authlevel = 2 + elseif privs.robot then + authlevel = 1 + else + authlevel = 0 + end + + meta:set_int("authlevel",authlevel) + local sec_hash = minetest.get_password_hash("",authlevel .. owner .. basic_robot.password) -- 'digitally sign' authlevel using password + meta:set_string("sec_hash", sec_hash); meta:set_string("code",""); meta:set_int("id",1); -- initial robot id @@ -1827,9 +1858,9 @@ minetest.register_craftitem("basic_robot:control", { local owner = user:get_player_name(); local script = itemstack:get_metadata(); - if script == "@" then -- remote control as a tool - notify robot in current block of pointed position + if script == "@" then -- remote control as a tool - notify robot in current block of pointed position, using keyboard event type 0 local round = math.floor; - local r = 32; local ry = 2*r; -- note: this is skyblock adjusted + local r = basic_robot.radius; local ry = 2*r; -- note: this is skyblock adjusted local pos = pointed_thing.under if not pos then return end local ppos = {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry+1,z=round(pos.z/r+0.5)*r}; -- just on top of basic_protect:protector! @@ -1850,7 +1881,7 @@ minetest.register_craftitem("basic_robot:control", { if data and data.sandbox then else - minetest.chat_send_player(name, "#remote control: your robot must be running"); + minetest.chat_send_player(owner, "#remote control: your robot must be running"); return end @@ -1859,7 +1890,7 @@ minetest.register_craftitem("basic_robot:control", { if t1-t0<1 then return end data.remoteuse = t1; - if data.isadmin == 1 then + if data.authlevel >= 3 then local privs = minetest.get_player_privs(owner); -- only admin can run admin robot if not privs.privs then return @@ -1872,7 +1903,7 @@ minetest.register_craftitem("basic_robot:control", { return end - if not data.isadmin then + if data.authlevel<3 then if check_code(script)~=nil then return end end diff --git a/scripts/sokoban_game.lua b/scripts/sokoban_game.lua index 99d0b1c..3d3e8af 100644 --- a/scripts/sokoban_game.lua +++ b/scripts/sokoban_game.lua @@ -1,7 +1,7 @@ -- SOKOBAN GAME, by rnd, robots port if not sokoban then sokoban = {}; - local players = find_player(4); + local players = find_player(5); if not players then error("sokoban: no player near") end name = players[1]; @@ -37,7 +37,7 @@ if lvl == nil then return end if lvl <0 or lvl >89 then return end - local file = _G.io.open(minetest.get_modpath("basic_robot").."/scripts/sokoban.txt","r") + local file = _G.io.open(minetest.get_modpath("basic_robot").."\\scripts\\sokoban.txt","r") if not file then return end local str = ""; local s; local p = {x=pos.x,y=pos.y,z=pos.z}; local i,j;i=0; local lvl_found = false diff --git a/textures/puzzle_checker.png b/textures/puzzle_checker.png new file mode 100644 index 0000000000000000000000000000000000000000..25a6d41151c9a1cfb3440051c06193acd5d48514 GIT binary patch literal 732 zcmV<20wev2P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02y>eSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E-^5z3JSmg00K-&L_t(IPi2z(a+*LC#(A2)MsJg88cR?> zM8G>jYy^!669l}V@fMAjs4*svHE}YTPWz7itTXv1JKrn^_V+F4oL%D2^W)2Uv3r zMglXQAyX0u!+6j&FLLKNUXjuLuvpK>VuayBq!4A_8?p%@9p||ag&yuxYS-+t zrUnDYNr}xQ#P^1Ro=Ztl^v%dCfQjo?6+Mo!A%Q!USn|Dr{Be9}D=@%&gKcOO`Mulm z7qe+L8F}*{DCL#uXjt`}FP}dG+Z%A^m9ic@JwXB2!`@Z15vKN~LotEcZRSSl9BpNp z5HP?*ukLiJc7$cml(Zrz+=`Wq^MDdDPLX3Z&x}i9HJb`E6fnTVa@5DIa>^IJTOPEl zj;Xinj;5r3%JGV!Yf7@1lg&atuVk7Pv+Z3HyZbrL{ORs?yO?5zHp}Ux-)h(fs&vY_ zXB8pDXi?L(2wdHMvpVYfSJg{=!u9I;ZrwJDxs0x+ApGPIScP2aJo^v$j7hIt%ACaj O0000Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02y>eSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E-^5z3JSmg00L@BL_t(IPc4#LQ`%4v$IlavFZk&A;AiQy zola3214#%W3HOjlB>@S^7;+H;auehtAfgOK8OQ0g-?5A7&VM#L$!||~_bmGJ`uw(< zZ=a^%e{YuW>jmiLanh?>gXT48)OI^{vt6q~+;2E&vlzqYzuVP%J_N01cfTG+&-VkZ zAX%znSBhp?wzMJ$j;LR$2p&ySmohxh5DXb2@nGRxNW>yxJjk(h@HBv9!6<>JIL0W; zuBoH96%;UKNG#3MkTB|Zw9EX3l+0%0YFV+ZDjgwBUF8|-buoQ^ULdF*1jm$$@^mts z-gOxAJNht5U@uF`px;fzIgX8bB!U*9ZjuOX)~kN6sVag;dnU^n+cX+(jR@m_0SpPt z<+#t%1c<=CdEEZ~{=vb47Zcdmc#Ps`YB}!h61GqC)ojE?Nji+NF$xHu&*z~>M@Qgu zNj8&U=r9g5+?CY2HY&0d3If^iLsCRTWuGmGXjCEEL3S zqpG#+E3|!_!JWT6+;8R+@Syc#GVV3&h6-Jp6~)#|Ac$c^4NFI`y1j-o?6^116}*D= s>bh3VP)qr&BBep_6EDz<`SL~XA8vs$-)ydV_y7O^07*qoM6N<$f=oD6MF0Q* literal 0 HcmV?d00001