]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/lua_api/l_util.cpp
Merge branch 'master' of https://github.com/minetest/minetest
[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 "irrlichttypes_extrabloated.h"
21 #include "lua_api/l_util.h"
22 #include "lua_api/l_internal.h"
23 #include "lua_api/l_settings.h"
24 #include "common/c_converter.h"
25 #include "common/c_content.h"
26 #include "cpp_api/s_async.h"
27 #include "serialization.h"
28 #include <json/json.h>
29 #include "cpp_api/s_security.h"
30 #include "porting.h"
31 #include "convert_json.h"
32 #include "debug.h"
33 #include "log.h"
34 #include "tool.h"
35 #include "filesys.h"
36 #include "settings.h"
37 #include "util/auth.h"
38 #include "util/base64.h"
39 #include "config.h"
40 #include "version.h"
41 #include "util/hex.h"
42 #include "util/sha1.h"
43 #include "util/png.h"
44 #include <cstdio>
45
46 // log([level,] text)
47 // Writes a line to the logger.
48 // The one-argument version logs to LL_NONE.
49 // The two-argument version accepts a log level.
50 // Either the special case "deprecated" for deprecation notices, or any specified in
51 // Logger::stringToLevel(name).
52 int ModApiUtil::l_log(lua_State *L)
53 {
54         NO_MAP_LOCK_REQUIRED;
55         std::string text;
56         LogLevel level = LL_NONE;
57         if (lua_isnone(L, 2)) {
58                 text = luaL_checkstring(L, 1);
59         } else {
60                 std::string name = luaL_checkstring(L, 1);
61                 text = luaL_checkstring(L, 2);
62                 if (name == "deprecated") {
63                         log_deprecated(L, text, 2);
64                         return 0;
65                 }
66                 level = Logger::stringToLevel(name);
67                 if (level == LL_MAX) {
68                         warningstream << "Tried to log at unknown level '" << name
69                                 << "'.  Defaulting to \"none\"." << std::endl;
70                         level = LL_NONE;
71                 }
72         }
73         g_logger.log(level, text);
74         return 0;
75 }
76
77 // get_us_time()
78 int ModApiUtil::l_get_us_time(lua_State *L)
79 {
80         NO_MAP_LOCK_REQUIRED;
81         lua_pushnumber(L, porting::getTimeUs());
82         return 1;
83 }
84
85 // parse_json(str[, nullvalue])
86 int ModApiUtil::l_parse_json(lua_State *L)
87 {
88         NO_MAP_LOCK_REQUIRED;
89
90         const char *jsonstr = luaL_checkstring(L, 1);
91
92         // Use passed nullvalue or default to nil
93         int nullindex = 2;
94         if (lua_isnone(L, nullindex)) {
95                 lua_pushnil(L);
96                 nullindex = lua_gettop(L);
97         }
98
99         Json::Value root;
100
101         {
102                 std::istringstream stream(jsonstr);
103
104                 Json::CharReaderBuilder builder;
105                 builder.settings_["collectComments"] = false;
106                 std::string errs;
107
108                 if (!Json::parseFromStream(builder, stream, &root, &errs)) {
109                         errorstream << "Failed to parse json data " << errs << std::endl;
110                         size_t jlen = strlen(jsonstr);
111                         if (jlen > 100) {
112                                 errorstream << "Data (" << jlen
113                                         << " bytes) printed to warningstream." << std::endl;
114                                 warningstream << "data: \"" << jsonstr << "\"" << std::endl;
115                         } else {
116                                 errorstream << "data: \"" << jsonstr << "\"" << std::endl;
117                         }
118                         lua_pushnil(L);
119                         return 1;
120                 }
121         }
122
123         if (!push_json_value(L, root, nullindex)) {
124                 errorstream << "Failed to parse json data, "
125                         << "depth exceeds lua stack limit" << std::endl;
126                 errorstream << "data: \"" << jsonstr << "\"" << std::endl;
127                 lua_pushnil(L);
128         }
129         return 1;
130 }
131
132 // write_json(data[, styled]) -> string or nil and error message
133 int ModApiUtil::l_write_json(lua_State *L)
134 {
135         NO_MAP_LOCK_REQUIRED;
136
137         bool styled = false;
138         if (!lua_isnone(L, 2)) {
139                 styled = readParam<bool>(L, 2);
140                 lua_pop(L, 1);
141         }
142
143         Json::Value root;
144         try {
145                 read_json_value(L, root, 1);
146         } catch (SerializationError &e) {
147                 lua_pushnil(L);
148                 lua_pushstring(L, e.what());
149                 return 2;
150         }
151
152         std::string out;
153         if (styled) {
154                 out = root.toStyledString();
155         } else {
156                 out = fastWriteJson(root);
157         }
158         lua_pushlstring(L, out.c_str(), out.size());
159         return 1;
160 }
161
162 // get_dig_params(groups, tool_capabilities[, wear])
163 int ModApiUtil::l_get_dig_params(lua_State *L)
164 {
165         NO_MAP_LOCK_REQUIRED;
166         ItemGroupList groups;
167         read_groups(L, 1, groups);
168         ToolCapabilities tp = read_tool_capabilities(L, 2);
169         if (lua_isnoneornil(L, 3)) {
170                 push_dig_params(L, getDigParams(groups, &tp));
171         } else {
172                 u16 wear = readParam<int>(L, 3);
173                 push_dig_params(L, getDigParams(groups, &tp, wear));
174         }
175         return 1;
176 }
177
178 // get_hit_params(groups, tool_capabilities[, time_from_last_punch, [, wear]])
179 int ModApiUtil::l_get_hit_params(lua_State *L)
180 {
181         NO_MAP_LOCK_REQUIRED;
182         std::unordered_map<std::string, int> groups;
183         read_groups(L, 1, groups);
184         ToolCapabilities tp = read_tool_capabilities(L, 2);
185         float time_from_last_punch = readParam<float>(L, 3, 1000000);
186         int wear = readParam<int>(L, 4, 0);
187         push_hit_params(L, getHitParams(groups, &tp,
188                 time_from_last_punch, wear));
189         return 1;
190 }
191
192 // check_password_entry(name, entry, password)
193 int ModApiUtil::l_check_password_entry(lua_State *L)
194 {
195         NO_MAP_LOCK_REQUIRED;
196         std::string name = luaL_checkstring(L, 1);
197         std::string entry = luaL_checkstring(L, 2);
198         std::string password = luaL_checkstring(L, 3);
199
200         if (base64_is_valid(entry)) {
201                 std::string hash = translate_password(name, password);
202                 lua_pushboolean(L, hash == entry);
203                 return 1;
204         }
205
206         std::string salt;
207         std::string verifier;
208
209         if (!decode_srp_verifier_and_salt(entry, &verifier, &salt)) {
210                 // invalid format
211                 warningstream << "Invalid password format for " << name << std::endl;
212                 lua_pushboolean(L, false);
213                 return 1;
214         }
215         std::string gen_verifier = generate_srp_verifier(name, password, salt);
216
217         lua_pushboolean(L, gen_verifier == verifier);
218         return 1;
219 }
220
221 // get_password_hash(name, raw_password)
222 int ModApiUtil::l_get_password_hash(lua_State *L)
223 {
224         NO_MAP_LOCK_REQUIRED;
225         std::string name = luaL_checkstring(L, 1);
226         std::string raw_password = luaL_checkstring(L, 2);
227         std::string hash = translate_password(name, raw_password);
228         lua_pushstring(L, hash.c_str());
229         return 1;
230 }
231
232 // is_yes(arg)
233 int ModApiUtil::l_is_yes(lua_State *L)
234 {
235         NO_MAP_LOCK_REQUIRED;
236
237         lua_getglobal(L, "tostring"); // function to be called
238         lua_pushvalue(L, 1); // 1st argument
239         lua_call(L, 1, 1); // execute function
240         std::string str = readParam<std::string>(L, -1); // get result
241         lua_pop(L, 1);
242
243         bool yes = is_yes(str);
244         lua_pushboolean(L, yes);
245         return 1;
246 }
247
248 // get_builtin_path()
249 int ModApiUtil::l_get_builtin_path(lua_State *L)
250 {
251         NO_MAP_LOCK_REQUIRED;
252
253         std::string path = porting::path_share + DIR_DELIM + "builtin" + DIR_DELIM;
254         lua_pushstring(L, path.c_str());
255
256         return 1;
257 }
258
259 // get_user_path()
260 int ModApiUtil::l_get_user_path(lua_State *L)
261 {
262         NO_MAP_LOCK_REQUIRED;
263
264         std::string path = porting::path_user;
265         lua_pushstring(L, path.c_str());
266
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_isnoneornil(L, 3))
280                 level = readParam<int>(L, 3);
281
282         std::ostringstream os(std::ios_base::binary);
283         compressZlib(reinterpret_cast<const u8 *>(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), std::ios_base::binary);
300         std::ostringstream os(std::ios_base::binary);
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 // encode_base64(string)
310 int ModApiUtil::l_encode_base64(lua_State *L)
311 {
312         NO_MAP_LOCK_REQUIRED;
313
314         size_t size;
315         const char *data = luaL_checklstring(L, 1, &size);
316
317         std::string out = base64_encode((const unsigned char *)(data), size);
318
319         lua_pushlstring(L, out.data(), out.size());
320         return 1;
321 }
322
323 // decode_base64(string)
324 int ModApiUtil::l_decode_base64(lua_State *L)
325 {
326         NO_MAP_LOCK_REQUIRED;
327
328         size_t size;
329         const char *d = luaL_checklstring(L, 1, &size);
330         const std::string data = std::string(d, size);
331
332         if (!base64_is_valid(data))
333                 return 0;
334
335         std::string out = base64_decode(data);
336
337         lua_pushlstring(L, out.data(), out.size());
338         return 1;
339 }
340
341 // mkdir(path)
342 int ModApiUtil::l_mkdir(lua_State *L)
343 {
344         NO_MAP_LOCK_REQUIRED;
345         const char *path = luaL_checkstring(L, 1);
346         CHECK_SECURE_PATH(L, path, true);
347         lua_pushboolean(L, fs::CreateAllDirs(path));
348         return 1;
349 }
350
351 // rmdir(path, recursive)
352 int ModApiUtil::l_rmdir(lua_State *L)
353 {
354         NO_MAP_LOCK_REQUIRED;
355         const char *path = luaL_checkstring(L, 1);
356         CHECK_SECURE_PATH(L, path, true);
357
358         bool recursive = readParam<bool>(L, 2, false);
359
360         if (recursive)
361                 lua_pushboolean(L, fs::RecursiveDelete(path));
362         else
363                 lua_pushboolean(L, fs::DeleteSingleFileOrEmptyDirectory(path));
364
365         return 1;
366 }
367
368 // cpdir(source, destination)
369 int ModApiUtil::l_cpdir(lua_State *L)
370 {
371         NO_MAP_LOCK_REQUIRED;
372         const char *source = luaL_checkstring(L, 1);
373         const char *destination = luaL_checkstring(L, 2);
374         CHECK_SECURE_PATH(L, source, false);
375         CHECK_SECURE_PATH(L, destination, true);
376
377         lua_pushboolean(L, fs::CopyDir(source, destination));
378         return 1;
379 }
380
381 // mpdir(source, destination)
382 int ModApiUtil::l_mvdir(lua_State *L)
383 {
384         NO_MAP_LOCK_REQUIRED;
385         const char *source = luaL_checkstring(L, 1);
386         const char *destination = luaL_checkstring(L, 2);
387         CHECK_SECURE_PATH(L, source, true);
388         CHECK_SECURE_PATH(L, destination, true);
389
390         lua_pushboolean(L, fs::MoveDir(source, destination));
391         return 1;
392 }
393
394 // get_dir_list(path, is_dir)
395 int ModApiUtil::l_get_dir_list(lua_State *L)
396 {
397         NO_MAP_LOCK_REQUIRED;
398         const char *path = luaL_checkstring(L, 1);
399         bool list_all = !lua_isboolean(L, 2); // if its not a boolean list all
400         bool list_dirs = readParam<bool>(L, 2); // true: list dirs, false: list files
401
402         CHECK_SECURE_PATH(L, path, false);
403
404         std::vector<fs::DirListNode> list = fs::GetDirListing(path);
405
406         int index = 0;
407         lua_newtable(L);
408
409         for (const fs::DirListNode &dln : list) {
410                 if (list_all || list_dirs == dln.dir) {
411                         lua_pushstring(L, dln.name.c_str());
412                         lua_rawseti(L, -2, ++index);
413                 }
414         }
415
416         return 1;
417 }
418
419 // safe_file_write(path, content)
420 int ModApiUtil::l_safe_file_write(lua_State *L)
421 {
422         NO_MAP_LOCK_REQUIRED;
423         const char *path = luaL_checkstring(L, 1);
424         size_t size;
425         const char *content = luaL_checklstring(L, 2, &size);
426
427         CHECK_SECURE_PATH(L, path, true);
428
429         bool ret = fs::safeWriteToFile(path, std::string(content, size));
430         lua_pushboolean(L, ret);
431
432         return 1;
433 }
434
435 // request_insecure_environment()
436 int ModApiUtil::l_request_insecure_environment(lua_State *L)
437 {
438         NO_MAP_LOCK_REQUIRED;
439
440         // Just return _G if security is disabled
441         if (!ScriptApiSecurity::isSecure(L)) {
442                 lua_getglobal(L, "_G");
443                 return 1;
444         }
445
446         if (!ScriptApiSecurity::checkWhitelisted(L, "secure.trusted_mods")) {
447                 return 0;
448         }
449
450         // Push insecure environment
451         lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
452         return 1;
453 }
454
455 // get_version()
456 int ModApiUtil::l_get_version(lua_State *L)
457 {
458         lua_createtable(L, 0, 3);
459         int table = lua_gettop(L);
460
461         lua_pushstring(L, PROJECT_NAME_C);
462         lua_setfield(L, table, "project");
463
464         lua_pushstring(L, g_version_string);
465         lua_setfield(L, table, "string");
466
467         if (strcmp(g_version_string, g_version_hash) != 0) {
468                 lua_pushstring(L, g_version_hash);
469                 lua_setfield(L, table, "hash");
470         }
471
472         return 1;
473 }
474
475 int ModApiUtil::l_sha1(lua_State *L)
476 {
477         NO_MAP_LOCK_REQUIRED;
478         size_t size;
479         const char *data = luaL_checklstring(L, 1, &size);
480         bool hex = !lua_isboolean(L, 2) || !readParam<bool>(L, 2);
481
482         // Compute actual checksum of data
483         std::string data_sha1;
484         {
485                 SHA1 ctx;
486                 ctx.addBytes(data, size);
487                 unsigned char *data_tmpdigest = ctx.getDigest();
488                 data_sha1.assign((char*) data_tmpdigest, 20);
489                 free(data_tmpdigest);
490         }
491
492         if (hex) {
493                 std::string sha1_hex = hex_encode(data_sha1);
494                 lua_pushstring(L, sha1_hex.c_str());
495         } else {
496                 lua_pushlstring(L, data_sha1.data(), data_sha1.size());
497         }
498
499         return 1;
500 }
501
502 // colorspec_to_colorstring(colorspec)
503 int ModApiUtil::l_colorspec_to_colorstring(lua_State *L)
504 {
505         NO_MAP_LOCK_REQUIRED;
506
507         video::SColor color(0);
508         if (read_color(L, 1, &color)) {
509                 char colorstring[10];
510                 snprintf(colorstring, 10, "#%02X%02X%02X%02X",
511                         color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
512                 lua_pushstring(L, colorstring);
513                 return 1;
514         }
515
516         return 0;
517 }
518
519 // colorspec_to_bytes(colorspec)
520 int ModApiUtil::l_colorspec_to_bytes(lua_State *L)
521 {
522         NO_MAP_LOCK_REQUIRED;
523
524         video::SColor color(0);
525         if (read_color(L, 1, &color)) {
526                 u8 colorbytes[4] = {
527                         (u8) color.getRed(),
528                         (u8) color.getGreen(),
529                         (u8) color.getBlue(),
530                         (u8) color.getAlpha(),
531                 };
532                 lua_pushlstring(L, (const char*) colorbytes, 4);
533                 return 1;
534         }
535
536         return 0;
537 }
538
539 // encode_png(w, h, data, level)
540 int ModApiUtil::l_encode_png(lua_State *L)
541 {
542         NO_MAP_LOCK_REQUIRED;
543
544         // The args are already pre-validated on the lua side.
545         u32 width = readParam<int>(L, 1);
546         u32 height = readParam<int>(L, 2);
547         const char *data = luaL_checklstring(L, 3, NULL);
548         s32 compression = readParam<int>(L, 4);
549
550         std::string out = encodePNG((const u8*)data, width, height, compression);
551
552         lua_pushlstring(L, out.data(), out.size());
553         return 1;
554 }
555
556 // get_last_run_mod()
557 int ModApiUtil::l_get_last_run_mod(lua_State *L)
558 {
559         NO_MAP_LOCK_REQUIRED;
560
561         lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
562         std::string current_mod = readParam<std::string>(L, -1, "");
563         if (current_mod.empty()) {
564                 lua_pop(L, 1);
565                 lua_pushstring(L, getScriptApiBase(L)->getOrigin().c_str());
566         }
567         return 1;
568 }
569
570 // set_last_run_mod(modname)
571 int ModApiUtil::l_set_last_run_mod(lua_State *L)
572 {
573         NO_MAP_LOCK_REQUIRED;
574
575         const char *mod = luaL_checkstring(L, 1);
576         getScriptApiBase(L)->setOriginDirect(mod);
577         return 0;
578 }
579
580 void ModApiUtil::Initialize(lua_State *L, int top)
581 {
582         API_FCT(log);
583
584         API_FCT(get_us_time);
585
586         API_FCT(parse_json);
587         API_FCT(write_json);
588
589         API_FCT(get_dig_params);
590         API_FCT(get_hit_params);
591
592         API_FCT(check_password_entry);
593         API_FCT(get_password_hash);
594
595         API_FCT(is_yes);
596
597         API_FCT(get_builtin_path);
598         API_FCT(get_user_path);
599
600         API_FCT(compress);
601         API_FCT(decompress);
602
603         API_FCT(mkdir);
604         API_FCT(rmdir);
605         API_FCT(cpdir);
606         API_FCT(mvdir);
607         API_FCT(get_dir_list);
608         API_FCT(safe_file_write);
609
610         API_FCT(request_insecure_environment);
611
612         API_FCT(encode_base64);
613         API_FCT(decode_base64);
614
615         API_FCT(get_version);
616         API_FCT(sha1);
617         API_FCT(colorspec_to_colorstring);
618         API_FCT(colorspec_to_bytes);
619
620         API_FCT(encode_png);
621
622         API_FCT(get_last_run_mod);
623         API_FCT(set_last_run_mod);
624
625         LuaSettings::create(L, g_settings, g_settings_path);
626         lua_setfield(L, top, "settings");
627 }
628
629 void ModApiUtil::InitializeClient(lua_State *L, int top)
630 {
631         API_FCT(log);
632
633         API_FCT(get_us_time);
634
635         API_FCT(parse_json);
636         API_FCT(write_json);
637
638         API_FCT(is_yes);
639
640         API_FCT(compress);
641         API_FCT(decompress);
642
643         API_FCT(request_insecure_environment);
644
645         API_FCT(encode_base64);
646         API_FCT(decode_base64);
647
648         API_FCT(get_version);
649         API_FCT(sha1);
650         API_FCT(colorspec_to_colorstring);
651         API_FCT(colorspec_to_bytes);
652
653         LuaSettings::create(L, g_settings, g_settings_path);
654         lua_setfield(L, top, "settings");
655 }
656
657 void ModApiUtil::InitializeAsync(lua_State *L, int top)
658 {
659         API_FCT(log);
660
661         API_FCT(get_us_time);
662
663         API_FCT(parse_json);
664         API_FCT(write_json);
665
666         API_FCT(is_yes);
667
668         API_FCT(get_builtin_path);
669         API_FCT(get_user_path);
670
671         API_FCT(compress);
672         API_FCT(decompress);
673
674         API_FCT(mkdir);
675         API_FCT(rmdir);
676         API_FCT(cpdir);
677         API_FCT(mvdir);
678         API_FCT(get_dir_list);
679         API_FCT(safe_file_write);
680
681         API_FCT(request_insecure_environment);
682
683         API_FCT(encode_base64);
684         API_FCT(decode_base64);
685
686         API_FCT(get_version);
687         API_FCT(sha1);
688         API_FCT(colorspec_to_colorstring);
689         API_FCT(colorspec_to_bytes);
690
691         API_FCT(encode_png);
692
693         API_FCT(get_last_run_mod);
694         API_FCT(set_last_run_mod);
695
696         LuaSettings::create(L, g_settings, g_settings_path);
697         lua_setfield(L, top, "settings");
698 }