]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/lua_api/l_util.cpp
C++11 patchset 2: remove util/cpp11.h and util/cpp11_container.h (#5821)
[dragonfireclient.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 "lua_api/l_settings.h"
23 #include "common/c_converter.h"
24 #include "common/c_content.h"
25 #include "cpp_api/s_async.h"
26 #include "serialization.h"
27 #include <json/json.h>
28 #include "cpp_api/s_security.h"
29 #include "porting.h"
30 #include "debug.h"
31 #include "log.h"
32 #include "tool.h"
33 #include "filesys.h"
34 #include "settings.h"
35 #include "util/auth.h"
36 #include "util/base64.h"
37 #include "config.h"
38 #include "version.h"
39 #include <algorithm>
40
41
42 // log([level,] text)
43 // Writes a line to the logger.
44 // The one-argument version logs to infostream.
45 // The two-argument version accepts a log level.
46 // Either the special case "deprecated" for deprecation notices, or any specified in
47 // Logger::stringToLevel(name).
48 int ModApiUtil::l_log(lua_State *L)
49 {
50         NO_MAP_LOCK_REQUIRED;
51         std::string text;
52         LogLevel level = LL_NONE;
53         if (lua_isnone(L, 2)) {
54                 text = luaL_checkstring(L, 1);
55         } else {
56                 std::string name = luaL_checkstring(L, 1);
57                 text = luaL_checkstring(L, 2);
58                 if (name == "deprecated") {
59                         log_deprecated(L, text);
60                         return 0;
61                 }
62                 level = Logger::stringToLevel(name);
63                 if (level == LL_MAX) {
64                         warningstream << "Tried to log at unknown level '" << name
65                                 << "'.  Defaulting to \"none\"." << std::endl;
66                         level = LL_NONE;
67                 }
68         }
69         g_logger.log(level, text);
70         return 0;
71 }
72
73 // get_us_time()
74 int ModApiUtil::l_get_us_time(lua_State *L)
75 {
76         NO_MAP_LOCK_REQUIRED;
77         lua_pushnumber(L, porting::getTimeUs());
78         return 1;
79 }
80
81 // parse_json(str[, nullvalue])
82 int ModApiUtil::l_parse_json(lua_State *L)
83 {
84         NO_MAP_LOCK_REQUIRED;
85
86         const char *jsonstr = luaL_checkstring(L, 1);
87
88         // Use passed nullvalue or default to nil
89         int nullindex = 2;
90         if (lua_isnone(L, nullindex)) {
91                 lua_pushnil(L);
92                 nullindex = lua_gettop(L);
93         }
94
95         Json::Value root;
96
97         {
98                 Json::Reader reader;
99                 std::istringstream stream(jsonstr);
100
101                 if (!reader.parse(stream, root)) {
102                         errorstream << "Failed to parse json data "
103                                 << reader.getFormattedErrorMessages();
104                         size_t jlen = strlen(jsonstr);
105                         if (jlen > 100) {
106                                 errorstream << "Data (" << jlen
107                                         << " bytes) printed to warningstream." << std::endl;
108                                 warningstream << "data: \"" << jsonstr << "\"" << std::endl;
109                         } else {
110                                 errorstream << "data: \"" << jsonstr << "\"" << std::endl;
111                         }
112                         lua_pushnil(L);
113                         return 1;
114                 }
115         }
116
117         if (!push_json_value(L, root, nullindex)) {
118                 errorstream << "Failed to parse json data, "
119                         << "depth exceeds lua stack limit" << std::endl;
120                 errorstream << "data: \"" << jsonstr << "\"" << std::endl;
121                 lua_pushnil(L);
122         }
123         return 1;
124 }
125
126 // write_json(data[, styled]) -> string or nil and error message
127 int ModApiUtil::l_write_json(lua_State *L)
128 {
129         NO_MAP_LOCK_REQUIRED;
130
131         bool styled = false;
132         if (!lua_isnone(L, 2)) {
133                 styled = lua_toboolean(L, 2);
134                 lua_pop(L, 1);
135         }
136
137         Json::Value root;
138         try {
139                 read_json_value(L, root, 1);
140         } catch (SerializationError &e) {
141                 lua_pushnil(L);
142                 lua_pushstring(L, e.what());
143                 return 2;
144         }
145
146         std::string out;
147         if (styled) {
148                 Json::StyledWriter writer;
149                 out = writer.write(root);
150         } else {
151                 Json::FastWriter writer;
152                 out = writer.write(root);
153         }
154         lua_pushlstring(L, out.c_str(), out.size());
155         return 1;
156 }
157
158 // get_dig_params(groups, tool_capabilities[, time_from_last_punch])
159 int ModApiUtil::l_get_dig_params(lua_State *L)
160 {
161         NO_MAP_LOCK_REQUIRED;
162         ItemGroupList groups;
163         read_groups(L, 1, groups);
164         ToolCapabilities tp = read_tool_capabilities(L, 2);
165         if(lua_isnoneornil(L, 3))
166                 push_dig_params(L, getDigParams(groups, &tp));
167         else
168                 push_dig_params(L, getDigParams(groups, &tp,
169                                         luaL_checknumber(L, 3)));
170         return 1;
171 }
172
173 // get_hit_params(groups, tool_capabilities[, time_from_last_punch])
174 int ModApiUtil::l_get_hit_params(lua_State *L)
175 {
176         NO_MAP_LOCK_REQUIRED;
177         std::unordered_map<std::string, int> groups;
178         read_groups(L, 1, groups);
179         ToolCapabilities tp = read_tool_capabilities(L, 2);
180         if(lua_isnoneornil(L, 3))
181                 push_hit_params(L, getHitParams(groups, &tp));
182         else
183                 push_hit_params(L, getHitParams(groups, &tp,
184                                         luaL_checknumber(L, 3)));
185         return 1;
186 }
187
188 // check_password_entry(name, entry, password)
189 int ModApiUtil::l_check_password_entry(lua_State *L)
190 {
191         NO_MAP_LOCK_REQUIRED;
192         std::string name = luaL_checkstring(L, 1);
193         std::string entry = luaL_checkstring(L, 2);
194         std::string password = luaL_checkstring(L, 3);
195
196         if (base64_is_valid(entry)) {
197                 std::string hash = translate_password(name, password);
198                 lua_pushboolean(L, hash == entry);
199                 return 1;
200         }
201
202         std::string salt;
203         std::string verifier;
204
205         if (!decode_srp_verifier_and_salt(entry, &verifier, &salt)) {
206                 // invalid format
207                 warningstream << "Invalid password format for " << name << std::endl;
208                 lua_pushboolean(L, false);
209                 return 1;
210         }
211         std::string gen_verifier = generate_srp_verifier(name, password, salt);
212
213         lua_pushboolean(L, gen_verifier == verifier);
214         return 1;
215 }
216
217 // get_password_hash(name, raw_password)
218 int ModApiUtil::l_get_password_hash(lua_State *L)
219 {
220         NO_MAP_LOCK_REQUIRED;
221         std::string name = luaL_checkstring(L, 1);
222         std::string raw_password = luaL_checkstring(L, 2);
223         std::string hash = translate_password(name, raw_password);
224         lua_pushstring(L, hash.c_str());
225         return 1;
226 }
227
228 // is_yes(arg)
229 int ModApiUtil::l_is_yes(lua_State *L)
230 {
231         NO_MAP_LOCK_REQUIRED;
232
233         lua_getglobal(L, "tostring"); // function to be called
234         lua_pushvalue(L, 1); // 1st argument
235         lua_call(L, 1, 1); // execute function
236         std::string str(lua_tostring(L, -1)); // get result
237         lua_pop(L, 1);
238
239         bool yes = is_yes(str);
240         lua_pushboolean(L, yes);
241         return 1;
242 }
243
244 // get_builtin_path()
245 int ModApiUtil::l_get_builtin_path(lua_State *L)
246 {
247         NO_MAP_LOCK_REQUIRED;
248
249         std::string path = porting::path_share + DIR_DELIM + "builtin";
250         lua_pushstring(L, path.c_str());
251
252         return 1;
253 }
254
255 // compress(data, method, level)
256 int ModApiUtil::l_compress(lua_State *L)
257 {
258         NO_MAP_LOCK_REQUIRED;
259
260         size_t size;
261         const char *data = luaL_checklstring(L, 1, &size);
262
263         int level = -1;
264         if (!lua_isnone(L, 3) && !lua_isnil(L, 3))
265                 level = luaL_checknumber(L, 3);
266
267         std::ostringstream os;
268         compressZlib(std::string(data, size), os, level);
269
270         std::string out = os.str();
271
272         lua_pushlstring(L, out.data(), out.size());
273         return 1;
274 }
275
276 // decompress(data, method)
277 int ModApiUtil::l_decompress(lua_State *L)
278 {
279         NO_MAP_LOCK_REQUIRED;
280
281         size_t size;
282         const char *data = luaL_checklstring(L, 1, &size);
283
284         std::istringstream is(std::string(data, size));
285         std::ostringstream os;
286         decompressZlib(is, os);
287
288         std::string out = os.str();
289
290         lua_pushlstring(L, out.data(), out.size());
291         return 1;
292 }
293
294 // encode_base64(string)
295 int ModApiUtil::l_encode_base64(lua_State *L)
296 {
297         NO_MAP_LOCK_REQUIRED;
298
299         size_t size;
300         const char *data = luaL_checklstring(L, 1, &size);
301
302         std::string out = base64_encode((const unsigned char *)(data), size);
303
304         lua_pushlstring(L, out.data(), out.size());
305         return 1;
306 }
307
308 // decode_base64(string)
309 int ModApiUtil::l_decode_base64(lua_State *L)
310 {
311         NO_MAP_LOCK_REQUIRED;
312
313         size_t size;
314         const char *data = luaL_checklstring(L, 1, &size);
315
316         std::string out = base64_decode(std::string(data, size));
317
318         lua_pushlstring(L, out.data(), out.size());
319         return 1;
320 }
321
322 // mkdir(path)
323 int ModApiUtil::l_mkdir(lua_State *L)
324 {
325         NO_MAP_LOCK_REQUIRED;
326         const char *path = luaL_checkstring(L, 1);
327         CHECK_SECURE_PATH(L, path, true);
328         lua_pushboolean(L, fs::CreateAllDirs(path));
329         return 1;
330 }
331
332 // get_dir_list(path, is_dir)
333 int ModApiUtil::l_get_dir_list(lua_State *L)
334 {
335         NO_MAP_LOCK_REQUIRED;
336         const char *path = luaL_checkstring(L, 1);
337         bool list_all = !lua_isboolean(L, 2); // if its not a boolean list all
338         bool list_dirs = lua_toboolean(L, 2); // true: list dirs, false: list files
339
340         CHECK_SECURE_PATH(L, path, false);
341
342         std::vector<fs::DirListNode> list = fs::GetDirListing(path);
343
344         int index = 0;
345         lua_newtable(L);
346
347         for (size_t i = 0; i < list.size(); i++) {
348                 if (list_all || list_dirs == list[i].dir) {
349                         lua_pushstring(L, list[i].name.c_str());
350                         lua_rawseti(L, -2, ++index);
351                 }
352         }
353
354         return 1;
355 }
356
357 int ModApiUtil::l_request_insecure_environment(lua_State *L)
358 {
359         NO_MAP_LOCK_REQUIRED;
360
361         // Just return _G if security is disabled
362         if (!ScriptApiSecurity::isSecure(L)) {
363                 lua_getglobal(L, "_G");
364                 return 1;
365         }
366
367         // We have to make sure that this function is being called directly by
368         // a mod, otherwise a malicious mod could override this function and
369         // steal its return value.
370         lua_Debug info;
371         // Make sure there's only one item below this function on the stack...
372         if (lua_getstack(L, 2, &info)) {
373                 return 0;
374         }
375         FATAL_ERROR_IF(!lua_getstack(L, 1, &info), "lua_getstack() failed");
376         FATAL_ERROR_IF(!lua_getinfo(L, "S", &info), "lua_getinfo() failed");
377         // ...and that that item is the main file scope.
378         if (strcmp(info.what, "main") != 0) {
379                 return 0;
380         }
381
382         // Get mod name
383         lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
384         if (!lua_isstring(L, -1)) {
385                 return 0;
386         }
387
388         // Check secure.trusted_mods
389         const char *mod_name = lua_tostring(L, -1);
390         std::string trusted_mods = g_settings->get("secure.trusted_mods");
391         trusted_mods.erase(std::remove_if(trusted_mods.begin(),
392                         trusted_mods.end(), static_cast<int(*)(int)>(&std::isspace)),
393                         trusted_mods.end());
394         std::vector<std::string> mod_list = str_split(trusted_mods, ',');
395         if (std::find(mod_list.begin(), mod_list.end(), mod_name) ==
396                         mod_list.end()) {
397                 return 0;
398         }
399
400         // Push insecure environment
401         lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
402         return 1;
403 }
404
405 // get_version()
406 int ModApiUtil::l_get_version(lua_State *L)
407 {
408         lua_createtable(L, 0, 3);
409         int table = lua_gettop(L);
410
411         lua_pushstring(L, PROJECT_NAME_C);
412         lua_setfield(L, table, "project");
413
414         lua_pushstring(L, g_version_string);
415         lua_setfield(L, table, "string");
416
417         if (strcmp(g_version_string, g_version_hash)) {
418                 lua_pushstring(L, g_version_hash);
419                 lua_setfield(L, table, "hash");
420         }
421
422         return 1;
423 }
424
425
426 void ModApiUtil::Initialize(lua_State *L, int top)
427 {
428         API_FCT(log);
429
430         API_FCT(get_us_time);
431
432         API_FCT(parse_json);
433         API_FCT(write_json);
434
435         API_FCT(get_dig_params);
436         API_FCT(get_hit_params);
437
438         API_FCT(check_password_entry);
439         API_FCT(get_password_hash);
440
441         API_FCT(is_yes);
442
443         API_FCT(get_builtin_path);
444
445         API_FCT(compress);
446         API_FCT(decompress);
447
448         API_FCT(mkdir);
449         API_FCT(get_dir_list);
450
451         API_FCT(request_insecure_environment);
452
453         API_FCT(encode_base64);
454         API_FCT(decode_base64);
455
456         API_FCT(get_version);
457
458         LuaSettings::create(L, g_settings, g_settings_path);
459         lua_setfield(L, top, "settings");
460 }
461
462 void ModApiUtil::InitializeClient(lua_State *L, int top)
463 {
464         API_FCT(log);
465
466         API_FCT(get_us_time);
467
468         API_FCT(parse_json);
469         API_FCT(write_json);
470
471         API_FCT(is_yes);
472
473         API_FCT(get_builtin_path);
474
475         API_FCT(compress);
476         API_FCT(decompress);
477
478         API_FCT(encode_base64);
479         API_FCT(decode_base64);
480
481         API_FCT(get_version);
482 }
483
484 void ModApiUtil::InitializeAsync(lua_State *L, int top)
485 {
486         API_FCT(log);
487
488         API_FCT(get_us_time);
489
490         API_FCT(parse_json);
491         API_FCT(write_json);
492
493         API_FCT(is_yes);
494
495         API_FCT(get_builtin_path);
496
497         API_FCT(compress);
498         API_FCT(decompress);
499
500         API_FCT(mkdir);
501         API_FCT(get_dir_list);
502
503         API_FCT(encode_base64);
504         API_FCT(decode_base64);
505
506         API_FCT(get_version);
507
508         LuaSettings::create(L, g_settings, g_settings_path);
509         lua_setfield(L, top, "settings");
510 }
511