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