Line data Source code
1 : /*
2 : Minetest
3 : Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 :
5 : This program is free software; you can redistribute it and/or modify
6 : it under the terms of the GNU Lesser General Public License as published by
7 : the Free Software Foundation; either version 2.1 of the License, or
8 : (at your option) any later version.
9 :
10 : This program is distributed in the hope that it will be useful,
11 : but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : GNU Lesser General Public License for more details.
14 :
15 : You should have received a copy of the GNU Lesser General Public License along
16 : with this program; if not, write to the Free Software Foundation, Inc.,
17 : 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 : */
19 :
20 : #include "lua_api/l_util.h"
21 : #include "lua_api/l_internal.h"
22 : #include "common/c_converter.h"
23 : #include "common/c_content.h"
24 : #include "cpp_api/s_async.h"
25 : #include "serialization.h"
26 : #include "json/json.h"
27 : #include "cpp_api/s_security.h"
28 : #include "debug.h"
29 : #include "porting.h"
30 : #include "log.h"
31 : #include "tool.h"
32 : #include "filesys.h"
33 : #include "settings.h"
34 : #include "util/auth.h"
35 : #include <algorithm>
36 :
37 : // debug(...)
38 : // Writes a line to dstream
39 0 : int ModApiUtil::l_debug(lua_State *L)
40 : {
41 0 : NO_MAP_LOCK_REQUIRED;
42 : // Handle multiple parameters to behave like standard lua print()
43 0 : int n = lua_gettop(L);
44 0 : lua_getglobal(L, "tostring");
45 0 : for (int i = 1; i <= n; i++) {
46 : /*
47 : Call tostring(i-th argument).
48 : This is what print() does, and it behaves a bit
49 : differently from directly calling lua_tostring.
50 : */
51 0 : lua_pushvalue(L, -1); /* function to be called */
52 0 : lua_pushvalue(L, i); /* value to print */
53 0 : lua_call(L, 1, 1);
54 : size_t len;
55 0 : const char *s = lua_tolstring(L, -1, &len);
56 0 : if (i > 1)
57 0 : dstream << "\t";
58 0 : if (s)
59 0 : dstream << std::string(s, len);
60 0 : lua_pop(L, 1);
61 : }
62 0 : dstream << std::endl;
63 0 : return 0;
64 : }
65 :
66 : // log([level,] text)
67 : // Writes a line to the logger.
68 : // The one-argument version logs to infostream.
69 : // The two-argument version accept a log level: error, action, info, or verbose.
70 4 : int ModApiUtil::l_log(lua_State *L)
71 : {
72 8 : NO_MAP_LOCK_REQUIRED;
73 8 : std::string text;
74 4 : LogMessageLevel level = LMT_INFO;
75 4 : if (lua_isnone(L, 2)) {
76 0 : text = lua_tostring(L, 1);
77 : }
78 : else {
79 8 : std::string levelname = luaL_checkstring(L, 1);
80 4 : text = luaL_checkstring(L, 2);
81 4 : if(levelname == "error")
82 0 : level = LMT_ERROR;
83 4 : else if(levelname == "action")
84 0 : level = LMT_ACTION;
85 4 : else if(levelname == "verbose")
86 0 : level = LMT_VERBOSE;
87 4 : else if (levelname == "deprecated") {
88 0 : log_deprecated(L,text);
89 0 : return 0;
90 : }
91 :
92 : }
93 4 : log_printline(level, text);
94 4 : return 0;
95 : }
96 :
97 : #define CHECK_SECURE_SETTING(L, name) \
98 : if (name.compare(0, 7, "secure.") == 0) {\
99 : lua_pushliteral(L, "Attempt to set secure setting.");\
100 : lua_error(L);\
101 : }
102 :
103 : // setting_set(name, value)
104 10 : int ModApiUtil::l_setting_set(lua_State *L)
105 : {
106 20 : NO_MAP_LOCK_REQUIRED;
107 20 : std::string name = luaL_checkstring(L, 1);
108 20 : std::string value = luaL_checkstring(L, 2);
109 10 : CHECK_SECURE_SETTING(L, name);
110 10 : g_settings->set(name, value);
111 20 : return 0;
112 : }
113 :
114 : // setting_get(name)
115 16 : int ModApiUtil::l_setting_get(lua_State *L)
116 : {
117 32 : NO_MAP_LOCK_REQUIRED;
118 16 : const char *name = luaL_checkstring(L, 1);
119 : try{
120 32 : std::string value = g_settings->get(name);
121 15 : lua_pushstring(L, value.c_str());
122 2 : } catch(SettingNotFoundException &e){
123 1 : lua_pushnil(L);
124 : }
125 32 : return 1;
126 : }
127 :
128 : // setting_setbool(name)
129 0 : int ModApiUtil::l_setting_setbool(lua_State *L)
130 : {
131 0 : NO_MAP_LOCK_REQUIRED;
132 0 : std::string name = luaL_checkstring(L, 1);
133 0 : bool value = lua_toboolean(L, 2);
134 0 : CHECK_SECURE_SETTING(L, name);
135 0 : g_settings->setBool(name, value);
136 0 : return 0;
137 : }
138 :
139 : // setting_getbool(name)
140 15 : int ModApiUtil::l_setting_getbool(lua_State *L)
141 : {
142 30 : NO_MAP_LOCK_REQUIRED;
143 15 : const char *name = luaL_checkstring(L, 1);
144 : try{
145 29 : bool value = g_settings->getBool(name);
146 1 : lua_pushboolean(L, value);
147 28 : } catch(SettingNotFoundException &e){
148 14 : lua_pushnil(L);
149 : }
150 30 : return 1;
151 : }
152 :
153 : // setting_save()
154 0 : int ModApiUtil::l_setting_save(lua_State *L)
155 : {
156 0 : NO_MAP_LOCK_REQUIRED;
157 0 : if(g_settings_path != "")
158 0 : g_settings->updateConfigFile(g_settings_path.c_str());
159 0 : return 0;
160 : }
161 :
162 : // parse_json(str[, nullvalue])
163 0 : int ModApiUtil::l_parse_json(lua_State *L)
164 : {
165 0 : NO_MAP_LOCK_REQUIRED;
166 :
167 0 : const char *jsonstr = luaL_checkstring(L, 1);
168 :
169 : // Use passed nullvalue or default to nil
170 0 : int nullindex = 2;
171 0 : if (lua_isnone(L, nullindex)) {
172 0 : lua_pushnil(L);
173 0 : nullindex = lua_gettop(L);
174 : }
175 :
176 0 : Json::Value root;
177 :
178 : {
179 0 : Json::Reader reader;
180 0 : std::istringstream stream(jsonstr);
181 :
182 0 : if (!reader.parse(stream, root)) {
183 0 : errorstream << "Failed to parse json data "
184 0 : << reader.getFormattedErrorMessages();
185 0 : errorstream << "data: \"" << jsonstr << "\""
186 0 : << std::endl;
187 0 : lua_pushnil(L);
188 0 : return 1;
189 : }
190 : }
191 :
192 0 : if (!push_json_value(L, root, nullindex)) {
193 0 : errorstream << "Failed to parse json data, "
194 0 : << "depth exceeds lua stack limit" << std::endl;
195 0 : errorstream << "data: \"" << jsonstr << "\"" << std::endl;
196 0 : lua_pushnil(L);
197 : }
198 0 : return 1;
199 : }
200 :
201 : // write_json(data[, styled]) -> string or nil and error message
202 0 : int ModApiUtil::l_write_json(lua_State *L)
203 : {
204 0 : NO_MAP_LOCK_REQUIRED;
205 :
206 0 : bool styled = false;
207 0 : if (!lua_isnone(L, 2)) {
208 0 : styled = lua_toboolean(L, 2);
209 0 : lua_pop(L, 1);
210 : }
211 :
212 0 : Json::Value root;
213 : try {
214 0 : read_json_value(L, root, 1);
215 0 : } catch (SerializationError &e) {
216 0 : lua_pushnil(L);
217 0 : lua_pushstring(L, e.what());
218 0 : return 2;
219 : }
220 :
221 0 : std::string out;
222 0 : if (styled) {
223 0 : Json::StyledWriter writer;
224 0 : out = writer.write(root);
225 : } else {
226 0 : Json::FastWriter writer;
227 0 : out = writer.write(root);
228 : }
229 0 : lua_pushlstring(L, out.c_str(), out.size());
230 0 : return 1;
231 : }
232 :
233 : // get_dig_params(groups, tool_capabilities[, time_from_last_punch])
234 0 : int ModApiUtil::l_get_dig_params(lua_State *L)
235 : {
236 0 : NO_MAP_LOCK_REQUIRED;
237 0 : std::map<std::string, int> groups;
238 0 : read_groups(L, 1, groups);
239 0 : ToolCapabilities tp = read_tool_capabilities(L, 2);
240 0 : if(lua_isnoneornil(L, 3))
241 0 : push_dig_params(L, getDigParams(groups, &tp));
242 : else
243 0 : push_dig_params(L, getDigParams(groups, &tp,
244 0 : luaL_checknumber(L, 3)));
245 0 : return 1;
246 : }
247 :
248 : // get_hit_params(groups, tool_capabilities[, time_from_last_punch])
249 0 : int ModApiUtil::l_get_hit_params(lua_State *L)
250 : {
251 0 : NO_MAP_LOCK_REQUIRED;
252 0 : std::map<std::string, int> groups;
253 0 : read_groups(L, 1, groups);
254 0 : ToolCapabilities tp = read_tool_capabilities(L, 2);
255 0 : if(lua_isnoneornil(L, 3))
256 0 : push_hit_params(L, getHitParams(groups, &tp));
257 : else
258 0 : push_hit_params(L, getHitParams(groups, &tp,
259 0 : luaL_checknumber(L, 3)));
260 0 : return 1;
261 : }
262 :
263 : // get_password_hash(name, raw_password)
264 0 : int ModApiUtil::l_get_password_hash(lua_State *L)
265 : {
266 0 : NO_MAP_LOCK_REQUIRED;
267 0 : std::string name = luaL_checkstring(L, 1);
268 0 : std::string raw_password = luaL_checkstring(L, 2);
269 0 : std::string hash = translatePassword(name, raw_password);
270 0 : lua_pushstring(L, hash.c_str());
271 0 : return 1;
272 : }
273 :
274 : // is_yes(arg)
275 4 : int ModApiUtil::l_is_yes(lua_State *L)
276 : {
277 8 : NO_MAP_LOCK_REQUIRED;
278 :
279 4 : lua_getglobal(L, "tostring"); // function to be called
280 4 : lua_pushvalue(L, 1); // 1st argument
281 4 : lua_call(L, 1, 1); // execute function
282 8 : std::string str(lua_tostring(L, -1)); // get result
283 4 : lua_pop(L, 1);
284 :
285 4 : bool yes = is_yes(str);
286 4 : lua_pushboolean(L, yes);
287 8 : return 1;
288 : }
289 :
290 6 : int ModApiUtil::l_get_builtin_path(lua_State *L)
291 : {
292 12 : std::string path = porting::path_share + DIR_DELIM + "builtin";
293 6 : lua_pushstring(L, path.c_str());
294 12 : return 1;
295 : }
296 :
297 : // compress(data, method, level)
298 0 : int ModApiUtil::l_compress(lua_State *L)
299 : {
300 : size_t size;
301 0 : const char *data = luaL_checklstring(L, 1, &size);
302 :
303 0 : int level = -1;
304 0 : if (!lua_isnone(L, 3) && !lua_isnil(L, 3))
305 0 : level = luaL_checknumber(L, 3);
306 :
307 0 : std::ostringstream os;
308 0 : compressZlib(std::string(data, size), os, level);
309 :
310 0 : std::string out = os.str();
311 :
312 0 : lua_pushlstring(L, out.data(), out.size());
313 0 : return 1;
314 : }
315 :
316 : // decompress(data, method)
317 0 : int ModApiUtil::l_decompress(lua_State *L)
318 : {
319 : size_t size;
320 0 : const char *data = luaL_checklstring(L, 1, &size);
321 :
322 0 : std::istringstream is(std::string(data, size));
323 0 : std::ostringstream os;
324 0 : decompressZlib(is, os);
325 :
326 0 : std::string out = os.str();
327 :
328 0 : lua_pushlstring(L, out.data(), out.size());
329 0 : return 1;
330 : }
331 :
332 : // mkdir(path)
333 0 : int ModApiUtil::l_mkdir(lua_State *L)
334 : {
335 0 : NO_MAP_LOCK_REQUIRED;
336 0 : const char *path = luaL_checkstring(L, 1);
337 0 : CHECK_SECURE_PATH_OPTIONAL(L, path);
338 0 : lua_pushboolean(L, fs::CreateAllDirs(path));
339 0 : return 1;
340 : }
341 :
342 : // get_dir_list(path, is_dir)
343 0 : int ModApiUtil::l_get_dir_list(lua_State *L)
344 : {
345 0 : NO_MAP_LOCK_REQUIRED;
346 0 : const char *path = luaL_checkstring(L, 1);
347 0 : short is_dir = lua_isboolean(L, 2) ? lua_toboolean(L, 2) : -1;
348 :
349 0 : CHECK_SECURE_PATH_OPTIONAL(L, path);
350 :
351 0 : std::vector<fs::DirListNode> list = fs::GetDirListing(path);
352 :
353 0 : int index = 0;
354 0 : lua_newtable(L);
355 :
356 0 : for (size_t i = 0; i < list.size(); i++) {
357 0 : if (is_dir == -1 || is_dir == list[i].dir) {
358 0 : lua_pushstring(L, list[i].name.c_str());
359 0 : lua_rawseti(L, -2, ++index);
360 : }
361 : }
362 :
363 0 : return 1;
364 : }
365 :
366 0 : int ModApiUtil::l_request_insecure_environment(lua_State *L)
367 : {
368 0 : NO_MAP_LOCK_REQUIRED;
369 0 : if (!ScriptApiSecurity::isSecure(L)) {
370 0 : lua_getglobal(L, "_G");
371 0 : return 1;
372 : }
373 0 : lua_getfield(L, LUA_REGISTRYINDEX, SCRIPT_MOD_NAME_FIELD);
374 0 : if (!lua_isstring(L, -1)) {
375 0 : lua_pushnil(L);
376 0 : return 1;
377 : }
378 0 : const char *mod_name = lua_tostring(L, -1);
379 0 : std::string trusted_mods = g_settings->get("secure.trusted_mods");
380 0 : std::vector<std::string> mod_list = str_split(trusted_mods, ',');
381 0 : if (std::find(mod_list.begin(), mod_list.end(), mod_name) == mod_list.end()) {
382 0 : lua_pushnil(L);
383 0 : return 1;
384 : }
385 0 : lua_getfield(L, LUA_REGISTRYINDEX, "globals_backup");
386 0 : return 1;
387 : }
388 :
389 :
390 1 : void ModApiUtil::Initialize(lua_State *L, int top)
391 : {
392 1 : API_FCT(debug);
393 1 : API_FCT(log);
394 :
395 1 : API_FCT(setting_set);
396 1 : API_FCT(setting_get);
397 1 : API_FCT(setting_setbool);
398 1 : API_FCT(setting_getbool);
399 1 : API_FCT(setting_save);
400 :
401 1 : API_FCT(parse_json);
402 1 : API_FCT(write_json);
403 :
404 1 : API_FCT(get_dig_params);
405 1 : API_FCT(get_hit_params);
406 :
407 1 : API_FCT(get_password_hash);
408 :
409 1 : API_FCT(is_yes);
410 :
411 1 : API_FCT(get_builtin_path);
412 :
413 1 : API_FCT(compress);
414 1 : API_FCT(decompress);
415 :
416 1 : API_FCT(mkdir);
417 1 : API_FCT(get_dir_list);
418 :
419 1 : API_FCT(request_insecure_environment);
420 1 : }
421 :
422 1 : void ModApiUtil::InitializeAsync(AsyncEngine& engine)
423 : {
424 1 : ASYNC_API_FCT(debug);
425 1 : ASYNC_API_FCT(log);
426 :
427 : //ASYNC_API_FCT(setting_set);
428 1 : ASYNC_API_FCT(setting_get);
429 : //ASYNC_API_FCT(setting_setbool);
430 1 : ASYNC_API_FCT(setting_getbool);
431 : //ASYNC_API_FCT(setting_save);
432 :
433 1 : ASYNC_API_FCT(parse_json);
434 1 : ASYNC_API_FCT(write_json);
435 :
436 1 : ASYNC_API_FCT(is_yes);
437 :
438 1 : ASYNC_API_FCT(get_builtin_path);
439 :
440 1 : ASYNC_API_FCT(compress);
441 1 : ASYNC_API_FCT(decompress);
442 :
443 1 : ASYNC_API_FCT(mkdir);
444 1 : ASYNC_API_FCT(get_dir_list);
445 4 : }
446 :
|