X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=src%2Fscript%2Flua_api%2Fl_util.cpp;h=dffbc66d16e2d6644c4b076d543112f1752ec3a6;hb=88b436e6a9c98af7215bd115e1b7a3f1a1db99d3;hp=2bcc114e289ae87afa70998a46187399aa14d369;hpb=6c06330daf04ed1c390131755b64338ca7d79a7e;p=dragonfireclient.git diff --git a/src/script/lua_api/l_util.cpp b/src/script/lua_api/l_util.cpp index 2bcc114e2..dffbc66d1 100644 --- a/src/script/lua_api/l_util.cpp +++ b/src/script/lua_api/l_util.cpp @@ -19,146 +19,65 @@ with this program; if not, write to the Free Software Foundation, Inc., #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 "debug.h" #include "porting.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 -// debug(...) -// Writes a line to dstream -int ModApiUtil::l_debug(lua_State *L) -{ - NO_MAP_LOCK_REQUIRED; - // Handle multiple parameters to behave like standard lua print() - int n = lua_gettop(L); - lua_getglobal(L, "tostring"); - for (int i = 1; i <= n; i++) { - /* - Call tostring(i-th argument). - This is what print() does, and it behaves a bit - differently from directly calling lua_tostring. - */ - lua_pushvalue(L, -1); /* function to be called */ - lua_pushvalue(L, i); /* value to print */ - lua_call(L, 1, 1); - size_t len; - const char *s = lua_tolstring(L, -1, &len); - if (i > 1) - dstream << "\t"; - if (s) - dstream << std::string(s, len); - lua_pop(L, 1); - } - dstream << std::endl; - return 0; -} // log([level,] text) // Writes a line to the logger. // The one-argument version logs to infostream. -// The two-argument version accept a log level: error, action, info, or verbose. +// The two-argument version accepts a log level. +// Either the special case "deprecated" for deprecation notices, or any specified in +// Logger::stringToLevel(name). int ModApiUtil::l_log(lua_State *L) { NO_MAP_LOCK_REQUIRED; std::string text; - LogMessageLevel level = LMT_INFO; + LogLevel level = LL_NONE; if (lua_isnone(L, 2)) { - text = lua_tostring(L, 1); - } - else { - std::string levelname = luaL_checkstring(L, 1); + text = luaL_checkstring(L, 1); + } else { + std::string name = luaL_checkstring(L, 1); text = luaL_checkstring(L, 2); - if(levelname == "error") - level = LMT_ERROR; - else if(levelname == "action") - level = LMT_ACTION; - else if(levelname == "verbose") - level = LMT_VERBOSE; - else if (levelname == "deprecated") { - log_deprecated(L,text); + if (name == "deprecated") { + log_deprecated(L, text); return 0; } - - } - log_printline(level, text); - return 0; -} - -#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); + level = Logger::stringToLevel(name); + if (level == LL_MAX) { + warningstream << "Tried to log at unknown level '" << name + << "'. Defaulting to \"none\"." << std::endl; + level = LL_NONE; + } } - 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); + g_logger.log(level, text); return 0; } -// setting_getbool(name) -int ModApiUtil::l_setting_getbool(lua_State *L) +// get_us_time() +int ModApiUtil::l_get_us_time(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); - } + lua_pushnumber(L, porting::getTimeUs()); 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) { @@ -182,8 +101,14 @@ int ModApiUtil::l_parse_json(lua_State *L) if (!reader.parse(stream, root)) { errorstream << "Failed to parse json data " << reader.getFormattedErrorMessages(); - errorstream << "data: \"" << jsonstr << "\"" - << std::endl; + size_t jlen = strlen(jsonstr); + if (jlen > 100) { + errorstream << "Data (" << jlen + << " bytes) printed to warningstream." << std::endl; + warningstream << "data: \"" << jsonstr << "\"" << std::endl; + } else { + errorstream << "data: \"" << jsonstr << "\"" << std::endl; + } lua_pushnil(L); return 1; } @@ -234,7 +159,7 @@ int ModApiUtil::l_write_json(lua_State *L) 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)) @@ -249,7 +174,7 @@ int ModApiUtil::l_get_dig_params(lua_State *L) 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)) @@ -260,13 +185,42 @@ int ModApiUtil::l_get_hit_params(lua_State *L) 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; +} + // get_password_hash(name, raw_password) 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; } @@ -287,16 +241,22 @@ int ModApiUtil::l_is_yes(lua_State *L) return 1; } +// get_builtin_path() int ModApiUtil::l_get_builtin_path(lua_State *L) { - std::string path = porting::path_share + DIR_DELIM + "builtin"; + NO_MAP_LOCK_REQUIRED; + + std::string path = porting::path_share + DIR_DELIM + "builtin" + DIR_DELIM; lua_pushstring(L, path.c_str()); + return 1; } // compress(data, method, level) int ModApiUtil::l_compress(lua_State *L) { + NO_MAP_LOCK_REQUIRED; + size_t size; const char *data = luaL_checklstring(L, 1, &size); @@ -316,6 +276,8 @@ int ModApiUtil::l_compress(lua_State *L) // decompress(data, method) int ModApiUtil::l_decompress(lua_State *L) { + NO_MAP_LOCK_REQUIRED; + size_t size; const char *data = luaL_checklstring(L, 1, &size); @@ -329,51 +291,143 @@ 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 *data = luaL_checklstring(L, 1, &size); + + std::string out = base64_decode(std::string(data, size)); + + 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; } +// get_dir_list(path, is_dir) +int ModApiUtil::l_get_dir_list(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + const char *path = luaL_checkstring(L, 1); + bool list_all = !lua_isboolean(L, 2); // if its not a boolean list all + bool list_dirs = lua_toboolean(L, 2); // true: list dirs, false: list files + + CHECK_SECURE_PATH(L, path, false); + + std::vector list = fs::GetDirListing(path); + + int index = 0; + lua_newtable(L); + + 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); + } + } + + return 1; +} int ModApiUtil::l_request_insecure_environment(lua_State *L) { NO_MAP_LOCK_REQUIRED; + + // Just return _G if security is disabled if (!ScriptApiSecurity::isSecure(L)) { lua_getglobal(L, "_G"); return 1; } - lua_getfield(L, LUA_REGISTRYINDEX, SCRIPT_MOD_NAME_FIELD); + + // We have to make sure that this function is being called directly by + // a mod, otherwise a malicious mod could override this function and + // steal its return value. + lua_Debug info; + // Make sure there's only one item below this function on the stack... + if (lua_getstack(L, 2, &info)) { + return 0; + } + 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; + } + + // Get mod name + lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME); if (!lua_isstring(L, -1)) { - lua_pushnil(L); - return 1; + return 0; } + + // Check secure.trusted_mods const char *mod_name = lua_tostring(L, -1); std::string trusted_mods = g_settings->get("secure.trusted_mods"); + 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()) { - lua_pushnil(L); - return 1; + if (std::find(mod_list.begin(), mod_list.end(), mod_name) == + mod_list.end()) { + return 0; + } + + // Push insecure environment + lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP); + 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"); } - lua_getfield(L, LUA_REGISTRYINDEX, "globals_backup"); + return 1; } void ModApiUtil::Initialize(lua_State *L, int top) { - API_FCT(debug); API_FCT(log); - API_FCT(setting_set); - API_FCT(setting_get); - API_FCT(setting_setbool); - API_FCT(setting_getbool); - API_FCT(setting_save); + API_FCT(get_us_time); API_FCT(parse_json); API_FCT(write_json); @@ -381,6 +435,7 @@ void ModApiUtil::Initialize(lua_State *L, int top) API_FCT(get_dig_params); API_FCT(get_hit_params); + API_FCT(check_password_entry); API_FCT(get_password_hash); API_FCT(is_yes); @@ -391,31 +446,64 @@ void ModApiUtil::Initialize(lua_State *L, int top) API_FCT(decompress); API_FCT(mkdir); + API_FCT(get_dir_list); API_FCT(request_insecure_environment); + + API_FCT(encode_base64); + API_FCT(decode_base64); + + API_FCT(get_version); + + LuaSettings::create(L, g_settings, g_settings_path); + lua_setfield(L, top, "settings"); +} + +void ModApiUtil::InitializeClient(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(compress); + API_FCT(decompress); + + API_FCT(encode_base64); + API_FCT(decode_base64); + + API_FCT(get_version); } -void ModApiUtil::InitializeAsync(AsyncEngine& engine) +void ModApiUtil::InitializeAsync(lua_State *L, int top) { - ASYNC_API_FCT(debug); - ASYNC_API_FCT(log); + API_FCT(log); + + API_FCT(get_us_time); - //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(parse_json); + API_FCT(write_json); - ASYNC_API_FCT(parse_json); - ASYNC_API_FCT(write_json); + API_FCT(is_yes); + + API_FCT(get_builtin_path); - ASYNC_API_FCT(is_yes); + API_FCT(compress); + API_FCT(decompress); + + API_FCT(mkdir); + API_FCT(get_dir_list); - ASYNC_API_FCT(get_builtin_path); + API_FCT(encode_base64); + API_FCT(decode_base64); - ASYNC_API_FCT(compress); - ASYNC_API_FCT(decompress); + API_FCT(get_version); - ASYNC_API_FCT(mkdir); + LuaSettings::create(L, g_settings, g_settings_path); + lua_setfield(L, top, "settings"); }