]> git.lizzy.rs Git - minetest.git/blob - src/script/lua_api/l_util.cpp
SAPI: Mark all Lua API functions requiring envlock
[minetest.git] / src / script / lua_api / l_util.cpp
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 "areastore.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 // log([level,] text)
38 // Writes a line to the logger.
39 // The one-argument version logs to infostream.
40 // The two-argument version accepts a log level.
41 // Either the special case "deprecated" for deprecation notices, or any specified in
42 // Logger::stringToLevel(name).
43 int ModApiUtil::l_log(lua_State *L)
44 {
45         NO_MAP_LOCK_REQUIRED;
46         std::string text;
47         LogLevel level = LL_NONE;
48         if (lua_isnone(L, 2)) {
49                 text = luaL_checkstring(L, 1);
50         } else {
51                 std::string name = luaL_checkstring(L, 1);
52                 text = luaL_checkstring(L, 2);
53                 if (name == "deprecated") {
54                         log_deprecated(L, text);
55                         return 0;
56                 }
57                 level = Logger::stringToLevel(name);
58                 if (level == LL_MAX) {
59                         warningstream << "Tried to log at unknown level '" << name
60                                 << "'.  Defaulting to \"none\"." << std::endl;
61                         level = LL_NONE;
62                 }
63         }
64         g_logger.log(level, text);
65         return 0;
66 }
67
68 #define CHECK_SECURE_SETTING(L, name) \
69         if (name.compare(0, 7, "secure.") == 0) {\
70                 lua_pushliteral(L, "Attempt to set secure setting.");\
71                 lua_error(L);\
72         }
73
74 // setting_set(name, value)
75 int ModApiUtil::l_setting_set(lua_State *L)
76 {
77         NO_MAP_LOCK_REQUIRED;
78         std::string name = luaL_checkstring(L, 1);
79         std::string value = luaL_checkstring(L, 2);
80         CHECK_SECURE_SETTING(L, name);
81         g_settings->set(name, value);
82         return 0;
83 }
84
85 // setting_get(name)
86 int ModApiUtil::l_setting_get(lua_State *L)
87 {
88         NO_MAP_LOCK_REQUIRED;
89         const char *name = luaL_checkstring(L, 1);
90         try{
91                 std::string value = g_settings->get(name);
92                 lua_pushstring(L, value.c_str());
93         } catch(SettingNotFoundException &e){
94                 lua_pushnil(L);
95         }
96         return 1;
97 }
98
99 // setting_setbool(name)
100 int ModApiUtil::l_setting_setbool(lua_State *L)
101 {
102         NO_MAP_LOCK_REQUIRED;
103         std::string name = luaL_checkstring(L, 1);
104         bool value = lua_toboolean(L, 2);
105         CHECK_SECURE_SETTING(L, name);
106         g_settings->setBool(name, value);
107         return 0;
108 }
109
110 // setting_getbool(name)
111 int ModApiUtil::l_setting_getbool(lua_State *L)
112 {
113         NO_MAP_LOCK_REQUIRED;
114         const char *name = luaL_checkstring(L, 1);
115         try{
116                 bool value = g_settings->getBool(name);
117                 lua_pushboolean(L, value);
118         } catch(SettingNotFoundException &e){
119                 lua_pushnil(L);
120         }
121         return 1;
122 }
123
124 // setting_save()
125 int ModApiUtil::l_setting_save(lua_State *L)
126 {
127         NO_MAP_LOCK_REQUIRED;
128         if(g_settings_path != "")
129                 g_settings->updateConfigFile(g_settings_path.c_str());
130         return 0;
131 }
132
133 // parse_json(str[, nullvalue])
134 int ModApiUtil::l_parse_json(lua_State *L)
135 {
136         NO_MAP_LOCK_REQUIRED;
137
138         const char *jsonstr = luaL_checkstring(L, 1);
139
140         // Use passed nullvalue or default to nil
141         int nullindex = 2;
142         if (lua_isnone(L, nullindex)) {
143                 lua_pushnil(L);
144                 nullindex = lua_gettop(L);
145         }
146
147         Json::Value root;
148
149         {
150                 Json::Reader reader;
151                 std::istringstream stream(jsonstr);
152
153                 if (!reader.parse(stream, root)) {
154                         errorstream << "Failed to parse json data "
155                                 << reader.getFormattedErrorMessages();
156                         errorstream << "data: \"" << jsonstr << "\""
157                                 << std::endl;
158                         lua_pushnil(L);
159                         return 1;
160                 }
161         }
162
163         if (!push_json_value(L, root, nullindex)) {
164                 errorstream << "Failed to parse json data, "
165                         << "depth exceeds lua stack limit" << std::endl;
166                 errorstream << "data: \"" << jsonstr << "\"" << std::endl;
167                 lua_pushnil(L);
168         }
169         return 1;
170 }
171
172 // write_json(data[, styled]) -> string or nil and error message
173 int ModApiUtil::l_write_json(lua_State *L)
174 {
175         NO_MAP_LOCK_REQUIRED;
176
177         bool styled = false;
178         if (!lua_isnone(L, 2)) {
179                 styled = lua_toboolean(L, 2);
180                 lua_pop(L, 1);
181         }
182
183         Json::Value root;
184         try {
185                 read_json_value(L, root, 1);
186         } catch (SerializationError &e) {
187                 lua_pushnil(L);
188                 lua_pushstring(L, e.what());
189                 return 2;
190         }
191
192         std::string out;
193         if (styled) {
194                 Json::StyledWriter writer;
195                 out = writer.write(root);
196         } else {
197                 Json::FastWriter writer;
198                 out = writer.write(root);
199         }
200         lua_pushlstring(L, out.c_str(), out.size());
201         return 1;
202 }
203
204 // get_dig_params(groups, tool_capabilities[, time_from_last_punch])
205 int ModApiUtil::l_get_dig_params(lua_State *L)
206 {
207         NO_MAP_LOCK_REQUIRED;
208         std::map<std::string, int> groups;
209         read_groups(L, 1, groups);
210         ToolCapabilities tp = read_tool_capabilities(L, 2);
211         if(lua_isnoneornil(L, 3))
212                 push_dig_params(L, getDigParams(groups, &tp));
213         else
214                 push_dig_params(L, getDigParams(groups, &tp,
215                                         luaL_checknumber(L, 3)));
216         return 1;
217 }
218
219 // get_hit_params(groups, tool_capabilities[, time_from_last_punch])
220 int ModApiUtil::l_get_hit_params(lua_State *L)
221 {
222         NO_MAP_LOCK_REQUIRED;
223         std::map<std::string, int> groups;
224         read_groups(L, 1, groups);
225         ToolCapabilities tp = read_tool_capabilities(L, 2);
226         if(lua_isnoneornil(L, 3))
227                 push_hit_params(L, getHitParams(groups, &tp));
228         else
229                 push_hit_params(L, getHitParams(groups, &tp,
230                                         luaL_checknumber(L, 3)));
231         return 1;
232 }
233
234 // get_password_hash(name, raw_password)
235 int ModApiUtil::l_get_password_hash(lua_State *L)
236 {
237         NO_MAP_LOCK_REQUIRED;
238         std::string name = luaL_checkstring(L, 1);
239         std::string raw_password = luaL_checkstring(L, 2);
240         std::string hash = translatePassword(name, raw_password);
241         lua_pushstring(L, hash.c_str());
242         return 1;
243 }
244
245 // is_yes(arg)
246 int ModApiUtil::l_is_yes(lua_State *L)
247 {
248         NO_MAP_LOCK_REQUIRED;
249
250         lua_getglobal(L, "tostring"); // function to be called
251         lua_pushvalue(L, 1); // 1st argument
252         lua_call(L, 1, 1); // execute function
253         std::string str(lua_tostring(L, -1)); // get result
254         lua_pop(L, 1);
255
256         bool yes = is_yes(str);
257         lua_pushboolean(L, yes);
258         return 1;
259 }
260
261 int ModApiUtil::l_get_builtin_path(lua_State *L)
262 {
263         NO_MAP_LOCK_REQUIRED;
264
265         std::string path = porting::path_share + DIR_DELIM + "builtin";
266         lua_pushstring(L, path.c_str());
267         return 1;
268 }
269
270 // compress(data, method, level)
271 int ModApiUtil::l_compress(lua_State *L)
272 {
273         NO_MAP_LOCK_REQUIRED;
274
275         size_t size;
276         const char *data = luaL_checklstring(L, 1, &size);
277
278         int level = -1;
279         if (!lua_isnone(L, 3) && !lua_isnil(L, 3))
280                 level = luaL_checknumber(L, 3);
281
282         std::ostringstream os;
283         compressZlib(std::string(data, size), os, level);
284
285         std::string out = os.str();
286
287         lua_pushlstring(L, out.data(), out.size());
288         return 1;
289 }
290
291 // decompress(data, method)
292 int ModApiUtil::l_decompress(lua_State *L)
293 {
294         NO_MAP_LOCK_REQUIRED;
295
296         size_t size;
297         const char *data = luaL_checklstring(L, 1, &size);
298
299         std::istringstream is(std::string(data, size));
300         std::ostringstream os;
301         decompressZlib(is, os);
302
303         std::string out = os.str();
304
305         lua_pushlstring(L, out.data(), out.size());
306         return 1;
307 }
308
309 // mkdir(path)
310 int ModApiUtil::l_mkdir(lua_State *L)
311 {
312         NO_MAP_LOCK_REQUIRED;
313         const char *path = luaL_checkstring(L, 1);
314         CHECK_SECURE_PATH_OPTIONAL(L, path);
315         lua_pushboolean(L, fs::CreateAllDirs(path));
316         return 1;
317 }
318
319 // get_dir_list(path, is_dir)
320 int ModApiUtil::l_get_dir_list(lua_State *L)
321 {
322         NO_MAP_LOCK_REQUIRED;
323         const char *path = luaL_checkstring(L, 1);
324         short is_dir = lua_isboolean(L, 2) ? lua_toboolean(L, 2) : -1;
325
326         CHECK_SECURE_PATH_OPTIONAL(L, path);
327
328         std::vector<fs::DirListNode> list = fs::GetDirListing(path);
329
330         int index = 0;
331         lua_newtable(L);
332
333         for (size_t i = 0; i < list.size(); i++) {
334                 if (is_dir == -1 || is_dir == list[i].dir) {
335                         lua_pushstring(L, list[i].name.c_str());
336                         lua_rawseti(L, -2, ++index);
337                 }
338         }
339
340         return 1;
341 }
342
343 int ModApiUtil::l_request_insecure_environment(lua_State *L)
344 {
345         NO_MAP_LOCK_REQUIRED;
346         if (!ScriptApiSecurity::isSecure(L)) {
347                 lua_getglobal(L, "_G");
348                 return 1;
349         }
350         lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
351         if (!lua_isstring(L, -1)) {
352                 lua_pushnil(L);
353                 return 1;
354         }
355         const char *mod_name = lua_tostring(L, -1);
356         std::string trusted_mods = g_settings->get("secure.trusted_mods");
357         std::vector<std::string> mod_list = str_split(trusted_mods, ',');
358         if (std::find(mod_list.begin(), mod_list.end(), mod_name) == mod_list.end()) {
359                 lua_pushnil(L);
360                 return 1;
361         }
362         lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
363         return 1;
364 }
365
366
367 void ModApiUtil::Initialize(lua_State *L, int top)
368 {
369         API_FCT(log);
370
371         API_FCT(setting_set);
372         API_FCT(setting_get);
373         API_FCT(setting_setbool);
374         API_FCT(setting_getbool);
375         API_FCT(setting_save);
376
377         API_FCT(parse_json);
378         API_FCT(write_json);
379
380         API_FCT(get_dig_params);
381         API_FCT(get_hit_params);
382
383         API_FCT(get_password_hash);
384
385         API_FCT(is_yes);
386
387         API_FCT(get_builtin_path);
388
389         API_FCT(compress);
390         API_FCT(decompress);
391
392         API_FCT(mkdir);
393         API_FCT(get_dir_list);
394
395         API_FCT(request_insecure_environment);
396 }
397
398 void ModApiUtil::InitializeAsync(AsyncEngine& engine)
399 {
400         ASYNC_API_FCT(log);
401
402         //ASYNC_API_FCT(setting_set);
403         ASYNC_API_FCT(setting_get);
404         //ASYNC_API_FCT(setting_setbool);
405         ASYNC_API_FCT(setting_getbool);
406         //ASYNC_API_FCT(setting_save);
407
408         ASYNC_API_FCT(parse_json);
409         ASYNC_API_FCT(write_json);
410
411         ASYNC_API_FCT(is_yes);
412
413         ASYNC_API_FCT(get_builtin_path);
414
415         ASYNC_API_FCT(compress);
416         ASYNC_API_FCT(decompress);
417
418         ASYNC_API_FCT(mkdir);
419         ASYNC_API_FCT(get_dir_list);
420 }
421