From 4ac8e0836deda2f85efb207f9418452451a927b8 Mon Sep 17 00:00:00 2001 From: Schimon Jehudah Date: Tue, 14 May 2024 19:39:58 +0000 Subject: [PATCH] Fix PubSub; Improve permission handling; Catch more errors. --- slixfeed/action.py | 23 +++- slixfeed/log.py | 2 +- slixfeed/sqlite.py | 29 ++--- slixfeed/version.py | 4 +- slixfeed/xmpp/chat.py | 88 +++++++------- slixfeed/xmpp/client.py | 241 ++++++++++++++++++++++--------------- slixfeed/xmpp/iq.py | 7 +- slixfeed/xmpp/privilege.py | 49 ++++++++ slixfeed/xmpp/profile.py | 26 ++-- slixfeed/xmpp/publish.py | 6 + slixfeed/xmpp/utility.py | 59 ++------- 11 files changed, 315 insertions(+), 219 deletions(-) create mode 100644 slixfeed/xmpp/privilege.py diff --git a/slixfeed/action.py b/slixfeed/action.py index 747c572..64c9b61 100644 --- a/slixfeed/action.py +++ b/slixfeed/action.py @@ -40,6 +40,7 @@ import slixfeed.crawl as crawl import slixfeed.dt as dt import slixfeed.fetch as fetch import slixfeed.sqlite as sqlite +import slixfeed.url as uri from slixfeed.url import ( complete_url, join_url, @@ -298,14 +299,30 @@ async def xmpp_pubsub_send_unread_items(self, jid_bare): # node_subtitle = feed_properties[5] node_id = sqlite.get_feed_identifier(db_file, feed_id) node_id = node_id[0] + if not node_id: + counter = 0 + hostname = uri.get_hostname(url) + hostname = hostname.replace('.','-') + identifier = hostname + ':' + str(counter) + while True: + if sqlite.check_identifier_exist(db_file, identifier): + counter += 1 + identifier = hostname + ':' + str(counter) + else: + break + await sqlite.update_feed_identifier(db_file, feed_id, identifier) + node_id = sqlite.get_feed_identifier(db_file, feed_id) + node_id = node_id[0] node_title = sqlite.get_feed_title(db_file, feed_id) node_title = node_title[0] node_subtitle = sqlite.get_feed_subtitle(db_file, feed_id) node_subtitle = node_subtitle[0] xep = None - iq_create_node = XmppPubsub.create_node( - self, jid_bare, node_id, xep, node_title, node_subtitle) - await XmppIQ.send(self, iq_create_node) + node_exist = await XmppPubsub.get_node_configuration(self, jid_bare, node_id) + if not node_exist: + iq_create_node = XmppPubsub.create_node( + self, jid_bare, node_id, xep, node_title, node_subtitle) + await XmppIQ.send(self, iq_create_node) entries = sqlite.get_unread_entries_of_feed(db_file, feed_id) report[url] = len(entries) for entry in entries: diff --git a/slixfeed/log.py b/slixfeed/log.py index 12d201b..e884a2a 100644 --- a/slixfeed/log.py +++ b/slixfeed/log.py @@ -17,7 +17,7 @@ class Logger: def __init__(self, name): self.logger = logging.getLogger(name) - self.logger.setLevel(logging.WARNING) + self.logger.setLevel(logging.WARNING) # DEBUG ch = logging.StreamHandler() ch.setLevel(logging.WARNING) diff --git a/slixfeed/sqlite.py b/slixfeed/sqlite.py index c62cdd3..709faa7 100644 --- a/slixfeed/sqlite.py +++ b/slixfeed/sqlite.py @@ -562,6 +562,7 @@ def insert_feed_preferences(cur, feed_id): logger.error(e) +# TODO Test def insert_feed_properties(cur, feed_id): """ Set feed properties. @@ -578,7 +579,7 @@ def insert_feed_properties(cur, feed_id): """ INSERT INTO feeds_properties( - feed_id) + id) VALUES( ?) """ @@ -953,7 +954,7 @@ def get_feed_identifier(db_file, feed_id): """ SELECT identifier FROM feeds_properties - WHERE feed_id = ? + WHERE id = ? """ ) par = (feed_id,) @@ -1762,20 +1763,20 @@ async def archive_entry(db_file, ix): cur.execute(sql, par) -def get_feed_title(db_file, ix): +def get_feed_title(db_file, feed_id): function_name = sys._getframe().f_code.co_name - logger.debug('{}: db_file: {} ix: {}' - .format(function_name, db_file, ix)) + logger.debug('{}: db_file: {} feed_id: {}' + .format(function_name, db_file, feed_id)) with create_connection(db_file) as conn: cur = conn.cursor() sql = ( """ SELECT title FROM feeds_properties - WHERE id = :ix + WHERE id = :feed_id """ ) - par = (ix,) + par = (feed_id,) title = cur.execute(sql, par).fetchone() return title @@ -1790,7 +1791,7 @@ def get_feed_subtitle(db_file, feed_id): """ SELECT subtitle FROM feeds_properties - WHERE feed_id = :feed_id + WHERE id = :feed_id """ ) par = (feed_id,) @@ -1885,20 +1886,20 @@ def get_entry_url(db_file, ix): return url -def get_feed_url(db_file, ix): +def get_feed_url(db_file, feed_id): function_name = sys._getframe().f_code.co_name - logger.debug('{}: db_file: {} ix: {}' - .format(function_name, db_file, ix)) + logger.debug('{}: db_file: {} feed_id: {}' + .format(function_name, db_file, feed_id)) with create_connection(db_file) as conn: cur = conn.cursor() sql = ( """ SELECT url FROM feeds_properties - WHERE id = :ix + WHERE id = :feed_id """ ) - par = (ix,) + par = (feed_id,) url = cur.execute(sql, par).fetchone() return url @@ -2355,7 +2356,7 @@ async def update_feed_identifier(db_file, feed_id, identifier): """ UPDATE feeds_properties SET identifier = :identifier - WHERE feed_id = :feed_id + WHERE id = :feed_id """ ) par = { diff --git a/slixfeed/version.py b/slixfeed/version.py index fc0d35d..57fe273 100644 --- a/slixfeed/version.py +++ b/slixfeed/version.py @@ -1,2 +1,2 @@ -__version__ = '0.1.65' -__version_info__ = (0, 1, 65) +__version__ = '0.1.66' +__version_info__ = (0, 1, 66) diff --git a/slixfeed/xmpp/chat.py b/slixfeed/xmpp/chat.py index ad658d8..2dae019 100644 --- a/slixfeed/xmpp/chat.py +++ b/slixfeed/xmpp/chat.py @@ -42,7 +42,8 @@ from slixfeed.xmpp.muc import XmppGroupchat from slixfeed.xmpp.message import XmppMessage from slixfeed.xmpp.presence import XmppPresence from slixfeed.xmpp.upload import XmppUpload -from slixfeed.xmpp.utility import get_chat_type, is_moderator, is_operator +from slixfeed.xmpp.privilege import is_moderator, is_operator, is_access +from slixfeed.xmpp.utility import get_chat_type import time from random import randrange @@ -720,12 +721,48 @@ class Chat: key_list = ['status'] await task.start_tasks_xmpp_chat(self, jid_bare, key_list) XmppMessage.send_reply(self, message, response) + case _ if message_lowercase.startswith('pubsub list '): + jid = message_text[12:] + from slixfeed.xmpp.publish import XmppPubsub + iq = await XmppPubsub.get_nodes(self, jid) + response = 'List of nodes for {}:\n```\n'.format(jid) + for item in iq['disco_items']: + item_id = item['node'] + item_name = item['name'] + response += 'Name: {}\nNode: {}\n\n'.format(item_name, item_id) + response += '```' + XmppMessage.send_reply(self, message, response) + case _ if message_lowercase.startswith('pubsub send '): + if is_operator(self, jid_bare): + info = message_text[12:] + info = info.split(' ') + jid = info[0] + # num = int(info[1]) + if jid: + # if num: + # report = await action.xmpp_pubsub_send_unread_items( + # self, jid, num) + # else: + # report = await action.xmpp_pubsub_send_unread_items( + # self, jid) + report = await action.xmpp_pubsub_send_unread_items( + self, jid) + response = '' + for url in report: + if report[url]: + response += url + ' : ' + str(report[url]) + '\n' + else: + response = 'PubSub JID is missing. Enter PubSub JID.' + else: + response = ('This action is restricted. ' + 'Type: sending news to PubSub.') + XmppMessage.send_reply(self, message, response) # TODO Handle node error # sqlite3.IntegrityError: UNIQUE constraint failed: feeds_pubsub.node # ERROR:slixmpp.basexmpp:UNIQUE constraint failed: feeds_pubsub.node - case _ if message_lowercase.startswith('send '): + case _ if message_lowercase.startswith('pubsub '): if is_operator(self, jid_bare): - info = message_text[5:].split(' ') + info = message_text[7:].split(' ') if len(info) > 1: jid = info[0] if '/' not in jid: @@ -810,7 +847,7 @@ class Chat: else: response = ('No action has been taken.' '\n' - 'JID Must not include "/".') + 'JID may not include "/".') else: response = ('No action has been taken.' '\n' @@ -823,6 +860,7 @@ class Chat: XmppMessage.send_reply(self, message, response) case _ if (message_lowercase.startswith('http') or message_lowercase.startswith('feed:/') or + message_lowercase.startswith('itpc:/') or message_lowercase.startswith('rss:/')): url = message_text # task.clean_tasks_xmpp_chat(self, jid_bare, ['status']) @@ -1029,9 +1067,9 @@ class Chat: db_file, key, val) response = 'Only new items of newly added feeds be delivered.' XmppMessage.send_reply(self, message, response) - case _ if message_lowercase.startswith('pubsub delete '): + case _ if message_lowercase.startswith('node delete '): if is_operator(self, jid_bare): - info = message_text[14:] + info = message_text[12:] info = info.split(' ') if len(info) > 2: jid = info[0] @@ -1051,20 +1089,9 @@ class Chat: response = ('This action is restricted. ' 'Type: sending news to PubSub.') XmppMessage.send_reply(self, message, response) - case _ if message_lowercase.startswith('pubsub list '): - jid = message_text[12:] - from slixfeed.xmpp.publish import XmppPubsub - iq = await XmppPubsub.get_nodes(self, jid) - response = 'List of nodes for {}:\n```\n'.format(jid) - for item in iq['disco_items']: - item_id = item['node'] - item_name = item['name'] - response += 'Name: {}\nNode: {}\n\n'.format(item_name, item_id) - response += '```' - XmppMessage.send_reply(self, message, response) - case _ if message_lowercase.startswith('pubsub purge '): + case _ if message_lowercase.startswith('node purge '): if is_operator(self, jid_bare): - info = message_text[13:] + info = message_text[11:] info = info.split(' ') if len(info) > 1: jid = info[0] @@ -1084,29 +1111,6 @@ class Chat: response = ('This action is restricted. ' 'Type: sending news to PubSub.') XmppMessage.send_reply(self, message, response) - case _ if message_lowercase.startswith('pubsub flash '): - if is_operator(self, jid_bare): - info = message_text[13:] - info = info.split(' ') - jid = info[0] - num = int(info[1]) - if jid: - if num: - report = await action.xmpp_pubsub_send_unread_items( - self, jid, num) - else: - report = await action.xmpp_pubsub_send_unread_items( - self, jid) - response = '' - for url in report: - if report[url]: - response += url + ' : ' + str(report[url]) + '\n' - else: - response = 'PubSub JID is missing. Enter PubSub JID.' - else: - response = ('This action is restricted. ' - 'Type: sending news to PubSub.') - XmppMessage.send_reply(self, message, response) case _ if message_lowercase.startswith('next'): num = message_text[5:] if num: diff --git a/slixfeed/xmpp/client.py b/slixfeed/xmpp/client.py index 2263963..f066b68 100644 --- a/slixfeed/xmpp/client.py +++ b/slixfeed/xmpp/client.py @@ -59,7 +59,8 @@ from slixfeed.xmpp.publish import XmppPubsub from slixfeed.xmpp.roster import XmppRoster # import slixfeed.xmpp.service as service from slixfeed.xmpp.presence import XmppPresence -from slixfeed.xmpp.utility import get_chat_type, is_operator +from slixfeed.xmpp.privilege import is_operator, is_access +from slixfeed.xmpp.utility import get_chat_type import sys import time @@ -87,7 +88,8 @@ from slixfeed.xmpp.message import XmppMessage from slixfeed.xmpp.presence import XmppPresence from slixfeed.xmpp.roster import XmppRoster from slixfeed.xmpp.upload import XmppUpload -from slixfeed.xmpp.utility import get_chat_type, is_moderator +from slixfeed.xmpp.privilege import is_moderator, is_operator, is_access +from slixfeed.xmpp.utility import get_chat_type main_task = [] jid_tasker = {} @@ -305,6 +307,9 @@ class Slixfeed(slixmpp.ClientXMPP): await self['xep_0115'].update_caps() # self.send_presence() await self.get_roster() + # XmppCommand.adhoc_commands(self) + # self.service_reactions() + task.task_ping(self) results = await XmppPubsub.get_pubsub_services(self) for result in results + [{'jid' : self.boundjid.bare, 'name' : self.alias}]: @@ -313,13 +318,10 @@ class Slixfeed(slixmpp.ClientXMPP): db_file = config.get_pathname_to_database(jid_bare) Config.add_settings_jid(self.settings, jid_bare, db_file) await task.start_tasks_xmpp_pubsub(self, jid_bare) - # XmppCommand.adhoc_commands(self) - # self.service_reactions() bookmarks = await XmppBookmark.get_bookmarks(self) print('iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii') await action.xmpp_muc_autojoin(self, bookmarks) print('ooooooooooooooooooooooooooooooooo') - task.task_ping(self) time_end = time.time() difference = time_end - time_begin if difference > 1: logger.warning('{} (time: {})'.format(function_name, @@ -818,19 +820,7 @@ class Slixfeed(slixmpp.ClientXMPP): .format(function_name, jid_full)) jid_bare = session['from'].bare chat_type = await get_chat_type(self, jid_bare) - access = None - print('PERMISSION JID : ' + jid_full) - print('PERMISSION CHAT : ' + chat_type) - operator = is_operator(self, jid_bare) - if operator: - if chat_type == 'groupchat': - if is_moderator(self, jid_bare, jid_full): - access = True - print('PERMISSION MOD') - else: - access = True - print('PERMISSION OP') - if access: + if is_access(self, jid_bare, jid_full, chat_type): form = self['xep_0004'].make_form('form', 'PubSub') form['instructions'] = 'Publish news items to PubSub nodes.' options = form.add_field(desc='From which medium source do you ' @@ -844,18 +834,21 @@ class Slixfeed(slixmpp.ClientXMPP): form.add_field(ftype='fixed', label='* Attention', desc='Results are viewed best with Movim and ' - 'Libervia.') + 'Libervia.') session['allow_prev'] = False session['has_next'] = True session['next'] = self._handle_publish_action session['prev'] = None session['payload'] = form else: - if not operator: + if not is_operator(self, jid_bare): text_warn = 'This resource is restricted to operators.' elif chat_type == 'groupchat': text_warn = ('This resource is restricted to moderators of {}.' .format(jid_bare)) + elif chat_type == 'error': + text_warn = ('Could not determine chat type of {}.' + .format(jid_bare)) else: text_warn = 'This resource is forbidden.' session['notes'] = [['warn', text_warn]] @@ -867,7 +860,8 @@ class Slixfeed(slixmpp.ClientXMPP): logger.debug('{}: jid_full: {}' .format(function_name, jid_full)) jid_bare = session['from'].bare - if is_operator(self, jid_bare): + chat_type = await get_chat_type(self, jid_bare) + if is_access(self, jid_bare, jid_full, chat_type): values = payload['values'] form = self['xep_0004'].make_form('form', 'Publish') form['instructions'] = ('Choose a PubSub Jabber ID and verify ' @@ -955,7 +949,16 @@ class Slixfeed(slixmpp.ClientXMPP): session['has_next'] = True session['prev'] = self._handle_publish else: - text_warn = 'This resource is restricted to operators.' + if not is_operator(self, jid_bare): + text_warn = 'This resource is restricted to operators.' + elif chat_type == 'groupchat': + text_warn = ('This resource is restricted to moderators of {}.' + .format(jid_bare)) + elif chat_type == 'error': + text_warn = ('Could not determine chat type of {}.' + .format(jid_bare)) + else: + text_warn = 'This resource is forbidden.' session['notes'] = [['warn', text_warn]] return session @@ -970,21 +973,23 @@ class Slixfeed(slixmpp.ClientXMPP): jid = values['jid'] if 'jid' in values else None jid_bare = session['from'].bare if jid != jid_bare and not is_operator(self, jid_bare): - text_warn = ('Posting to {} is restricted to operators only.' - .format(jid_bare)) # Should not this be self.boundjid.bare? - session['allow_prev'] = False - session['has_next'] = False - session['next'] = None - session['notes'] = [['warn', text_warn]] - session['prev'] = None - session['payload'] = None - return session + text_warn = ('Posting to {} is restricted to operators only.' + .format(jid_bare)) # Should not this be self.boundjid.bare? + session['allow_prev'] = False + session['has_next'] = False + session['next'] = None + session['notes'] = [['warn', text_warn]] + session['prev'] = None + session['payload'] = None + return session jid_file = values['jid_file'] node = values['node'] # xep = values['xep'] if not node: if jid == self.boundjid.bare: node = 'urn:xmpp:microblog:0' + else: + node = 'slixfeed' form = self['xep_0004'].make_form('form', 'Publish') form.add_field(var='node', @@ -1039,14 +1044,15 @@ class Slixfeed(slixmpp.ClientXMPP): #if jid: jid = jid[0] if isinstance(jid, list) else jid jid_bare = session['from'].bare if jid != jid_bare and not is_operator(self, jid_bare): - text_warn = 'You are not suppose to be here.' - session['allow_prev'] = False - session['has_next'] = False - session['next'] = None - session['notes'] = [['warn', text_warn]] - session['prev'] = None - session['payload'] = None - return session + # TODO Report incident + text_warn = 'You are not suppose to be here.' + session['allow_prev'] = False + session['has_next'] = False + session['next'] = None + session['notes'] = [['warn', text_warn]] + session['prev'] = None + session['payload'] = None + return session # xep = values['xep'][0] # xep = None @@ -1073,15 +1079,17 @@ class Slixfeed(slixmpp.ClientXMPP): jid = values['jid'] if 'jid' in values else None jid_bare = session['from'].bare if jid != jid_bare and not is_operator(self, jid_bare): - text_warn = ('Posting to {} is restricted to operators only.' - .format(jid_bare)) # Should not this be self.boundjid.bare? - session['allow_prev'] = False - session['has_next'] = False - session['next'] = None - session['notes'] = [['warn', text_warn]] - session['prev'] = None - session['payload'] = None - return session + # TODO Report incident + text_warn = 'You are not suppose to be here.' + # text_warn = ('Posting to {} is restricted to operators only.' + # .format(jid_bare)) # Should not this be self.boundjid.bare? + session['allow_prev'] = False + session['has_next'] = False + session['next'] = None + session['notes'] = [['warn', text_warn]] + session['prev'] = None + session['payload'] = None + return session node = values['node'] url = values['url'] # xep = values['xep'] @@ -1197,14 +1205,15 @@ class Slixfeed(slixmpp.ClientXMPP): #if jid: jid = jid[0] if isinstance(jid, list) else jid jid_bare = session['from'].bare if jid != jid_bare and not is_operator(self, jid_bare): - text_warn = 'You are not suppose to be here.' - session['allow_prev'] = False - session['has_next'] = False - session['next'] = None - session['notes'] = [['warn', text_warn]] - session['prev'] = None - session['payload'] = None - return session + # TODO Report incident + text_warn = 'You are not suppose to be here.' + session['allow_prev'] = False + session['has_next'] = False + session['next'] = None + session['notes'] = [['warn', text_warn]] + session['prev'] = None + session['payload'] = None + return session url = values['url'][0] # xep = values['xep'][0] xep = None @@ -1364,10 +1373,7 @@ class Slixfeed(slixmpp.ClientXMPP): .format(function_name, jid_full)) jid_bare = session['from'].bare chat_type = await get_chat_type(self, jid_bare) - moderator = None - if chat_type == 'groupchat': - moderator = is_moderator(self, jid_bare, jid_full) - if chat_type == 'chat' or moderator: + if is_access(self, jid_bare, jid_full, chat_type): jid = session['from'].bare jid_file = jid db_file = config.get_pathname_to_database(jid_file) @@ -1407,8 +1413,16 @@ class Slixfeed(slixmpp.ClientXMPP): session['next'] = self._handle_filters_complete session['payload'] = form else: - text_warn = ('This resource is restricted to moderators of {}.' - .format(jid)) + if not is_operator(self, jid_bare): + text_warn = 'This resource is restricted to operators.' + elif chat_type == 'groupchat': + text_warn = ('This resource is restricted to moderators of {}.' + .format(jid_bare)) + elif chat_type == 'error': + text_warn = ('Could not determine chat type of {}.' + .format(jid_bare)) + else: + text_warn = 'This resource is forbidden.' session['notes'] = [['warn', text_warn]] return session @@ -1470,10 +1484,7 @@ class Slixfeed(slixmpp.ClientXMPP): .format(function_name, jid_full)) jid_bare = session['from'].bare chat_type = await get_chat_type(self, jid_bare) - moderator = None - if chat_type == 'groupchat': - moderator = is_moderator(self, jid_bare, jid_full) - if chat_type == 'chat' or moderator: + if is_access(self, jid_bare, jid_full, chat_type): form = self['xep_0004'].make_form('form', 'Subscribe') # form['instructions'] = 'Add a new custom subscription.' form.add_field(desc='Enter a URL.', @@ -1515,8 +1526,16 @@ class Slixfeed(slixmpp.ClientXMPP): session['prev'] = None session['payload'] = form else: - text_warn = ('This resource is restricted to moderators of {}.' - .format(jid_bare)) + if not is_operator(self, jid_bare): + text_warn = 'This resource is restricted to operators.' + elif chat_type == 'groupchat': + text_warn = ('This resource is restricted to moderators of {}.' + .format(jid_bare)) + elif chat_type == 'error': + text_warn = ('Could not determine chat type of {}.' + .format(jid_bare)) + else: + text_warn = 'This resource is forbidden.' session['notes'] = [['warn', text_warn]] return session @@ -2047,11 +2066,7 @@ class Slixfeed(slixmpp.ClientXMPP): .format(function_name, jid_full)) jid_bare = session['from'].bare chat_type = await get_chat_type(self, jid_bare) - moderator = None - if chat_type == 'groupchat': - moderator = is_moderator(self, jid_bare, jid_full) - # moderator = moderator if moderator else None - if chat_type == 'chat' or moderator: + if is_access(self, jid_bare, jid_full, chat_type): form = self['xep_0004'].make_form('form', 'Discover & Search') form['instructions'] = 'Discover news subscriptions of all kinds' options = form.add_field(desc='Select type of search.', @@ -2068,8 +2083,16 @@ class Slixfeed(slixmpp.ClientXMPP): session['payload'] = form session['prev'] = None else: - text_warn = ('This resource is restricted to moderators of {}.' - .format(jid_bare)) + if not is_operator(self, jid_bare): + text_warn = 'This resource is restricted to operators.' + elif chat_type == 'groupchat': + text_warn = ('This resource is restricted to moderators of {}.' + .format(jid_bare)) + elif chat_type == 'error': + text_warn = ('Could not determine chat type of {}.' + .format(jid_bare)) + else: + text_warn = 'This resource is forbidden.' session['notes'] = [['warn', text_warn]] return session @@ -2167,10 +2190,7 @@ class Slixfeed(slixmpp.ClientXMPP): .format(function_name, jid_full)) jid_bare = session['from'].bare chat_type = await get_chat_type(self, jid_bare) - moderator = None - if chat_type == 'groupchat': - moderator = is_moderator(self, jid_bare, jid_full) - if chat_type == 'chat' or moderator: + if is_access(self, jid_bare, jid_full, chat_type): form = self['xep_0004'].make_form('form', 'Subscriptions') form['instructions'] = ('Browse, view, toggle or remove ' 'tags and subscriptions.') @@ -2214,8 +2234,16 @@ class Slixfeed(slixmpp.ClientXMPP): session['next'] = self._handle_subscriptions_result session['has_next'] = True else: - text_warn = ('This resource is restricted to moderators of {}.' - .format(jid_bare)) + if not is_operator(self, jid_bare): + text_warn = 'This resource is restricted to operators.' + elif chat_type == 'groupchat': + text_warn = ('This resource is restricted to moderators of {}.' + .format(jid_bare)) + elif chat_type == 'error': + text_warn = ('Could not determine chat type of {}.' + .format(jid_bare)) + else: + text_warn = 'This resource is forbidden.' session['notes'] = [['warn', text_warn]] return session @@ -2534,10 +2562,7 @@ class Slixfeed(slixmpp.ClientXMPP): .format(function_name, jid_full)) jid_bare = session['from'].bare chat_type = await get_chat_type(self, jid_bare) - moderator = None - if chat_type == 'groupchat': - moderator = is_moderator(self, jid_bare, jid_full) - if chat_type == 'chat' or moderator: + if is_access(self, jid_bare, jid_full, chat_type): form = self['xep_0004'].make_form('form', 'Advanced') form['instructions'] = 'Extended options' options = form.add_field(ftype='list-single', @@ -2558,8 +2583,16 @@ class Slixfeed(slixmpp.ClientXMPP): session['next'] = self._handle_advanced_result session['prev'] = self._handle_advanced else: - text_warn = ('This resource is restricted to moderators of {}.' - .format(jid_bare)) + if not is_operator(self, jid_bare): + text_warn = 'This resource is restricted to operators.' + elif chat_type == 'groupchat': + text_warn = ('This resource is restricted to moderators of {}.' + .format(jid_bare)) + elif chat_type == 'error': + text_warn = ('Could not determine chat type of {}.' + .format(jid_bare)) + else: + text_warn = 'This resource is forbidden.' session['notes'] = [['warn', text_warn]] return session @@ -2942,10 +2975,7 @@ class Slixfeed(slixmpp.ClientXMPP): jid_bare = session['from'].bare jid_full = str(session['from']) chat_type = await get_chat_type(self, jid_bare) - moderator = None - if chat_type == 'groupchat': - moderator = is_moderator(self, jid_bare, jid_full) - if chat_type == 'chat' or moderator: + if is_access(self, jid_bare, jid_full, chat_type): form = self['xep_0004'].make_form('form', 'Subscribe') # NOTE Refresh button would be of use form['instructions'] = 'Featured subscriptions' @@ -2996,8 +3026,16 @@ class Slixfeed(slixmpp.ClientXMPP): session['payload'] = form session['prev'] = self._handle_promoted else: - text_warn = ('This resource is restricted to moderators of {}.' - .format(jid_bare)) + if not is_operator(self, jid_bare): + text_warn = 'This resource is restricted to operators.' + elif chat_type == 'groupchat': + text_warn = ('This resource is restricted to moderators of {}.' + .format(jid_bare)) + elif chat_type == 'error': + text_warn = ('Could not determine chat type of {}.' + .format(jid_bare)) + else: + text_warn = 'This resource is forbidden.' session['notes'] = [['warn', text_warn]] return session @@ -3640,10 +3678,7 @@ class Slixfeed(slixmpp.ClientXMPP): .format(function_name, jid_full)) jid_bare = session['from'].bare chat_type = await get_chat_type(self, jid_bare) - moderator = None - if chat_type == 'groupchat': - moderator = is_moderator(self, jid_bare, jid_full) - if chat_type == 'chat' or moderator: + if is_access(self, jid_bare, jid_full, chat_type): jid_file = jid_bare db_file = config.get_pathname_to_database(jid_file) if jid_bare not in self.settings: @@ -3742,8 +3777,16 @@ class Slixfeed(slixmpp.ClientXMPP): session['next'] = self._handle_settings_complete session['payload'] = form else: - text_warn = ('This resource is restricted to moderators of {}.' - .format(jid_bare)) + if not is_operator(self, jid_bare): + text_warn = 'This resource is restricted to operators.' + elif chat_type == 'groupchat': + text_warn = ('This resource is restricted to moderators of {}.' + .format(jid_bare)) + elif chat_type == 'error': + text_warn = ('Could not determine chat type of {}.' + .format(jid_bare)) + else: + text_warn = 'This resource is forbidden.' session['notes'] = [['warn', text_warn]] return session diff --git a/slixfeed/xmpp/iq.py b/slixfeed/xmpp/iq.py index df87dfd..479996e 100644 --- a/slixfeed/xmpp/iq.py +++ b/slixfeed/xmpp/iq.py @@ -8,7 +8,10 @@ class XmppIQ: async def send(self, iq): try: - await iq.send(timeout=5) - except (IqError, IqTimeout) as e: + await iq.send(timeout=15) + except IqTimeout as e: + logging.error('Error Timeout') + logging.error(str(e)) + except IqError as e: logging.error('Error XmppIQ') logging.error(str(e)) diff --git a/slixfeed/xmpp/privilege.py b/slixfeed/xmpp/privilege.py new file mode 100644 index 0000000..b39f3de --- /dev/null +++ b/slixfeed/xmpp/privilege.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + + +def is_access(self, jid_bare, jid_full, chat_type): + """Determine access privilege""" + operator = is_operator(self, jid_bare) + if operator: + if chat_type == 'groupchat': + if is_moderator(self, jid_bare, jid_full): + access = True + else: + access = True + else: + access = False + return access + + +def is_operator(self, jid_bare): + """Check if given JID is an operator""" + result = False + for operator in self.operators: + if jid_bare == operator['jid']: + result = True + # operator_name = operator['name'] + break + return result + + +def is_moderator(self, jid_bare, jid_full): + """Check if given JID is a moderator""" + alias = jid_full[jid_full.index('/')+1:] + role = self.plugin['xep_0045'].get_jid_property(jid_bare, alias, 'role') + if role == 'moderator': + result = True + else: + result = False + return result + + +def is_member(self, jid_bare, jid_full): + """Check if given JID is a member""" + alias = jid_full[jid_full.index('/')+1:] + affiliation = self.plugin['xep_0045'].get_jid_property(jid_bare, alias, 'affiliation') + if affiliation == 'member': + result = True + else: + result = False + return result \ No newline at end of file diff --git a/slixfeed/xmpp/profile.py b/slixfeed/xmpp/profile.py index 45fdcf3..0fb4b97 100644 --- a/slixfeed/xmpp/profile.py +++ b/slixfeed/xmpp/profile.py @@ -28,18 +28,30 @@ TODO import glob from slixfeed.config import Config import slixfeed.config as config -# from slixmpp.exceptions import IqTimeout, IqError -# import logging +from slixmpp.exceptions import IqTimeout, IqError +import logging import os # class XmppProfile: async def update(self): - """ - Update profile. - """ - await set_vcard(self) - await set_avatar(self) + """ Update profile """ + try: + await set_vcard(self) + except IqTimeout as e: + logging.error('Profile vCard: Error Timeout') + logging.error(str(e)) + except IqError as e: + logging.error('Profile vCard: Error XmppIQ') + logging.error(str(e)) + try: + await set_avatar(self) + except IqTimeout as e: + logging.error('Profile Photo: Error Timeout') + logging.error(str(e)) + except IqError as e: + logging.error('Profile Photo: Error XmppIQ') + logging.error(str(e)) async def set_avatar(self): diff --git a/slixfeed/xmpp/publish.py b/slixfeed/xmpp/publish.py index 297122e..df7d009 100644 --- a/slixfeed/xmpp/publish.py +++ b/slixfeed/xmpp/publish.py @@ -42,6 +42,12 @@ class XmppPubsub: return properties + async def get_node_configuration(self, jid, node_id): + node = await self.plugin['xep_0060'].get_node_config(jid, node_id) + print(node) + return node + + async def get_nodes(self, jid): nodes = await self.plugin['xep_0060'].get_nodes(jid) # 'self' would lead to slixmpp.jid.InvalidJID: idna validation failed: diff --git a/slixfeed/xmpp/utility.py b/slixfeed/xmpp/utility.py index c874026..2231cc8 100644 --- a/slixfeed/xmpp/utility.py +++ b/slixfeed/xmpp/utility.py @@ -8,36 +8,6 @@ import logging # class XmppUtility: -def is_operator(self, jid_bare): - result = False - for operator in self.operators: - if jid_bare == operator['jid']: - result = True - # operator_name = operator['name'] - break - return result - - -def is_moderator(self, jid_bare, jid_full): - alias = jid_full[jid_full.index('/')+1:] - role = self.plugin['xep_0045'].get_jid_property(jid_bare, alias, 'role') - if role == 'moderator': - result = True - else: - result = False - return result - - -def is_member(self, jid_bare, jid_full): - alias = jid_full[jid_full.index('/')+1:] - affiliation = self.plugin['xep_0045'].get_jid_property(jid_bare, alias, 'affiliation') - if affiliation == 'member': - result = True - else: - result = False - return result - - # TODO Rename to get_jid_type async def get_chat_type(self, jid): """ @@ -58,8 +28,8 @@ async def get_chat_type(self, jid): Returns ------- - chat_type : str - 'chat' or 'groupchat'. + result : str + 'chat' or 'groupchat' or 'error'. """ try: iqresult = await self["xep_0030"].get_info(jid=jid) @@ -68,28 +38,19 @@ async def get_chat_type(self, jid): # if 'account' in indentity: # if 'conference' in indentity: if ('http://jabber.org/protocol/muc' in features) and not ('/' in jid): - chat_type = "groupchat" + result = "groupchat" # TODO elif # NOTE Is it needed? We do not interact with gateways or services else: - chat_type = "chat" + result = "chat" logging.info('Jabber ID: {}\n' - 'Chat Type: {}'.format(jid, chat_type)) - return chat_type - # TODO Test whether this exception is realized - except IqError as e: - message = ('IQ Error\n' - 'IQ Stanza: {}' - 'Jabber ID: {}' - .format(e, jid)) - logging.error(message) - except IqTimeout as e: - message = ('IQ Timeout\n' - 'IQ Stanza: {}' - 'Jabber ID: {}' - .format(e, jid)) - logging.error(message) + 'Chat Type: {}'.format(jid, result)) + except (IqError, IqTimeout) as e: + logging.error(str(e)) + logging.error(jid) + result = 'error' # except BaseException as e: # logging.error('BaseException', str(e)) # finally: # logging.info('Chat type is:', chat_type) + return result