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_dig_params(groups, tool_capabilities[, wear])
163 int ModApiUtil::l_get_dig_params(lua_State *L)
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));
172 u16 wear = readParam<int>(L, 3);
173 push_dig_params(L, getDigParams(groups, &tp, wear));
178 // get_hit_params(groups, tool_capabilities[, time_from_last_punch, [, wear]])
179 int ModApiUtil::l_get_hit_params(lua_State *L)
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));
192 // check_password_entry(name, entry, password)
193 int ModApiUtil::l_check_password_entry(lua_State *L)
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);
200 if (base64_is_valid(entry)) {
201 std::string hash = translate_password(name, password);
202 lua_pushboolean(L, hash == entry);
207 std::string verifier;
209 if (!decode_srp_verifier_and_salt(entry, &verifier, &salt)) {
211 warningstream << "Invalid password format for " << name << std::endl;
212 lua_pushboolean(L, false);
215 std::string gen_verifier = generate_srp_verifier(name, password, salt);
217 lua_pushboolean(L, gen_verifier == verifier);
221 // get_password_hash(name, raw_password)
222 int ModApiUtil::l_get_password_hash(lua_State *L)
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());
233 int ModApiUtil::l_is_yes(lua_State *L)
235 NO_MAP_LOCK_REQUIRED;
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
243 bool yes = is_yes(str);
244 lua_pushboolean(L, yes);
248 // get_builtin_path()
249 int ModApiUtil::l_get_builtin_path(lua_State *L)
251 NO_MAP_LOCK_REQUIRED;
253 std::string path = porting::path_share + DIR_DELIM + "builtin" + DIR_DELIM;
254 lua_pushstring(L, path.c_str());
260 int ModApiUtil::l_get_user_path(lua_State *L)
262 NO_MAP_LOCK_REQUIRED;
264 std::string path = porting::path_user;
265 lua_pushstring(L, path.c_str());
270 // compress(data, method, level)
271 int ModApiUtil::l_compress(lua_State *L)
273 NO_MAP_LOCK_REQUIRED;
276 const char *data = luaL_checklstring(L, 1, &size);
279 if (!lua_isnoneornil(L, 3))
280 level = readParam<int>(L, 3);
282 std::ostringstream os(std::ios_base::binary);
283 compressZlib(reinterpret_cast<const u8 *>(data), size, os, level);
285 std::string out = os.str();
287 lua_pushlstring(L, out.data(), out.size());
291 // decompress(data, method)
292 int ModApiUtil::l_decompress(lua_State *L)
294 NO_MAP_LOCK_REQUIRED;
297 const char *data = luaL_checklstring(L, 1, &size);
299 std::istringstream is(std::string(data, size), std::ios_base::binary);
300 std::ostringstream os(std::ios_base::binary);
301 decompressZlib(is, os);
303 std::string out = os.str();
305 lua_pushlstring(L, out.data(), out.size());
309 // encode_base64(string)
310 int ModApiUtil::l_encode_base64(lua_State *L)
312 NO_MAP_LOCK_REQUIRED;
315 const char *data = luaL_checklstring(L, 1, &size);
317 std::string out = base64_encode((const unsigned char *)(data), size);
319 lua_pushlstring(L, out.data(), out.size());
323 // decode_base64(string)
324 int ModApiUtil::l_decode_base64(lua_State *L)
326 NO_MAP_LOCK_REQUIRED;
329 const char *d = luaL_checklstring(L, 1, &size);
330 const std::string data = std::string(d, size);
332 if (!base64_is_valid(data))
335 std::string out = base64_decode(data);
337 lua_pushlstring(L, out.data(), out.size());
342 int ModApiUtil::l_mkdir(lua_State *L)
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));
351 // rmdir(path, recursive)
352 int ModApiUtil::l_rmdir(lua_State *L)
354 NO_MAP_LOCK_REQUIRED;
355 const char *path = luaL_checkstring(L, 1);
356 CHECK_SECURE_PATH(L, path, true);
358 bool recursive = readParam<bool>(L, 2, false);
361 lua_pushboolean(L, fs::RecursiveDelete(path));
363 lua_pushboolean(L, fs::DeleteSingleFileOrEmptyDirectory(path));
368 // cpdir(source, destination)
369 int ModApiUtil::l_cpdir(lua_State *L)
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);
377 lua_pushboolean(L, fs::CopyDir(source, destination));
381 // mpdir(source, destination)
382 int ModApiUtil::l_mvdir(lua_State *L)
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);
390 lua_pushboolean(L, fs::MoveDir(source, destination));
394 // get_dir_list(path, is_dir)
395 int ModApiUtil::l_get_dir_list(lua_State *L)
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
402 CHECK_SECURE_PATH(L, path, false);
404 std::vector<fs::DirListNode> list = fs::GetDirListing(path);
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);
419 // safe_file_write(path, content)
420 int ModApiUtil::l_safe_file_write(lua_State *L)
422 NO_MAP_LOCK_REQUIRED;
423 const char *path = luaL_checkstring(L, 1);
425 const char *content = luaL_checklstring(L, 2, &size);
427 CHECK_SECURE_PATH(L, path, true);
429 bool ret = fs::safeWriteToFile(path, std::string(content, size));
430 lua_pushboolean(L, ret);
435 // request_insecure_environment()
436 int ModApiUtil::l_request_insecure_environment(lua_State *L)
438 NO_MAP_LOCK_REQUIRED;
440 // Just return _G if security is disabled
441 if (!ScriptApiSecurity::isSecure(L)) {
442 lua_getglobal(L, "_G");
446 if (!ScriptApiSecurity::checkWhitelisted(L, "secure.trusted_mods")) {
450 // Push insecure environment
451 lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
456 int ModApiUtil::l_get_version(lua_State *L)
458 lua_createtable(L, 0, 3);
459 int table = lua_gettop(L);
461 lua_pushstring(L, PROJECT_NAME_C);
462 lua_setfield(L, table, "project");
464 lua_pushstring(L, g_version_string);
465 lua_setfield(L, table, "string");
467 if (strcmp(g_version_string, g_version_hash) != 0) {
468 lua_pushstring(L, g_version_hash);
469 lua_setfield(L, table, "hash");
475 int ModApiUtil::l_sha1(lua_State *L)
477 NO_MAP_LOCK_REQUIRED;
479 const char *data = luaL_checklstring(L, 1, &size);
480 bool hex = !lua_isboolean(L, 2) || !readParam<bool>(L, 2);
482 // Compute actual checksum of data
483 std::string data_sha1;
486 ctx.addBytes(data, size);
487 unsigned char *data_tmpdigest = ctx.getDigest();
488 data_sha1.assign((char*) data_tmpdigest, 20);
489 free(data_tmpdigest);
493 std::string sha1_hex = hex_encode(data_sha1);
494 lua_pushstring(L, sha1_hex.c_str());
496 lua_pushlstring(L, data_sha1.data(), data_sha1.size());
502 // colorspec_to_colorstring(colorspec)
503 int ModApiUtil::l_colorspec_to_colorstring(lua_State *L)
505 NO_MAP_LOCK_REQUIRED;
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);
519 // colorspec_to_bytes(colorspec)
520 int ModApiUtil::l_colorspec_to_bytes(lua_State *L)
522 NO_MAP_LOCK_REQUIRED;
524 video::SColor color(0);
525 if (read_color(L, 1, &color)) {
528 (u8) color.getGreen(),
529 (u8) color.getBlue(),
530 (u8) color.getAlpha(),
532 lua_pushlstring(L, (const char*) colorbytes, 4);
539 // encode_png(w, h, data, level)
540 int ModApiUtil::l_encode_png(lua_State *L)
542 NO_MAP_LOCK_REQUIRED;
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);
550 std::string out = encodePNG((const u8*)data, width, height, compression);
552 lua_pushlstring(L, out.data(), out.size());
556 // get_last_run_mod()
557 int ModApiUtil::l_get_last_run_mod(lua_State *L)
559 NO_MAP_LOCK_REQUIRED;
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()) {
565 lua_pushstring(L, getScriptApiBase(L)->getOrigin().c_str());
570 // set_last_run_mod(modname)
571 int ModApiUtil::l_set_last_run_mod(lua_State *L)
573 NO_MAP_LOCK_REQUIRED;
575 const char *mod = luaL_checkstring(L, 1);
576 getScriptApiBase(L)->setOriginDirect(mod);
580 void ModApiUtil::Initialize(lua_State *L, int top)
584 API_FCT(get_us_time);
589 API_FCT(get_dig_params);
590 API_FCT(get_hit_params);
592 API_FCT(check_password_entry);
593 API_FCT(get_password_hash);
597 API_FCT(get_builtin_path);
598 API_FCT(get_user_path);
607 API_FCT(get_dir_list);
608 API_FCT(safe_file_write);
610 API_FCT(request_insecure_environment);
612 API_FCT(encode_base64);
613 API_FCT(decode_base64);
615 API_FCT(get_version);
617 API_FCT(colorspec_to_colorstring);
618 API_FCT(colorspec_to_bytes);
622 API_FCT(get_last_run_mod);
623 API_FCT(set_last_run_mod);
625 LuaSettings::create(L, g_settings, g_settings_path);
626 lua_setfield(L, top, "settings");
629 void ModApiUtil::InitializeClient(lua_State *L, int top)
633 API_FCT(get_us_time);
643 API_FCT(request_insecure_environment);
645 API_FCT(encode_base64);
646 API_FCT(decode_base64);
648 API_FCT(get_version);
650 API_FCT(colorspec_to_colorstring);
651 API_FCT(colorspec_to_bytes);
653 LuaSettings::create(L, g_settings, g_settings_path);
654 lua_setfield(L, top, "settings");
657 void ModApiUtil::InitializeAsync(lua_State *L, int top)
661 API_FCT(get_us_time);
668 API_FCT(get_builtin_path);
669 API_FCT(get_user_path);
678 API_FCT(get_dir_list);
679 API_FCT(safe_file_write);
681 API_FCT(request_insecure_environment);
683 API_FCT(encode_base64);
684 API_FCT(decode_base64);
686 API_FCT(get_version);
688 API_FCT(colorspec_to_colorstring);
689 API_FCT(colorspec_to_bytes);
693 API_FCT(get_last_run_mod);
694 API_FCT(set_last_run_mod);
696 LuaSettings::create(L, g_settings, g_settings_path);
697 lua_setfield(L, top, "settings");