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 "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"
34 #include "util/auth.h"
35 #include "util/base64.h"
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)
51 LogLevel level = LL_NONE;
52 if (lua_isnone(L, 2)) {
53 text = luaL_checkstring(L, 1);
55 std::string name = luaL_checkstring(L, 1);
56 text = luaL_checkstring(L, 2);
57 if (name == "deprecated") {
58 log_deprecated(L, text);
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;
68 g_logger.log(level, text);
73 int ModApiUtil::l_get_us_time(lua_State *L)
76 lua_pushnumber(L, porting::getTimeUs());
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."); \
86 // setting_set(name, value)
87 int ModApiUtil::l_setting_set(lua_State *L)
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);
98 int ModApiUtil::l_setting_get(lua_State *L)
100 NO_MAP_LOCK_REQUIRED;
101 const char *name = luaL_checkstring(L, 1);
103 std::string value = g_settings->get(name);
104 lua_pushstring(L, value.c_str());
105 } catch(SettingNotFoundException &e){
111 // setting_setbool(name)
112 int ModApiUtil::l_setting_setbool(lua_State *L)
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);
122 // setting_getbool(name)
123 int ModApiUtil::l_setting_getbool(lua_State *L)
125 NO_MAP_LOCK_REQUIRED;
126 const char *name = luaL_checkstring(L, 1);
128 bool value = g_settings->getBool(name);
129 lua_pushboolean(L, value);
130 } catch(SettingNotFoundException &e){
137 int ModApiUtil::l_setting_save(lua_State *L)
139 NO_MAP_LOCK_REQUIRED;
140 if(g_settings_path != "")
141 g_settings->updateConfigFile(g_settings_path.c_str());
145 // parse_json(str[, nullvalue])
146 int ModApiUtil::l_parse_json(lua_State *L)
148 NO_MAP_LOCK_REQUIRED;
150 const char *jsonstr = luaL_checkstring(L, 1);
152 // Use passed nullvalue or default to nil
154 if (lua_isnone(L, nullindex)) {
156 nullindex = lua_gettop(L);
163 std::istringstream stream(jsonstr);
165 if (!reader.parse(stream, root)) {
166 errorstream << "Failed to parse json data "
167 << reader.getFormattedErrorMessages();
168 size_t jlen = strlen(jsonstr);
170 errorstream << "Data (" << jlen
171 << " bytes) printed to warningstream." << std::endl;
172 warningstream << "data: \"" << jsonstr << "\"" << std::endl;
174 errorstream << "data: \"" << jsonstr << "\"" << std::endl;
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;
190 // write_json(data[, styled]) -> string or nil and error message
191 int ModApiUtil::l_write_json(lua_State *L)
193 NO_MAP_LOCK_REQUIRED;
196 if (!lua_isnone(L, 2)) {
197 styled = lua_toboolean(L, 2);
203 read_json_value(L, root, 1);
204 } catch (SerializationError &e) {
206 lua_pushstring(L, e.what());
212 Json::StyledWriter writer;
213 out = writer.write(root);
215 Json::FastWriter writer;
216 out = writer.write(root);
218 lua_pushlstring(L, out.c_str(), out.size());
222 // get_dig_params(groups, tool_capabilities[, time_from_last_punch])
223 int ModApiUtil::l_get_dig_params(lua_State *L)
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));
232 push_dig_params(L, getDigParams(groups, &tp,
233 luaL_checknumber(L, 3)));
237 // get_hit_params(groups, tool_capabilities[, time_from_last_punch])
238 int ModApiUtil::l_get_hit_params(lua_State *L)
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));
247 push_hit_params(L, getHitParams(groups, &tp,
248 luaL_checknumber(L, 3)));
252 // check_password_entry(name, entry, password)
253 int ModApiUtil::l_check_password_entry(lua_State *L)
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);
260 if (base64_is_valid(entry)) {
261 std::string hash = translate_password(name, password);
262 lua_pushboolean(L, hash == entry);
267 std::string verifier;
269 if (!decode_srp_verifier_and_salt(entry, &verifier, &salt)) {
271 warningstream << "Invalid password format for " << name << std::endl;
272 lua_pushboolean(L, false);
275 std::string gen_verifier = generate_srp_verifier(name, password, salt);
277 lua_pushboolean(L, gen_verifier == verifier);
281 // get_password_hash(name, raw_password)
282 int ModApiUtil::l_get_password_hash(lua_State *L)
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());
293 int ModApiUtil::l_is_yes(lua_State *L)
295 NO_MAP_LOCK_REQUIRED;
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
303 bool yes = is_yes(str);
304 lua_pushboolean(L, yes);
308 // get_builtin_path()
309 int ModApiUtil::l_get_builtin_path(lua_State *L)
311 NO_MAP_LOCK_REQUIRED;
313 std::string path = porting::path_share + DIR_DELIM + "builtin";
314 lua_pushstring(L, path.c_str());
319 // compress(data, method, level)
320 int ModApiUtil::l_compress(lua_State *L)
322 NO_MAP_LOCK_REQUIRED;
325 const char *data = luaL_checklstring(L, 1, &size);
328 if (!lua_isnone(L, 3) && !lua_isnil(L, 3))
329 level = luaL_checknumber(L, 3);
331 std::ostringstream os;
332 compressZlib(std::string(data, size), os, level);
334 std::string out = os.str();
336 lua_pushlstring(L, out.data(), out.size());
340 // decompress(data, method)
341 int ModApiUtil::l_decompress(lua_State *L)
343 NO_MAP_LOCK_REQUIRED;
346 const char *data = luaL_checklstring(L, 1, &size);
348 std::istringstream is(std::string(data, size));
349 std::ostringstream os;
350 decompressZlib(is, os);
352 std::string out = os.str();
354 lua_pushlstring(L, out.data(), out.size());
358 // encode_base64(string)
359 int ModApiUtil::l_encode_base64(lua_State *L)
361 NO_MAP_LOCK_REQUIRED;
364 const char *data = luaL_checklstring(L, 1, &size);
366 std::string out = base64_encode((const unsigned char *)(data), size);
368 lua_pushlstring(L, out.data(), out.size());
372 // decode_base64(string)
373 int ModApiUtil::l_decode_base64(lua_State *L)
375 NO_MAP_LOCK_REQUIRED;
378 const char *data = luaL_checklstring(L, 1, &size);
380 std::string out = base64_decode(std::string(data, size));
382 lua_pushlstring(L, out.data(), out.size());
387 int ModApiUtil::l_mkdir(lua_State *L)
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));
396 // get_dir_list(path, is_dir)
397 int ModApiUtil::l_get_dir_list(lua_State *L)
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
404 CHECK_SECURE_PATH(L, path, false);
406 std::vector<fs::DirListNode> list = fs::GetDirListing(path);
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);
421 int ModApiUtil::l_request_insecure_environment(lua_State *L)
423 NO_MAP_LOCK_REQUIRED;
425 // Just return _G if security is disabled
426 if (!ScriptApiSecurity::isSecure(L)) {
427 lua_getglobal(L, "_G");
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.
435 // Make sure there's only one item below this function on the stack...
436 if (lua_getstack(L, 2, &info)) {
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) {
447 lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
448 if (!lua_isstring(L, -1)) {
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)),
458 std::vector<std::string> mod_list = str_split(trusted_mods, ',');
459 if (std::find(mod_list.begin(), mod_list.end(), mod_name) ==
464 // Push insecure environment
465 lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
470 int ModApiUtil::l_get_version(lua_State *L)
472 lua_createtable(L, 0, 3);
473 int table = lua_gettop(L);
475 lua_pushstring(L, PROJECT_NAME_C);
476 lua_setfield(L, table, "project");
478 lua_pushstring(L, g_version_string);
479 lua_setfield(L, table, "string");
481 if (strcmp(g_version_string, g_version_hash)) {
482 lua_pushstring(L, g_version_hash);
483 lua_setfield(L, table, "hash");
490 void ModApiUtil::Initialize(lua_State *L, int top)
494 API_FCT(get_us_time);
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);
505 API_FCT(get_dig_params);
506 API_FCT(get_hit_params);
508 API_FCT(check_password_entry);
509 API_FCT(get_password_hash);
513 API_FCT(get_builtin_path);
519 API_FCT(get_dir_list);
521 API_FCT(request_insecure_environment);
523 API_FCT(encode_base64);
524 API_FCT(decode_base64);
526 API_FCT(get_version);
529 void ModApiUtil::InitializeClient(lua_State *L, int top)
533 API_FCT(setting_set);
534 API_FCT(setting_get);
535 API_FCT(setting_setbool);
536 API_FCT(setting_getbool);
537 API_FCT(setting_save);
544 API_FCT(get_builtin_path);
549 API_FCT(encode_base64);
550 API_FCT(decode_base64);
552 API_FCT(get_version);
555 void ModApiUtil::InitializeAsync(AsyncEngine& engine)
559 ASYNC_API_FCT(get_us_time);
561 //ASYNC_API_FCT(setting_set);
562 ASYNC_API_FCT(setting_get);
563 //ASYNC_API_FCT(setting_setbool);
564 ASYNC_API_FCT(setting_getbool);
565 //ASYNC_API_FCT(setting_save);
567 ASYNC_API_FCT(parse_json);
568 ASYNC_API_FCT(write_json);
570 ASYNC_API_FCT(is_yes);
572 ASYNC_API_FCT(get_builtin_path);
574 ASYNC_API_FCT(compress);
575 ASYNC_API_FCT(decompress);
577 ASYNC_API_FCT(mkdir);
578 ASYNC_API_FCT(get_dir_list);
580 ASYNC_API_FCT(encode_base64);
581 ASYNC_API_FCT(decode_base64);
583 ASYNC_API_FCT(get_version);