X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fscript%2Flua_api%2Fl_util.cpp;h=53319ccfd2a21f569446181be0ba80a63f5a0096;hb=6910c8d920acedb3f1df1ac03a5cdf14f5fb6081;hp=c04f09f9016232e4ebb4fe079e5180deb2244552;hpb=1b9aef43c94a79ca58f488bbfee8c40ab5b5b5b0;p=dragonfireclient.git diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp index c04f09f90..53319ccfd 100644 --- a/src/script/lua_api/l_util.cpp +++ b/src/script/lua_api/l_util.cpp @@ -17,26 +17,36 @@ with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "irrlichttypes_extrabloated.h" #include "lua_api/l_util.h" #include "lua_api/l_internal.h" +#include "lua_api/l_settings.h" #include "common/c_converter.h" #include "common/c_content.h" #include "cpp_api/s_async.h" #include "serialization.h" -#include "json/json.h" +#include #include "cpp_api/s_security.h" -#include "areastore.h" #include "porting.h" +#include "convert_json.h" +#include "debug.h" #include "log.h" #include "tool.h" #include "filesys.h" #include "settings.h" #include "util/auth.h" +#include "util/base64.h" +#include "config.h" +#include "version.h" +#include "util/hex.h" +#include "util/sha1.h" +#include "util/png.h" #include +#include // log([level,] text) // Writes a line to the logger. -// The one-argument version logs to infostream. +// The one-argument version logs to LL_NONE. // The two-argument version accepts a log level. // Either the special case "deprecated" for deprecation notices, or any specified in // Logger::stringToLevel(name). @@ -51,7 +61,7 @@ int ModApiUtil::l_log(lua_State *L) std::string name = luaL_checkstring(L, 1); text = luaL_checkstring(L, 2); if (name == "deprecated") { - log_deprecated(L, text); + log_deprecated(L, text, 2); return 0; } level = Logger::stringToLevel(name); @@ -73,71 +83,6 @@ int ModApiUtil::l_get_us_time(lua_State *L) return 1; } -#define CHECK_SECURE_SETTING(L, name) \ - if (name.compare(0, 7, "secure.") == 0) {\ - lua_pushliteral(L, "Attempt to set secure setting.");\ - lua_error(L);\ - } - -// setting_set(name, value) -int ModApiUtil::l_setting_set(lua_State *L) -{ - NO_MAP_LOCK_REQUIRED; - std::string name = luaL_checkstring(L, 1); - std::string value = luaL_checkstring(L, 2); - CHECK_SECURE_SETTING(L, name); - g_settings->set(name, value); - return 0; -} - -// setting_get(name) -int ModApiUtil::l_setting_get(lua_State *L) -{ - NO_MAP_LOCK_REQUIRED; - const char *name = luaL_checkstring(L, 1); - try{ - std::string value = g_settings->get(name); - lua_pushstring(L, value.c_str()); - } catch(SettingNotFoundException &e){ - lua_pushnil(L); - } - return 1; -} - -// setting_setbool(name) -int ModApiUtil::l_setting_setbool(lua_State *L) -{ - NO_MAP_LOCK_REQUIRED; - std::string name = luaL_checkstring(L, 1); - bool value = lua_toboolean(L, 2); - CHECK_SECURE_SETTING(L, name); - g_settings->setBool(name, value); - return 0; -} - -// setting_getbool(name) -int ModApiUtil::l_setting_getbool(lua_State *L) -{ - NO_MAP_LOCK_REQUIRED; - const char *name = luaL_checkstring(L, 1); - try{ - bool value = g_settings->getBool(name); - lua_pushboolean(L, value); - } catch(SettingNotFoundException &e){ - lua_pushnil(L); - } - return 1; -} - -// setting_save() -int ModApiUtil::l_setting_save(lua_State *L) -{ - NO_MAP_LOCK_REQUIRED; - if(g_settings_path != "") - g_settings->updateConfigFile(g_settings_path.c_str()); - return 0; -} - // parse_json(str[, nullvalue]) int ModApiUtil::l_parse_json(lua_State *L) { @@ -155,12 +100,14 @@ int ModApiUtil::l_parse_json(lua_State *L) Json::Value root; { - Json::Reader reader; std::istringstream stream(jsonstr); - if (!reader.parse(stream, root)) { - errorstream << "Failed to parse json data " - << reader.getFormattedErrorMessages(); + Json::CharReaderBuilder builder; + builder.settings_["collectComments"] = false; + std::string errs; + + if (!Json::parseFromStream(builder, stream, &root, &errs)) { + errorstream << "Failed to parse json data " << errs << std::endl; size_t jlen = strlen(jsonstr); if (jlen > 100) { errorstream << "Data (" << jlen @@ -190,7 +137,7 @@ int ModApiUtil::l_write_json(lua_State *L) bool styled = false; if (!lua_isnone(L, 2)) { - styled = lua_toboolean(L, 2); + styled = readParam(L, 2); lua_pop(L, 1); } @@ -205,43 +152,70 @@ int ModApiUtil::l_write_json(lua_State *L) std::string out; if (styled) { - Json::StyledWriter writer; - out = writer.write(root); + out = root.toStyledString(); } else { - Json::FastWriter writer; - out = writer.write(root); + out = fastWriteJson(root); } lua_pushlstring(L, out.c_str(), out.size()); return 1; } -// get_dig_params(groups, tool_capabilities[, time_from_last_punch]) +// get_dig_params(groups, tool_capabilities[, wear]) int ModApiUtil::l_get_dig_params(lua_State *L) { NO_MAP_LOCK_REQUIRED; - std::map groups; + ItemGroupList groups; read_groups(L, 1, groups); ToolCapabilities tp = read_tool_capabilities(L, 2); - if(lua_isnoneornil(L, 3)) + if (lua_isnoneornil(L, 3)) { push_dig_params(L, getDigParams(groups, &tp)); - else - push_dig_params(L, getDigParams(groups, &tp, - luaL_checknumber(L, 3))); + } else { + u16 wear = readParam(L, 3); + push_dig_params(L, getDigParams(groups, &tp, wear)); + } return 1; } -// get_hit_params(groups, tool_capabilities[, time_from_last_punch]) +// get_hit_params(groups, tool_capabilities[, time_from_last_punch, [, wear]]) int ModApiUtil::l_get_hit_params(lua_State *L) { NO_MAP_LOCK_REQUIRED; - std::map groups; + std::unordered_map groups; read_groups(L, 1, groups); ToolCapabilities tp = read_tool_capabilities(L, 2); - if(lua_isnoneornil(L, 3)) - push_hit_params(L, getHitParams(groups, &tp)); - else - push_hit_params(L, getHitParams(groups, &tp, - luaL_checknumber(L, 3))); + float time_from_last_punch = readParam(L, 3, 1000000); + int wear = readParam(L, 4, 0); + push_hit_params(L, getHitParams(groups, &tp, + time_from_last_punch, wear)); + return 1; +} + +// check_password_entry(name, entry, password) +int ModApiUtil::l_check_password_entry(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + std::string name = luaL_checkstring(L, 1); + std::string entry = luaL_checkstring(L, 2); + std::string password = luaL_checkstring(L, 3); + + if (base64_is_valid(entry)) { + std::string hash = translate_password(name, password); + lua_pushboolean(L, hash == entry); + return 1; + } + + std::string salt; + std::string verifier; + + if (!decode_srp_verifier_and_salt(entry, &verifier, &salt)) { + // invalid format + warningstream << "Invalid password format for " << name << std::endl; + lua_pushboolean(L, false); + return 1; + } + std::string gen_verifier = generate_srp_verifier(name, password, salt); + + lua_pushboolean(L, gen_verifier == verifier); return 1; } @@ -251,7 +225,7 @@ int ModApiUtil::l_get_password_hash(lua_State *L) NO_MAP_LOCK_REQUIRED; std::string name = luaL_checkstring(L, 1); std::string raw_password = luaL_checkstring(L, 2); - std::string hash = translatePassword(name, raw_password); + std::string hash = translate_password(name, raw_password); lua_pushstring(L, hash.c_str()); return 1; } @@ -264,7 +238,7 @@ int ModApiUtil::l_is_yes(lua_State *L) lua_getglobal(L, "tostring"); // function to be called lua_pushvalue(L, 1); // 1st argument lua_call(L, 1, 1); // execute function - std::string str(lua_tostring(L, -1)); // get result + std::string str = readParam(L, -1); // get result lua_pop(L, 1); bool yes = is_yes(str); @@ -272,12 +246,25 @@ int ModApiUtil::l_is_yes(lua_State *L) return 1; } +// get_builtin_path() int ModApiUtil::l_get_builtin_path(lua_State *L) { NO_MAP_LOCK_REQUIRED; - std::string path = porting::path_share + DIR_DELIM + "builtin"; + std::string path = porting::path_share + DIR_DELIM + "builtin" + DIR_DELIM; + lua_pushstring(L, path.c_str()); + + return 1; +} + +// get_user_path() +int ModApiUtil::l_get_user_path(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + std::string path = porting::path_user; lua_pushstring(L, path.c_str()); + return 1; } @@ -290,11 +277,11 @@ int ModApiUtil::l_compress(lua_State *L) const char *data = luaL_checklstring(L, 1, &size); int level = -1; - if (!lua_isnone(L, 3) && !lua_isnil(L, 3)) - level = luaL_checknumber(L, 3); + if (!lua_isnoneornil(L, 3)) + level = readParam(L, 3); - std::ostringstream os; - compressZlib(std::string(data, size), os, level); + std::ostringstream os(std::ios_base::binary); + compressZlib(reinterpret_cast(data), size, os, level); std::string out = os.str(); @@ -310,8 +297,8 @@ int ModApiUtil::l_decompress(lua_State *L) size_t size; const char *data = luaL_checklstring(L, 1, &size); - std::istringstream is(std::string(data, size)); - std::ostringstream os; + std::istringstream is(std::string(data, size), std::ios_base::binary); + std::ostringstream os(std::ios_base::binary); decompressZlib(is, os); std::string out = os.str(); @@ -320,12 +307,44 @@ int ModApiUtil::l_decompress(lua_State *L) return 1; } +// encode_base64(string) +int ModApiUtil::l_encode_base64(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + size_t size; + const char *data = luaL_checklstring(L, 1, &size); + + std::string out = base64_encode((const unsigned char *)(data), size); + + lua_pushlstring(L, out.data(), out.size()); + return 1; +} + +// decode_base64(string) +int ModApiUtil::l_decode_base64(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + size_t size; + const char *d = luaL_checklstring(L, 1, &size); + const std::string data = std::string(d, size); + + if (!base64_is_valid(data)) + return 0; + + std::string out = base64_decode(data); + + lua_pushlstring(L, out.data(), out.size()); + return 1; +} + // mkdir(path) int ModApiUtil::l_mkdir(lua_State *L) { NO_MAP_LOCK_REQUIRED; const char *path = luaL_checkstring(L, 1); - CHECK_SECURE_PATH_OPTIONAL(L, path); + CHECK_SECURE_PATH(L, path, true); lua_pushboolean(L, fs::CreateAllDirs(path)); return 1; } @@ -335,18 +354,19 @@ int ModApiUtil::l_get_dir_list(lua_State *L) { NO_MAP_LOCK_REQUIRED; const char *path = luaL_checkstring(L, 1); - short is_dir = lua_isboolean(L, 2) ? lua_toboolean(L, 2) : -1; + bool list_all = !lua_isboolean(L, 2); // if its not a boolean list all + bool list_dirs = readParam(L, 2); // true: list dirs, false: list files - CHECK_SECURE_PATH_OPTIONAL(L, path); + CHECK_SECURE_PATH(L, path, false); std::vector list = fs::GetDirListing(path); int index = 0; lua_newtable(L); - for (size_t i = 0; i < list.size(); i++) { - if (is_dir == -1 || is_dir == list[i].dir) { - lua_pushstring(L, list[i].name.c_str()); + for (const fs::DirListNode &dln : list) { + if (list_all || list_dirs == dln.dir) { + lua_pushstring(L, dln.name.c_str()); lua_rawseti(L, -2, ++index); } } @@ -354,6 +374,23 @@ int ModApiUtil::l_get_dir_list(lua_State *L) return 1; } +// safe_file_write(path, content) +int ModApiUtil::l_safe_file_write(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + const char *path = luaL_checkstring(L, 1); + size_t size; + const char *content = luaL_checklstring(L, 2, &size); + + CHECK_SECURE_PATH(L, path, true); + + bool ret = fs::safeWriteToFile(path, std::string(content, size)); + lua_pushboolean(L, ret); + + return 1; +} + +// request_insecure_environment() int ModApiUtil::l_request_insecure_environment(lua_State *L) { NO_MAP_LOCK_REQUIRED; @@ -372,8 +409,8 @@ int ModApiUtil::l_request_insecure_environment(lua_State *L) if (lua_getstack(L, 2, &info)) { return 0; } - assert(lua_getstack(L, 1, &info)); - assert(lua_getinfo(L, "S", &info)); + FATAL_ERROR_IF(!lua_getstack(L, 1, &info), "lua_getstack() failed"); + FATAL_ERROR_IF(!lua_getinfo(L, "S", &info), "lua_getinfo() failed"); // ...and that that item is the main file scope. if (strcmp(info.what, "main") != 0) { return 0; @@ -386,10 +423,11 @@ int ModApiUtil::l_request_insecure_environment(lua_State *L) } // Check secure.trusted_mods - const char *mod_name = lua_tostring(L, -1); + std::string mod_name = readParam(L, -1); std::string trusted_mods = g_settings->get("secure.trusted_mods"); - trusted_mods.erase(std::remove(trusted_mods.begin(), - trusted_mods.end(), ' '), trusted_mods.end()); + trusted_mods.erase(std::remove_if(trusted_mods.begin(), + trusted_mods.end(), static_cast(&std::isspace)), + trusted_mods.end()); std::vector mod_list = str_split(trusted_mods, ','); if (std::find(mod_list.begin(), mod_list.end(), mod_name) == mod_list.end()) { @@ -401,6 +439,130 @@ int ModApiUtil::l_request_insecure_environment(lua_State *L) return 1; } +// get_version() +int ModApiUtil::l_get_version(lua_State *L) +{ + lua_createtable(L, 0, 3); + int table = lua_gettop(L); + + lua_pushstring(L, PROJECT_NAME_C); + lua_setfield(L, table, "project"); + + lua_pushstring(L, g_version_string); + lua_setfield(L, table, "string"); + + if (strcmp(g_version_string, g_version_hash) != 0) { + lua_pushstring(L, g_version_hash); + lua_setfield(L, table, "hash"); + } + + return 1; +} + +int ModApiUtil::l_sha1(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + size_t size; + const char *data = luaL_checklstring(L, 1, &size); + bool hex = !lua_isboolean(L, 2) || !readParam(L, 2); + + // Compute actual checksum of data + std::string data_sha1; + { + SHA1 ctx; + ctx.addBytes(data, size); + unsigned char *data_tmpdigest = ctx.getDigest(); + data_sha1.assign((char*) data_tmpdigest, 20); + free(data_tmpdigest); + } + + if (hex) { + std::string sha1_hex = hex_encode(data_sha1); + lua_pushstring(L, sha1_hex.c_str()); + } else { + lua_pushlstring(L, data_sha1.data(), data_sha1.size()); + } + + return 1; +} + +// colorspec_to_colorstring(colorspec) +int ModApiUtil::l_colorspec_to_colorstring(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + video::SColor color(0); + if (read_color(L, 1, &color)) { + char colorstring[10]; + snprintf(colorstring, 10, "#%02X%02X%02X%02X", + color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); + lua_pushstring(L, colorstring); + return 1; + } + + return 0; +} + +// colorspec_to_bytes(colorspec) +int ModApiUtil::l_colorspec_to_bytes(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + video::SColor color(0); + if (read_color(L, 1, &color)) { + u8 colorbytes[4] = { + (u8) color.getRed(), + (u8) color.getGreen(), + (u8) color.getBlue(), + (u8) color.getAlpha(), + }; + lua_pushlstring(L, (const char*) colorbytes, 4); + return 1; + } + + return 0; +} + +// encode_png(w, h, data, level) +int ModApiUtil::l_encode_png(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + // The args are already pre-validated on the lua side. + u32 width = readParam(L, 1); + u32 height = readParam(L, 2); + const char *data = luaL_checklstring(L, 3, NULL); + s32 compression = readParam(L, 4); + + std::string out = encodePNG((const u8*)data, width, height, compression); + + lua_pushlstring(L, out.data(), out.size()); + return 1; +} + +// get_last_run_mod() +int ModApiUtil::l_get_last_run_mod(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME); + std::string current_mod = readParam(L, -1, ""); + if (current_mod.empty()) { + lua_pop(L, 1); + lua_pushstring(L, getScriptApiBase(L)->getOrigin().c_str()); + } + return 1; +} + +// set_last_run_mod(modname) +int ModApiUtil::l_set_last_run_mod(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + + const char *mod = luaL_checkstring(L, 1); + getScriptApiBase(L)->setOriginDirect(mod); + return 0; +} void ModApiUtil::Initialize(lua_State *L, int top) { @@ -408,56 +570,100 @@ void ModApiUtil::Initialize(lua_State *L, int top) API_FCT(get_us_time); - API_FCT(setting_set); - API_FCT(setting_get); - API_FCT(setting_setbool); - API_FCT(setting_getbool); - API_FCT(setting_save); - API_FCT(parse_json); API_FCT(write_json); API_FCT(get_dig_params); API_FCT(get_hit_params); + API_FCT(check_password_entry); API_FCT(get_password_hash); API_FCT(is_yes); API_FCT(get_builtin_path); + API_FCT(get_user_path); API_FCT(compress); API_FCT(decompress); API_FCT(mkdir); API_FCT(get_dir_list); + API_FCT(safe_file_write); API_FCT(request_insecure_environment); + + API_FCT(encode_base64); + API_FCT(decode_base64); + + API_FCT(get_version); + API_FCT(sha1); + API_FCT(colorspec_to_colorstring); + API_FCT(colorspec_to_bytes); + + API_FCT(encode_png); + + API_FCT(get_last_run_mod); + API_FCT(set_last_run_mod); + + LuaSettings::create(L, g_settings, g_settings_path); + lua_setfield(L, top, "settings"); } -void ModApiUtil::InitializeAsync(AsyncEngine& engine) +void ModApiUtil::InitializeClient(lua_State *L, int top) { - ASYNC_API_FCT(log); - - ASYNC_API_FCT(get_us_time); + API_FCT(log); - //ASYNC_API_FCT(setting_set); - ASYNC_API_FCT(setting_get); - //ASYNC_API_FCT(setting_setbool); - ASYNC_API_FCT(setting_getbool); - //ASYNC_API_FCT(setting_save); + API_FCT(get_us_time); - ASYNC_API_FCT(parse_json); - ASYNC_API_FCT(write_json); + API_FCT(parse_json); + API_FCT(write_json); - ASYNC_API_FCT(is_yes); + API_FCT(is_yes); - ASYNC_API_FCT(get_builtin_path); + API_FCT(compress); + API_FCT(decompress); - ASYNC_API_FCT(compress); - ASYNC_API_FCT(decompress); + API_FCT(encode_base64); + API_FCT(decode_base64); - ASYNC_API_FCT(mkdir); - ASYNC_API_FCT(get_dir_list); + API_FCT(get_version); + API_FCT(sha1); + API_FCT(colorspec_to_colorstring); + API_FCT(colorspec_to_bytes); } +void ModApiUtil::InitializeAsync(lua_State *L, int top) +{ + API_FCT(log); + + API_FCT(get_us_time); + + API_FCT(parse_json); + API_FCT(write_json); + + API_FCT(is_yes); + + API_FCT(get_builtin_path); + API_FCT(get_user_path); + + API_FCT(compress); + API_FCT(decompress); + + API_FCT(mkdir); + API_FCT(get_dir_list); + + API_FCT(encode_base64); + API_FCT(decode_base64); + + API_FCT(get_version); + API_FCT(sha1); + API_FCT(colorspec_to_colorstring); + API_FCT(colorspec_to_bytes); + + API_FCT(get_last_run_mod); + API_FCT(set_last_run_mod); + + LuaSettings::create(L, g_settings, g_settings_path); + lua_setfield(L, top, "settings"); +}