mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-09 17:48:19 +00:00
Merge pull request #8834 from KebsCS/pr-command-argument-validation
Add validation for chat and console command arguments
This commit is contained in:
commit
bb3c76a290
|
@ -53,7 +53,7 @@ public:
|
||||||
virtual int GetInteger(unsigned Index) const = 0;
|
virtual int GetInteger(unsigned Index) const = 0;
|
||||||
virtual float GetFloat(unsigned Index) const = 0;
|
virtual float GetFloat(unsigned Index) const = 0;
|
||||||
virtual const char *GetString(unsigned Index) const = 0;
|
virtual const char *GetString(unsigned Index) const = 0;
|
||||||
virtual ColorHSLA GetColor(unsigned Index, bool Light) const = 0;
|
virtual std::optional<ColorHSLA> GetColor(unsigned Index, bool Light) const = 0;
|
||||||
|
|
||||||
virtual void RemoveArgument(unsigned Index) = 0;
|
virtual void RemoveArgument(unsigned Index) = 0;
|
||||||
|
|
||||||
|
|
|
@ -111,14 +111,16 @@ void SIntConfigVariable::ResetToOld()
|
||||||
void SColorConfigVariable::CommandCallback(IConsole::IResult *pResult, void *pUserData)
|
void SColorConfigVariable::CommandCallback(IConsole::IResult *pResult, void *pUserData)
|
||||||
{
|
{
|
||||||
SColorConfigVariable *pData = static_cast<SColorConfigVariable *>(pUserData);
|
SColorConfigVariable *pData = static_cast<SColorConfigVariable *>(pUserData);
|
||||||
|
char aBuf[IConsole::CMDLINE_LENGTH + 64];
|
||||||
if(pResult->NumArguments())
|
if(pResult->NumArguments())
|
||||||
{
|
{
|
||||||
if(pData->CheckReadOnly())
|
if(pData->CheckReadOnly())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const ColorHSLA Color = pResult->GetColor(0, pData->m_Light);
|
const auto Color = pResult->GetColor(0, pData->m_Light);
|
||||||
const unsigned Value = Color.Pack(pData->m_Light ? 0.5f : 0.0f, pData->m_Alpha);
|
if(Color)
|
||||||
|
{
|
||||||
|
const unsigned Value = Color->Pack(pData->m_Light ? 0.5f : 0.0f, pData->m_Alpha);
|
||||||
|
|
||||||
*pData->m_pVariable = Value;
|
*pData->m_pVariable = Value;
|
||||||
if(pResult->m_ClientId != IConsole::CLIENT_ID_GAME)
|
if(pResult->m_ClientId != IConsole::CLIENT_ID_GAME)
|
||||||
|
@ -126,7 +128,12 @@ void SColorConfigVariable::CommandCallback(IConsole::IResult *pResult, void *pUs
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char aBuf[256];
|
str_format(aBuf, sizeof(aBuf), "%s is not a valid color.", pResult->GetString(0));
|
||||||
|
pData->m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "config", aBuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
str_format(aBuf, sizeof(aBuf), "Value: %u", *pData->m_pVariable);
|
str_format(aBuf, sizeof(aBuf), "Value: %u", *pData->m_pVariable);
|
||||||
pData->m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "config", aBuf);
|
pData->m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "config", aBuf);
|
||||||
|
|
||||||
|
@ -493,8 +500,8 @@ void CConfigManager::Con_Toggle(IConsole::IResult *pResult, void *pUserData)
|
||||||
{
|
{
|
||||||
SColorConfigVariable *pColorVariable = static_cast<SColorConfigVariable *>(pVariable);
|
SColorConfigVariable *pColorVariable = static_cast<SColorConfigVariable *>(pVariable);
|
||||||
const float Darkest = pColorVariable->m_Light ? 0.5f : 0.0f;
|
const float Darkest = pColorVariable->m_Light ? 0.5f : 0.0f;
|
||||||
const ColorHSLA Value = *pColorVariable->m_pVariable == pResult->GetColor(1, pColorVariable->m_Light).Pack(Darkest, pColorVariable->m_Alpha) ? pResult->GetColor(2, pColorVariable->m_Light) : pResult->GetColor(1, pColorVariable->m_Light);
|
const std::optional<ColorHSLA> Value = *pColorVariable->m_pVariable == pResult->GetColor(1, pColorVariable->m_Light).value_or(ColorHSLA(0, 0, 0)).Pack(Darkest, pColorVariable->m_Alpha) ? pResult->GetColor(2, pColorVariable->m_Light) : pResult->GetColor(1, pColorVariable->m_Light);
|
||||||
pColorVariable->SetValue(Value.Pack(Darkest, pColorVariable->m_Alpha));
|
pColorVariable->SetValue(Value.value_or(ColorHSLA(0, 0, 0)).Pack(Darkest, pColorVariable->m_Alpha));
|
||||||
}
|
}
|
||||||
else if(pVariable->m_Type == SConfigVariable::VAR_STRING)
|
else if(pVariable->m_Type == SConfigVariable::VAR_STRING)
|
||||||
{
|
{
|
||||||
|
|
|
@ -40,22 +40,29 @@ float CConsole::CResult::GetFloat(unsigned Index) const
|
||||||
return str_tofloat(m_apArgs[Index]);
|
return str_tofloat(m_apArgs[Index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ColorHSLA CConsole::CResult::GetColor(unsigned Index, bool Light) const
|
std::optional<ColorHSLA> CConsole::CResult::GetColor(unsigned Index, bool Light) const
|
||||||
{
|
{
|
||||||
if(Index >= m_NumArgs)
|
if(Index >= m_NumArgs)
|
||||||
return ColorHSLA(0, 0, 0);
|
return std::nullopt;
|
||||||
|
|
||||||
const char *pStr = m_apArgs[Index];
|
const char *pStr = m_apArgs[Index];
|
||||||
if(str_isallnum(pStr) || ((pStr[0] == '-' || pStr[0] == '+') && str_isallnum(pStr + 1))) // Teeworlds Color (Packed HSL)
|
if(str_isallnum(pStr) || ((pStr[0] == '-' || pStr[0] == '+') && str_isallnum(pStr + 1))) // Teeworlds Color (Packed HSL)
|
||||||
{
|
{
|
||||||
const ColorHSLA Hsla = ColorHSLA(str_toulong_base(pStr, 10), true);
|
unsigned long Value = str_toulong_base(pStr, 10);
|
||||||
|
if(Value == std::numeric_limits<unsigned long>::max())
|
||||||
|
return std::nullopt;
|
||||||
|
const ColorHSLA Hsla = ColorHSLA(Value, true);
|
||||||
if(Light)
|
if(Light)
|
||||||
return Hsla.UnclampLighting();
|
return Hsla.UnclampLighting();
|
||||||
return Hsla;
|
return Hsla;
|
||||||
}
|
}
|
||||||
else if(*pStr == '$') // Hex RGB/RGBA
|
else if(*pStr == '$') // Hex RGB/RGBA
|
||||||
{
|
{
|
||||||
return color_cast<ColorHSLA>(color_parse<ColorRGBA>(pStr + 1).value_or(ColorRGBA(0.0f, 0.0f, 0.0f, 1.0f)));
|
auto ParsedColor = color_parse<ColorRGBA>(pStr + 1);
|
||||||
|
if(ParsedColor)
|
||||||
|
return color_cast<ColorHSLA>(ParsedColor.value());
|
||||||
|
else
|
||||||
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
else if(!str_comp_nocase(pStr, "red"))
|
else if(!str_comp_nocase(pStr, "red"))
|
||||||
return ColorHSLA(0.0f / 6.0f, 1, .5f);
|
return ColorHSLA(0.0f / 6.0f, 1, .5f);
|
||||||
|
@ -76,7 +83,7 @@ ColorHSLA CConsole::CResult::GetColor(unsigned Index, bool Light) const
|
||||||
else if(!str_comp_nocase(pStr, "black"))
|
else if(!str_comp_nocase(pStr, "black"))
|
||||||
return ColorHSLA(0, 0, 0);
|
return ColorHSLA(0, 0, 0);
|
||||||
|
|
||||||
return ColorHSLA(0, 0, 0);
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
const IConsole::CCommandInfo *CConsole::CCommand::NextCommandInfo(int AccessLevel, int FlagMask) const
|
const IConsole::CCommandInfo *CConsole::CCommand::NextCommandInfo(int AccessLevel, int FlagMask) const
|
||||||
|
@ -129,12 +136,12 @@ int CConsole::ParseStart(CResult *pResult, const char *pString, int Length)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CConsole::ParseArgs(CResult *pResult, const char *pFormat)
|
int CConsole::ParseArgs(CResult *pResult, const char *pFormat, FCommandCallback pfnCallback)
|
||||||
{
|
{
|
||||||
char Command = *pFormat;
|
char Command = *pFormat;
|
||||||
char *pStr;
|
char *pStr;
|
||||||
int Optional = 0;
|
int Optional = 0;
|
||||||
int Error = 0;
|
int Error = PARSEARGS_OK;
|
||||||
|
|
||||||
pResult->ResetVictim();
|
pResult->ResetVictim();
|
||||||
|
|
||||||
|
@ -155,7 +162,7 @@ int CConsole::ParseArgs(CResult *pResult, const char *pFormat)
|
||||||
{
|
{
|
||||||
if(!Optional)
|
if(!Optional)
|
||||||
{
|
{
|
||||||
Error = 1;
|
Error = PARSEARGS_MISSING_VALUE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,7 +198,7 @@ int CConsole::ParseArgs(CResult *pResult, const char *pFormat)
|
||||||
pStr++; // skip due to escape
|
pStr++; // skip due to escape
|
||||||
}
|
}
|
||||||
else if(pStr[0] == 0)
|
else if(pStr[0] == 0)
|
||||||
return 1; // return error
|
return PARSEARGS_MISSING_VALUE; // return error
|
||||||
|
|
||||||
*pDst = *pStr;
|
*pDst = *pStr;
|
||||||
pDst++;
|
pDst++;
|
||||||
|
@ -215,13 +222,7 @@ int CConsole::ParseArgs(CResult *pResult, const char *pFormat)
|
||||||
|
|
||||||
if(Command == 'r') // rest of the string
|
if(Command == 'r') // rest of the string
|
||||||
break;
|
break;
|
||||||
else if(Command == 'v') // validate victim
|
else if(Command == 'v' || Command == 'i' || Command == 'f' || Command == 's')
|
||||||
pStr = str_skip_to_whitespace(pStr);
|
|
||||||
else if(Command == 'i') // validate int
|
|
||||||
pStr = str_skip_to_whitespace(pStr);
|
|
||||||
else if(Command == 'f') // validate float
|
|
||||||
pStr = str_skip_to_whitespace(pStr);
|
|
||||||
else if(Command == 's') // validate string
|
|
||||||
pStr = str_skip_to_whitespace(pStr);
|
pStr = str_skip_to_whitespace(pStr);
|
||||||
|
|
||||||
if(pStr[0] != 0) // check for end of string
|
if(pStr[0] != 0) // check for end of string
|
||||||
|
@ -230,6 +231,32 @@ int CConsole::ParseArgs(CResult *pResult, const char *pFormat)
|
||||||
pStr++;
|
pStr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validate args
|
||||||
|
if(Command == 'i')
|
||||||
|
{
|
||||||
|
// don't validate colors here
|
||||||
|
if(pfnCallback != &SColorConfigVariable::CommandCallback)
|
||||||
|
{
|
||||||
|
int Value;
|
||||||
|
if(!str_toint(pResult->GetString(pResult->NumArguments() - 1), &Value) ||
|
||||||
|
Value == std::numeric_limits<int>::max() || Value == std::numeric_limits<int>::min())
|
||||||
|
{
|
||||||
|
Error = PARSEARGS_INVALID_INTEGER;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(Command == 'f')
|
||||||
|
{
|
||||||
|
float Value;
|
||||||
|
if(!str_tofloat(pResult->GetString(pResult->NumArguments() - 1), &Value) ||
|
||||||
|
Value == std::numeric_limits<float>::max() || Value == std::numeric_limits<float>::min())
|
||||||
|
{
|
||||||
|
Error = PARSEARGS_INVALID_FLOAT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(pVictim)
|
if(pVictim)
|
||||||
{
|
{
|
||||||
pResult->SetVictim(pVictim);
|
pResult->SetVictim(pVictim);
|
||||||
|
@ -487,9 +514,14 @@ void CConsole::ExecuteLineStroked(int Stroke, const char *pStr, int ClientId, bo
|
||||||
|
|
||||||
if(Stroke || IsStrokeCommand)
|
if(Stroke || IsStrokeCommand)
|
||||||
{
|
{
|
||||||
if(ParseArgs(&Result, pCommand->m_pParams))
|
if(int Error = ParseArgs(&Result, pCommand->m_pParams, pCommand->m_pfnCallback))
|
||||||
{
|
{
|
||||||
char aBuf[TEMPCMD_NAME_LENGTH + TEMPCMD_PARAMS_LENGTH + 32];
|
char aBuf[CMDLINE_LENGTH + 64];
|
||||||
|
if(Error == PARSEARGS_INVALID_INTEGER)
|
||||||
|
str_format(aBuf, sizeof(aBuf), "%s is not a valid integer.", Result.GetString(Result.NumArguments() - 1));
|
||||||
|
else if(Error == PARSEARGS_INVALID_FLOAT)
|
||||||
|
str_format(aBuf, sizeof(aBuf), "%s is not a valid decimal number.", Result.GetString(Result.NumArguments() - 1));
|
||||||
|
else
|
||||||
str_format(aBuf, sizeof(aBuf), "Invalid arguments. Usage: %s %s", pCommand->m_pName, pCommand->m_pParams);
|
str_format(aBuf, sizeof(aBuf), "Invalid arguments. Usage: %s %s", pCommand->m_pName, pCommand->m_pParams);
|
||||||
Print(OUTPUT_LEVEL_STANDARD, "chatresp", aBuf);
|
Print(OUTPUT_LEVEL_STANDARD, "chatresp", aBuf);
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,7 +115,7 @@ class CConsole : public IConsole
|
||||||
const char *GetString(unsigned Index) const override;
|
const char *GetString(unsigned Index) const override;
|
||||||
int GetInteger(unsigned Index) const override;
|
int GetInteger(unsigned Index) const override;
|
||||||
float GetFloat(unsigned Index) const override;
|
float GetFloat(unsigned Index) const override;
|
||||||
ColorHSLA GetColor(unsigned Index, bool Light) const override;
|
std::optional<ColorHSLA> GetColor(unsigned Index, bool Light) const override;
|
||||||
|
|
||||||
void RemoveArgument(unsigned Index) override
|
void RemoveArgument(unsigned Index) override
|
||||||
{
|
{
|
||||||
|
@ -144,7 +144,16 @@ class CConsole : public IConsole
|
||||||
};
|
};
|
||||||
|
|
||||||
int ParseStart(CResult *pResult, const char *pString, int Length);
|
int ParseStart(CResult *pResult, const char *pString, int Length);
|
||||||
int ParseArgs(CResult *pResult, const char *pFormat);
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PARSEARGS_OK = 0,
|
||||||
|
PARSEARGS_MISSING_VALUE,
|
||||||
|
PARSEARGS_INVALID_INTEGER,
|
||||||
|
PARSEARGS_INVALID_FLOAT,
|
||||||
|
};
|
||||||
|
|
||||||
|
int ParseArgs(CResult *pResult, const char *pFormat, FCommandCallback pfnCallback = 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
this function will set pFormat to the next parameter (i,s,r,v,?) it contains and
|
this function will set pFormat to the next parameter (i,s,r,v,?) it contains and
|
||||||
|
|
|
@ -109,8 +109,8 @@ void cxxbridge1$IConsole_IResult$GetString(const ::IConsole_IResult &self, ::std
|
||||||
}
|
}
|
||||||
|
|
||||||
void cxxbridge1$IConsole_IResult$GetColor(const ::IConsole_IResult &self, ::std::uint32_t Index, bool Light, ::ColorHSLA *return$) noexcept {
|
void cxxbridge1$IConsole_IResult$GetColor(const ::IConsole_IResult &self, ::std::uint32_t Index, bool Light, ::ColorHSLA *return$) noexcept {
|
||||||
::ColorHSLA (::IConsole_IResult::*GetColor$)(::std::uint32_t, bool) const = &::IConsole_IResult::GetColor;
|
std::optional<::ColorHSLA> (::IConsole_IResult::*GetColor$)(::std::uint32_t, bool) const = &::IConsole_IResult::GetColor;
|
||||||
new (return$) ::ColorHSLA((self.*GetColor$)(Index, Light));
|
new(return$)::ColorHSLA((self.*GetColor$)(Index, Light).value_or(::ColorHSLA(0, 0, 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
::std::int32_t cxxbridge1$IConsole_IResult$NumArguments(const ::IConsole_IResult &self) noexcept {
|
::std::int32_t cxxbridge1$IConsole_IResult$NumArguments(const ::IConsole_IResult &self) noexcept {
|
||||||
|
|
Loading…
Reference in a new issue