]> kaliko git repositories - sid.git/blob - sid/rtbl.py
Add rtbl pluglin
[sid.git] / sid / rtbl.py
1 # -*- coding: utf-8 -*-
2 # SPDX-FileCopyrightText: 2014, 2020, 2023 kaliko <kaliko@azylum.org>
3 # SPDX-FileCopyrightText: 2007-2012 Thomas Perl <thp.io/about>
4 # SPDX-License-Identifier: GPL-3.0-or-later
5
6 from hashlib import sha256
7
8 from slixmpp.exceptions import XMPPError
9 from slixmpp.xmlstream import tostring
10
11 from .plugin import Plugin
12
13
14 class RTBL(Plugin):
15     """Spam guard for MUC
16     """
17     pubsub_server = 'example.org'
18     node = 'muc_bans_sha256'
19
20     def __init__(self, bot):
21         Plugin.__init__(self, bot)
22         bot.register_plugin('xep_0059')  # Mediated Information eXchange (MIX)
23         bot.register_plugin('xep_0060')  # Publish-Subscribe
24         self.handlers = [
25                 ('session_start', self._subscribe),
26                 ('pubsub_retract', self._retract),
27                 ('pubsub_publish', self._publish)
28         ]
29         self.add_handlers()
30         self.blocklist = None
31         self.bot = bot
32
33     def _exit(self):
34         self.rm_handlers()
35         self.bot.unregister_bot_plugin(self)
36
37     async def _subscribe(self, *args, **kwargs):
38         try:
39             nodes = await self.bot['xep_0060'].get_nodes(self.pubsub_server)
40             nodes_av = [_.get('node') for _ in nodes['disco_items']]
41             self.log.debug(f'nodes available: {nodes_av}')
42             if self.node not in nodes_av:
43                 self.log.error(f'{self.node} node not available on {self.pubsub_server}')
44                 await self._create()
45             iq = await self.bot['xep_0060'].subscribe(self.pubsub_server, self.node)
46             subscription = iq['pubsub']['subscription']
47             self.log.info('Subscribed %s to node %s', subscription['jid'], subscription['node'])
48         except XMPPError as error:
49             self.log.error('Could not subscribe %s to node %s: %s',
50                            self.bot.boundjid.bare, self.node, error.format())
51             self._exit()
52             return
53         self.blocklist = await self.bot['xep_0060'].get_items(self.pubsub_server, self.node)
54         message = f'Got {len(self.blocklist["pubsub"]["items"])} items in block list'
55         self.log.info(message)
56         # Add got_online handler once the blocklist is set
57         self.bot.add_event_handler(f'muc::{self.bot.room}::got_online', self.got_online)
58
59     async def _create(self):
60         """Try to create node"""
61         try:
62             await self.bot['xep_0060'].create_node(self.pubsub_server, self.node)
63             self.log.info('Created node %s', self.node)
64         except XMPPError as err:
65             self.log.error('Could not create node %s: %s', self.node, err.format())
66             raise XMPPError(f'Could not create node {self.node}') from err
67
68     def _retract(self, msg):
69         """Handler receiving a retract item event."""
70         self.log.debug('Retracted item %s from %s' % (
71             msg['pubsub_event']['items']['retract']['id'],
72             msg['pubsub_event']['items']['node']))
73
74     async def _publish(self, msg):
75         """Handler receiving a publish item event."""
76         self.log.debug('Published item %s to %s:' % (
77               msg['pubsub_event']['items']['item']['id'],
78               msg['pubsub_event']['items']['node']))
79         data = msg['pubsub_event']['items']['item']['payload']
80         if data is not None:
81             self.log.debug(tostring(data))
82         else:
83             self.log.debug('No item content')
84         self.blocklist = await self.bot['xep_0060'].get_items(self.pubsub_server, self.node)
85
86     async def got_online(self, pres):
87         """Handler method for new MUC participants"""
88         bjid = pres['muc']['jid'].bare
89         bjid_hash = sha256(bjid.encode('utf-8')).hexdigest()
90         if bjid_hash in [_['id'] for _ in self.blocklist['pubsub']['items']]:
91             self.log.debug(f'About to ban {bjid}')
92             await self.ban(bjid, reason='rtbl <timestamp>')
93
94 # VIM MODLINE
95 # vim: ai ts=4 sw=4 sts=4 expandtab