anti_spam/0000755000175500017550000000000013772335470012576 5ustar debacledebacleanti_spam/anti_spam.png0000644000175500017550000000146513772335470015265 0ustar debacledebaclePNG  IHDRabKGD pHYs  tIME  XLIDAT8mMh\U{޹hBLآ  BQDDBVYi Y骛R.B* Y )1N6jmN2i94]>pα1[.KB>,JX*=}FzVe28󌍍-y>avz_ZMQJEvwtt վurƐ4@Ǐc0E4M=999D9cĀFt(&EzV"8xZ+ J-,6Xo83IF+Rƻ=nQ.<|H(h- Q޳]mx7yvO^J#CL{^08yrl:Uߑ=8L`t. # from nbxmpp import NodeProcessed from nbxmpp.protocol import Message from nbxmpp.structs import StanzaHandler from gajim.common import app from gajim.common import ged from gajim.common.modules.base import BaseModule # Module name name = 'AntiSpam' zeroconf = False class AntiSpam(BaseModule): def __init__(self, con): BaseModule.__init__(self, con, plugin=True) self.handlers = [ StanzaHandler(name='message', callback=self._message_received, priority=48), StanzaHandler(name='presence', callback=self._subscribe_received, typ='subscribe', priority=48), ] self.register_events([ ('message-sent', ged.OUT_PRECORE, self._on_message_sent), ]) for plugin in app.plugin_manager.plugins: if plugin.short_name == 'anti_spam': self._config = plugin.config self._contacted_jids = set() def _on_message_sent(self, event): if event.type_ not in ('chat', 'normal'): return # We need self._contacted_jids in order to prevent two # Anti Spam Plugins from chatting with each other. # This set contains JIDs of all outgoing chats. if isinstance(event.jid, list): for jid in event.jid: self._contacted_jids.add(jid) else: self._contacted_jids.add(event.jid) def _message_received(self, _con, _stanza, properties): if properties.is_sent_carbon: # Another device already sent a message self._contacted_jids.add(properties.jid) return msg_body = properties.body if not msg_body: return if self._ask_question(properties): raise NodeProcessed msg_from = properties.jid limit = self._config['msgtxt_limit'] if limit > 0 and len(msg_body) > limit: self._log.info('Discarded message from %s: message ' 'length exceeded' % msg_from) raise NodeProcessed if self._config['disable_xhtml_muc'] and properties.type.is_groupchat: properties.xhtml = None self._log.info('Stripped message from %s: message ' 'contained XHTML' % msg_from) if self._config['disable_xhtml_pm'] and properties.is_muc_pm: properties.xhtml = None self._log.info('Stripped message from %s: message ' 'contained XHTML' % msg_from) def _ask_question(self, properties): answer = self._config['msgtxt_answer'] if len(answer) == 0: return False is_muc_pm = properties.is_muc_pm if is_muc_pm and not self._config['antispam_for_conference']: return False if (properties.type.value not in ('chat', 'normal') or properties.is_mam_message): return False msg_from = properties.jid if is_muc_pm else properties.jid.getBare() if msg_from in self._contacted_jids: return False # If we receive a PM or a message from an unknown user, our anti spam # question will silently be sent in the background whitelist = self._config['whitelist'] if msg_from in whitelist: return False is_contact = app.contacts.get_contacts(self._account, msg_from) if is_muc_pm or not is_contact: if answer in properties.body.split('\n'): if msg_from not in whitelist: whitelist.append(msg_from) # We need to explicitly save, because 'append' does not # implement the __setitem__ method self._config.save() else: self._send_question(properties, msg_from) return True return False def _send_question(self, properties, jid): message = 'Anti Spam Question: %s' % self._config['msgtxt_question'] stanza = Message(to=jid, body=message, typ=properties.type.value) self._con.connection.send_stanza(stanza) self._log.info('Anti spam question sent to %s', jid) def _subscribe_received(self, _con, _stanza, properties): msg_from = properties.jid block_sub = self._config['block_subscription_requests'] is_contact = app.contacts.get_contacts(self._account, msg_from) if block_sub and not is_contact: self._con.get_module('Presence').unsubscribed(msg_from) self._log.info('Denied subscription request from %s' % msg_from) raise NodeProcessed def get_instance(*args, **kwargs): return AntiSpam(*args, **kwargs), 'AntiSpam' anti_spam/config_dialog.py0000644000175500017550000001024613772335470015737 0ustar debacledebacle# This file is part of Gajim. # # Gajim is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Gajim is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Gajim. If not, see . from gi.repository import Gtk from gajim.gui.settings import SettingsDialog from gajim.gui.const import Setting from gajim.gui.const import SettingKind from gajim.gui.const import SettingType from gajim.plugins.plugins_i18n import _ class AntiSpamConfigDialog(SettingsDialog): def __init__(self, plugin, parent): self.plugin = plugin msgtxt_limit = self.plugin.config['msgtxt_limit'] max_length = '' if msgtxt_limit == 0 else msgtxt_limit settings = [ Setting(SettingKind.ENTRY, _('Limit Message Length'), SettingType.VALUE, max_length, callback=self._on_length_setting, data='msgtxt_limit', desc=_('Limits maximum message length (leave empty to ' 'disable)')), Setting(SettingKind.SWITCH, _('Deny Subscription Requests'), SettingType.VALUE, self.plugin.config['block_subscription_requests'], callback=self._on_setting, data='block_subscription_requests'), Setting(SettingKind.SWITCH, _('Disable XHTML for Group Chats'), SettingType.VALUE, self.plugin.config['disable_xhtml_muc'], callback=self._on_setting, data='disable_xhtml_muc', desc=_('Removes XHTML formatting from group chat ' 'messages')), Setting(SettingKind.SWITCH, _('Disable XHTML for PMs'), SettingType.VALUE, self.plugin.config['disable_xhtml_pm'], callback=self._on_setting, data='disable_xhtml_pm', desc=_('Removes XHTML formatting from private messages ' 'in group chats')), Setting(SettingKind.ENTRY, _('Anti Spam Question'), SettingType.VALUE, self.plugin.config['msgtxt_question'], callback=self._on_setting, data='msgtxt_question', desc=_('Question has to be answered in order to ' 'contact you')), Setting(SettingKind.ENTRY, _('Anti Spam Answer'), SettingType.VALUE, self.plugin.config['msgtxt_answer'], callback=self._on_setting, data='msgtxt_answer', desc=_('Correct answer to your Anti Spam Question ' '(leave empty to disable question)')), Setting(SettingKind.SWITCH, _('Anti Spam Question in Group Chats'), SettingType.VALUE, self.plugin.config['antispam_for_conference'], callback=self._on_setting, data='antispam_for_conference', desc=_('Enables anti spam question for private messages ' 'in group chats')), ] SettingsDialog.__init__(self, parent, _('Anti Spam Configuration'), Gtk.DialogFlags.MODAL, settings, None) def _on_setting(self, value, data): self.plugin.config[data] = value def _on_length_setting(self, value, data): try: self.plugin.config[data] = int(value) except Exception: self.plugin.config[data] = 0 anti_spam/__init__.py0000644000175500017550000000004613772335470014707 0ustar debacledebaclefrom .anti_spam import AntiSpamPlugin anti_spam/manifest.ini0000644000175500017550000000053513772335470015110 0ustar debacledebacle[info] name: Anti Spam short_name: anti_spam version: 1.5.2 description: Block some incoming messages. authors: Yann Leboulanger Denis Fomin Ilya Kanyukov homepage: https://dev.gajim.org/gajim/gajim-plugins/wikis/AntiSpamPlugin min_gajim_version: 1.2.91 max_gajim_version: 1.3.90 anti_spam/anti_spam.py0000644000175500017550000000333613772335470015130 0ustar debacledebacle# This file is part of Gajim. # # Gajim is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published # by the Free Software Foundation; version 3 only. # # Gajim is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Gajim. If not, see . # ''' :author: Yann Leboulanger :since: 16 August 2012 :copyright: Copyright (2012) Yann Leboulanger :license: GPLv3 ''' from functools import partial from gajim.plugins import GajimPlugin from gajim.plugins.plugins_i18n import _ from anti_spam.modules import anti_spam from anti_spam.config_dialog import AntiSpamConfigDialog class AntiSpamPlugin(GajimPlugin): def init(self): self.description = _('Allows you to block various kinds of incoming ' 'messages (Spam, XHTML formatting, etc.)') self.config_dialog = partial(AntiSpamConfigDialog, self) self.config_default_values = { 'disable_xhtml_muc': (False, ''), 'disable_xhtml_pm': (False, ''), 'block_subscription_requests': (False, ''), 'msgtxt_limit': (0, ''), 'msgtxt_question': ('12 x 12 = ?', ''), 'msgtxt_answer': ('', ''), 'antispam_for_conference': (False, ''), 'block_domains': ('', ''), 'whitelist': ([], ''), } self.gui_extension_points = {} self.modules = [anti_spam] anti_spam/CHANGELOG0000644000175500017550000000122113772335470014004 0ustar debacledebacle1.5.1 / 2020-05-03 - Rework plugin - Adapt to upstream changes in Gajim and python-nbxmpp - Use new configuration dialog - Remove pubsub blocking (Gajim handles these messages differently now) - Remove domain blocking feature (Gajim handles this) 1.4.3 / 2016-12-04 - Added filtering 'normal' type messages - User from private conference conversation permanently stored in file - Switched to GTK3 - Messages sent before the correct answer were marked as received - Fixed chat between the two antispam plugins 0.4.2 / 2016-11-28 - Added anti spam question functionality - Added README with some explanation of functionality - Added website in manifest.ini