summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Powell <petpow@saberuk.com>2018-01-01 18:01:47 +0000
committerPeter Powell <petpow@saberuk.com>2018-01-03 22:33:29 +0000
commit40514d0ba8279309f350a47652fffef745662926 (patch)
tree14c772d5e39b6a52398e5dcac46abac6c06851e2
parent57e4bf97250a20f0b54957f2d5aabf02f158c171 (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.
-rw-r--r--docs/conf/modules.conf.example21
-rw-r--r--src/modules/m_blockcaps.cpp63
2 files changed, 60 insertions, 24 deletions
diff --git a/docs/conf/modules.conf.example b/docs/conf/modules.conf.example
index eb6bfd475..65bb3b9cb 100644
--- a/docs/conf/modules.conf.example
+++ b/docs/conf/modules.conf.example
@@ -245,19 +245,22 @@
#
#-#-#-#-#-#-#-#-#-#-#- BLOCKCAPS CONFIGURATION -#-#-#-#-#-#-#-#-#-#-#
# #
-# percent - What percentage of the text must be caps before #
-# text will be blocked. #
+# percent - The percentage of a message which must be upper #
+# case before it will be blocked. #
# #
-# minlen - The minimum length a line must be for the block #
-# percent to have any effect. #
+# minlen - The minimum length a message must be before it #
+# will be blocked. #
# #
-# capsmap - A list of chars to be considered CAPS. Can be used #
-# to add CAPS characters for your language. Also you #
-# can add things like ! and space to further lock #
-# down on caps usage. #
+# lowercase - The characters which will be considered lower #
+# case. #
+# #
+# uppercase - The characters which will be considered upper #
+# case. #
+#
#<blockcaps percent="50"
# minlen="5"
-# capsmap="ABCDEFGHIJKLMNOPQRSTUVWXYZ! ">
+# lowercase="abcdefghijklmnopqrstuvwxyz"
+# uppercase="ABCDEFGHIJKLMNOPQRSTUVWXYZ">
#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
# Block color module: Blocking color-coded messages with chan mode +c.
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