[Tkabber-dev] r170 - in trunk/plugins: . antispam antispam/msgs

tkabber-svn at jabber.ru tkabber-svn at jabber.ru
Thu Feb 19 00:11:00 MSK 2009


Author: gebb
Date: 2009-02-19 00:10:59 +0300 (Thu, 19 Feb 2009)
New Revision: 170

Added:
   trunk/plugins/antispam/
   trunk/plugins/antispam/AUTHORS
   trunk/plugins/antispam/ChangeLog
   trunk/plugins/antispam/INSTALL
   trunk/plugins/antispam/README
   trunk/plugins/antispam/TODO
   trunk/plugins/antispam/antispam.tcl
   trunk/plugins/antispam/license.terms
   trunk/plugins/antispam/msgs/
   trunk/plugins/antispam/msgs/ru.msg
Log:
Added new Tkabber plugin "Antispam".
This plugin blocks (hides form the user) spam messages and subscription requests.

Added: trunk/plugins/antispam/AUTHORS
===================================================================
--- trunk/plugins/antispam/AUTHORS	                        (rev 0)
+++ trunk/plugins/antispam/AUTHORS	2009-02-18 21:10:59 UTC (rev 170)
@@ -0,0 +1,2 @@
+Otto Gebb
+Konstantin Khomoutov <flatworm at users.sourceforge.net>


Property changes on: trunk/plugins/antispam/AUTHORS
___________________________________________________________________
Added: svn:eol-style
   + native

Added: trunk/plugins/antispam/ChangeLog
===================================================================
--- trunk/plugins/antispam/ChangeLog	                        (rev 0)
+++ trunk/plugins/antispam/ChangeLog	2009-02-18 21:10:59 UTC (rev 170)
@@ -0,0 +1,40 @@
+2009-02-19 Otto Gebb
+
+	* Bug fixed: All offline messages were blocked. Added check if
+	roster is initialized. This inroduces a new issue, however:
+	offline spam messages are now not blocked.
+
+2008-10-21 Otto Gebb
+
+	* Bug fixed: Accept subscription if there is evidence that 
+	the sender is not a spammer.
+
+2008-10-19 Otto Gebb
+
+	* Feature added: Added a setting to suppresses empty error
+	messages from transports.
+	
+	* Bug fixed: Empty chat messages are now considered service
+	messages and therefore not blocked.
+
+	* Upgrade: Plugin code was brought in compliance with the
+	greatly reworked Tkabber code, due to the migration to 
+	the tclxmpp library.
+
+2008-09-25 Otto Gebb 
+
+	* Bug fixed: Error messages containing the correct password were
+	accepted.
+
+2008-09-24 Otto Gebb 
+
+	* Suppression of opening a chat tab for an error message caused by a
+	password request.
+
+	* Proper debug messaging support.
+
+2008-09-23 Otto Gebb 
+
+	* Initial version.
+
+vim:ai:si:noet:nosta:ts=3:sw=3


Property changes on: trunk/plugins/antispam/ChangeLog
___________________________________________________________________
Added: svn:eol-style
   + native

Added: trunk/plugins/antispam/INSTALL
===================================================================
--- trunk/plugins/antispam/INSTALL	                        (rev 0)
+++ trunk/plugins/antispam/INSTALL	2009-02-18 21:10:59 UTC (rev 170)
@@ -0,0 +1,10 @@
+As usually, copy this directory under the ~/.tkabber/plugins directory
+so that you get a hierarchy like this:
+  ~/.tkabber/plugins
+  ~/.tkabber/plugins/antispam/
+  ~/.tkabber/plugins/antispam/antispam.tcl
+
+Restart Tkabber, to get the plugin loaded.
+Visit the "Customize->Plugins->Antispam" block of settings
+and adjust them if needed.
+Consult the README file for the details about using this plugin.


Property changes on: trunk/plugins/antispam/INSTALL
___________________________________________________________________
Added: svn:eol-style
   + native

Added: trunk/plugins/antispam/README
===================================================================
--- trunk/plugins/antispam/README	                        (rev 0)
+++ trunk/plugins/antispam/README	2009-02-18 21:10:59 UTC (rev 170)
@@ -0,0 +1,81 @@
+"Antispam" plugin for Tkabber.
+
+I. The idea.
+
+This plugin provides functionality to block annoying
+subscription requests and chat messages from spammers
+by simply not showing them to the user.
+A message from an unknown JID (that is not in the roster)
+is required to contain a special antispam password to be
+considered not spam.
+
+II. Configuration.
+
+There are several options that affect the behavior of this
+plugin. They can be found in the Tkabber settings dialog
+("Customize") by the following path:
+Tkabber -> Plugins -> Atispam.
+
+::plugins::antispam::options(enabled)
+
+Specifies whether the spam protection is on. When this mode is
+on, Tkabber will discard all subscription requests and messages
+from all JIDs that don't exist in the roster and meet the 
+restriction rules (see below). Also, Tkabber will optionally
+reply to the sender with a message describing how to bypass
+the spam protection.
+
+::plugins::antispam::options(disable_regex)
+
+A regexp determining JIDs for which the spam protection is
+always disabled. No automatic reply will ever be sent to JIDs 
+that match the expression and their messages and subscription
+requests are always shown. A value of "^$" (without the quotes),
+which is default, means no restrictions (because no JID will
+match this regular expression).
+
+::plugins::antispam::options(enable_regex)
+
+A regexp determining JIDs for which the spam protection is
+enabled. Only JIDs restricted to matching this expression and
+not matching the disable_regex expression (defined in the 
+previous paragraph) will be sent an automatic reply, and their
+messages will be discarded until receiving a correct password.
+When set to an empty string (the default) matches any JID.
+
+::plugins::antispam::options(message)
+
+The body of the password request that is sent in response to 
+a chat message or a subscription request when the antispam 
+protection is on. Before sending, the following substitutions 
+are made in the reply:
+Token    Replaced by
+%%       %
+%p       Password (see below)
+If this value is an empty string, the password request 
+will not be sent.
+
+::plugins::antispam::options(password)
+
+A regular expression, that an incoming message must match for
+the sender to be considered "legal". When the match occurs,
+messages from the sending JID will no longer be blocked.
+
+III. Debugging.
+
+To enable debug messages from this plugin put the following line
+in your configuration file:
+
+lappend debug_lvls antispam
+
+Or, if you are using the debug plugin, insert a line into the
+finload procedure in your configuration file (create one if it
+does not exist) so it looks like this:
+
+proc finload {} {
+   # Other stuff ...
+   set ::plugins::debug::debug(antispam) 1
+}
+
+
+vim:et:ts=4:sw=4:tw=64


Property changes on: trunk/plugins/antispam/README
___________________________________________________________________
Added: svn:eol-style
   + native

Added: trunk/plugins/antispam/TODO
===================================================================
--- trunk/plugins/antispam/TODO	                        (rev 0)
+++ trunk/plugins/antispam/TODO	2009-02-18 21:10:59 UTC (rev 170)
@@ -0,0 +1,2 @@
+* Log the hidden messages to a file.
+* When we request subscriptuin from a JID, put that JID on the white list.


Property changes on: trunk/plugins/antispam/TODO
___________________________________________________________________
Added: svn:eol-style
   + native

Added: trunk/plugins/antispam/antispam.tcl
===================================================================
--- trunk/plugins/antispam/antispam.tcl	                        (rev 0)
+++ trunk/plugins/antispam/antispam.tcl	2009-02-18 21:10:59 UTC (rev 170)
@@ -0,0 +1,327 @@
+# "Antispam" plugin for Tkabber.
+# This plugin blocks (hides from the user) 
+# spam messages and subscription requests.
+# Implementation:
+#   Otto von Gebbels <gebb at ngs dot ru>
+# Guidance and code review:
+#   Konstantin Khomoutov <flatworm at users.sourceforge.net>
+
+namespace eval antispam {
+	variable options
+
+	package require msgcat
+	::msgcat::mcload [file join [file dir [info script]] msgs]
+
+	custom::defgroup Plugins [::msgcat::mc "Plugins options."] -group Tkabber
+
+	set group "Antispam"
+
+	custom::defgroup $group \
+		[::msgcat::mc "Antispam plugin discards incoming\
+			subscription requests and chat messages\
+			from JIDs that are not in the roster,\
+			optionally requesting a password that\
+			enables the showing of messages."] \
+		-group Plugins
+
+	custom::defvar options(enabled) 1 \
+		[::msgcat::mc "Enables or disables the spam protection."] \
+		-group $group \
+		-type boolean
+
+	custom::defvar options(disable_regex) "^$" \
+		[::msgcat::mc "Regular expression to match JIDs for which\
+			the spam protection will not be used. A (default) value\
+			of \"^$\" means no JIDs."] \
+		-group $group \
+		-type string
+
+	custom::defvar options(enable_regex) "" \
+		[::msgcat::mc "Regular expression to match unknown JIDs,\
+			messages from which will be discarded util\
+			a correct password is received. A (default)\
+			value of \"\" means any JID."] \
+		-group $group \
+		-type string
+
+	custom::defvar options(message) "You seem to not exist\
+			in my roster. To bypass the spam protection system\
+			your message must contain the password: %p." \
+		[::msgcat::mc "Body of the message used to notify the sender\
+			about the spam protection and to request a password\
+			that enables the showing of messages from that JID.\
+			A token %% is expanded to a single % and %p to the\
+			password before sending.\
+			Specify an empty string to disable notification."] \
+		-group $group \
+		-type string
+
+	custom::defvar options(password) "666" \
+		[::msgcat::mc "Password, providing which will\
+			let the messages from the sender reach you. This\
+			is essentially a regexp that an incoming message\
+			has to match."] \
+		-group $group \
+		-type string
+
+	custom::defvar options(empty_err_regex) "^$" \
+		[::msgcat::mc "Regular expression to match JIDs from which\
+			empty error messages will be ignored.\
+			This setting is intended to suppress occasional\
+			error messages from transports. A (default) value\
+			of \"^$\" means no JIDs."] \
+		-group $group \
+		-type string
+
+	unset group
+}
+
+# Sends a password request.
+#
+proc antispam::notify {xlib to} {
+	variable options
+	if {$options(message) ne ""} {
+		debugmsg antispam \
+			"REQUEST_PASSWORD: sending request to $to."
+		message::send_msg $xlib $to -type chat -body [string map [list \
+			%% % \
+			%p $options(password)] $options(message)]
+	}
+}
+
+# Checks if the rules defined by the user
+# are met for a JID, and the spam protection
+# must be engaged.
+#
+proc antispam::meets_rules {jid} {
+	variable options
+	if { ![regexp -nocase $options(disable_regex) $jid] \
+		&& [regexp -nocase $options(enable_regex) $jid] } {
+		return yes
+	}
+	return no
+}
+
+# Sets the "roster loaded" flag for the specified connection.
+#
+proc antispam::roster_loaded_handler {xlib} {
+	variable roster_loaded
+	set roster_loaded($xlib) 1
+}
+
+# Clears the "roster loaded" flag for the specified connection.
+#
+proc antispam::disconnected_handler {xlib} {
+	variable roster_loaded
+	set roster_loaded($xlib) 0
+}
+
+# Checks if the roster is loaded for
+# the specified connection.
+#
+proc antispam::is_roster_loaded {xlib} {
+	variable roster_loaded
+	upvar 0 roster_loaded($xlib) rl
+	if { [info exists rl] && $rl } {
+		return yes
+	}
+	return no
+}
+
+# Blocks messages from unknown JIDs
+# and requests the password (sending $options(message)).
+#
+proc antispam::process_message {xlib from id type is_subject subject body args} {
+	variable options
+	variable answered
+	global whitelist
+	# Do nothing if antispam is disabled.
+	if { !$options(enabled) } {
+		return
+	}
+	if { $type ne "groupchat" } {
+		debugmsg antispam \
+			"PROCESS: message from $from, type $type, body: $body, args: $args."
+	}
+	# Block chat and error messages only.
+	if {$type ne "chat" \
+			&& $type ne "error"} {
+		return
+	}
+	# Accept service messages.
+	if {$body eq "" \
+			&& $type eq "chat"} {
+		debugmsg antispam \
+			"ACCEPT: empty body (possible service message)."
+		return
+	}
+
+	set chatid [chat::chatid $xlib $from]
+	set jid [connection_jid $xlib]
+	set my_barejid [connection_bare_jid $xlib]
+	set sender_barejid [xmpp::jid::stripResource $from]
+	set barejid_chatid [chat::chatid $xlib $sender_barejid]
+	
+	# Do nothing if the sender is on the white list.
+	upvar 0 whitelist($sender_barejid) onwlist
+	if { [info exists onwlist] } {
+		debugmsg antispam \
+			"ACCEPT: white list."
+		return
+	}
+	# Do not block MUC messages.
+	if { [chat::is_groupchat $barejid_chatid] } {
+		debugmsg antispam \
+			"ACCEPT: groupchat."
+		return
+	}
+	# A chat window was manually opened for this JID,
+	# so we assume the other side is not a spammer.
+	if {[chat::is_opened $barejid_chatid]
+		|| [chat::is_opened $chatid]} {
+		debugmsg antispam \
+			"ACCEPT: chat window open."
+		return
+	}
+	# Do not block messages from self.
+	if { $my_barejid eq $sender_barejid } {
+		debugmsg antispam \
+			"ACCEPT: from myself."
+		return
+	}
+	# Block empty errors from specified JIDs (defined by regexp).
+	if { $type eq "error" \
+		&& $body eq "" \
+		&& [regexp -nocase $options(empty_err_regex) $from] } {
+		debugmsg antispam \
+			"BLOCK_EMPTY_ERR: blocking empty error from $from."
+		return stop
+	}
+	# Do not block messages if roster has not been initialized.
+	if { ![is_roster_loaded $xlib] } {
+		debugmsg antispam \
+			"ACCEPT: roster not initialized."
+		return
+	}
+	# Do not block messages from contacts in roster.
+	if {[roster::find_jid $xlib $sender_barejid] ne "" } {
+		debugmsg antispam \
+			"ACCEPT: sender in roster."
+		return
+	}
+	# Do nothing if regexp rules are not met.
+	if { ![meets_rules $from] } {
+		debugmsg antispam \
+			"ACCEPT: blocking rules not met."
+		return
+	}
+	# If the correct password was given, put the sender
+	# on the white list.
+	# (Ignore the password in error messages.)
+	if { $type eq "chat"
+			&& [regexp -nocase $options(password) $body] } {
+		set onwlist 1
+		debugmsg antispam \
+			"ACCEPT: correct password given."
+		return
+	}
+
+	# If code flow reached this point, 
+	# the message is considered spam.
+
+	# Suppress error messages from spammers.
+	if { $type eq "error" } {
+		debugmsg antispam \
+			"BLOCK_SPAM: blocking error from $from."
+		return stop
+	}
+	debugmsg antispam \
+		"BLOCK_SPAM: blocking message from $from."
+	# Increment the number of times we replied to this JID.
+	upvar 0 answered($sender_barejid) answ
+	if {![info exists answ]} {
+		set answ 1
+	} else {
+		incr answ
+	}
+	# Stop sending request after doing it 1 time
+	# (should we make this number customizable?),
+	# but still prevent messages from being shown to the user.
+	if { $answ > 1 } {
+		return stop
+	}
+	# TODO: Log spam messages and bot replies to a file.
+	# Send a password request without opening a chat window.
+	notify $xlib $from
+	return stop
+}
+
+# Automatically rejects subscription if the request
+# does not contain the password.
+#
+proc antispam::block_subscription_spam {xlib from type x args} {
+	variable options
+	global whitelist
+	# Do nothing if antispam is disabled.
+	if { !$options(enabled) } {
+		return
+	}
+	if {$type ne "subscribe"} {
+		return
+	}
+	# Do nothing if the sender is on the white list.
+	set sender_barejid [xmpp::jid::stripResource $from]
+	if { [info exists whitelist($sender_barejid)] } {
+		debugmsg antispam \
+			"ACCEPT_SUBSC: Sender on white list."
+		return
+	}
+	# Do not block requests from contacts in roster.
+	if {[roster::find_jid $xlib $sender_barejid] ne "" } {
+		debugmsg antispam \
+			"ACCEPT_SUBSC: Sender in roster."
+		return
+	}
+	set chatid [chat::chatid $xlib $from]
+	set barejid_chatid [chat::chatid $xlib $sender_barejid]
+	# Do not request password if a chat window is 
+	# open for this JID.
+	if {[chat::is_opened $barejid_chatid]
+		|| [chat::is_opened $chatid]} {
+		debugmsg antispam \
+			"ACCEPT_SUBSC: Chat window open."
+		return
+	}
+	set status ""
+	foreach {opt val} $args {
+		switch -- $opt {
+			-status { set status $val }
+		}
+	}
+	# TODO: Log the subscription request.
+	if { ![meets_rules $from] \
+		|| [regexp -nocase $options(password) $status] } {
+		return
+	}
+	roster::remove_item $xlib $from
+	# Notify the sender on how to bypass the antispam system.
+	notify $xlib $from
+	debugmsg antispam \
+		"BLOCK_SUBSCR_SPAM: $from."
+	return stop
+}
+
+namespace eval antispam {
+	# Must be run before other handlers to prevent
+	# chat window opening for spam messages.
+	hook::add process_message_hook \
+		[namespace current]::process_message 40
+	# Must be run before the handler showing subcription dialog.
+	hook::add client_presence_hook \
+		[namespace current]::block_subscription_spam 40
+	hook::add roster_end_hook \
+		[namespace current]::roster_loaded_handler
+	hook::add disconnected_hook \
+		[namespace current]::disconnected_handler
+}
+# vim:ai:si:noet:nosta:ts=3:sw=3


Property changes on: trunk/plugins/antispam/antispam.tcl
___________________________________________________________________
Added: svn:eol-style
   + native

Added: trunk/plugins/antispam/license.terms
===================================================================
--- trunk/plugins/antispam/license.terms	                        (rev 0)
+++ trunk/plugins/antispam/license.terms	2009-02-18 21:10:59 UTC (rev 170)
@@ -0,0 +1,19 @@
+Copyright (c) 2008 Otto Gebb, Konstantin Khomoutov <flatworm at users.sourceforge.net>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.


Property changes on: trunk/plugins/antispam/license.terms
___________________________________________________________________
Added: svn:eol-style
   + native

Added: trunk/plugins/antispam/msgs/ru.msg
===================================================================
--- trunk/plugins/antispam/msgs/ru.msg	                        (rev 0)
+++ trunk/plugins/antispam/msgs/ru.msg	2009-02-18 21:10:59 UTC (rev 170)
@@ -0,0 +1,19 @@
+# vim:enc=utf-8
+
+::msgcat::mcset ru "Antispam plugin discards incoming subscription requests and chat messages from JIDs that are not in the roster, optionally requesting a password that enables the showing of messages." \
+	"Antispam блокирует входящие запросы на подписку и сообщения типа \"чат\", посланные с адресов, отсутствующих в ростере, и запрашивает при этом пароль для отмены блокировки."
+::msgcat::mcset ru "Enables or disables the spam protection." \
+	"Включает или выключает защиту от спама."
+::msgcat::mcset ru "Plugins options." \
+	"Настройки плагинов."
+::msgcat::mcset ru "Regular expression to match unknown JIDs, messages from which will be discarded util a correct password is received. A (default) value of \"\" means any JID." \
+	"Регулярное выражение, задающее JID'ы, сообщения от которых будут игнорироваться до получения правильного пароля. Значение по умолчанию \"\" означает любой JID."
+::msgcat::mcset ru "Regular expression to match JIDs for which the spam protection will not be used. A (default) value of \"^$\" means no JIDs." \
+	"Регулярное выражение, задающее \"запрещённые\" JID'ы, для которых защита от спама использоваться не будет. Значение по умолчанию \"^$\" означает отсутствие ограничения."
+::msgcat::mcset ru "Body of the message used to notify the sender about the spam protection and to request a password that enables the showing of messages from that JID. A token %% is expanded to a single % and %p to the password before sending. Specify an empty string to disable notification." \
+	"Тело сообщения, уведомляющего о необходимости ввести пароль, чтобы дальнейшие сообщения были показаны адресату. Ключевое слово %% перед отправкой раскрывается в %, %p — в пароль. Укажите пустую строку, чтобы отключить уведомление."
+::msgcat::mcset ru "Password, providing which will let the messages from the sender reach you. This is essentially a regexp that an incoming message has to match." \
+	"Пароль, который нужно указать отправителю, чтобы его сообщения не блокировались. Фактически представляет собой регулярное выражение, которому должно соответствовать входящее сообщение."
+::msgcat::mcset ru "Regular expression to match JIDs from which empty error messages will be ignored. This setting is intended to suppress occasional error messages from transports. A (default) value of \"^$\" means no JIDs." \
+	"Регулярное выражение, задающее JID'ы, сообщения об шибках от которых будут игнорироваться, если их тело пусто. Настройка нужна для блокировки ошибок от транспортов, рапортующих о невозможности доставить запрос пароля.  Значение по умолчанию \"^$\" не соответствует никакому JID'у."
+


Property changes on: trunk/plugins/antispam/msgs/ru.msg
___________________________________________________________________
Added: svn:eol-style
   + native



More information about the Tkabber-dev mailing list