tmb_mod package¶
Submodules¶
tmb_mod.antiflood module¶
Anti-flood module
If enabled, we keep track of messages sent by all users in all moderated channels. If a user sends more than the configured number of messages within the configured time period, they are considered to be flooding and we take some action(s) against them.
The Action
class lists all possible actions to take. For example,
quiet_host
will mute the user’s host in the channel they flooded.
See the ANTIFLOOD_*
options in config
for our configuration options.
- class tmb_mod.antiflood.Action(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)¶
Bases:
Enum
Actions we can take when a user floods.
- quiet_host = 'quiet_host'¶
tell chanserv to +q *!*@example.com
- class tmb_mod.antiflood.AntiFloodModule¶
Bases:
Module
See the module-level documentation
- NAME = 'antiflood'¶
Required: The name of this module, used for finding config options
- max_msgs()¶
How many messages a user may send “recently” before they are considered to be flooding
- privmsg_cb(user, receiver, message, is_opmod)¶
Main tormodbot code calls into this when we’re enabled and the given
tmb_util.userstr.UserStr
has sentmessage
(str
) torecevier
(str
). The receiver can be a channel (“#foo”) or a nick (“foo”).
- recent¶
Storage for recent message timestamps. Items are a three-tuple:
(ts, nick, chan)
If the above changes, then look for usage of this and update it.
- recent_actions¶
A FIFO list of
Action
s we’ve recently made. This is used to not repeat ourselves in case the flooder is able to send multiple messages after crossing the “is flooding” threshold before we’ve stopped them.Append Actions that you are taking to the right and cleanup old actions from the left.
The items in this queue are a tuple:
(timestamp, Action, UserStr, '#channel')
If this fact changes, then
AntiFloodModule._action_done_recently()
needs to be updated
- recent_secs()¶
The duration in which a user may send max_msgs, and if they send more, they are flooding.
- tmb_mod.antiflood.RECENT_ACTION_SECS = 300¶
The
RECENT_ACTION_SECS
cleanup function will forgotAction
s #: older than this number of seconds.
- tmb_mod.antiflood.TEMP_QUIET_DAYS = 0.010416666666666666¶
The duration of a quiet. 0.25/24 is 15 minutes
tmb_mod.autovoice module¶
Auto-voice module
If enabled, the autovoice module can:
auto +v users with a matching
nick!user@host
stringauto +v users who have registered at least
X
seconds ago with a matchingnick!user@host
string
See the AUTOVOICE_*
options in config
for our configuration options.
See Limitations, especially regarding cloaks.
- class tmb_mod.autovoice.AutoVoiceModule¶
Bases:
Module
See the module-level documentation
- NAME = 'autovoice'¶
Required: The name of this module, used for finding config options
- join_cb(user, chan)¶
Main tormodbot code calls into this when we’re enabled and the given
tmb_util.userstr.UserStr
has joined the given channel
- nickserv_time_reg_q¶
Queue of (UserStr, chan) we want to ask nickserv about to see if they registered, and if so, when they did so
- notice_cb(sender, receiver, message)¶
Main tormodbot code calls into this when we’re enabled and have received a notice message
tmb_mod.badwords module¶
Bad words module
If enabled, look for people sending a message that matches a “bad word,” and if found, take action against them.
The Action
class lists all possible actions to take. For example,
quiet_nick
will mute the user’s nick in the channel they flooded.
See the BADWORDS_*
options in config
for our configuration options.
- class tmb_mod.badwords.Action(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)¶
Bases:
Enum
Actions we can take when a user says a bad word.
- plusr_chan = 'plusr_chan'¶
set the channel to +R
- quiet_nick = 'quiet_nick'¶
tell chanserv to +q pastly!*@*
- class tmb_mod.badwords.BadWordsModule¶
Bases:
Module
See the module-level documentation
- NAME = 'badwords'¶
Required: The name of this module, used for finding config options
- privmsg_cb(user, receiver, message, is_opmod)¶
Main tormodbot code calls into this when we’re enabled and the given
tmb_util.userstr.UserStr
has sentmessage
(str
) torecevier
(str
). The receiver can be a channel (“#foo”) or a nick (“foo”).
tmb_mod.botabuse module¶
Anti-bot abuse module
If enabled, look for bots spamming a specific channel and temporarily mute them.
This is a lot like the anti-flood module, except we undo our mutes and are specifically meant for mitigating bots’ nicks from spamming.
- class tmb_mod.botabuse.BotAbuseModule¶
Bases:
Module
See the module-level documentation
- NAME = 'botabuse'¶
Required: The name of this module, used for finding config options
- actions¶
Storage for recording actions we’ve taken so that we don’t remake them and end up spamming a channel ourselves. Items are a the same as in self.recent, and the same places need to be updated if this changes.
- actions_secs¶
How long we remember an action that we took.
- handle_message(nick, chan)¶
- mute_secs¶
How long to mute, in seconds
- notice_cb(sender, receiver, message)¶
Called whenever we are enabled and see a NOTICE.
Note
Bots aren’t supposed to take action based on notices. It’s in the standards! Most likely you don’t want to overwrite this.
Note
Globally-ignored users do not trigger this.
- Parameters:
sender (str) – Who sent the NOTICE. Not necessarily a string that can be turned into a :class:`UserStr`. Servers send NOTICEs. Expect something like “dacia.oftc.net” or “nick!user@host”. Only the latter can be turned into a
UserStr
.receiver (str) – The channel name in which the NOTICE was seen, or our nick.
messge (str) – The message sent, without leading or trailing whitespace.
- privmsg_cb(user, receiver, message, is_opmod)¶
Called whenever we are enabled and see a PRIVMSG.
You want to overwrite this function if you care about messages in moderated channels and/or PMs directly to us.
Note
Globally-ignored users do not trigger this.
- Parameters:
user (UserStr) – Who PRIVMSGed.
dest (str) – The channel name (e.g. “#foo”) in which the message was seen, or our nick (if a literal PM to us).
message (str) – The message sent, without leading or trailing whitespace.
is_opmod (bool) – Whether or not this message is a statusmsg targeted to @#channel as opposed to #channel as usual. OFTC’s +z channel mode (hybrid, not solanum) sends messages that would otherwise be blocked to chanops using this method, and when it does, it calls it opmod. If this is set on this message, you must be a chanop in the channel (congratulations!) and you and your fellow chanops are the only ones that saw the message.
- recent¶
Storage for recent bot messages. Items are three-tuples:
(ts, nick, chan)
If the above changes, then _clear_old and handle_message needs to be updated.
- recent_max¶
How many messages a bot chan send in a channel per recent_secs. Hitting this causes us to mute the bot
- recent_secs¶
How long ago a message is considered recent
tmb_mod.faq module¶
FAQ module¶
If enabled, we can read a library of FAQ responses from plain-text files on disk, both bundled with tormodbot and ones the operator wrote themself.
Usage¶
In public (in a moderated channel)¶
A FAQ query can take one of two forms:
# public usage
!faq
!faq <keyword>
A simple
!faq
in public will case us to list, in public, all keywords we know about in that channel.!faq foo
, where foo is a keyword known in that channel, will case us to respond with the FAQ response for foo. If we do not have a response, we respond saying so and include a link to the configured source code repository.
If more than one argument is provided, we behave as if we received just
!faq
.
In private (via a private message)¶
A FAQ query can take one of four forms:
# private usage
!faq
!faq <#chan>
!faq <keyword>
!faq <#chan> <keyword>
A simple
!faq
will case us to behave as if we received!faq all about
, i.e. we respond with text regarding this bot.!faq #bar
will case us to list all keywords we know about in #bar.!faq foo
will case us to behave as if we received!faq all foo
.!faq #bar foo
will case us to respond with the FAQ response for foo in #bar.
In all the above cases where a channel can be specified, instead you can
provide all
to search the globally known FAQ responses only, as opposed to
responses known to a specific channel and those known globally.
If more than two arguments are provided, we behave as if we received just
!faq
.
If we cannot find a FAQ response, we respond saying so and include a link to the configured source code repository.
Note
If just one argument is provided and it is not all
or a moderated
channel, it is treated as a keyword. Assume #baz is not a moderated
channel. That means while !faq #baz
looks like we should respond
with the list of known keywords in #baz, since we don’t have any
(it’s not moderated), we treat it as a keyword and act as if we received
!faq all #baz
.
FAQ response file format¶
FAQ response files can be multiple lines; however, blank lines are ignored and leading/trailing whitespace is stripped. Comment lines – those whose first non-whitespace character is ‘#’ – are also ignored. There is no such thing as an end-of-line comment.
This is the first line of a FAQ response.
This line is printed right after the first, with no blank line in between.
# This is a comment, thus isn't printed.
This entire line is printed # because this isn't a comment.
Regardless of the length of the lines in the input file, paragraphs are wrapped to 400-character-length lines. Paragraphs are separated by a blank line.
This is the first paragraph.
This is the second sentence
of the first paragraph, and these
five lines appear as a single
IRC message.
This is the second paragraph and
would start a second IRC message.
FAQ response search order¶
FAQ responses can be specific to a moderated channel, or they can be general
for all channels. Assuming the default WeeChat data directory, when searching
for the response to FAQ keyword bar
in channel #foo
, we search in the
following places in order and select the first FAQ response found:
~/.weechat/tmb_data/faq/#foo/bar.txt
~/.weechat/tmb_data/faq/all/bar.txt
~/.weechat/python/faq/#foo/bar.txt
~/.weechat/python/faq/all/bar.txt
Put your FAQ responses in ``~/.weechat/tmb_data/faq``. If you believe your
FAQ response should be bundled with the code, make a pull request, get it
merged, and then you can pull the latest code and have tne FAQ response in
~/.weechat/python/faq
.
The motivation for this order is to allow the operator to have a general keyword with the same response in all channels, but override that response in specific channels. Additionally, any FAQ responses that come bundled with this code will be overridden by any operator-created FAQ response that uses the same keyword.
Keywords¶
The keyword is not case-sensitive, has no spaces, and otherwise lacks any characters that would constitute an invalid filename.
Anti-spam¶
To limit the extent to which we can be used for a spam tool, we rate limits
ourself in each moderated channel. See the FAQ_*
options in config
for the options how many responses we can burst in a channel, as well as the
steady-state rate at which we will send responses in a channel. Additionally,
we won’t give the same FAQ response in a channel if we have done so recently.
- class tmb_mod.faq.FAQModule¶
Bases:
Module
See the module-level documentation
- NAME = 'faq'¶
Required: The name of this module, used for finding config options
- initialize()¶
Called whenever we are (re)starting
- privmsg_cb(user, receiver, message, is_opmod)¶
Main tormodbot code calls into this when we’re enabled and the given
tmb_util.userstr.UserStr
has sentmessage
(str
) torecevier
(str
). The receiver can be a channel (“#foo”) or a nick (“foo”).
- recent_faqs¶
A FIFO list of responses we’ve recently made. This is used to not repeat ourselves in case we are asked to paste the same FAQ rapidly.
Append responses that you are taking to the right and cleanup old ones from the left.
The items in this queue are a tuple:
(timestamp, destination, channel, keyword)
If this fact changes, then
_faq_done_recently()
needs to be updated
- tb_func¶
Function to call every time we send a message to take away a token from that channel’s bucket. The function takes the channels’s state as an argument and returns
(wait_time, new_state)
.wait_time
is the amount of time we need to wait until we would have a non-zero number of tokens left (so if we currently have tokens for this channel,wait_time
is 0), andnew_state
is the channels’s updated state that should be passed in next time.
- token_buckets¶
Store per-
chan
token buckets so we prevent ourselves from flooding when used as a toy
- tmb_mod.faq.UNKNOWN_FAQ_RESP = 'I do not know about "{1}" in {0}. If I should, please open a ticket at {2}. Also try sending me a private message with "!faq {0}".'¶
Reponse template to give when we do not know the answer. The arguments, in order: - The channel - The unknown keyword - The URL at which to report bugs
tmb_mod.hello module¶
Module that notices new nicks saying something simple like “hello?” upon joining and responds with a message.
The module keeps track of how many times they’ve seen a nick join each channel and how many times a nick has ever sent a message in each channel. If their number of joins and messages are sufficiently low, then we send them an automated reply such as “this is a support channel, please ask your question.”
If enabled, this module keeps track of joins and messages in all moderated channels; however, it will not send an automated response in channels that do not have a response configured.
The responses for channels are stored in weechat’s configuration with the
prefix hello_reponse_*
where *
is the channel name. To configure a
response for channel #foo
, use weechat’s /set
command:
/set plugins.var.python.tormodbot.hello_response_#foo This is a support channel. Please ask your question.
See the HELLO_*
options in config
for our configuration options.
- class tmb_mod.hello.HelloModule¶
Bases:
Module
See the module-level documentation
- NAME = 'hello'¶
Required: The name of this module, used for finding config options
- hello_words()¶
- initialize()¶
Called whenever we are (re)starting
- interval()¶
- join_cb(user, chan)¶
Main tormodbot code calls into this when we’re enabled and the given
tmb_util.userstr.UserStr
has joined the given channel
- last_response¶
Keep track of last time we sent a manual autoreponse in each channel so we don’t spam.
- msg_max_len()¶
- new_joins()¶
Return maximum number of joins in a channel we can see from a nick and still consider the nick a new user
- new_msgs()¶
Return maximum number of messages in a channel we can see from a nick and still consider the nick a new user
- privmsg_cb(user, receiver, message, is_opmod)¶
Main tormodbot code calls into this when we’re enabled and the given
tmb_util.userstr.UserStr
has sentmessage
(str
) torecevier
(str
). The receiver can be a channel (“#foo”) or a nick (“foo”).
- response_for_chan(chan)¶
Returns the response we have for chan, or
None
if no configured response
tmb_mod.joinspam module¶
Join spam module
If enabled, look for people (possibly unintentionally) join/part or join/quit spamming. If found, take action against them.
See the JOINSPAM_*
options in config
for our configuration options.
- class tmb_mod.joinspam.JoinSpamModule¶
Bases:
Module
See the module-level documentation
- NAME = 'joinspam'¶
Required: The name of this module, used for finding config options
- join_cb(user, receiver)¶
Called whenever we are enabled and see a JOIN.
You want to overwrite this function if you care about JOINs.
- max_joins()¶
- recent¶
Storage for recent joins. Items are three-tuples:
(ts, nick, chan)
If the above changes, then look for usage of this and update it.
- recent_mins()¶
- tmb_mod.joinspam.TEMP_BAN_DAYS = 0.16666666666666666¶
The duration of a temporary ban
- tmb_mod.joinspam.TEMP_BAN_REASON = 'Your client rejoined >={} times in {} minutes. Tell pastly when fixed or wait 4 hours for the ban to expire.'¶
The reason to log for a temporary ban
Module contents¶
- class tmb_mod.Module¶
Bases:
object
TorModBot modules – essentially major “self contained” features – have this class as a parent. We provide a uniform interface for
tormodbot.py
to use and default implementations for all of the functions exposed to it.There are required static class values values that must be set.
- NAME = ''¶
Required: The name of this module, used for finding config options
- enabled()¶
Returns True if this module is configured to be enabled, otherwise False.
It is very unlikely that you should overwrite this member function with your own.
- initialize()¶
Called whenever the plugin is restarting or reloading and this module is enabled.
It’s possible you need to overwrite this member function with your own if your module keeps state.
- join_cb(user, chan)¶
Called whenever we are enabled and see a JOIN.
You want to overwrite this function if you care about JOINs.
- notice_cb(sender, receiver, message)¶
Called whenever we are enabled and see a NOTICE.
Note
Bots aren’t supposed to take action based on notices. It’s in the standards! Most likely you don’t want to overwrite this.
Note
Globally-ignored users do not trigger this.
- Parameters:
sender (str) – Who sent the NOTICE. Not necessarily a string that can be turned into a :class:`UserStr`. Servers send NOTICEs. Expect something like “dacia.oftc.net” or “nick!user@host”. Only the latter can be turned into a
UserStr
.receiver (str) – The channel name in which the NOTICE was seen, or our nick.
messge (str) – The message sent, without leading or trailing whitespace.
- privmsg_cb(user, dest, message, is_opmod)¶
Called whenever we are enabled and see a PRIVMSG.
You want to overwrite this function if you care about messages in moderated channels and/or PMs directly to us.
Note
Globally-ignored users do not trigger this.
- Parameters:
user (UserStr) – Who PRIVMSGed.
dest (str) – The channel name (e.g. “#foo”) in which the message was seen, or our nick (if a literal PM to us).
message (str) – The message sent, without leading or trailing whitespace.
is_opmod (bool) – Whether or not this message is a statusmsg targeted to @#channel as opposed to #channel as usual. OFTC’s +z channel mode (hybrid, not solanum) sends messages that would otherwise be blocked to chanops using this method, and when it does, it calls it opmod. If this is set on this message, you must be a chanop in the channel (congratulations!) and you and your fellow chanops are the only ones that saw the message.
- timer_cb()¶
tormodbot.py
needs to be edited to call this if you use WeeChat timers.
- tmb_mod.w¶
To make calling weechat functions easier