From 33c756979fbd236c68e0907b293fde6cdf9114c0 Mon Sep 17 00:00:00 2001 From: Chris Caron Date: Sat, 13 Apr 2024 19:59:43 -0400 Subject: [PATCH] RocketChat Token Support (#1060) --- apprise/plugins/NotifyRocketChat.py | 59 +++++++++++++++++++++-------- test/test_plugin_rocket_chat.py | 10 +++++ 2 files changed, 54 insertions(+), 15 deletions(-) diff --git a/apprise/plugins/NotifyRocketChat.py b/apprise/plugins/NotifyRocketChat.py index 8e6c0751..9011a5e7 100644 --- a/apprise/plugins/NotifyRocketChat.py +++ b/apprise/plugins/NotifyRocketChat.py @@ -59,6 +59,9 @@ class RocketChatAuthMode: # providing a webhook WEBHOOK = "webhook" + # Support token submission + TOKEN = "token" + # Providing a username and password (default) BASIC = "basic" @@ -66,6 +69,7 @@ class RocketChatAuthMode: # Define our authentication modes ROCKETCHAT_AUTH_MODES = ( RocketChatAuthMode.WEBHOOK, + RocketChatAuthMode.TOKEN, RocketChatAuthMode.BASIC, ) @@ -107,6 +111,8 @@ class NotifyRocketChat(NotifyBase): templates = ( '{schema}://{user}:{password}@{host}:{port}/{targets}', '{schema}://{user}:{password}@{host}/{targets}', + '{schema}://{user}:{token}@{host}:{port}/{targets}', + '{schema}://{user}:{token}@{host}/{targets}', '{schema}://{webhook}@{host}', '{schema}://{webhook}@{host}:{port}', '{schema}://{webhook}@{host}/{targets}', @@ -135,6 +141,11 @@ class NotifyRocketChat(NotifyBase): 'type': 'string', 'private': True, }, + 'token': { + 'name': _('API Token'), + 'map_to': 'password', + 'private': True, + }, 'webhook': { 'name': _('Webhook'), 'type': 'string', @@ -230,13 +241,20 @@ class NotifyRocketChat(NotifyBase): if self.webhook is not None: # Just a username was specified, we treat this as a webhook self.mode = RocketChatAuthMode.WEBHOOK + elif self.password and len(self.password) > 32: + self.mode = RocketChatAuthMode.TOKEN else: self.mode = RocketChatAuthMode.BASIC - if self.mode == RocketChatAuthMode.BASIC \ + self.logger.debug( + "Auto-Detected Rocketchat Auth Mode: %s", self.mode) + + if self.mode in (RocketChatAuthMode.BASIC, RocketChatAuthMode.TOKEN) \ and not (self.user and self.password): # Username & Password is required for Rocket Chat to work - msg = 'No Rocket.Chat user/pass combo was specified.' + msg = 'No Rocket.Chat {} was specified.'.format( + 'user/pass combo' if self.mode == RocketChatAuthMode.BASIC else + 'user/apikey') self.logger.warning(msg) raise TypeError(msg) @@ -245,6 +263,13 @@ class NotifyRocketChat(NotifyBase): self.logger.warning(msg) raise TypeError(msg) + if self.mode == RocketChatAuthMode.TOKEN: + # Set our headers for further communication + self.headers.update({ + 'X-User-Id': self.user, + 'X-Auth-Token': self.password, + }) + # Validate recipients and drop bad ones: for recipient in parse_list(targets): result = IS_CHANNEL.match(recipient) @@ -309,12 +334,13 @@ class NotifyRocketChat(NotifyBase): params.update(self.url_parameters(privacy=privacy, *args, **kwargs)) # Determine Authentication - if self.mode == RocketChatAuthMode.BASIC: + if self.mode in (RocketChatAuthMode.BASIC, RocketChatAuthMode.TOKEN): auth = '{user}:{password}@'.format( user=NotifyRocketChat.quote(self.user, safe=''), password=self.pprint( self.password, privacy, mode=PrivacyMode.Secret, safe=''), ) + else: auth = '{user}{webhook}@'.format( user='{}:'.format(NotifyRocketChat.quote(self.user, safe='')) @@ -359,8 +385,11 @@ class NotifyRocketChat(NotifyBase): # Call the _send_ function applicable to whatever mode we're in # - calls _send_webhook_notification if the mode variable is set # - calls _send_basic_notification if the mode variable is not set - return getattr(self, '_send_{}_notification'.format(self.mode))( - body=body, title=title, notify_type=notify_type, **kwargs) + return getattr(self, '_send_{}_notification'.format( + RocketChatAuthMode.WEBHOOK + if self.mode == RocketChatAuthMode.WEBHOOK + else RocketChatAuthMode.BASIC))( + body=body, title=title, notify_type=notify_type, **kwargs) def _send_webhook_notification(self, body, title='', notify_type=NotifyType.INFO, **kwargs): @@ -412,7 +441,7 @@ class NotifyRocketChat(NotifyBase): """ # Track whether we authenticated okay - if not self.login(): + if self.mode == RocketChatAuthMode.BASIC and not self.login(): return False # prepare JSON Object @@ -432,9 +461,7 @@ class NotifyRocketChat(NotifyBase): channel = channels.pop(0) payload['channel'] = channel - if not self._send( - payload, notify_type=notify_type, headers=self.headers, - **kwargs): + if not self._send(payload, notify_type=notify_type, **kwargs): # toggle flag has_error = True @@ -447,15 +474,14 @@ class NotifyRocketChat(NotifyBase): room = rooms.pop(0) payload['roomId'] = room - if not self._send( - payload, notify_type=notify_type, headers=self.headers, - **kwargs): + if not self._send(payload, notify_type=notify_type, **kwargs): # toggle flag has_error = True - # logout - self.logout() + if self.mode == RocketChatAuthMode.BASIC: + # logout + self.logout() return not has_error @@ -476,7 +502,7 @@ class NotifyRocketChat(NotifyBase): return payload def _send(self, payload, notify_type, path='api/v1/chat.postMessage', - headers={}, **kwargs): + **kwargs): """ Perform Notify Rocket.Chat Notification """ @@ -487,6 +513,9 @@ class NotifyRocketChat(NotifyBase): api_url, self.verify_certificate)) self.logger.debug('Rocket.Chat Payload: %s' % str(payload)) + # Copy our existing headers + headers = self.headers.copy() + # Apply minimum headers headers.update({ 'User-Agent': self.app_id, diff --git a/test/test_plugin_rocket_chat.py b/test/test_plugin_rocket_chat.py index e5797016..858d79d1 100644 --- a/test/test_plugin_rocket_chat.py +++ b/test/test_plugin_rocket_chat.py @@ -107,6 +107,16 @@ apprise_url_tests = ( }, 'privacy_url': 'rockets://user:****@localhost', }), + # A channel using token based + ('rockets://user:token@localhost/#channel?mode=token', { + 'instance': NotifyRocketChat, + 'privacy_url': 'rockets://user:****@localhost', + }), + # Token is detected based o it's length + ('rockets://user:{}@localhost/#channel'.format('t' * 40), { + 'instance': NotifyRocketChat, + 'privacy_url': 'rockets://user:****@localhost', + }), # Several channels ('rocket://user:pass@localhost/#channel1/#channel2/?avatar=Yes', { 'instance': NotifyRocketChat,