3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
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.
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.
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.
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"
31 #include "convert_json.h"
37 #include "util/auth.h"
38 #include "util/base64.h"
42 #include "util/sha1.h"
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)
56 LogLevel level = LL_NONE;
57 if (lua_isnone(L, 2)) {
58 text = luaL_checkstring(L, 1);
60 std::string name = luaL_checkstring(L, 1);
61 text = luaL_checkstring(L, 2);
62 if (name == "deprecated") {
63 log_deprecated(L, text, 2);
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;
73 g_logger.log(level, text);
78 int ModApiUtil::l_get_us_time(lua_State *L)
81 lua_pushnumber(L, porting::getTimeUs());
85 // parse_json(str[, nullvalue])
86 int ModApiUtil::l_parse_json(lua_State *L)
90 const char *jsonstr = luaL_checkstring(L, 1);
92 // Use passed nullvalue or default to nil
94 if (lua_isnone(L, nullindex)) {
96 nullindex = lua_gettop(L);
102 std::istringstream stream(jsonstr);
104 Json::CharReaderBuilder builder;
105 builder.settings_["collectComments"] = false;
108 if (!Json::parseFromStream(builder, stream, &root, &errs)) {
109 errorstream << "Failed to parse json data " << errs << std::endl;
110 size_t jlen = strlen(jsonstr);
112 errorstream << "Data (" << jlen
113 << " bytes) printed to warningstream." << std::endl;
114 warningstream << "data: \"" << jsonstr << "\"" << std::endl;
116 errorstream << "data: \"" << jsonstr << "\"" << std::endl;
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;
132 // write_json(data[, styled]) -> string or nil and error message
133 int ModApiUtil::l_write_json(lua_State *L)
135 NO_MAP_LOCK_REQUIRED;
138 if (!lua_isnone(L, 2)) {
139 styled = readParam<bool>(L, 2);
145 read_json_value(L, root, 1);
146 } catch (SerializationError &e) {
148 lua_pushstring(L, e.what());
154 out = root.toStyledString();
156 out = fastWriteJson(root);
158 lua_pushlstring(L, out.c_str(), out.size());
162 // get_tool_wear_after_use(uses[, initial_wear])
163 int ModApiUtil::l_get_tool_wear_after_use(lua_State *L)
165 NO_MAP_LOCK_REQUIRED;
166 u32 uses = readParam<int>(L, 1);
167 u16 initial_wear = readParam<int>(L, 2, 0);
168 u16 wear = calculateResultWear(uses, initial_wear);
169 lua_pushnumber(L, wear);
173 // get_dig_params(groups, tool_capabilities[, wear])
174 int ModApiUtil::l_get_dig_params(lua_State *L)
176 NO_MAP_LOCK_REQUIRED;
177 ItemGroupList groups;
178 read_groups(L, 1, groups);
179 ToolCapabilities tp = read_tool_capabilities(L, 2);
180 if (lua_isnoneornil(L, 3)) {
181 push_dig_params(L, getDigParams(groups, &tp));
183 u16 wear = readParam<int>(L, 3);
184 push_dig_params(L, getDigParams(groups, &tp, wear));
189 // get_hit_params(groups, tool_capabilities[, time_from_last_punch, [, wear]])
190 int ModApiUtil::l_get_hit_params(lua_State *L)
192 NO_MAP_LOCK_REQUIRED;
193 std::unordered_map<std::string, int> groups;
194 read_groups(L, 1, groups);
195 ToolCapabilities tp = read_tool_capabilities(L, 2);
196 float time_from_last_punch = readParam<float>(L, 3, 1000000);
197 int wear = readParam<int>(L, 4, 0);
198 push_hit_params(L, getHitParams(groups, &tp,
199 time_from_last_punch, wear));
203 // check_password_entry(name, entry, password)
204 int ModApiUtil::l_check_password_entry(lua_State *L)
206 NO_MAP_LOCK_REQUIRED;
207 std::string name = luaL_checkstring(L, 1);
208 std::string entry = luaL_checkstring(L, 2);
209 std::string password = luaL_checkstring(L, 3);
211 if (base64_is_valid(entry)) {
212 std::string hash = translate_password(name, password);
213 lua_pushboolean(L, hash == entry);
218 std::string verifier;
220 if (!decode_srp_verifier_and_salt(entry, &verifier, &salt)) {
222 warningstream << "Invalid password format for " << name << std::endl;
223 lua_pushboolean(L, false);
226 std::string gen_verifier = generate_srp_verifier(name, password, salt);
228 lua_pushboolean(L, gen_verifier == verifier);
232 // get_password_hash(name, raw_password)
233 int ModApiUtil::l_get_password_hash(lua_State *L)
235 NO_MAP_LOCK_REQUIRED;
236 std::string name = luaL_checkstring(L, 1);
237 std::string raw_password = luaL_checkstring(L, 2);
238 std::string hash = translate_password(name, raw_password);
239 lua_pushstring(L, hash.c_str());
244 int ModApiUtil::l_is_yes(lua_State *L)
246 NO_MAP_LOCK_REQUIRED;
248 lua_getglobal(L, "tostring"); // function to be called
249 lua_pushvalue(L, 1); // 1st argument
250 lua_call(L, 1, 1); // execute function
251 std::string str = readParam<std::string>(L, -1); // get result
254 bool yes = is_yes(str);
255 lua_pushboolean(L, yes);
259 // get_builtin_path()
260 int ModApiUtil::l_get_builtin_path(lua_State *L)
262 NO_MAP_LOCK_REQUIRED;
264 std::string path = porting::path_share + DIR_DELIM + "builtin" + DIR_DELIM;
265 lua_pushstring(L, path.c_str());
271 int ModApiUtil::l_get_user_path(lua_State *L)
273 NO_MAP_LOCK_REQUIRED;
275 std::string path = porting::path_user;
276 lua_pushstring(L, path.c_str());
281 // compress(data, method, level)
282 int ModApiUtil::l_compress(lua_State *L)
284 NO_MAP_LOCK_REQUIRED;
287 const char *data = luaL_checklstring(L, 1, &size);
290 if (!lua_isnoneornil(L, 3))
291 level = readParam<int>(L, 3);
293 std::ostringstream os(std::ios_base::binary);
294 compressZlib(reinterpret_cast<const u8 *>(data), size, os, level);
296 std::string out = os.str();
298 lua_pushlstring(L, out.data(), out.size());
302 // decompress(data, method)
303 int ModApiUtil::l_decompress(lua_State *L)
305 NO_MAP_LOCK_REQUIRED;
308 const char *data = luaL_checklstring(L, 1, &size);
310 std::istringstream is(std::string(data, size), std::ios_base::binary);
311 std::ostringstream os(std::ios_base::binary);
312 decompressZlib(is, os);
314 std::string out = os.str();
316 lua_pushlstring(L, out.data(), out.size());
320 // encode_base64(string)
321 int ModApiUtil::l_encode_base64(lua_State *L)
323 NO_MAP_LOCK_REQUIRED;
326 const char *data = luaL_checklstring(L, 1, &size);
328 std::string out = base64_encode((const unsigned char *)(data), size);
330 lua_pushlstring(L, out.data(), out.size());
334 // decode_base64(string)
335 int ModApiUtil::l_decode_base64(lua_State *L)
337 NO_MAP_LOCK_REQUIRED;
340 const char *d = luaL_checklstring(L, 1, &size);
341 const std::string data = std::string(d, size);
343 if (!base64_is_valid(data))
346 std::string out = base64_decode(data);
348 lua_pushlstring(L, out.data(), out.size());
353 int ModApiUtil::l_mkdir(lua_State *L)
355 NO_MAP_LOCK_REQUIRED;
356 const char *path = luaL_checkstring(L, 1);
357 CHECK_SECURE_PATH(L, path, true);
358 lua_pushboolean(L, fs::CreateAllDirs(path));
362 // rmdir(path, recursive)
363 int ModApiUtil::l_rmdir(lua_State *L)
365 NO_MAP_LOCK_REQUIRED;
366 const char *path = luaL_checkstring(L, 1);
367 CHECK_SECURE_PATH(L, path, true);
369 bool recursive = readParam<bool>(L, 2, false);
372 lua_pushboolean(L, fs::RecursiveDelete(path));
374 lua_pushboolean(L, fs::DeleteSingleFileOrEmptyDirectory(path));
379 // cpdir(source, destination)
380 int ModApiUtil::l_cpdir(lua_State *L)
382 NO_MAP_LOCK_REQUIRED;
383 const char *source = luaL_checkstring(L, 1);
384 const char *destination = luaL_checkstring(L, 2);
385 CHECK_SECURE_PATH(L, source, false);
386 CHECK_SECURE_PATH(L, destination, true);
388 lua_pushboolean(L, fs::CopyDir(source, destination));
392 // mpdir(source, destination)
393 int ModApiUtil::l_mvdir(lua_State *L)
395 NO_MAP_LOCK_REQUIRED;
396 const char *source = luaL_checkstring(L, 1);
397 const char *destination = luaL_checkstring(L, 2);
398 CHECK_SECURE_PATH(L, source, true);
399 CHECK_SECURE_PATH(L, destination, true);
401 lua_pushboolean(L, fs::MoveDir(source, destination));
405 // get_dir_list(path, is_dir)
406 int ModApiUtil::l_get_dir_list(lua_State *L)
408 NO_MAP_LOCK_REQUIRED;
409 const char *path = luaL_checkstring(L, 1);
410 bool list_all = !lua_isboolean(L, 2); // if its not a boolean list all
411 bool list_dirs = readParam<bool>(L, 2); // true: list dirs, false: list files
413 CHECK_SECURE_PATH(L, path, false);
415 std::vector<fs::DirListNode> list = fs::GetDirListing(path);
420 for (const fs::DirListNode &dln : list) {
421 if (list_all || list_dirs == dln.dir) {
422 lua_pushstring(L, dln.name.c_str());
423 lua_rawseti(L, -2, ++index);
430 // safe_file_write(path, content)
431 int ModApiUtil::l_safe_file_write(lua_State *L)
433 NO_MAP_LOCK_REQUIRED;
434 const char *path = luaL_checkstring(L, 1);
436 const char *content = luaL_checklstring(L, 2, &size);
438 CHECK_SECURE_PATH(L, path, true);
440 bool ret = fs::safeWriteToFile(path, std::string(content, size));
441 lua_pushboolean(L, ret);
446 // request_insecure_environment()
447 int ModApiUtil::l_request_insecure_environment(lua_State *L)
449 NO_MAP_LOCK_REQUIRED;
451 // Just return _G if security is disabled
452 if (!ScriptApiSecurity::isSecure(L)) {
453 lua_getglobal(L, "_G");
457 if (!ScriptApiSecurity::checkWhitelisted(L, "secure.trusted_mods")) {
461 // Push insecure environment
462 lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
467 int ModApiUtil::l_get_version(lua_State *L)
469 lua_createtable(L, 0, 3);
470 int table = lua_gettop(L);
472 lua_pushstring(L, PROJECT_NAME_C);
473 lua_setfield(L, table, "project");
475 lua_pushstring(L, g_version_string);
476 lua_setfield(L, table, "string");
478 if (strcmp(g_version_string, g_version_hash) != 0) {
479 lua_pushstring(L, g_version_hash);
480 lua_setfield(L, table, "hash");
486 int ModApiUtil::l_sha1(lua_State *L)
488 NO_MAP_LOCK_REQUIRED;
490 const char *data = luaL_checklstring(L, 1, &size);
491 bool hex = !lua_isboolean(L, 2) || !readParam<bool>(L, 2);
493 // Compute actual checksum of data
494 std::string data_sha1;
497 ctx.addBytes(data, size);
498 unsigned char *data_tmpdigest = ctx.getDigest();
499 data_sha1.assign((char*) data_tmpdigest, 20);
500 free(data_tmpdigest);
504 std::string sha1_hex = hex_encode(data_sha1);
505 lua_pushstring(L, sha1_hex.c_str());
507 lua_pushlstring(L, data_sha1.data(), data_sha1.size());
513 // colorspec_to_colorstring(colorspec)
514 int ModApiUtil::l_colorspec_to_colorstring(lua_State *L)
516 NO_MAP_LOCK_REQUIRED;
518 video::SColor color(0);
519 if (read_color(L, 1, &color)) {
520 char colorstring[10];
521 snprintf(colorstring, 10, "#%02X%02X%02X%02X",
522 color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha());
523 lua_pushstring(L, colorstring);
530 // colorspec_to_bytes(colorspec)
531 int ModApiUtil::l_colorspec_to_bytes(lua_State *L)
533 NO_MAP_LOCK_REQUIRED;
535 video::SColor color(0);
536 if (read_color(L, 1, &color)) {
539 (u8) color.getGreen(),
540 (u8) color.getBlue(),
541 (u8) color.getAlpha(),
543 lua_pushlstring(L, (const char*) colorbytes, 4);
550 // encode_png(w, h, data, level)
551 int ModApiUtil::l_encode_png(lua_State *L)
553 NO_MAP_LOCK_REQUIRED;
555 // The args are already pre-validated on the lua side.
556 u32 width = readParam<int>(L, 1);
557 u32 height = readParam<int>(L, 2);
558 const char *data = luaL_checklstring(L, 3, NULL);
559 s32 compression = readParam<int>(L, 4);
561 std::string out = encodePNG((const u8*)data, width, height, compression);
563 lua_pushlstring(L, out.data(), out.size());
567 // get_last_run_mod()
568 int ModApiUtil::l_get_last_run_mod(lua_State *L)
570 NO_MAP_LOCK_REQUIRED;
572 lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
573 std::string current_mod = readParam<std::string>(L, -1, "");
574 if (current_mod.empty()) {
576 lua_pushstring(L, getScriptApiBase(L)->getOrigin().c_str());
581 // set_last_run_mod(modname)
582 int ModApiUtil::l_set_last_run_mod(lua_State *L)
584 NO_MAP_LOCK_REQUIRED;
586 const char *mod = luaL_checkstring(L, 1);
587 getScriptApiBase(L)->setOriginDirect(mod);
591 void ModApiUtil::Initialize(lua_State *L, int top)
595 API_FCT(get_us_time);
600 API_FCT(get_tool_wear_after_use);
601 API_FCT(get_dig_params);
602 API_FCT(get_hit_params);
604 API_FCT(check_password_entry);
605 API_FCT(get_password_hash);
609 API_FCT(get_builtin_path);
610 API_FCT(get_user_path);
619 API_FCT(get_dir_list);
620 API_FCT(safe_file_write);
622 API_FCT(request_insecure_environment);
624 API_FCT(encode_base64);
625 API_FCT(decode_base64);
627 API_FCT(get_version);
629 API_FCT(colorspec_to_colorstring);
630 API_FCT(colorspec_to_bytes);
634 API_FCT(get_last_run_mod);
635 API_FCT(set_last_run_mod);
637 LuaSettings::create(L, g_settings, g_settings_path);
638 lua_setfield(L, top, "settings");
641 void ModApiUtil::InitializeClient(lua_State *L, int top)
645 API_FCT(get_us_time);
655 API_FCT(encode_base64);
656 API_FCT(decode_base64);
658 API_FCT(get_version);
660 API_FCT(colorspec_to_colorstring);
661 API_FCT(colorspec_to_bytes);
664 void ModApiUtil::InitializeAsync(lua_State *L, int top)
668 API_FCT(get_us_time);
675 API_FCT(get_builtin_path);
676 API_FCT(get_user_path);
685 API_FCT(get_dir_list);
686 API_FCT(safe_file_write);
688 API_FCT(request_insecure_environment);
690 API_FCT(encode_base64);
691 API_FCT(decode_base64);
693 API_FCT(get_version);
695 API_FCT(colorspec_to_colorstring);
696 API_FCT(colorspec_to_bytes);
700 API_FCT(get_last_run_mod);
701 API_FCT(set_last_run_mod);
703 LuaSettings::create(L, g_settings, g_settings_path);
704 lua_setfield(L, top, "settings");