SaferLua added

Lua controller added
This commit is contained in:
Joachim Stolberg 2018-06-24 22:33:00 +02:00
parent eb0ea4602a
commit 7d8d25026c
17 changed files with 317 additions and 37 deletions

6
safer_lua/.gitignore vendored Normal file

@ -0,0 +1,6 @@
.buildpath
.project
org.eclipse.*
test_*.lua

@ -1,4 +1,4 @@
SaferLUA [safer_lua], a subset of the language LUA for safe and secure LUA sandboxes
SaferLua [safer_lua], a subset of the language Lua for safe and secure Lua sandboxes

@ -1,3 +1,17 @@
--[[
SaferLua [safer_lua]
====================
Copyright (C) 2018 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
environ.lua:
]]--
safer_lua.MaxCodeSize = 1000 -- size in length of byte code
safer_lua.MaxTableSize = 1000 -- number of table entries considering string lenghts

@ -1,13 +1,15 @@
--[[
SaferLUA
========
SaferLua [safer_lua]
====================
Copyright (C) 2018 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
environ.lua:
]]--
safer_lua = {}

@ -1,11 +1,19 @@
SaferLUA [safer_lua]
====================
SaferLua [safer_lua] v0.01
==========================
A subset of the language LUA for safe and secure LUA sandboxes with:
A subset of the language Lua for safe and secure Lua sandboxes with:
- limited code length
- limited execution time
- limited memory use
- limited posibilities to call functions
### License
Copyright (C) 2018 Joachim Stolberg
Code: Licensed under the GNU LGPL version 2.1 or later. See LICENSE.txt
### Dependencies
none
### History
- 2018-06-24 v0.01 * first draft

@ -1,3 +1,17 @@
--[[
SaferLua [safer_lua]
====================
Copyright (C) 2018 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
scanner.lua:
]]--
local function trim(s)
return (s:gsub("^%s*(.-)%s*$", "%1"))
end

@ -1,3 +1,17 @@
--[[
SaferLua [safer_lua]
====================
Copyright (C) 2018 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
store.lua:
]]--
safer_lua.StoreHelp = [[
Store - a secure shell over the LUA table type.

121
sl_controller/battery.lua Normal file

@ -0,0 +1,121 @@
--[[
sl_controller
=============
Copyright (C) 2018 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
battery.lua:
]]--
local function on_timer(pos, elapsed)
local meta = minetest.get_meta(pos)
local percent = (sl_controller.battery_capacity - meta:get_int("content"))
percent = 100 - math.floor((percent * 100.0 / sl_controller.battery_capacity))
print("percent", percent, meta:get_int("content"))
meta:set_string("infotext", "Battery ("..percent.."%)")
if percent == 0 then
local node = minetest.get_node(pos)
node.name = "sl_controller:battery_empty"
minetest.swap_node(pos, node)
return false
end
return true
end
minetest.register_node("sl_controller:battery", {
description = "Battery",
inventory_image = 'sl_controller_battery_inventory.png',
wield_image = 'sl_controller_battery_inventory.png',
tiles = {
-- up, down, right, left, back, front
"smartline.png",
"smartline.png",
"smartline.png",
"smartline.png",
"smartline.png",
"smartline.png^sl_controller_battery_green.png",
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{ -6/32, -6/32, 14/32, 6/32, 6/32, 16/32},
},
},
after_place_node = function(pos, placer)
local meta = minetest.get_meta(pos)
meta:set_int("content", sl_controller.battery_capacity)
minetest.get_node_timer(pos):start(2)
end,
on_timer = on_timer,
paramtype = "light",
sunlight_propagates = true,
paramtype2 = "facedir",
groups = {choppy=1, cracky=1, crumbly=1},
is_ground_content = false,
sounds = default.node_sound_stone_defaults(),
})
minetest.register_node("sl_controller:battery_empty", {
description = "Battery",
tiles = {
-- up, down, right, left, back, front
"smartline.png",
"smartline.png",
"smartline.png",
"smartline.png",
"smartline.png",
"smartline.png^sl_controller_battery_red.png",
},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{ -6/32, -6/32, 14/32, 6/32, 6/32, 16/32},
},
},
after_place_node = function(pos, placer)
local meta = minetest.get_meta(pos)
meta:set_int("content", nil)
end,
paramtype = "light",
sunlight_propagates = true,
paramtype2 = "facedir",
groups = {choppy=1, cracky=1, crumbly=1, not_in_creative_inventory=1},
drop = "",
is_ground_content = false,
sounds = default.node_sound_stone_defaults(),
})
if minetest.global_exists("moreores") then
minetest.register_craft({
output = "sl_controller:battery 2",
recipe = {
{"", "moreores:silver_ingot", ""},
{"", "default:copper_ingot", ""},
{"", "moreores:silver_ingot", ""},
}
})
else
minetest.register_craft({
output = "sl_controller:battery 2",
recipe = {
{"", "default:tin_ingot", ""},
{"", "default:copper_ingot", ""},
{"", "default:tin_ingot", ""},
}
})
end

@ -17,6 +17,7 @@
sl_controller.register_function("get_input", {
cmnd = function(self, num)
_G = self._G
num = tostring(num or "")
return sl_controller.get_input(self.meta.number, num)
end,
help = " $get_input(num) --> 'on', 'off', or nil\n"..
@ -28,6 +29,7 @@ sl_controller.register_function("get_input", {
sl_controller.register_function("get_status", {
cmnd = function(self, num)
_G = self._G
num = tostring(num or "")
return tubelib.send_request(num, "state", nil)
end,
help = " $get_status(num) --> 'stopped', 'running',\n"..
@ -65,6 +67,7 @@ sl_controller.register_function("time_as_num", {
sl_controller.register_function("playerdetector", {
cmnd = function(self, num)
_G = self._G
num = tostring(num or "")
return tubelib.send_request(num, "name", nil)
end,
help = " $playerdetector(num) --> e.g. 'Joe'\n"..
@ -75,6 +78,8 @@ sl_controller.register_function("playerdetector", {
sl_controller.register_action("send_cmnd", {
cmnd = function(self, num, text)
_G = self._G
num = tostring(num or "")
text = tostring(text or "")
tubelib.send_message(num, self.meta.owner, nil, text, nil)
end,
help = " $send_cmnd(num, text)\n"..
@ -87,8 +92,10 @@ sl_controller.register_action("send_cmnd", {
sl_controller.register_action("display", {
cmnd = function(self, num, row, text1, text2, text3)
_G = self._G
local text = (text1 or "") .. (text2 or "") .. (text3 or "")
tubelib.send_message(num, self.meta.owner, nil, "row", {row = row, str = text})
text1 = tostring(text1 or "")
text2 = tostring(text2 or "")
text3 = tostring(text3 or "")
tubelib.send_message(num, self.meta.owner, nil, "row", {row = row, str = text1..text2..text3})
end,
help = " $display(num, row, text,...)\n"..
" Send a text line to the display with number 'num'.\n"..
@ -100,6 +107,7 @@ sl_controller.register_action("display", {
sl_controller.register_action("clear_screen", {
cmnd = function(self, num)
_G = self._G
num = tostring(num or "")
tubelib.send_message(num, self.meta.owner, nil, "clear", nil)
end,
help = " $clear_screen(num)\n"..
@ -109,18 +117,24 @@ sl_controller.register_action("clear_screen", {
})
sl_controller.register_action("chat", {
cmnd = function(self, text)
cmnd = function(self, text1, text2, text3)
_G = self._G
minetest.chat_send_player(self.meta.owner, "[SmartLine Controller] "..text)
text1 = tostring(text1 or "")
text2 = tostring(text2 or "")
text3 = tostring(text3 or "")
minetest.chat_send_player(self.meta.owner, "[SmartLine Controller] "..text1..text2..text3)
end,
help = " $chat(text)\n"..
help = " $chat(text,...)\n"..
" Send yourself a chat message.\n"..
' example: $chat("Hello")'
" The function accepts up to 3 text parameters\n"..
' example: $chat("Hello ", name)'
})
sl_controller.register_action("door", {
cmnd = function(self, pos, text)
_G = self._G
pos = tostring(pos or "")
text = tostring(text or "")
pos = minetest.string_to_pos("("..pos..")")
if pos then
local door = doors.get(pos)

2
sl_controller/config.lua Normal file

@ -0,0 +1,2 @@
-- Battery capacity in usec CPU time
sl_controller.battery_capacity = tonumber(minetest.setting_get("battery_capacity")) or 10000000

@ -12,20 +12,16 @@
]]--
local sHELP = [[Safer LUA Controller
local sHELP = [[SaferLua Controller
Safer LUA is a subset of LUA with the following restrictions:
- No loop keywords like: for, while, repeat,...
- No table constructions via: { ... }
- No table construction {..}
- Limited set of available functions
- Store() as alternative to LUA tables
]]
local mail_exists = minetest.get_modpath("mail") and mail ~= nil
sl_controller = {}
local Cache = {}
local tCommands = {}
@ -74,8 +70,10 @@ sl_controller.register_action("print", {
cmnd = function(self, text1, text2, text3)
_G = self._G
local pos = self.meta.pos
local text = (text1 or "")..(text2 or "")..(text3 or "")
output(pos, text)
text1 = tostring(text1 or "")
text2 = tostring(text2 or "")
text3 = tostring(text3 or "")
output(pos, text1..text2..text3)
end,
help = "$print(text,...)\n"..
"Send a text line to the output window.\n"..
@ -84,6 +82,19 @@ sl_controller.register_action("print", {
})
local function formspec0(meta)
local running = meta:get_int("state") == tubelib.RUNNING
local cmnd = running and "stop;Stop" or "start;Start"
local init = meta:get_string("init")
init = minetest.formspec_escape(init)
return "size[4,3]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
"label[0,0;No Battery?]"..
"button[1,2;1.8,1;start;Start]"
end
local function formspec1(meta)
local running = meta:get_int("state") == tubelib.RUNNING
local cmnd = running and "stop;Stop" or "start;Start"
@ -163,6 +174,7 @@ local function error(pos, err)
output(pos, err)
local meta = minetest.get_meta(pos)
local number = meta:get_string("number")
meta:set_string("formspec", formspec3(meta))
meta:set_string("infotext", "Controller "..number..": error")
return false
end
@ -182,18 +194,12 @@ local function compile(pos, meta, number)
return false
end
local function on_timer(pos, elapsed)
local t = minetest.get_us_time()
local function battery(pos)
local battery_pos = minetest.find_node_near(pos, 1, {"sl_controller:battery"})
if battery_pos then
local meta = minetest.get_meta(pos)
local number = meta:get_string("number")
if Cache[number] or compile(pos, meta, number) then
local code = Cache[number].code
local res = safer_lua.run_loop(pos, elapsed, code, error)
t = minetest.get_us_time() - t
print("time", t)
return res
meta:set_string("battery", minetest.pos_to_string(battery_pos))
return true
end
return false
end
@ -201,6 +207,10 @@ end
local function start_controller(pos)
local meta = minetest.get_meta(pos)
local number = meta:get_string("number")
if not battery(pos) then
meta:set_string("formspec", formspec0(meta))
return
end
if compile(pos, meta, number) then
meta:set_int("state", tubelib.RUNNING)
minetest.get_node_timer(pos):start(1)
@ -219,6 +229,58 @@ local function stop_controller(pos)
meta:set_string("formspec", formspec2(meta))
end
local function no_battery(pos)
local meta = minetest.get_meta(pos)
local number = meta:get_string("number")
meta:set_int("state", tubelib.STOPPED)
minetest.get_node_timer(pos):stop()
meta:set_string("infotext", "Controller "..number..": No battery")
meta:set_string("formspec", formspec0(meta))
end
local function update_battery(meta, cpu)
local pos = minetest.string_to_pos(meta:get_string("battery"))
if pos then
meta = minetest.get_meta(pos)
local content = meta:get_int("content") - cpu
print("content", content)
if content <= 0 then
meta:set_int("content", 0)
return false
end
meta:set_int("content", content)
return true
end
end
local function on_timer(pos, elapsed)
local t = minetest.get_us_time()
local meta = minetest.get_meta(pos)
local number = meta:get_string("number")
if Cache[number] or compile(pos, meta, number) then
local cpu = meta:get_int("cpu") or 0
local code = Cache[number].code
local res = safer_lua.run_loop(pos, elapsed, code, error)
if res then
t = minetest.get_us_time() - t
cpu = math.floor(((cpu * 20) + t) / 21)
meta:set_int("cpu", cpu)
meta:set_string("infotext", "Controller "..number..": running ("..cpu.."us)")
if not update_battery(meta, cpu) then
no_battery(pos)
return false
end
else
stop_controller(pos)
end
return res
else
stop_controller(pos)
end
return false
end
local function on_receive_fields(pos, formname, fields, player)
if minetest.is_protected(pos, player:get_player_name()) then
return
@ -267,7 +329,7 @@ local function on_receive_fields(pos, formname, fields, player)
end
minetest.register_node("sl_controller:controller", {
description = "SaferLUA Controller",
description = "SaferLua Controller",
inventory_image = "sl_controller_inventory.png",
wield_image = "sl_controller_inventory.png",
stack_max = 1,

@ -1,2 +1,2 @@
tbd.
SaferLua Controller - a controller to be programmed in LUA

@ -10,5 +10,9 @@
]]--
sl_controller = {}
dofile(minetest.get_modpath("sl_controller") .. "/config.lua")
dofile(minetest.get_modpath("sl_controller") .. "/controller.lua")
dofile(minetest.get_modpath("sl_controller") .. "/commands.lua")
dofile(minetest.get_modpath("sl_controller") .. "/battery.lua")

19
sl_controller/readme.md Normal file

@ -0,0 +1,19 @@
SaferLua Controller [sl_controller] v0.01
=========================================
A tubelib compatible controller to be programmed in LUA
The mod uses SaferLua [safer_lua] as Lua sandbox for safe and secure code execution.
### License
Copyright (C) 2018 Joachim Stolberg
Code: Licensed under the GNU LGPL version 2.1 or later. See LICENSE.txt
### Dependencies
tubelib, safer_lua
### History
- 2018-06-24 v0.01 * first draft

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 B