sandbox.lua 4.35 KB
Newer Older
1 2
-- Units
kB = 1024
3 4
MB = 1024*kB
GB = 1024*MB
5 6 7 8
-- Time
sec = 1000
minute = 60 * sec
hour = 60 * minute
9
day = 24 * hour
10

11 12
-- Resolver bindings
kres = require('kres')
13
trust_anchors = require('trust_anchors')
14
resolve = worker.resolve
15

16 17 18 19 20 21 22 23 24
-- Function aliases
-- `env.VAR returns os.getenv(VAR)`
env = {}
setmetatable(env, {
	__index = function (t, k) return os.getenv(k) end
})

-- Quick access to interfaces
-- `net.<iface>` => `net.interfaces()[iface]`
25
-- `net = {addr1, ..}` => `net.listen(name, addr1)`
26 27 28 29 30 31
setmetatable(net, {
	__index = function (t, k)
		local v = rawget(t, k)
		if v then return v
		else return net.interfaces()[k]
		end
32 33 34 35 36 37
	end,
	__newindex = function (t,k,v)
		local iname = rawget(net.interfaces(), v)
		if iname then t.listen(iname)
		else t.listen(v)
		end
38 39 40
	end
})

41 42
-- Syntactic sugar for module loading
-- `modules.<name> = <config>`
43
setmetatable(modules, {
44
	__newindex = function (t,k,v)
45
		if type(k) == 'number' then k = v end
46 47
		if not rawget(_G, k) then
			modules.load(k)
48 49 50 51 52
			local mod = _G[k]
			if mod and mod['config'] then
				if k ~= v then mod['config'](v)
				else           mod['config']()
				end
53 54
			end
		end
55 56 57 58 59 60 61
	end
})

-- Syntactic sugar for cache
-- `cache.{size|storage} = value`
setmetatable(cache, {
	__newindex = function (t,k,v)
62 63 64 65 66 67 68 69
		-- Defaults
		local storage = rawget(t, 'current_storage')
		if not storage then storage = 'lmdb://' end
		local size = rawget(t, 'current_size')
		if not size then size = 10*MB end
		-- Declarative interface for cache
		if     k == 'size'    then t.open(v, storage)
		elseif k == 'storage' then t.open(size, v)
70
		else   rawset(t, k, v) end
71
	end
72
})
73 74
-- Defaults
cache.size = 10 * MB
75

76 77 78 79
-- Syntactic sugar for TA store
setmetatable(trust_anchors, {
	__newindex = function (t,k,v)
	if     k == 'file' then t.config(v)
80
	elseif k == 'negative' then t.set_insecure(v)
81 82 83 84
	else   rawset(t, k, v) end
	end,
})

85 86 87 88 89 90 91
-- Register module in Lua environment
function modules_register(module)
	-- Syntactic sugar for get() and set() properties
	setmetatable(module, {
		__index = function (t, k)
			local  v = rawget(t, k)
			if     v     then return v
92
			elseif rawget(t, 'get') then return t.get(k)
93 94 95 96
			end
		end,
		__newindex = function (t, k, v)
			local  old_v = rawget(t, k)
97
			if not old_v and rawget(t, 'set') then
98 99 100 101 102 103
				t.set(k..' '..v)
			end
		end
	})
end

104
-- Make sandboxed environment
105
local function make_sandbox(defined)
106
	local __protected = { modules = true, cache = true, net = true, trust_anchors = true }
107 108 109 110 111 112 113 114 115 116 117 118 119
	return setmetatable({}, {
		__index = defined,
		__newindex = function (t, k, v)
			if __protected[k] then
				for k2,v2 in pairs(v) do
					defined[k][k2] = v2
				end
			else
				defined[k] = v
			end
		end
	})
end
120

121
-- Compatibility sandbox
122 123 124 125 126 127
if setfenv then -- Lua 5.1 and less
	_G = make_sandbox(getfenv(0))
	setfenv(0, _G)
else -- Lua 5.2+
	_SANDBOX = make_sandbox(_ENV)
end
128

129 130 131 132 133 134 135 136 137 138 139
-- Interactive command evaluation
function eval_cmd(line)
	-- Compatibility sandbox code loading
	local function load_code(code)
	    if getfenv then -- Lua 5.1
	        return loadstring(code)
	    else            -- Lua 5.2+
	        return load(code, nil, 't', _ENV)
	    end
	end
	local status, err, chunk
140
	chunk, err = load_code('return table_print('..line..')')
141 142 143 144
	if err then
		chunk, err = load_code(line)
	end
	if not err then
145 146 147
		return chunk()
	else
		error(err)
148 149 150
	end
end

151 152 153 154
-- Pretty printing
function table_print (tt, indent, done)
	done = done or {}
	indent = indent or 0
155
	result = ""
156 157 158 159 160 161 162 163 164 165 166 167 168
	-- Convert to printable string (escape unprintable)
	local function printable(value)
		value = tostring(value)
		local bytes = {}
		for i = 1, #value do
			local c = string.byte(value, i)
			if c >= 0x20 and c < 0x7f then table.insert(bytes, string.char(c))
			else                           table.insert(bytes, '\\'..tostring(c))
			end
			if i > 50 then table.insert(bytes, '...') break end
		end
		return table.concat(bytes)
	end
169 170
	if type(tt) == "table" then
		for key, value in pairs (tt) do
171
			result = result .. string.rep (" ", indent)
172 173
			if type (value) == "table" and not done [value] then
				done [value] = true
174
				result = result .. string.format("[%s] => {\n", printable (key))
175
				result = result .. table_print (value, indent + 4, done)
176 177
				result = result .. string.rep (" ", indent)
				result = result .. "}\n"
178
			else
179
				result = result .. string.format("[%s] => %s\n",
180
				         tostring (key), printable(value))
181 182 183
			end
		end
	else
184
		result = result .. tostring(tt) .. "\n"
185
	end
186
	return result
187
end