diff --git a/src/game/Anticheat/module/anticheat.conf.dist.in b/src/game/Anticheat/module/anticheat.conf.dist.in index f6c533cf2b..ac65a2fd3c 100644 --- a/src/game/Anticheat/module/anticheat.conf.dist.in +++ b/src/game/Anticheat/module/anticheat.conf.dist.in @@ -3,6 +3,16 @@ # This file is intended to be used in a setting where the anticheat should run # purely in a read-only mode. It will do all of its tasks, but take no action, # aside from sending out notifications. It is intended for testing purposes. +# +# To overwrite configuration fields with environment variables +# use the following pattern to generate environment variable names: +# +# For Enable: +# export Anticheat_Enable=0 +# +# For IPBanDelay.Max: +# export Anticheat_IPBanDelay_Max=120 +# [AnticheatConf] ConfVersion=2017102301 diff --git a/src/game/Anticheat/module/libanticheat.cpp b/src/game/Anticheat/module/libanticheat.cpp index d53d97d31f..191c78cb52 100644 --- a/src/game/Anticheat/module/libanticheat.cpp +++ b/src/game/Anticheat/module/libanticheat.cpp @@ -215,7 +215,7 @@ namespace NamreebAnticheat { void AnticheatLib::Reload() { - if (!sAnticheatConfig.SetSource(_LIB_ANTICHEAT_CONFIG)) + if (!sAnticheatConfig.SetSource(_LIB_ANTICHEAT_CONFIG, "Anticheat_")) sLog.outError("[Anticheat] Could not find configuration file %s.", _LIB_ANTICHEAT_CONFIG); // the configuration setting must be loaded before the database data because the current config settings diff --git a/src/game/AuctionHouseBot/AuctionHouseBot.cpp b/src/game/AuctionHouseBot/AuctionHouseBot.cpp index 060313e091..c47e7f732b 100644 --- a/src/game/AuctionHouseBot/AuctionHouseBot.cpp +++ b/src/game/AuctionHouseBot/AuctionHouseBot.cpp @@ -40,7 +40,7 @@ AuctionHouseBot::~AuctionHouseBot() void AuctionHouseBot::Initialize() { - if (!m_ahBotCfg.SetSource(m_configFileName)) + if (!m_ahBotCfg.SetSource(m_configFileName, "Mangosd_")) { // set buy/sell chance to 0, this prevents Update() from accessing uninitialized variables m_chanceBuy = 0; diff --git a/src/mangosd/Main.cpp b/src/mangosd/Main.cpp index 10be8aa018..135061af74 100644 --- a/src/mangosd/Main.cpp +++ b/src/mangosd/Main.cpp @@ -141,7 +141,7 @@ int main(int argc, char* argv[]) } #endif - if (!sConfig.SetSource(configFile)) + if (!sConfig.SetSource(configFile, "Mangosd_")) { sLog.outError("Could not find configuration file %s.", configFile.c_str()); Log::WaitBeforeContinueIfNeed(); diff --git a/src/mangosd/mangosd.conf.dist.in b/src/mangosd/mangosd.conf.dist.in index 85d3e9a0d5..28460d934f 100644 --- a/src/mangosd/mangosd.conf.dist.in +++ b/src/mangosd/mangosd.conf.dist.in @@ -1,5 +1,15 @@ ##################################### -# MaNGOS Configuration file # +# MaNGOS Configuration file +# +# To overwrite configuration fields with environment variables +# use the following pattern to generate environment variable names: +# +# For Rate.Health: +# export Mangosd_Rate_Health=1.2 +# +# For DataDir: +# export Mangosd_DataDir=/tmp +# ##################################### [MangosdConf] diff --git a/src/realmd/Main.cpp b/src/realmd/Main.cpp index f997aabe36..9e3e52d32c 100644 --- a/src/realmd/Main.cpp +++ b/src/realmd/Main.cpp @@ -125,7 +125,7 @@ int main(int argc, char* argv[]) } #endif - if (!sConfig.SetSource(configFile)) + if (!sConfig.SetSource(configFile, "Realmd_")) { sLog.outError("Could not find configuration file %s.", configFile.c_str()); Log::WaitBeforeContinueIfNeed(); diff --git a/src/realmd/realmd.conf.dist.in b/src/realmd/realmd.conf.dist.in index 4a8f50c714..ea0205d810 100644 --- a/src/realmd/realmd.conf.dist.in +++ b/src/realmd/realmd.conf.dist.in @@ -1,5 +1,15 @@ ############################################ -# MaNGOS realmd configuration file # +# MaNGOS realmd configuration file +# +# To overwrite configuration fields with environment variables +# use the following pattern to generate environment variable names: +# +# For WrongPass.MaxCount: +# export Realmd_WrongPass_MaxCount=10 +# +# For RealmServerPort: +# export Realmd_RealmServerPort=3333 +# ############################################ [RealmdConf] diff --git a/src/shared/Config/Config.cpp b/src/shared/Config/Config.cpp index c5172fc52e..dfcd7aa8e4 100644 --- a/src/shared/Config/Config.cpp +++ b/src/shared/Config/Config.cpp @@ -18,6 +18,7 @@ #include "Config.h" #include "Policies/Singleton.h" +#include "Util/Util.h" #include #include @@ -25,12 +26,18 @@ #include #include #include +#include +#include +#include INSTANTIATE_SINGLETON_1(Config); -bool Config::SetSource(const std::string& file) +std::optional EnvVarForIniKey(std::string const&, std::string const&); + +bool Config::SetSource(const std::string& file, const std::string& envVarPrefix) { m_filename = file; + m_envVarPrefix = envVarPrefix; return Reload(); } @@ -62,9 +69,14 @@ bool Config::Reload() if (equals == std::string::npos) return false; - auto const entry = boost::algorithm::trim_copy(boost::algorithm::to_lower_copy(line.substr(0, equals))); - auto const value = boost::algorithm::trim_copy_if(boost::algorithm::trim_copy(line.substr(equals + 1)), boost::algorithm::is_any_of("\"")); + auto const trimmedEntry = boost::algorithm::trim_copy(line.substr(0, equals)); + auto const entry = boost::algorithm::to_lower_copy(trimmedEntry); + auto value = boost::algorithm::trim_copy_if(boost::algorithm::trim_copy(line.substr(equals + 1)), boost::algorithm::is_any_of("\"")); + std::optional envValue = EnvVarForIniKey(m_envVarPrefix, trimmedEntry); + if (envValue) + value = *envValue; + newEntries[entry] = value; } while (in.good()); @@ -85,8 +97,21 @@ const std::string Config::GetStringDefault(const std::string& name, const std::s auto const nameLower = boost::algorithm::to_lower_copy(name); auto const entry = m_entries.find(nameLower); + + if (entry == m_entries.cend()) + { + std::optional envVar = EnvVarForIniKey(m_envVarPrefix, name); + if (envVar) + { + sLog.outString("Missing key '%s' in config file '%s', recovered with environment '%s' value.", name.c_str(), m_filename.c_str(), envVar->c_str()); - return entry == m_entries.cend() ? def : entry->second; + return *envVar; + } + + return def; + } + + return entry->second; } bool Config::GetBoolDefault(const std::string& name, bool def) const @@ -113,3 +138,14 @@ float Config::GetFloatDefault(const std::string& name, float def) const return std::stof(value); } +std::optional EnvVarForIniKey(std::string const& prefix, std::string const& key) +{ + std::string escapedKey = key; + std::replace(escapedKey.begin(), escapedKey.end(), '.', '_'); + std::string envKey = prefix + escapedKey; + char* val = std::getenv(envKey.c_str()); + if (!val) + return {}; + + return std::string(val); +} diff --git a/src/shared/Config/Config.h b/src/shared/Config/Config.h index 66f9f5b18a..f9b439af01 100644 --- a/src/shared/Config/Config.h +++ b/src/shared/Config/Config.h @@ -31,10 +31,11 @@ class Config { private: std::string m_filename; + std::string m_envVarPrefix; std::unordered_map m_entries; // keys are converted to lower case. values cannot be. public: - bool SetSource(const std::string& file); + bool SetSource(const std::string& file, const std::string& envVarPrefix); bool Reload(); bool IsSet(const std::string& name) const;