diff options
author | Peter Powell <petpow@saberuk.com> | 2018-01-01 18:01:47 +0000 |
---|---|---|
committer | Peter Powell <petpow@saberuk.com> | 2018-01-03 22:33:29 +0000 |
commit | 40514d0ba8279309f350a47652fffef745662926 (patch) | |
tree | 14c772d5e39b6a52398e5dcac46abac6c06851e2 /src/modules | |
parent | 57e4bf97250a20f0b54957f2d5aabf02f158c171 (diff) |
Improve the method that blockcaps uses to block messages.
Previously it had a list of upper case letters and assumed that all
other characters were lower case. This method is flawed as it can
be evaded by using non-alphanumeric characters.
The new method takes a list of lower case letters as well as upper
case letters and ignores any letters which are not listed in one of
the two lists.
The majority of the code for this was borrowed from the m_anticaps
module in inspircd-extras.
Diffstat (limited to 'src/modules')
-rw-r--r-- | src/modules/m_blockcaps.cpp | 63 |
1 files changed, 48 insertions, 15 deletions
diff --git a/src/modules/m_blockcaps.cpp b/src/modules/m_blockcaps.cpp index b5347e9ad..c36eeabff 100644 --- a/src/modules/m_blockcaps.cpp +++ b/src/modules/m_blockcaps.cpp @@ -29,7 +29,8 @@ class ModuleBlockCAPS : public Module SimpleChannelModeHandler bc; unsigned int percent; unsigned int minlen; - std::bitset<UCHAR_MAX> capsmap; + std::bitset<UCHAR_MAX> lowercase; + std::bitset<UCHAR_MAX> uppercase; public: ModuleBlockCAPS() @@ -47,7 +48,7 @@ public: { if (target_type == TYPE_CHANNEL) { - if ((!IS_LOCAL(user)) || (text.length() < minlen) || (text == "\1ACTION\1") || (text == "\1ACTION")) + if (!IS_LOCAL(user)) return MOD_RES_PASSTHRU; Channel* c = (Channel*)dest; @@ -58,17 +59,43 @@ public: if (!c->GetExtBanStatus(user, 'B').check(!c->IsModeSet(bc))) { - std::string::size_type caps = 0; - unsigned int offset = 0; - // Ignore the beginning of the text if it's a CTCP ACTION (/me) - if (!text.compare(0, 8, "\1ACTION ", 8)) - offset = 8; + // If the message is a CTCP then we skip it unless it is + // an ACTION in which case we strip the prefix and suffix. + std::string::const_iterator text_begin = text.begin(); + std::string::const_iterator text_end = text.end(); + if (text[0] == '\1') + { + // If the CTCP is not an action then skip it. + if (text.compare(0, 8, "\1ACTION ", 8)) + return MOD_RES_PASSTHRU; + + // Skip the CTCP message characters. + text_begin += 8; + if (*text.rbegin() == '\1') + text_end -= 1; + } + + // If the message is shorter than the minimum length + // then we don't need to do anything else. + size_t length = std::distance(text_begin, text_end); + if (length < minlen) + return MOD_RES_PASSTHRU; - for (std::string::const_iterator i = text.begin() + offset; i != text.end(); ++i) - if (capsmap.test(*i)) - caps += 1; + // Count the characters to see how many upper case and + // ignored (non upper or lower) characters there are. + size_t upper = 0; + for (std::string::const_iterator iter = text_begin; iter != text_end; ++iter) + { + if (uppercase.test(*iter)) + upper += 1; + else if (!lowercase.test(*iter)) + length -= 1; + } - if (((caps * 100) / text.length()) >= percent) + // Calculate the percentage which is upper case. If the + // message was entirely symbols then it can't contain + // any upper case letters. + if (length > 0 && round((upper * 100) / length) >= percent) { user->WriteNumeric(ERR_CANNOTSENDTOCHAN, c->name, InspIRCd::Format("Your message cannot contain %d%% or more capital letters if it's longer than %d characters", percent, minlen)); return MOD_RES_DENY; @@ -83,10 +110,16 @@ public: ConfigTag* tag = ServerInstance->Config->ConfValue("blockcaps"); percent = tag->getInt("percent", 100, 1, 100); minlen = tag->getInt("minlen", 1, 1, ServerInstance->Config->Limits.MaxLine); - std::string hmap = tag->getString("capsmap", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); - capsmap.reset(); - for (std::string::iterator n = hmap.begin(); n != hmap.end(); n++) - capsmap.set(*n); + + lowercase.reset(); + const std::string lower = tag->getString("lowercase", "abcdefghijklmnopqrstuvwxyz"); + for (std::string::const_iterator iter = lower.begin(); iter != lower.end(); ++iter) + lowercase.set(*iter); + + uppercase.reset(); + const std::string upper = tag->getString("uppercase", tag->getString("capsmap", "ABCDEFGHIJKLMNOPQRSTUVWXYZ")); + for (std::string::const_iterator iter = upper.begin(); iter != upper.end(); ++iter) + uppercase.set(*iter); } Version GetVersion() CXX11_OVERRIDE |