From 2e274d3baf1ca9933eb0e02a1fb876d6beb24550 Mon Sep 17 00:00:00 2001 From: Basraah Date: Tue, 28 Feb 2017 11:30:26 +1000 Subject: [PATCH] Update Openfire broadcast tool (#742) Allow users to ignore invalid certificates. Added some limited user feedback. Removed threading. Prevent infinite connection attempt loops. --- docs/installation/auth/settings.md | 1 + docs/installation/services/openfire.md | 2 ++ services/modules/openfire/manager.py | 47 ++++++++++++++------------ services/modules/openfire/views.py | 38 +++++++++++---------- 4 files changed, 48 insertions(+), 40 deletions(-) diff --git a/docs/installation/auth/settings.md b/docs/installation/auth/settings.md index 8fa74d05..e854e165 100644 --- a/docs/installation/auth/settings.md +++ b/docs/installation/auth/settings.md @@ -68,6 +68,7 @@ If using Openfire, the following need to be set in accordance with the [install - [BROADCAST_USER](#broadcast-user) - [BROADCAST_USER_PASSWORD](#broadcast-user-password) - [BROADCAST_SERVICE_NAME](#broadcast-service-name) + - [BROADCAST_IGNORE_INVALID_CERT](#broadcast-ignore-invalid-cert) ### Mumble If using Mumble, the following needs to be set to the address of the mumble server: diff --git a/docs/installation/services/openfire.md b/docs/installation/services/openfire.md index ac4d1ae8..34c7715b 100644 --- a/docs/installation/services/openfire.md +++ b/docs/installation/services/openfire.md @@ -82,6 +82,8 @@ Navigate to the `Server` tab, `Server Manager` subtab, and select `System Proper - Name: `plugin.broadcast.allowedUsers` - Value: `broadcast@example.com`, replacing the domain name with yours - Do not encrypt this property value + +If you have troubles getting broadcasts to work, you can try setting the optional (you will need to add it) `BROADCAST_IGNORE_INVALID_CERT` setting to `True`. This will allow invalid certificates to be used when connecting to the Openfire server to send a broadcast. ### Group Chat Channels are available which function like a chat room. Access can be controlled either by password or ACL (not unlike mumble). diff --git a/services/modules/openfire/manager.py b/services/modules/openfire/manager.py index 672d57f7..7cf18ea7 100755 --- a/services/modules/openfire/manager.py +++ b/services/modules/openfire/manager.py @@ -11,7 +11,6 @@ except ImportError: import sleekxmpp from django.conf import settings -import threading from ofrestapi.users import Users as ofUsers from ofrestapi import exception @@ -24,12 +23,6 @@ class OpenfireManager: def __init__(self): pass - @staticmethod - def send_broadcast_threaded(group_name, broadcast_message): - logger.debug("Starting broadcast to %s with message %s" % (group_name, broadcast_message)) - broadcast_thread = XmppThread(1, "XMPP Broadcast Thread", 1, group_name, broadcast_message) - broadcast_thread.start() - @staticmethod def __add_address_to_username(username): address = urlparse(settings.OPENFIRE_ADDRESS).netloc.split(":")[0] @@ -169,11 +162,19 @@ class OpenfireManager: xmpp = PingBot(settings.BROADCAST_USER, settings.BROADCAST_USER_PASSWORD, to_address, broadcast_message) xmpp.register_plugin('xep_0030') # Service Discovery xmpp.register_plugin('xep_0199') # XMPP Ping - if xmpp.connect(): + if xmpp.connect(reattempt=False): xmpp.process(block=True) - logger.info("Sent jabber ping to group %s" % group_name) + message = None + if xmpp.message_sent: + logger.debug("Sent jabber ping to group %s" % group_name) + return + else: + message = "Failed to send Openfire broadcast message." + logger.error(message) + raise PingBotException(message) else: - raise ValueError("Unable to connect to jabber server.") + logger.error("Unable to connect to jabber server") + raise PingBotException("Unable to connect to jabber server.") class PingBot(sleekxmpp.ClientXMPP): @@ -184,17 +185,28 @@ class PingBot(sleekxmpp.ClientXMPP): def __init__(self, jid, password, recipient, message): sleekxmpp.ClientXMPP.__init__(self, jid, password) + self.reconnect_max_attempts = 5 + self.auto_reconnect = False # The message we wish to send, and the JID that # will receive it. self.recipient = recipient self.msg = message + # Success checking + self.message_sent = False + # The session_start event will be triggered when # the bot establishes its connection with the server # and the XML streams are ready for use. We want to # listen for this event so that we we can initialize # our roster. self.add_event_handler("session_start", self.start) + if getattr(settings, 'BROADCAST_IGNORE_INVALID_CERT', False): + self.add_event_handler("ssl_invalid_cert", self.discard) + + def discard(self, *args, **kwargs): + # Discard the event + return def start(self, event): self.send_presence() @@ -203,20 +215,11 @@ class PingBot(sleekxmpp.ClientXMPP): self.send_message(mto=self.recipient, mbody=self.msg, mtype='chat') - + self.message_sent = True # Using wait=True ensures that the send queue will be # emptied before ending the session. self.disconnect(wait=True) -class XmppThread(threading.Thread): - def __init__(self, thread_id, name, counter, group, message, ): - threading.Thread.__init__(self) - self.threadID = thread_id - self.name = name - self.counter = counter - self.group = group - self.message = message - - def run(self): - OpenfireManager.send_broadcast_message(self.group, self.message) +class PingBotException(Exception): + pass diff --git a/services/modules/openfire/views.py b/services/modules/openfire/views.py index bebb3309..712ac0c9 100644 --- a/services/modules/openfire/views.py +++ b/services/modules/openfire/views.py @@ -10,7 +10,7 @@ from eveonline.managers import EveManager from eveonline.models import EveCharacter from services.forms import ServicePasswordForm -from .manager import OpenfireManager +from .manager import OpenfireManager, PingBotException from .tasks import OpenfireTasks from .forms import JabberBroadcastForm from .models import OpenfireUser @@ -103,27 +103,29 @@ def jabber_broadcast_view(request): if form.is_valid(): main_char = EveManager.get_main_character(request.user) logger.debug("Processing jabber broadcast for user %s with main character %s" % (request.user, main_char)) - if main_char is not None: - message_to_send = form.cleaned_data[ - 'message'] + "\n##### SENT BY: " + "[" + main_char.corporation_ticker + "]" + \ - main_char.character_name + " TO: " + \ - form.cleaned_data['group'] + " WHEN: " + datetime.datetime.utcnow().strftime( - "%Y-%m-%d %H:%M:%S") + " #####\n##### Replies are NOT monitored #####\n" - group_to_send = form.cleaned_data['group'] + try: + if main_char is not None: + message_to_send = form.cleaned_data[ + 'message'] + "\n##### SENT BY: " + "[" + main_char.corporation_ticker + "]" + \ + main_char.character_name + " TO: " + \ + form.cleaned_data['group'] + " WHEN: " + datetime.datetime.utcnow().strftime( + "%Y-%m-%d %H:%M:%S") + " #####\n##### Replies are NOT monitored #####\n" + group_to_send = form.cleaned_data['group'] - OpenfireManager.send_broadcast_threaded(group_to_send, message_to_send, ) + else: + message_to_send = form.cleaned_data[ + 'message'] + "\n##### SENT BY: " + "No character but can send pings?" + " TO: " + \ + form.cleaned_data['group'] + " WHEN: " + datetime.datetime.utcnow().strftime( + "%Y-%m-%d %H:%M:%S") + " #####\n##### Replies are NOT monitored #####\n" + group_to_send = form.cleaned_data['group'] - else: - message_to_send = form.cleaned_data[ - 'message'] + "\n##### SENT BY: " + "No character but can send pings?" + " TO: " + \ - form.cleaned_data['group'] + " WHEN: " + datetime.datetime.utcnow().strftime( - "%Y-%m-%d %H:%M:%S") + " #####\n##### Replies are NOT monitored #####\n" - group_to_send = form.cleaned_data['group'] + OpenfireManager.send_broadcast_message(group_to_send, message_to_send) - OpenfireManager.send_broadcast_threaded(group_to_send, message_to_send, ) + messages.success(request, 'Sent jabber broadcast to %s' % group_to_send) + logger.info("Sent jabber broadcast on behalf of user %s" % request.user) + except PingBotException as e: + messages.error(request, e) - messages.success(request, 'Sent jabber broadcast to %s' % group_to_send) - logger.info("Sent jabber broadcast on behalf of user %s" % request.user) else: form = JabberBroadcastForm() form.fields['group'].choices = allchoices