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 "lua_api/l_settings.h"
23 #include "common/c_converter.h"
24 #include "common/c_content.h"
25 #include "cpp_api/s_async.h"
26 #include "serialization.h"
27 #include <json/json.h>
28 #include "cpp_api/s_security.h"
30 #include "convert_json.h"
36 #include "util/auth.h"
37 #include "util/base64.h"
41 #include "util/sha1.h"
46 // Writes a line to the logger.
47 // The one-argument version logs to LL_NONE.
48 // The two-argument version accepts a log level.
49 // Either the special case "deprecated" for deprecation notices, or any specified in
50 // Logger::stringToLevel(name).
51 int ModApiUtil::l_log(lua_State *L)
55 LogLevel level = LL_NONE;
56 if (lua_isnone(L, 2)) {
57 text = luaL_checkstring(L, 1);
59 std::string name = luaL_checkstring(L, 1);
60 text = luaL_checkstring(L, 2);
61 if (name == "deprecated") {
62 log_deprecated(L, text, 2);
65 level = Logger::stringToLevel(name);
66 if (level == LL_MAX) {
67 warningstream << "Tried to log at unknown level '" << name
68 << "'. Defaulting to \"none\"." << std::endl;
72 g_logger.log(level, text);
77 int ModApiUtil::l_get_us_time(lua_State *L)
80 lua_pushnumber(L, porting::getTimeUs());
84 // parse_json(str[, nullvalue])
85 int ModApiUtil::l_parse_json(lua_State *L)
89 const char *jsonstr = luaL_checkstring(L, 1);
91 // Use passed nullvalue or default to nil
93 if (lua_isnone(L, nullindex)) {
95 nullindex = lua_gettop(L);
101 std::istringstream stream(jsonstr);
103 Json::CharReaderBuilder builder;
104 builder.settings_["collectComments"] = false;
107 if (!Json::parseFromStream(builder, stream, &root, &errs)) {
108 errorstream << "Failed to parse json data " << errs << std::endl;
109 size_t jlen = strlen(jsonstr);
111 errorstream << "Data (" << jlen
112 << " bytes) printed to warningstream." << std::endl;
113 warningstream << "data: \"" << jsonstr << "\"" << std::endl;
115 errorstream << "data: \"" << jsonstr << "\"" << std::endl;
122 if (!push_json_value(L, root, nullindex)) {
123 errorstream << "Failed to parse json data, "
124 << "depth exceeds lua stack limit" << std::endl;
125 errorstream << "data: \"" << jsonstr << "\"" << std::endl;
131 // write_json(data[, styled]) -> string or nil and error message
132 int ModApiUtil::l_write_json(lua_State *L)
134 NO_MAP_LOCK_REQUIRED;
137 if (!lua_isnone(L, 2)) {
138 styled = readParam<bool>(L, 2);
144 read_json_value(L, root, 1);
145 } catch (SerializationError &e) {
147 lua_pushstring(L, e.what());
153 out = root.toStyledString();
155 out = fastWriteJson(root);
157 lua_pushlstring(L, out.c_str(), out.size());
161 // get_dig_params(groups, tool_capabilities)
162 int ModApiUtil::l_get_dig_params(lua_State *L)
164 NO_MAP_LOCK_REQUIRED;
165 ItemGroupList groups;
166 read_groups(L, 1, groups);
167 ToolCapabilities tp = read_tool_capabilities(L, 2);
168 push_dig_params(L, getDigParams(groups, &tp));
172 // get_hit_params(groups, tool_capabilities[, time_from_last_punch])
173 int ModApiUtil::l_get_hit_params(lua_State *L)
175 NO_MAP_LOCK_REQUIRED;
176 std::unordered_map<std::string, int> groups;
177 read_groups(L, 1, groups);
178 ToolCapabilities tp = read_tool_capabilities(L, 2);
179 if(lua_isnoneornil(L, 3))
180 push_hit_params(L, getHitParams(groups, &tp));
182 push_hit_params(L, getHitParams(groups, &tp, readParam<float>(L, 3)));
186 // check_password_entry(name, entry, password)
187 int ModApiUtil::l_check_password_entry(lua_State *L)
189 NO_MAP_LOCK_REQUIRED;
190 std::string name = luaL_checkstring(L, 1);
191 std::string entry = luaL_checkstring(L, 2);
192 std::string password = luaL_checkstring(L, 3);
194 if (base64_is_valid(entry)) {
195 std::string hash = translate_password(name, password);
196 lua_pushboolean(L, hash == entry);
201 std::string verifier;
203 if (!decode_srp_verifier_and_salt(entry, &verifier, &salt)) {
205 warningstream << "Invalid password format for " << name << std::endl;
206 lua_pushboolean(L, false);
209 std::string gen_verifier = generate_srp_verifier(name, password, salt);
211 lua_pushboolean(L, gen_verifier == verifier);
215 // get_password_hash(name, raw_password)
216 int ModApiUtil::l_get_password_hash(lua_State *L)
218 NO_MAP_LOCK_REQUIRED;
219 std::string name = luaL_checkstring(L, 1);
220 std::string raw_password = luaL_checkstring(L, 2);
221 std::string hash = translate_password(name, raw_password);
222 lua_pushstring(L, hash.c_str());
227 int ModApiUtil::l_is_yes(lua_State *L)
229 NO_MAP_LOCK_REQUIRED;
231 lua_getglobal(L, "tostring"); // function to be called
232 lua_pushvalue(L, 1); // 1st argument
233 lua_call(L, 1, 1); // execute function
234 std::string str = readParam<std::string>(L, -1); // get result
237 bool yes = is_yes(str);
238 lua_pushboolean(L, yes);
243 int ModApiUtil::l_is_nan(lua_State *L)
245 NO_MAP_LOCK_REQUIRED;
247 lua_pushboolean(L, isNaN(L, 1));
251 // get_builtin_path()
252 int ModApiUtil::l_get_builtin_path(lua_State *L)
254 NO_MAP_LOCK_REQUIRED;
256 std::string path = porting::path_share + DIR_DELIM + "builtin" + DIR_DELIM;
257 lua_pushstring(L, path.c_str());
262 // compress(data, method, level)
263 int ModApiUtil::l_compress(lua_State *L)
265 NO_MAP_LOCK_REQUIRED;
268 const char *data = luaL_checklstring(L, 1, &size);
271 if (!lua_isnone(L, 3) && !lua_isnil(L, 3))
272 level = readParam<float>(L, 3);
274 std::ostringstream os;
275 compressZlib(std::string(data, size), os, level);
277 std::string out = os.str();
279 lua_pushlstring(L, out.data(), out.size());
283 // decompress(data, method)
284 int ModApiUtil::l_decompress(lua_State *L)
286 NO_MAP_LOCK_REQUIRED;
289 const char *data = luaL_checklstring(L, 1, &size);
291 std::istringstream is(std::string(data, size));
292 std::ostringstream os;
293 decompressZlib(is, os);
295 std::string out = os.str();
297 lua_pushlstring(L, out.data(), out.size());
301 // encode_base64(string)
302 int ModApiUtil::l_encode_base64(lua_State *L)
304 NO_MAP_LOCK_REQUIRED;
307 const char *data = luaL_checklstring(L, 1, &size);
309 std::string out = base64_encode((const unsigned char *)(data), size);
311 lua_pushlstring(L, out.data(), out.size());
315 // decode_base64(string)
316 int ModApiUtil::l_decode_base64(lua_State *L)
318 NO_MAP_LOCK_REQUIRED;
321 const char *d = luaL_checklstring(L, 1, &size);
322 const std::string data = std::string(d, size);
324 if (!base64_is_valid(data))
327 std::string out = base64_decode(data);
329 lua_pushlstring(L, out.data(), out.size());
334 int ModApiUtil::l_mkdir(lua_State *L)
336 NO_MAP_LOCK_REQUIRED;
337 const char *path = luaL_checkstring(L, 1);
338 CHECK_SECURE_PATH(L, path, true);
339 lua_pushboolean(L, fs::CreateAllDirs(path));
343 // get_dir_list(path, is_dir)
344 int ModApiUtil::l_get_dir_list(lua_State *L)
346 NO_MAP_LOCK_REQUIRED;
347 const char *path = luaL_checkstring(L, 1);
348 bool list_all = !lua_isboolean(L, 2); // if its not a boolean list all
349 bool list_dirs = readParam<bool>(L, 2); // true: list dirs, false: list files
351 CHECK_SECURE_PATH(L, path, false);
353 std::vector<fs::DirListNode> list = fs::GetDirListing(path);
358 for (const fs::DirListNode &dln : list) {
359 if (list_all || list_dirs == dln.dir) {
360 lua_pushstring(L, dln.name.c_str());
361 lua_rawseti(L, -2, ++index);
368 // safe_file_write(path, content)
369 int ModApiUtil::l_safe_file_write(lua_State *L)
371 NO_MAP_LOCK_REQUIRED;
372 const char *path = luaL_checkstring(L, 1);
374 const char *content = luaL_checklstring(L, 2, &size);
376 CHECK_SECURE_PATH(L, path, true);
378 bool ret = fs::safeWriteToFile(path, std::string(content, size));
379 lua_pushboolean(L, ret);
384 // request_insecure_environment()
385 int ModApiUtil::l_request_insecure_environment(lua_State *L)
387 NO_MAP_LOCK_REQUIRED;
389 // Just return _G if security is disabled
390 if (!ScriptApiSecurity::isSecure(L)) {
391 lua_getglobal(L, "_G");
395 // We have to make sure that this function is being called directly by
396 // a mod, otherwise a malicious mod could override this function and
397 // steal its return value.
399 // Make sure there's only one item below this function on the stack...
400 if (lua_getstack(L, 2, &info)) {
403 FATAL_ERROR_IF(!lua_getstack(L, 1, &info), "lua_getstack() failed");
404 FATAL_ERROR_IF(!lua_getinfo(L, "S", &info), "lua_getinfo() failed");
405 // ...and that that item is the main file scope.
406 if (strcmp(info.what, "main") != 0) {
411 lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_CURRENT_MOD_NAME);
412 if (!lua_isstring(L, -1)) {
416 // Check secure.trusted_mods
417 std::string mod_name = readParam<std::string>(L, -1);
418 std::string trusted_mods = g_settings->get("secure.trusted_mods");
419 trusted_mods.erase(std::remove_if(trusted_mods.begin(),
420 trusted_mods.end(), static_cast<int(*)(int)>(&std::isspace)),
422 std::vector<std::string> mod_list = str_split(trusted_mods, ',');
423 if (std::find(mod_list.begin(), mod_list.end(), mod_name) ==
428 // Push insecure environment
429 lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_GLOBALS_BACKUP);
434 int ModApiUtil::l_get_version(lua_State *L)
436 lua_createtable(L, 0, 3);
437 int table = lua_gettop(L);
439 lua_pushstring(L, PROJECT_NAME_C);
440 lua_setfield(L, table, "project");
442 lua_pushstring(L, g_version_string);
443 lua_setfield(L, table, "string");
445 if (strcmp(g_version_string, g_version_hash) != 0) {
446 lua_pushstring(L, g_version_hash);
447 lua_setfield(L, table, "hash");
453 int ModApiUtil::l_sha1(lua_State *L)
455 NO_MAP_LOCK_REQUIRED;
457 const char *data = luaL_checklstring(L, 1, &size);
458 bool hex = !lua_isboolean(L, 2) || !readParam<bool>(L, 2);
460 // Compute actual checksum of data
461 std::string data_sha1;
464 ctx.addBytes(data, size);
465 unsigned char *data_tmpdigest = ctx.getDigest();
466 data_sha1.assign((char*) data_tmpdigest, 20);
467 free(data_tmpdigest);
471 std::string sha1_hex = hex_encode(data_sha1);
472 lua_pushstring(L, sha1_hex.c_str());
474 lua_pushlstring(L, data_sha1.data(), data_sha1.size());
480 void ModApiUtil::Initialize(lua_State *L, int top)
484 API_FCT(get_us_time);
489 API_FCT(get_dig_params);
490 API_FCT(get_hit_params);
492 API_FCT(check_password_entry);
493 API_FCT(get_password_hash);
498 API_FCT(get_builtin_path);
504 API_FCT(get_dir_list);
505 API_FCT(safe_file_write);
507 API_FCT(request_insecure_environment);
509 API_FCT(encode_base64);
510 API_FCT(decode_base64);
512 API_FCT(get_version);
515 LuaSettings::create(L, g_settings, g_settings_path);
516 lua_setfield(L, top, "settings");
519 void ModApiUtil::InitializeClient(lua_State *L, int top)
523 API_FCT(get_us_time);
534 API_FCT(encode_base64);
535 API_FCT(decode_base64);
537 API_FCT(get_version);
541 void ModApiUtil::InitializeAsync(lua_State *L, int top)
545 API_FCT(get_us_time);
552 API_FCT(get_builtin_path);
558 API_FCT(get_dir_list);
560 API_FCT(encode_base64);
561 API_FCT(decode_base64);
563 API_FCT(get_version);
566 LuaSettings::create(L, g_settings, g_settings_path);
567 lua_setfield(L, top, "settings");