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"
39 // Writes a line to the logger.
40 // The one-argument version logs to infostream.
41 // The two-argument version accepts a log level.
42 // Either the special case "deprecated" for deprecation notices, or any specified in
43 // Logger::stringToLevel(name).
44 int ModApiUtil::l_log(lua_State *L)
48 LogLevel level = LL_NONE;
49 if (lua_isnone(L, 2)) {
50 text = luaL_checkstring(L, 1);
52 std::string name = luaL_checkstring(L, 1);
53 text = luaL_checkstring(L, 2);
54 if (name == "deprecated") {
55 log_deprecated(L, text);
58 level = Logger::stringToLevel(name);
59 if (level == LL_MAX) {
60 warningstream << "Tried to log at unknown level '" << name
61 << "'. Defaulting to \"none\"." << std::endl;
65 g_logger.log(level, text);
70 int ModApiUtil::l_get_us_time(lua_State *L)
73 lua_pushnumber(L, porting::getTimeUs());
77 #define CHECK_SECURE_SETTING(L, name) \
78 if (ScriptApiSecurity::isSecure(L) && \
79 name.compare(0, 7, "secure.") == 0) { \
80 throw LuaError("Attempt to set secure setting."); \
83 // setting_set(name, value)
84 int ModApiUtil::l_setting_set(lua_State *L)
87 std::string name = luaL_checkstring(L, 1);
88 std::string value = luaL_checkstring(L, 2);
89 CHECK_SECURE_SETTING(L, name);
90 g_settings->set(name, value);
95 int ModApiUtil::l_setting_get(lua_State *L)
98 const char *name = luaL_checkstring(L, 1);
100 std::string value = g_settings->get(name);
101 lua_pushstring(L, value.c_str());
102 } catch(SettingNotFoundException &e){
108 // setting_setbool(name)
109 int ModApiUtil::l_setting_setbool(lua_State *L)
111 NO_MAP_LOCK_REQUIRED;
112 std::string name = luaL_checkstring(L, 1);
113 bool value = lua_toboolean(L, 2);
114 CHECK_SECURE_SETTING(L, name);
115 g_settings->setBool(name, value);
119 // setting_getbool(name)
120 int ModApiUtil::l_setting_getbool(lua_State *L)
122 NO_MAP_LOCK_REQUIRED;
123 const char *name = luaL_checkstring(L, 1);
125 bool value = g_settings->getBool(name);
126 lua_pushboolean(L, value);
127 } catch(SettingNotFoundException &e){
134 int ModApiUtil::l_setting_save(lua_State *L)
136 NO_MAP_LOCK_REQUIRED;
137 if(g_settings_path != "")
138 g_settings->updateConfigFile(g_settings_path.c_str());
142 // parse_json(str[, nullvalue])
143 int ModApiUtil::l_parse_json(lua_State *L)
145 NO_MAP_LOCK_REQUIRED;
147 const char *jsonstr = luaL_checkstring(L, 1);
149 // Use passed nullvalue or default to nil
151 if (lua_isnone(L, nullindex)) {
153 nullindex = lua_gettop(L);
160 std::istringstream stream(jsonstr);
162 if (!reader.parse(stream, root)) {
163 errorstream << "Failed to parse json data "
164 << reader.getFormattedErrorMessages();
165 size_t jlen = strlen(jsonstr);
167 errorstream << "Data (" << jlen
168 << " bytes) printed to warningstream." << std::endl;
169 warningstream << "data: \"" << jsonstr << "\"" << std::endl;
171 errorstream << "data: \"" << jsonstr << "\"" << std::endl;
178 if (!push_json_value(L, root, nullindex)) {
179 errorstream << "Failed to parse json data, "
180 << "depth exceeds lua stack limit" << std::endl;
181 errorstream << "data: \"" << jsonstr << "\"" << std::endl;
187 // write_json(data[, styled]) -> string or nil and error message
188 int ModApiUtil::l_write_json(lua_State *L)
190 NO_MAP_LOCK_REQUIRED;
193 if (!lua_isnone(L, 2)) {
194 styled = lua_toboolean(L, 2);
200 read_json_value(L, root, 1);
201 } catch (SerializationError &e) {
203 lua_pushstring(L, e.what());
209 Json::StyledWriter writer;
210 out = writer.write(root);
212 Json::FastWriter writer;
213 out = writer.write(root);
215 lua_pushlstring(L, out.c_str(), out.size());
219 // get_dig_params(groups, tool_capabilities[, time_from_last_punch])
220 int ModApiUtil::l_get_dig_params(lua_State *L)
222 NO_MAP_LOCK_REQUIRED;
223 std::map<std::string, int> groups;
224 read_groups(L, 1, groups);
225 ToolCapabilities tp = read_tool_capabilities(L, 2);
226 if(lua_isnoneornil(L, 3))
227 push_dig_params(L, getDigParams(groups, &tp));
229 push_dig_params(L, getDigParams(groups, &tp,
230 luaL_checknumber(L, 3)));
234 // get_hit_params(groups, tool_capabilities[, time_from_last_punch])
235 int ModApiUtil::l_get_hit_params(lua_State *L)
237 NO_MAP_LOCK_REQUIRED;
238 std::map<std::string, int> groups;
239 read_groups(L, 1, groups);
240 ToolCapabilities tp = read_tool_capabilities(L, 2);
241 if(lua_isnoneornil(L, 3))
242 push_hit_params(L, getHitParams(groups, &tp));
244 push_hit_params(L, getHitParams(groups, &tp,
245 luaL_checknumber(L, 3)));
249 // check_password_entry(name, entry, password)
250 int ModApiUtil::l_check_password_entry(lua_State *L)
252 NO_MAP_LOCK_REQUIRED;
253 std::string name = luaL_checkstring(L, 1);
254 std::string entry = luaL_checkstring(L, 2);
255 std::string password = luaL_checkstring(L, 3);
257 if (base64_is_valid(entry)) {
258 std::string hash = translate_password(name, password);
259 lua_pushboolean(L, hash == entry);
264 std::string verifier;
266 if (!decode_srp_verifier_and_salt(entry, &verifier, &salt)) {
268 warningstream << "Invalid password format for " << name << std::endl;
269 lua_pushboolean(L, false);
272 std::string gen_verifier = generate_srp_verifier(name, password, salt);
274 lua_pushboolean(L, gen_verifier == verifier);
278 // get_password_hash(name, raw_password)
279 int ModApiUtil::l_get_password_hash(lua_State *L)
281 NO_MAP_LOCK_REQUIRED;
282 std::string name = luaL_checkstring(L, 1);
283 std::string raw_password = luaL_checkstring(L, 2);
284 std::string hash = translate_password(name, raw_password);
285 lua_pushstring(L, hash.c_str());
290 int ModApiUtil::l_is_yes(lua_State *L)
292 NO_MAP_LOCK_REQUIRED;
294 lua_getglobal(L, "tostring"); // function to be called
295 lua_pushvalue(L, 1); // 1st argument
296 lua_call(L, 1, 1); // execute function
297 std::string str(lua_tostring(L, -1)); // get result
300 bool yes = is_yes(str);
301 lua_pushboolean(L, yes);
305 int ModApiUtil::l_get_builtin_path(lua_State *L)
307 NO_MAP_LOCK_REQUIRED;
309 std::string path = porting::path_share + DIR_DELIM + "builtin";
310 lua_pushstring(L, path.c_str());
314 // compress(data, method, level)
315 int ModApiUtil::l_compress(lua_State *L)
317 NO_MAP_LOCK_REQUIRED;
320 const char *data = luaL_checklstring(L, 1, &size);
323 if (!lua_isnone(L, 3) && !lua_isnil(L, 3))
324 level = luaL_checknumber(L, 3);
326 std::ostringstream os;
327 compressZlib(std::string(data, size), os, level);
329 std::string out = os.str();
331 lua_pushlstring(L, out.data(), out.size());
335 // decompress(data, method)
336 int ModApiUtil::l_decompress(lua_State *L)
338 NO_MAP_LOCK_REQUIRED;
341 const char *data = luaL_checklstring(L, 1, &size);
343 std::istringstream is(std::string(data, size));
344 std::ostringstream os;
345 decompressZlib(is, os);
347 std::string out = os.str();
349 lua_pushlstring(L, out.data(), out.size());
353 // encode_base64(string)
354 int ModApiUtil::l_encode_base64(lua_State *L)
356 NO_MAP_LOCK_REQUIRED;
359 const char *data = luaL_checklstring(L, 1, &size);
361 std::string out = base64_encode((const unsigned char *)(data), size);
363 lua_pushlstring(L, out.data(), out.size());
367 // decode_base64(string)
368 int ModApiUtil::l_decode_base64(lua_State *L)
370 NO_MAP_LOCK_REQUIRED;
373 const char *data = luaL_checklstring(L, 1, &size);
375 std::string out = base64_decode(std::string(data, size));
377 lua_pushlstring(L, out.data(), out.size());
382 int ModApiUtil::l_mkdir(lua_State *L)
384 NO_MAP_LOCK_REQUIRED;
385 const char *path = luaL_checkstring(L, 1);
386 CHECK_SECURE_PATH_OPTIONAL(L, path);
387 lua_pushboolean(L, fs::CreateAllDirs(path));
391 // get_dir_list(path, is_dir)
392 int ModApiUtil::l_get_dir_list(lua_State *L)
394 NO_MAP_LOCK_REQUIRED;
395 const char *path = luaL_checkstring(L, 1);
396 short is_dir = lua_isboolean(L, 2) ? lua_toboolean(L, 2) : -1;
398 CHECK_SECURE_PATH_OPTIONAL(L, path);
400 std::vector<fs::DirListNode> list = fs::GetDirListing(path);
405 for (size_t i = 0; i < list.size(); i++) {
406 if (is_dir == -1 || is_dir == list[i].dir) {
407 lua_pushstring(L, list[i].name.c_str());
408 lua_rawseti(L, -2, ++index);
415 int ModApiUtil::l_request_insecure_environment(lua_State *L)
417 NO_MAP_LOCK_REQUIRED;
419 // Just return _G if security is disabled
420 if (!ScriptApiSecurity::isSecure(L)) {
421 lua_getglobal(L, "_G");
425 // We have to make sure that this function is being called directly by
426 // a mod, otherwise a malicious mod could override this function and
427 // steal its return value.
429 // Make sure there's only one item below this function on the stack...
430 if (lua_getstack(L, 2, &info)) {
433 FATAL_ERROR_IF(!lua_getstack(L, 1, &info), "lua_getstack() failed");
434 FATAL_ERROR_IF(!lua_getinfo(L, "S", &info), "lua_getinfo() failed");
435 // ...and that that item is the main file scope.
436 if (strcmp(info.what, "main") != 0) {
441 lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
442 if (!lua_isstring(L, -1)) {
446 // Check secure.trusted_mods
447 const char *mod_name = lua_tostring(L, -1);
448 std::string trusted_mods = g_settings->get("secure.trusted_mods");
449 trusted_mods.erase(std::remove(trusted_mods.begin(),
450 trusted_mods.end(), ' '), trusted_mods.end());
451 std::vector<std::string> mod_list = str_split(trusted_mods, ',');
452 if (std::find(mod_list.begin(), mod_list.end(), mod_name) ==
457 // Push insecure environment
458 lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
463 void ModApiUtil::Initialize(lua_State *L, int top)
467 API_FCT(get_us_time);
469 API_FCT(setting_set);
470 API_FCT(setting_get);
471 API_FCT(setting_setbool);
472 API_FCT(setting_getbool);
473 API_FCT(setting_save);
478 API_FCT(get_dig_params);
479 API_FCT(get_hit_params);
481 API_FCT(check_password_entry);
482 API_FCT(get_password_hash);
486 API_FCT(get_builtin_path);
492 API_FCT(get_dir_list);
494 API_FCT(request_insecure_environment);
496 API_FCT(encode_base64);
497 API_FCT(decode_base64);
500 void ModApiUtil::InitializeAsync(AsyncEngine& engine)
504 ASYNC_API_FCT(get_us_time);
506 //ASYNC_API_FCT(setting_set);
507 ASYNC_API_FCT(setting_get);
508 //ASYNC_API_FCT(setting_setbool);
509 ASYNC_API_FCT(setting_getbool);
510 //ASYNC_API_FCT(setting_save);
512 ASYNC_API_FCT(parse_json);
513 ASYNC_API_FCT(write_json);
515 ASYNC_API_FCT(is_yes);
517 ASYNC_API_FCT(get_builtin_path);
519 ASYNC_API_FCT(compress);
520 ASYNC_API_FCT(decompress);
522 ASYNC_API_FCT(mkdir);
523 ASYNC_API_FCT(get_dir_list);
525 ASYNC_API_FCT(encode_base64);
526 ASYNC_API_FCT(decode_base64);