forked from sch/KaikOut
Add RTBL configuration file;
Add functionality to exclude specified RTBL lists.
This commit is contained in:
parent
9e051fa0a6
commit
8df43fd327
7 changed files with 148 additions and 25 deletions
|
@ -159,6 +159,14 @@ timer <number>
|
|||
Timer value (in seconds) for countdown before committing an action.
|
||||
"""
|
||||
|
||||
[rtbl]
|
||||
allow = """
|
||||
ignore [+|-] <keyword>
|
||||
Jabber IDs to ignore
|
||||
comma-separated keywords
|
||||
'+' appends to, '-' removes from.
|
||||
"""
|
||||
|
||||
[statistics]
|
||||
score = """
|
||||
scores <jid>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# This file lists default RTBL sources per database.
|
||||
# See file /usr/share/kaikout/rtbl.toml
|
||||
|
||||
[[node]]
|
||||
[[sources]]
|
||||
description = "A general block list focussing on spam and service abuse."
|
||||
jabber_id = "xmppbl.org"
|
||||
node_name = "muc_bans_sha256"
|
||||
node_id = "muc_bans_sha256"
|
||||
|
|
|
@ -13,6 +13,7 @@ frequency_messages = 1 # The maximum allowed frequency (in seconds) of sent me
|
|||
frequency_presence = 180 # The maximum allowed frequency (in seconds) of changed status messages.
|
||||
inactivity_span = 30 # The maximum allowed time (in days) of inactivity.
|
||||
inactivity_warn = 300 # The time (in minutes) of inactivity to send a warning upon before action. Value can not be higher than of inactivity_span.
|
||||
rtbl_ignore = [] # A list of RTBL lists to exclude.
|
||||
score_messages = 3 # The maximum allowed number of message faults to act upon.
|
||||
score_presence = 10 # The maximum allowed number of presence faults to act upon.
|
||||
timer = 180 # Timer value (in seconds) for countdown before committing an action.
|
||||
|
|
|
@ -199,6 +199,67 @@ class Log:
|
|||
with open(filename, 'w') as f: f.write(content)
|
||||
|
||||
|
||||
class BlockList:
|
||||
|
||||
|
||||
def get_filename():
|
||||
"""
|
||||
Get pathname of filename.
|
||||
If filename does not exist, create it.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
None.
|
||||
|
||||
Returns
|
||||
-------
|
||||
filename : str
|
||||
Pathname.
|
||||
"""
|
||||
data_dir = Config.get_default_data_directory()
|
||||
if not os.path.isdir(data_dir): os.mkdir(data_dir)
|
||||
filename = os.path.join(data_dir, r"blocklist.toml")
|
||||
if not os.path.exists(filename):
|
||||
data = {'entries' : {}}
|
||||
content = tomli_w.dumps(data)
|
||||
with open(filename, 'w') as f: f.write(content)
|
||||
return filename
|
||||
|
||||
|
||||
def load_blocklist(self):
|
||||
filename = BlockList.get_filename()
|
||||
with open(filename, 'rb') as f:
|
||||
self.blocklist = tomllib.load(f)
|
||||
|
||||
|
||||
def add_entry_to_blocklist(self, jabber_id, node_id, item_id):
|
||||
"""
|
||||
Update blocklist file.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
jabber_id : str
|
||||
Jabber ID.
|
||||
node_id : str
|
||||
Node name.
|
||||
item_id : str
|
||||
Item ID.
|
||||
|
||||
Returns
|
||||
-------
|
||||
None.
|
||||
"""
|
||||
if jabber_id not in self.blocklist['entries']:
|
||||
self.blocklist['entries'][jabber_id] = {}
|
||||
if node_id not in self.blocklist['entries'][jabber_id]:
|
||||
self.blocklist['entries'][jabber_id][node_id] = []
|
||||
self.blocklist['entries'][jabber_id][node_id].append(item_id)
|
||||
data = self.blocklist
|
||||
content = tomli_w.dumps(data)
|
||||
filename = BlockList.get_filename()
|
||||
with open(filename, 'w') as f: f.write(content)
|
||||
|
||||
|
||||
class Url:
|
||||
|
||||
|
||||
|
|
|
@ -260,7 +260,7 @@ class XmppChat:
|
|||
else:
|
||||
response = str(self.settings[room]['action'])
|
||||
case _ if command_lowercase.startswith('allow +'):
|
||||
value = command[7:]
|
||||
value = command[7:].strip()
|
||||
if value:
|
||||
response = XmppCommands.set_filter(
|
||||
self, room, db_file, value, 'allow', True)
|
||||
|
@ -268,7 +268,7 @@ class XmppChat:
|
|||
response = ('No action has been taken. '
|
||||
'Missing keywords.')
|
||||
case _ if command_lowercase.startswith('allow -'):
|
||||
value = command[7:]
|
||||
value = command[7:].strip()
|
||||
if value:
|
||||
response = XmppCommands.set_filter(
|
||||
self, room, db_file, value, 'allow', False)
|
||||
|
@ -386,6 +386,22 @@ class XmppChat:
|
|||
await XmppCommands.muc_leave(self, room)
|
||||
else:
|
||||
response = 'This command is valid in groupchat only.'
|
||||
case _ if command_lowercase.startswith('ignore +'):
|
||||
value = command[8:].strip()
|
||||
if value:
|
||||
response = XmppCommands.set_filter(
|
||||
self, room, db_file, value, 'rtbl_ignore', True)
|
||||
else:
|
||||
response = ('No action has been taken. '
|
||||
'Missing Jabber IDs.')
|
||||
case _ if command_lowercase.startswith('ignore -'):
|
||||
value = command[8:].strip()
|
||||
if value:
|
||||
response = XmppCommands.set_filter(
|
||||
self, room, db_file, value, 'rtbl_ignore', False)
|
||||
else:
|
||||
response = ('No action has been taken. '
|
||||
'Missing Jabber IDs.')
|
||||
case 'inactivity off':
|
||||
XmppCommands.update_setting_value(
|
||||
self, room, db_file, 'check_inactivity', 0)
|
||||
|
@ -537,4 +553,4 @@ class XmppChat:
|
|||
if room in self.settings and self.settings[room]['finished']:
|
||||
response_finished = ('Finished. Total time: {}s'
|
||||
.format(command_time_total))
|
||||
XmppMessage.send_reply(self, message, response_finished)
|
||||
XmppMessage.send_reply(self, message, response_finished)
|
||||
|
|
|
@ -3,11 +3,10 @@
|
|||
|
||||
import asyncio
|
||||
from datetime import datetime
|
||||
import slixmpp
|
||||
from kaikout.about import Documentation
|
||||
from kaikout.database import Toml
|
||||
from kaikout.log import Logger
|
||||
from kaikout.utilities import Config, Log
|
||||
from kaikout.utilities import Config, Log, BlockList
|
||||
from kaikout.xmpp.bookmark import XmppBookmark
|
||||
from kaikout.xmpp.chat import XmppChat
|
||||
from kaikout.xmpp.commands import XmppCommands
|
||||
|
@ -17,6 +16,7 @@ from kaikout.xmpp.moderation import XmppModeration
|
|||
from kaikout.xmpp.muc import XmppMuc
|
||||
from kaikout.xmpp.pubsub import XmppPubsub
|
||||
from kaikout.xmpp.status import XmppStatus
|
||||
import slixmpp
|
||||
import time
|
||||
|
||||
# time_now = datetime.now()
|
||||
|
@ -53,10 +53,13 @@ class XmppClient(slixmpp.ClientXMPP):
|
|||
self.reconnect_timeout = Config.get_values('accounts.toml', 'xmpp')['settings']['reconnect_timeout']
|
||||
# A handler for operators.
|
||||
self.operators = Config.get_values('accounts.toml', 'xmpp')['operators']
|
||||
# A handler for settings.
|
||||
self.settings = {}
|
||||
# A handler for blocklist.
|
||||
#self.blocklist = {}
|
||||
BlockList.load_blocklist(self)
|
||||
# A handler for sessions.
|
||||
self.sessions = {}
|
||||
# A handler for settings.
|
||||
self.settings = {}
|
||||
# A handler for tasks.
|
||||
self.tasks = {}
|
||||
# Register plugins.
|
||||
|
@ -267,14 +270,15 @@ class XmppClient(slixmpp.ClientXMPP):
|
|||
jid = presence['muc']['jid']
|
||||
from hashlib import sha256
|
||||
jid_to_sha256 = sha256(jid.bare.encode('utf-8')).hexdigest()
|
||||
rtbl_jid_full = 'xmppbl.org'
|
||||
rtbl_node_id = 'muc_bans_sha256'
|
||||
rtbl_list = await XmppPubsub.get_items(self, rtbl_jid_full, rtbl_node_id)
|
||||
for item in rtbl_list['pubsub']['items']:
|
||||
if jid_to_sha256 == item['id']:
|
||||
reason = 'Jabber ID has been marked by RTBL.'
|
||||
await XmppCommands.devoice(self, room, alias, reason)
|
||||
break
|
||||
for jid in self.blocklist['entries']:
|
||||
if jid not in self.settings[room]['rtbl_ignore']:
|
||||
for node in self.blocklist['entries'][jid]:
|
||||
for item_id in self.blocklist['entries'][jid][node]:
|
||||
if jid_to_sha256 == item_id:
|
||||
reason = 'Jabber ID has been marked by RTBL: Publisher: {}; Node: {}.'.format(
|
||||
jid, node)
|
||||
await XmppCommands.devoice(self, room, alias, reason)
|
||||
break
|
||||
# message_body = 'Greetings {} and welcome to groupchat {}'.format(alias, room)
|
||||
# XmppMessage.send(self, jid.bare, message_body, 'chat')
|
||||
# Send MUC-PM in case there is no indication for reception of 1:1
|
||||
|
@ -477,14 +481,32 @@ class XmppClient(slixmpp.ClientXMPP):
|
|||
"""
|
||||
# self.command_list()
|
||||
# await self.get_roster()
|
||||
subscriptions_of_node = await self['xep_0060'].get_node_subscriptions("xmppbl.org", "muc_bans_sha256")
|
||||
print()
|
||||
print('=== subscriptions_of_node ===')
|
||||
print()
|
||||
print(subscriptions_of_node)
|
||||
print()
|
||||
print('=== subscriptions_of_node ===')
|
||||
print()
|
||||
rtbl_sources = Config.get_values('rtbl.toml')['sources']
|
||||
for source in rtbl_sources:
|
||||
jabber_id = source['jabber_id']
|
||||
node_id = source['node_id']
|
||||
subscribe = await XmppPubsub.subscribe(self, jabber_id, node_id)
|
||||
if subscribe['pubsub']['subscription']['subscription'] == 'subscribed':
|
||||
rtbl_list = await XmppPubsub.get_items(self, jabber_id, node_id)
|
||||
rtbl_items = rtbl_list['pubsub']['items']
|
||||
for item in rtbl_items:
|
||||
exist = False
|
||||
item_id = item['id']
|
||||
for jid in self.blocklist['entries']:
|
||||
for node in jid:
|
||||
for item in node:
|
||||
if item_id == item:
|
||||
exist = True
|
||||
break
|
||||
if not exist:
|
||||
# TODO Extract items item_payload.find(namespace + 'title')
|
||||
# NOTE (Pdb)
|
||||
# for i in item['payload'].iter(): i.attrib
|
||||
# {'reason': 'urn:xmpp:reporting:abuse'}
|
||||
BlockList.add_entry_to_blocklist(self, jabber_id, node_id, item_id)
|
||||
# subscribe['from'] = xmppbl.org
|
||||
# subscribe['pubsub']['subscription']['node'] = 'muc_bans_sha256'
|
||||
subscriptions = await XmppPubsub.get_node_subscriptions(self, jabber_id, node_id)
|
||||
await self['xep_0115'].update_caps()
|
||||
bookmarks = await XmppBookmark.get_bookmarks(self)
|
||||
print(bookmarks)
|
||||
|
|
|
@ -9,6 +9,7 @@ Functions create_node and create_entry are derived from project atomtopubsub.
|
|||
|
||||
import hashlib
|
||||
from kaikout.log import Logger
|
||||
from slixmpp.exceptions import IqTimeout, IqError
|
||||
|
||||
logger = Logger(__name__)
|
||||
|
||||
|
@ -66,3 +67,16 @@ class XmppPubsub:
|
|||
async def get_items(self, jid, node):
|
||||
items = await self.plugin['xep_0060'].get_items(jid, node)
|
||||
return items
|
||||
|
||||
|
||||
async def subscribe(self, jid, node):
|
||||
result = await self['xep_0060'].subscribe(jid, node)
|
||||
return result
|
||||
|
||||
|
||||
async def get_node_subscriptions(self, jid, node):
|
||||
try:
|
||||
subscriptions = await self['xep_0060'].get_node_subscriptions(jid, node)
|
||||
return subscriptions
|
||||
except IqError as e:
|
||||
print(e)
|
||||
|
|
Loading…
Reference in a new issue