From 37c5d05d71b2dedafe2187dc2d3fb444b94cd913 Mon Sep 17 00:00:00 2001 From: sbx320 Date: Mon, 27 May 2019 12:23:05 +0200 Subject: [PATCH 01/25] Initial version of new style Lua argument parsing --- .../mods/deathmatch/logic/luadefs/CLuaDefs.h | 39 ++- .../mods/deathmatch/logic/luadefs/CLuaDefs.h | 37 +++ .../deathmatch/logic/lua/CLuaFunctionParser.h | 223 +++++++++++++++ Shared/mods/deathmatch/logic/lua/LuaBasic.cpp | 53 ++++ Shared/mods/deathmatch/logic/lua/LuaBasic.h | 97 +++++++ .../logic/luadefs/CLuaCryptDefs.cpp | 260 +++++------------- .../deathmatch/logic/luadefs/CLuaCryptDefs.h | 22 +- Shared/sdk/SharedUtil.Template.h | 68 +++++ 8 files changed, 604 insertions(+), 195 deletions(-) create mode 100644 Shared/mods/deathmatch/logic/lua/CLuaFunctionParser.h create mode 100644 Shared/mods/deathmatch/logic/lua/LuaBasic.cpp create mode 100644 Shared/mods/deathmatch/logic/lua/LuaBasic.h create mode 100644 Shared/sdk/SharedUtil.Template.h diff --git a/Client/mods/deathmatch/logic/luadefs/CLuaDefs.h b/Client/mods/deathmatch/logic/luadefs/CLuaDefs.h index d533baef6c1..a136499026a 100644 --- a/Client/mods/deathmatch/logic/luadefs/CLuaDefs.h +++ b/Client/mods/deathmatch/logic/luadefs/CLuaDefs.h @@ -64,4 +64,41 @@ class CLuaDefs static CClientDFFManager* m_pDFFManager; static CClientColModelManager* m_pColModelManager; static CRegisteredCommands* m_pRegisteredCommands; -}; \ No newline at end of file + +protected: + // Old style: Only warn on failure. This should + // not be used for new functions + template + static inline int ArgumentParserWarn(lua_State* L) + { + int iReturnValue = CLuaFunctionParser()(L); + if (iReturnValue < 0) + { + m_pScriptDebugging->LogCustom(L, "todo fix error message"); + lua_pushboolean(L, false); + return 1; + } + return iReturnValue; + } + + // New style: hard error on usage mistakes + template + static inline int ArgumentParser(lua_State* L) + { + try + { + int iReturnValue = CLuaFunctionParser()(L); + if (iReturnValue < 0) + { + luaL_error(L, "todo fix error message"); + return 1; + } + return iReturnValue; + } + catch (CLuaError& e) + { + luaL_error(L, e.what()); + return 0; + } + } +}; diff --git a/Server/mods/deathmatch/logic/luadefs/CLuaDefs.h b/Server/mods/deathmatch/logic/luadefs/CLuaDefs.h index 0fb4473690a..8f28da906dd 100644 --- a/Server/mods/deathmatch/logic/luadefs/CLuaDefs.h +++ b/Server/mods/deathmatch/logic/luadefs/CLuaDefs.h @@ -84,4 +84,41 @@ class CLuaDefs static CResourceManager* m_pResourceManager; static CAccessControlListManager* m_pACLManager; static CMainConfig* m_pMainConfig; + +protected: + // Old style: Only warn on failure. This should + // not be used for new functions + template + static inline int ArgumentParserWarn(lua_State* L) + { + int iReturnValue = CLuaFunctionParser()(L); + if (iReturnValue < 0) + { + m_pScriptDebugging->LogCustom(L, "todo fix error message"); + lua_pushboolean(L, false); + return 1; + } + return iReturnValue; + } + + // New style: hard error on usage mistakes + template + static inline int ArgumentParser(lua_State* L) + { + try + { + int iReturnValue = CLuaFunctionParser()(L); + if (iReturnValue < 0) + { + luaL_error(L, "todo fix error message"); + return 1; + } + return iReturnValue; + } + catch (CLuaError& e) + { + luaL_error(L, e.what()); + return 0; + } + } }; diff --git a/Shared/mods/deathmatch/logic/lua/CLuaFunctionParser.h b/Shared/mods/deathmatch/logic/lua/CLuaFunctionParser.h new file mode 100644 index 00000000000..17224a49da3 --- /dev/null +++ b/Shared/mods/deathmatch/logic/lua/CLuaFunctionParser.h @@ -0,0 +1,223 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * LICENSE: See LICENSE in the top level directory + * + * Multi Theft Auto is available from http://www.multitheftauto.com/ + * + *****************************************************************************/ + +#include +#include +#include +#include "lua/LuaBasic.h" + +template +struct CLuaFunctionParser +{ +}; + +template Ret> +struct CLuaFunctionParser +{ + std::size_t iIndex = 1; + bool bFailed = false; + + // Pop should remove a T from the Lua Stack after verifying that it is a valid type + // Pop may also throw a LuaArgumentError to indicate failure + template + inline T Pop(lua_State* L, std::size_t& index) + { + if (!TypeMatch(L, index)) + { + // TODO: resolve error + bFailed = true; + return T{}; + } + return PopUnsafe(L, index); + } + + // TypeMatch should return true if the value on top of the Lua stack can be popped via + // PopUnsafe. This must accurately reflect the associated PopUnsafe. Note that TypeMatch + // should only check for obvious type violations (e.g. false is not a string) but not + // for internal type errors (passing a vehicle to a function expecting a ped) + template + inline bool TypeMatch(lua_State* L, std::size_t index) + { + int iArgument = lua_type(L, index); + // trivial types + if constexpr (std::is_same_v) + return (iArgument == LUA_TSTRING || iArgument == LUA_TNUMBER); + if constexpr (std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v) + return (iArgument == LUA_TSTRING || iArgument == LUA_TNUMBER); + + // advanced types + // Enums are represented as strings to Lua + if constexpr (std::is_enum_v) + return iArgument == LUA_TSTRING; + // std::optional is used for optional parameters + // which may also be in the middle of a parameter list + // therefore it is always valid to attempt to read an + // optional + if constexpr (is_specialization::value) + return true; + + // std::vector is used for arrays built from tables + if constexpr (is_2specialization::value) + return iArgument == LUA_TTABLE; + + // std::unordered_map is used for maps built from tables + if constexpr (is_5specialization::value) + return iArgument == LUA_TTABLE; + + // CLuaFunctionRef is used for functions + if constexpr (std::is_same_v) + return iArgument == LUA_TFUNCTION; + + // lua_State* can be taken as argument anywhere + if constexpr (std::is_same_v) + return true; + + // Catch all for class pointer types, assume all classes are valid script entities + // and can be fetched from a userdata + if constexpr (std::is_pointer_v && std::is_class_v>) + return iArgument == LUA_TUSERDATA || iArgument == LUA_TLIGHTUSERDATA; + } + + template + inline T PopUnsafe(lua_State* L, std::size_t& index) + { + // trivial types are directly popped + if constexpr (std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v || std::is_same_v) + return lua::PopTrivial(L, index); + else if constexpr (std::is_enum_v) + { + // Enums are considered strings in Lua + std::string strValue = lua::PopTrivial(L, index); + T eValue; + if (StringToEnum(strValue, eValue)) + return eValue; + else + { + bFailed = true; + // TODO: resolve error + return static_cast(0); + } + } + else if constexpr (is_specialization::value) + { + // optionals may either type match the desired value, or be nullopt + using param = typename is_specialization::param_t; + if (TypeMatch(L, index)) + return PopUnsafe(L, index); + else + return std::nullopt; + } + + else if constexpr (is_2specialization::value) // 2 specialization due to allocator + { + using param = typename is_2specialization::param1_t; + T vecData; + lua_pushnil(L); /* first key */ + while (lua_next(L, index) != 0) + { + if (!TypeMatch(L, -1) || !TypeMatch(L, -2)) + { + bFailed = true; + // TODO: resolve error + return vecData; + } + + std::size_t i = -1; + vecData.emplace_back(PopUnsafe(L, i)); + lua_pop(L, 1); // drop value, keep key for lua_next + } + ++index; + return vecData; + } + else if constexpr (is_5specialization::value) + { + using key_t = typename is_5specialization::param1_t; + using value_t = typename is_5specialization::param2_t; + T map; + lua_pushnil(L); /* first key */ + while (lua_next(L, index) != 0) + { + if (!TypeMatch(L, -1) || !TypeMatch(L, -2)) + { + bFailed = true; + // TODO: resolve error + return map; + } + + + std::size_t i = -2; + auto k = PopUnsafe(L, i); + auto v = PopUnsafe(L, i); + map.emplace(std::move(k), std::move(v)); + lua_pop(L, 1); // drop value, keep key for lua_next + } + ++index; + return map; + } + else if constexpr (std::is_same_v) + { + return luaM_toref(L, index++); + } + if constexpr (std::is_same_v) + return L; + // Catch all for class pointer types, assume all classes are valid script entities + // and can be fetched from a userdata + else if constexpr (std::is_pointer_v && std::is_class_v>) + { + bool isLightUserData = lua_type(L, index) == LUA_TLIGHTUSERDATA; + void* pValue = PopTrivial(L, index); + using class_t = std::remove_pointer_t; + T result = nullptr; + if (isLightUserData) + { + result = UserDataCast((class_t*)0, pValue, L); + } + else + { + result = UserDataCast((class_t*)0, *reinterpret_cast(pValue), L); + } + if (result == nullptr) + { + bFailed = true; + // TODO: resolve error + return nullptr; + } + return result; + } + } + + template + inline auto Call(lua_State* L, Params&&... ps) + { + if (bFailed) + { + return -1; + } + if constexpr (sizeof...(Params) == sizeof...(Args)) + { + if constexpr (std::is_same_v) + { + Func(std::forward(ps)...); + return 0; + } + else + { + return lua::Push(L, Func(std::forward(ps)...)); + } + } + else + { + return Call(L, ps..., Pop::type>(L, iIndex)); + } + } + + inline auto operator()(lua_State* L) { return Call(L); } +}; diff --git a/Shared/mods/deathmatch/logic/lua/LuaBasic.cpp b/Shared/mods/deathmatch/logic/lua/LuaBasic.cpp new file mode 100644 index 00000000000..d5be1e51343 --- /dev/null +++ b/Shared/mods/deathmatch/logic/lua/LuaBasic.cpp @@ -0,0 +1,53 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * LICENSE: See LICENSE in the top level directory + * + * Multi Theft Auto is available from http://www.multitheftauto.com/ + * + *****************************************************************************/ +#include +#include "LuaBasic.h" + +namespace lua +{ + int Push(lua_State* L, int value) + { + lua_pushnumber(L, value); + return 1; + } + + int Push(lua_State* L, bool value) + { + lua_pushboolean(L, value); + return 1; + } + + int Push(lua_State* L, const std::string& value) + { + lua_pushlstring(L, value.data(), value.length()); + return 1; + } + + + template <> + std::string PopTrivial(lua_State* L, std::size_t& index) + { + uint uiLength = lua_strlen(L, index); + std::string outValue; + outValue.assign(lua_tostring(L, index++), uiLength); + return outValue; + } + + template <> + int PopTrivial(lua_State* L, std::size_t& index) + { + return static_cast(lua_tonumber(L, index++)); + } + + template <> + void* PopTrivial(lua_State* L, std::size_t& index) + { + return lua_touserdata(L, index++); + } +} // namespace mta::impl diff --git a/Shared/mods/deathmatch/logic/lua/LuaBasic.h b/Shared/mods/deathmatch/logic/lua/LuaBasic.h new file mode 100644 index 00000000000..ee7d5d8cd6d --- /dev/null +++ b/Shared/mods/deathmatch/logic/lua/LuaBasic.h @@ -0,0 +1,97 @@ +/***************************************************************************** + * + * PROJECT: Multi Theft Auto + * LICENSE: See LICENSE in the top level directory + * + * Multi Theft Auto is available from http://www.multitheftauto.com/ + * + *****************************************************************************/ +#pragma once +#include +#include + +/* + Basic Lua operations: + int Push(L, T value) + T PopTrivial(L, std::size_t stackIndex) + bool TypeMatch(L, std::size_t stackIndex) +*/ + + +namespace lua +{ + // PopTrival should read a simple value of type T from the stack without extra type checks + // If whatever is at that point in the stack is not convertible to T, the behavior is undefined + template + inline T PopTrivial(lua_State* L, std::size_t& index); + + + // Push should push a value of type T to the Lua Stack + // The return value must be the amount of items pushed to the stack, which should + // be 1 for trivial types (e.g. Push) but may be any number for special cases + // like tuples + + template + int Push(lua_State* L, const std::variant&& val) + { + return std::visit([L](auto&& value) -> int { return Push(L, value); }, val); + } + + template + int Push(lua_State* L, const std::optional&& val) + { + if (val.has_value()) + return Push(L, val.value()); + else + return Push(L, nullptr); + } + + template + int Push(lua_State* L, const std::vector&& val) + { + lua_newtable(L); + int i = 1; + for (auto&& v : val) + { + Push(L, i++); + Push(L, v); + lua_settable(L, -3); + } + return 1; + } + + template + int Push(lua_State* L, const std::unordered_map&& val) + { + lua_newtable(L); + for (auto&& [k, v] : val) + { + Push(L, k); + Push(L, v); + lua_settable(L, -3); + } + return 1; + } + + template + typename std::enable_if_t, int> Push(lua_State* L, const T&& val) + { + return Push(L, EnumToString(val)); + } + + template + typename std::enable_if_t<(std::is_pointer_v && std::is_class_v>), int> Push(lua_State* L, const T&& val) + { + lua_pushelement(L, val); + return 1; + } + + int Push(lua_State* L, int val); + int Push(lua_State* L, const std::string& val); + int Push(lua_State* L, bool val); + int Push(lua_State* L, nullptr_t); + int Push(lua_State* L, float val); + int Push(lua_State* L, double val); + int Push(lua_State* L, unsigned int val); + int Push(lua_State* L, unsigned short val); +} diff --git a/Shared/mods/deathmatch/logic/luadefs/CLuaCryptDefs.cpp b/Shared/mods/deathmatch/logic/luadefs/CLuaCryptDefs.cpp index ab444625b68..c367137e509 100644 --- a/Shared/mods/deathmatch/logic/luadefs/CLuaCryptDefs.cpp +++ b/Shared/mods/deathmatch/logic/luadefs/CLuaCryptDefs.cpp @@ -9,17 +9,19 @@ *****************************************************************************/ #include "StdInc.h" #include +#include + void CLuaCryptDefs::LoadFunctions() { std::map functions{ - {"md5", Md5}, - {"sha256", Sha256}, - {"hash", Hash}, - {"teaEncode", TeaEncode}, - {"teaDecode", TeaDecode}, - {"base64Encode", Base64encode}, - {"base64Decode", Base64decode}, + {"md5", ArgumentParserWarn}, + {"sha256", ArgumentParserWarn}, + {"hash", ArgumentParserWarn}, + {"teaEncode", ArgumentParserWarn}, + {"teaDecode", ArgumentParserWarn}, + {"base64Encode", ArgumentParserWarn}, + {"base64Decode", ArgumentParserWarn}, {"passwordHash", PasswordHash}, {"passwordVerify", PasswordVerify}, {"encodeString", EncodeString}, @@ -33,182 +35,87 @@ void CLuaCryptDefs::LoadFunctions() } } -int CLuaCryptDefs::Md5(lua_State* luaVM) -{ - SString strMd5 = ""; - CScriptArgReader argStream(luaVM); - argStream.ReadString(strMd5); - if (!argStream.HasErrors()) - { - MD5 md5bytes; - char szResult[33]; - CMD5Hasher hasher; - hasher.Calculate(strMd5, strMd5.length(), md5bytes); - hasher.ConvertToHex(md5bytes, szResult); - lua_pushstring(luaVM, szResult); - return 1; - } - else - m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage()); - - lua_pushboolean(luaVM, false); - return 1; +std::string CLuaCryptDefs::Md5(std::string strMd5) +{ + MD5 md5bytes; + char szResult[33]; + CMD5Hasher hasher; + hasher.Calculate(strMd5.data(), strMd5.length(), md5bytes); + hasher.ConvertToHex(md5bytes, szResult); + return szResult; } -int CLuaCryptDefs::Sha256(lua_State* luaVM) +std::string CLuaCryptDefs::Sha256(std::string strSourceData) { - // string sha256 ( string str ) - SString strSourceData; - - CScriptArgReader argStream(luaVM); - argStream.ReadString(strSourceData); - - if (!argStream.HasErrors()) - { - SString strResult = GenerateSha256HexString(strSourceData); - lua_pushstring(luaVM, strResult); - return 1; - } - else - m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage()); - - lua_pushboolean(luaVM, false); - return 1; + return GenerateSha256HexString(strSourceData); } -int CLuaCryptDefs::Hash(lua_State* luaVM) +std::string CLuaCryptDefs::Hash(EHashFunctionType hashFunction, std::string strSourceData) { - // string hash ( string type, string data ) - EHashFunctionType hashFunction; - SString strSourceData; - - CScriptArgReader argStream(luaVM); - argStream.ReadEnumString(hashFunction); - argStream.ReadString(strSourceData); - - if (!argStream.HasErrors()) - { - SString strResult = GenerateHashHexString(hashFunction, strSourceData); - lua_pushstring(luaVM, strResult.ToLower()); - return 1; - } - else - m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage()); - - lua_pushboolean(luaVM, false); - return 1; + return GenerateHashHexString(hashFunction, strSourceData); } -int CLuaCryptDefs::TeaEncode(lua_State* luaVM) +std::string CLuaCryptDefs::TeaEncode(std::string str, std::string key) { - SString str; - SString key; - - CScriptArgReader argStream(luaVM); - argStream.ReadString(str); - argStream.ReadString(key); - - if (!argStream.HasErrors()) - { - SString result; - SString humanReadableResult; - SharedUtil::TeaEncode(str, key, &result); - humanReadableResult = SharedUtil::Base64encode(result); - lua_pushstring(luaVM, humanReadableResult); - return 1; - } - else - m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage()); - - lua_pushboolean(luaVM, false); - return 1; + SString result; + SharedUtil::TeaEncode(str, key, &result); + return SharedUtil::Base64encode(result); } -int CLuaCryptDefs::TeaDecode(lua_State* luaVM) +std::string CLuaCryptDefs::TeaDecode(std::string str, std::string key) { - SString str; - SString key; - - CScriptArgReader argStream(luaVM); - argStream.ReadString(str); - argStream.ReadString(key); - - if (!argStream.HasErrors()) - { - SString result = SharedUtil::Base64decode(str); - SharedUtil::TeaDecode(result, key, &str); - lua_pushstring(luaVM, str); - return 1; - } - else - m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage()); - - lua_pushboolean(luaVM, false); - return 1; + SString fixme = str; + SString result = SharedUtil::Base64decode(str); + SharedUtil::TeaDecode(result, key, &fixme); + return fixme; } -int CLuaCryptDefs::Base64encode(lua_State* luaVM) +std::string CLuaCryptDefs::Base64encode(std::string str) { - SString str; - - CScriptArgReader argStream(luaVM); - argStream.ReadString(str); - - if (!argStream.HasErrors()) - { - lua_pushstring(luaVM, SharedUtil::Base64encode(str)); - return 1; - } - else - m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage()); - - lua_pushboolean(luaVM, false); - return 1; + return SharedUtil::Base64encode(str); } -int CLuaCryptDefs::Base64decode(lua_State* luaVM) +std::string CLuaCryptDefs::Base64decode(std::string str) { - SString str; - - CScriptArgReader argStream(luaVM); - argStream.ReadString(str); + return SharedUtil::Base64decode(str); +} - if (!argStream.HasErrors()) +std::variant CLuaCryptDefs::PasswordHash(lua_State* luaVM, std::string password, PasswordHashFunction algorithm, + std::unordered_map options, std::optional luaFunctionRef) +{ + // string password_hash(string password, string algorithm, table options = {} [, function callback]) + if (algorithm != PasswordHashFunction::Bcrypt) { - SString result = SharedUtil::Base64decode(str); - lua_pushlstring(luaVM, result, result.length()); - return 1; + throw std::invalid_argument("Invalid algorithm"); } - else - m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage()); - lua_pushboolean(luaVM, false); - return 1; -} + // Set default value to 10 + if (options["cost"].empty()) + options["cost"] = "10"; -int CLuaCryptDefs::PasswordHash(lua_State* luaVM) -{ - // string password_hash(string password, string algorithm, table options = {} [, function callback]) - SString password; - PasswordHashFunction algorithm; - CStringMap options; - CLuaFunctionRef luaFunctionRef; + std::stringstream ss(options["cost"]); + std::size_t cost; + ss >> cost; - CScriptArgReader argStream(luaVM); - argStream.ReadString(password); - argStream.ReadEnumString(algorithm); - argStream.ReadStringMap(options); + if (ss.fail()) + throw std::invalid_argument("Invalid value for field 'cost'"); - if (argStream.NextIsFunction()) + // Sync + if (!luaFunctionRef.has_value()) { - argStream.ReadFunction(luaFunctionRef); - argStream.ReadFunctionComplete(); + SString hash = SharedUtil::BcryptHash(password, options["salt"], cost); + if (!hash.empty()) + { + return hash; + } + else + throw std::invalid_argument("Invalid value for field 'salt'"); } - - if (!argStream.HasErrors()) + else // Async { - if (algorithm == PasswordHashFunction::Bcrypt) + CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine(luaVM); + if (pLuaMain) { // Set default value to 10 if (options["cost"].empty()) @@ -244,43 +151,24 @@ int CLuaCryptDefs::PasswordHash(lua_State* luaVM) CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine(luaVM); if (pLuaMain) { - CLuaShared::GetAsyncTaskScheduler()->PushTask( - [password, salt = options["salt"], cost] { - // Execute time-consuming task - return SharedUtil::BcryptHash(password, salt, cost); - }, - [luaFunctionRef](const SString& hash) { - CLuaMain* pLuaMain = m_pLuaManager->GetVirtualMachine(luaFunctionRef.GetLuaVM()); - if (pLuaMain) - { - CLuaArguments arguments; + CLuaArguments arguments; - if (hash.empty()) - { - m_pScriptDebugging->LogCustom(pLuaMain->GetVM(), "Invalid value for field 'salt'"); - arguments.PushBoolean(false); - } - else - arguments.PushString(hash); + if (hash.empty()) + { + m_pScriptDebugging->LogCustom(pLuaMain->GetVM(), "Invalid value for field 'salt'"); + arguments.PushBoolean(false); + } + else + arguments.PushString(hash); - arguments.Call(pLuaMain, luaFunctionRef); - } - }); - - lua_pushboolean(luaVM, true); - return 1; + arguments.Call(pLuaMain, luaFunctionRef.value()); } - } - } - else - m_pScriptDebugging->LogWarning(luaVM, "Invalid value for field 'cost'"); + }); + + return true; } + return false; } - else - m_pScriptDebugging->LogCustom(luaVM, argStream.GetFullErrorMessage()); - - lua_pushboolean(luaVM, false); - return 1; } int CLuaCryptDefs::PasswordVerify(lua_State* luaVM) diff --git a/Shared/mods/deathmatch/logic/luadefs/CLuaCryptDefs.h b/Shared/mods/deathmatch/logic/luadefs/CLuaCryptDefs.h index 5c6e652b48a..99bb9c7f965 100644 --- a/Shared/mods/deathmatch/logic/luadefs/CLuaCryptDefs.h +++ b/Shared/mods/deathmatch/logic/luadefs/CLuaCryptDefs.h @@ -10,20 +10,26 @@ #pragma once #include "luadefs/CLuaDefs.h" +#include +#include class CLuaCryptDefs : public CLuaDefs { public: static void LoadFunctions(); - LUA_DECLARE(Md5); - LUA_DECLARE(Sha256); - LUA_DECLARE(Hash); - LUA_DECLARE(TeaEncode); - LUA_DECLARE(TeaDecode); - LUA_DECLARE(Base64encode); - LUA_DECLARE(Base64decode); - LUA_DECLARE(PasswordHash); + static std::string Md5(std::string strMd5); + + static std::string Hash(EHashFunctionType hashFunction, std::string strSourceData); + + static std::string TeaEncode(std::string str, std::string key); + static std::string TeaDecode(std::string str, std::string key); + static std::string Base64encode(std::string str); + static std::string Base64decode(std::string str); + static std::variant PasswordHash(lua_State* luaVM, std::string password, PasswordHashFunction algorithm, + std::unordered_map options, + std::optional luaFunctionRef); + static std::string Sha256(std::string strSourceData); LUA_DECLARE(PasswordVerify); LUA_DECLARE(EncodeString); LUA_DECLARE(DecodeString); diff --git a/Shared/sdk/SharedUtil.Template.h b/Shared/sdk/SharedUtil.Template.h new file mode 100644 index 00000000000..d5284e563d5 --- /dev/null +++ b/Shared/sdk/SharedUtil.Template.h @@ -0,0 +1,68 @@ +#pragma once + +/** + is_Nspecialization + + These structs allow testing whether a type is a specialization of a + class template + + Note: Take care of optional parameters. For example std::unordered_map + has 5 template arguments, thus is_5specialization needs to be used, rather + than is_2specialization (Key, Value). +**/ + +template class Ref> +struct is_specialization : std::false_type +{ +}; + +template