Browse Source

RocketChat Token Support (#1060)

pull/1109/head
Chris Caron 7 months ago committed by GitHub
parent
commit
33c756979f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 53
      apprise/plugins/NotifyRocketChat.py
  2. 10
      test/test_plugin_rocket_chat.py

53
apprise/plugins/NotifyRocketChat.py

@ -59,6 +59,9 @@ class RocketChatAuthMode:
# providing a webhook # providing a webhook
WEBHOOK = "webhook" WEBHOOK = "webhook"
# Support token submission
TOKEN = "token"
# Providing a username and password (default) # Providing a username and password (default)
BASIC = "basic" BASIC = "basic"
@ -66,6 +69,7 @@ class RocketChatAuthMode:
# Define our authentication modes # Define our authentication modes
ROCKETCHAT_AUTH_MODES = ( ROCKETCHAT_AUTH_MODES = (
RocketChatAuthMode.WEBHOOK, RocketChatAuthMode.WEBHOOK,
RocketChatAuthMode.TOKEN,
RocketChatAuthMode.BASIC, RocketChatAuthMode.BASIC,
) )
@ -107,6 +111,8 @@ class NotifyRocketChat(NotifyBase):
templates = ( templates = (
'{schema}://{user}:{password}@{host}:{port}/{targets}', '{schema}://{user}:{password}@{host}:{port}/{targets}',
'{schema}://{user}:{password}@{host}/{targets}', '{schema}://{user}:{password}@{host}/{targets}',
'{schema}://{user}:{token}@{host}:{port}/{targets}',
'{schema}://{user}:{token}@{host}/{targets}',
'{schema}://{webhook}@{host}', '{schema}://{webhook}@{host}',
'{schema}://{webhook}@{host}:{port}', '{schema}://{webhook}@{host}:{port}',
'{schema}://{webhook}@{host}/{targets}', '{schema}://{webhook}@{host}/{targets}',
@ -135,6 +141,11 @@ class NotifyRocketChat(NotifyBase):
'type': 'string', 'type': 'string',
'private': True, 'private': True,
}, },
'token': {
'name': _('API Token'),
'map_to': 'password',
'private': True,
},
'webhook': { 'webhook': {
'name': _('Webhook'), 'name': _('Webhook'),
'type': 'string', 'type': 'string',
@ -230,13 +241,20 @@ class NotifyRocketChat(NotifyBase):
if self.webhook is not None: if self.webhook is not None:
# Just a username was specified, we treat this as a webhook # Just a username was specified, we treat this as a webhook
self.mode = RocketChatAuthMode.WEBHOOK self.mode = RocketChatAuthMode.WEBHOOK
elif self.password and len(self.password) > 32:
self.mode = RocketChatAuthMode.TOKEN
else: else:
self.mode = RocketChatAuthMode.BASIC 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): and not (self.user and self.password):
# Username & Password is required for Rocket Chat to work # 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) self.logger.warning(msg)
raise TypeError(msg) raise TypeError(msg)
@ -245,6 +263,13 @@ class NotifyRocketChat(NotifyBase):
self.logger.warning(msg) self.logger.warning(msg)
raise TypeError(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: # Validate recipients and drop bad ones:
for recipient in parse_list(targets): for recipient in parse_list(targets):
result = IS_CHANNEL.match(recipient) result = IS_CHANNEL.match(recipient)
@ -309,12 +334,13 @@ class NotifyRocketChat(NotifyBase):
params.update(self.url_parameters(privacy=privacy, *args, **kwargs)) params.update(self.url_parameters(privacy=privacy, *args, **kwargs))
# Determine Authentication # Determine Authentication
if self.mode == RocketChatAuthMode.BASIC: if self.mode in (RocketChatAuthMode.BASIC, RocketChatAuthMode.TOKEN):
auth = '{user}:{password}@'.format( auth = '{user}:{password}@'.format(
user=NotifyRocketChat.quote(self.user, safe=''), user=NotifyRocketChat.quote(self.user, safe=''),
password=self.pprint( password=self.pprint(
self.password, privacy, mode=PrivacyMode.Secret, safe=''), self.password, privacy, mode=PrivacyMode.Secret, safe=''),
) )
else: else:
auth = '{user}{webhook}@'.format( auth = '{user}{webhook}@'.format(
user='{}:'.format(NotifyRocketChat.quote(self.user, safe='')) user='{}:'.format(NotifyRocketChat.quote(self.user, safe=''))
@ -359,7 +385,10 @@ class NotifyRocketChat(NotifyBase):
# Call the _send_ function applicable to whatever mode we're in # Call the _send_ function applicable to whatever mode we're in
# - calls _send_webhook_notification if the mode variable is set # - calls _send_webhook_notification if the mode variable is set
# - calls _send_basic_notification if the mode variable is not set # - calls _send_basic_notification if the mode variable is not set
return getattr(self, '_send_{}_notification'.format(self.mode))( 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) body=body, title=title, notify_type=notify_type, **kwargs)
def _send_webhook_notification(self, body, title='', def _send_webhook_notification(self, body, title='',
@ -412,7 +441,7 @@ class NotifyRocketChat(NotifyBase):
""" """
# Track whether we authenticated okay # Track whether we authenticated okay
if not self.login(): if self.mode == RocketChatAuthMode.BASIC and not self.login():
return False return False
# prepare JSON Object # prepare JSON Object
@ -432,9 +461,7 @@ class NotifyRocketChat(NotifyBase):
channel = channels.pop(0) channel = channels.pop(0)
payload['channel'] = channel payload['channel'] = channel
if not self._send( if not self._send(payload, notify_type=notify_type, **kwargs):
payload, notify_type=notify_type, headers=self.headers,
**kwargs):
# toggle flag # toggle flag
has_error = True has_error = True
@ -447,13 +474,12 @@ class NotifyRocketChat(NotifyBase):
room = rooms.pop(0) room = rooms.pop(0)
payload['roomId'] = room payload['roomId'] = room
if not self._send( if not self._send(payload, notify_type=notify_type, **kwargs):
payload, notify_type=notify_type, headers=self.headers,
**kwargs):
# toggle flag # toggle flag
has_error = True has_error = True
if self.mode == RocketChatAuthMode.BASIC:
# logout # logout
self.logout() self.logout()
@ -476,7 +502,7 @@ class NotifyRocketChat(NotifyBase):
return payload return payload
def _send(self, payload, notify_type, path='api/v1/chat.postMessage', def _send(self, payload, notify_type, path='api/v1/chat.postMessage',
headers={}, **kwargs): **kwargs):
""" """
Perform Notify Rocket.Chat Notification Perform Notify Rocket.Chat Notification
""" """
@ -487,6 +513,9 @@ class NotifyRocketChat(NotifyBase):
api_url, self.verify_certificate)) api_url, self.verify_certificate))
self.logger.debug('Rocket.Chat Payload: %s' % str(payload)) self.logger.debug('Rocket.Chat Payload: %s' % str(payload))
# Copy our existing headers
headers = self.headers.copy()
# Apply minimum headers # Apply minimum headers
headers.update({ headers.update({
'User-Agent': self.app_id, 'User-Agent': self.app_id,

10
test/test_plugin_rocket_chat.py

@ -107,6 +107,16 @@ apprise_url_tests = (
}, },
'privacy_url': 'rockets://user:****@localhost', '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 # Several channels
('rocket://user:pass@localhost/#channel1/#channel2/?avatar=Yes', { ('rocket://user:pass@localhost/#channel1/#channel2/?avatar=Yes', {
'instance': NotifyRocketChat, 'instance': NotifyRocketChat,

Loading…
Cancel
Save