Skip to content

Instantly share code, notes, and snippets.

@jowrjowr
Created February 7, 2019 05:10
Show Gist options
  • Save jowrjowr/116edefd87d1362c7bcd362111504e95 to your computer and use it in GitHub Desktop.
Save jowrjowr/116edefd87d1362c7bcd362111504e95 to your computer and use it in GitHub Desktop.
slack forwarding
from slackclient import SlackClient
from time import sleep
import requests
import re
import time
import threading
def start_slack(logger, discord_queue, credentials):
username = credentials['username']
password = credentials['password']
covername = credentials['covername']
server = credentials['server']
logger.info('starting slack')
# set the thread name to the spy cover, for logging purposes
thread = threading.current_thread()
thread.setName(covername)
# build the login session for slack
s = requests.Session()
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:55.0) Gecko/20100101 Firefox/55.0'}
url = 'https://' + server + '/'
r = s.get(url, headers=headers)
code = r.status_code
if not code == 200:
msg = 'unable to connect to {0} slack. http code {0}'.format(covername, code)
logger.critical(msg)
msg = '```diff' + '\n' + '- {0} offline```'.format(covername)
discord_queue.put(msg)
return
# need to fetch a hidden form value associated with the session cookie
# it is of the form: <input type="hidden" name="crumb" value="s-1503129907-027251bef8-☃" />
crumb = None
lines = r.text.split('\n')
regex = r'.*<input type="hidden" name="crumb" value="(\S+)" />.*'
for line in lines:
match = re.match(regex, line)
if match:
crumb = match.group(1)
continue
if crumb is None:
msg = 'cannot find {0} slack form crumb'.format(covername)
logger.critical(msg)
msg = '```diff' + '\n' + '- {0} offline```'.format(covername)
discord_queue.put(msg)
return
# try to login
form = dict()
form['signin'] = 1
form['redir'] = ''
form['crumb'] = crumb
form['email'] = username
form['password'] = password
form['remember'] = ''
r = s.post(url, headers=headers, data=form)
code = r.status_code
if not code == 200:
msg = 'unable to login to {0} slack. http code {1}'.format(covername, code)
logger.critical(msg)
msg = '```diff' + '\n' + '- {0} offline```'.format(covername)
discord_queue.put(msg)
return
# a http 200 doesn't _necessarily_ mean we are logged in
token = None
lines = r.text.split('\n')
regex = r'.*api_token: "(.*)"'
for line in lines:
match = re.match(regex, line)
if match:
token = match.group(1)
continue
if token is None:
msg = 'unable to locate slack token. wrong pw?'
logger.critical(msg)
msg = '```diff' + '\n' + '- {0} offline```'.format(covername)
discord_queue.put(msg)
return
client = SlackClient(token)
if not client.rtm_connect():
msg = 'unable to connect to {0} slack api'.format(covername)
logger.critical(msg)
msg = '```diff' + '\n' + '- {0} offline```'.format(covername)
discord_queue.put(msg)
return
tick = 0
connected = True
while connected:
logger.debug('new loop')
try:
process_update( logger, discord_queue, covername, client, client.rtm_read() )
except Exception as e:
logger.error('issue with slack: {}'.format(e))
# try to reconnect
error = True
client = SlackClient(token)
try:
connected = client.rtm_connect()
except Exception as e:
logger.error('issue reconnecting to slack: {}'.format(e))
connected = False
if connected and error:
logger.info('reconnected to slack')
elif not connected and error:
logger.critical('unable to reconnect to slack')
break
tick += 30
if tick % 120 == 0:
# every hour log that you are alive
msg = 'slack life ping'
logger.debug(msg)
sleep(30)
msg = 'slack irrevocably disconnected'.format(covername)
logger.critical(msg)
msg = '```diff' + '\n' + '- {0} offline```'.format(covername)
discord_queue.put(msg)
def process_update(logger, discord_queue, covername, client, item):
# each item seems to be a hash within an array
# api documented here:
# https://api.slack.com/rtm#events
if len(item) == 0:
logger.debug('slack life ping')
return
else:
item = item[0]
msg = 'new slack item: {0}'.format(item)
logger.debug(msg)
# past here, each update has a distinct type which we are interested in
item_type = item['type']
if item_type == 'hello':
# the connection was just established. announce an online state.
msg = 'slack online'
logger.info(msg)
msg = '```diff' + '\n' + '+ {0} online```'.format(covername)
discord_queue.put(msg)
if item_type == 'message':
# this a message of some sort.
process_message(logger, discord_queue, covername, client, item)
def process_message(logger, discord_queue, covername, client, item):
msg = 'new message: {0}'.format(item)
logger.debug(msg)
timestamp = int(float(item['ts']))
channel_id = item['channel']
sender_id = item['user']
content = item['text']
# get my info
user = client.api_call("auth.test")
user_id = user['user_id']
user_name = user['user']
# map the ids to names
sender = client.api_call("users.info", user=sender_id)
sender_name = sender['user']['name']
# channels can be of 3 types:
# 1: public channel. this is covered by a channels.info call
# 2: locked channel: same, but groups.info
# 3: private message: neither
priv_channel = client.api_call("groups.info", channel=channel_id)
pub_channel = client.api_call("channels.info", channel=channel_id)
if priv_channel.get('error') and pub_channel.get('error') == 'channel_not_found':
# this is a private message, forward this.
msg = 'direct message from {0}: {1}'.format(sender_name, content)
logger.info(msg)
ping = '--------------------\n'
ping += 'DM FROM: {0}\n'.format(sender_name)
ping += 'MESSAGE: {0}\n\n'.format(content)
ping = "**[{0}]** | __{1}__\n```css\n{2}```".format(covername, time.strftime("%H:%M:%S %z / %d-%m-%Y", time.localtime(timestamp)), ping)
# send to discord
discord_queue.put(ping)
return
# past here, this will be a direct channel message which won't always be forwarded
elif priv_channel.get('error') is not None and pub_channel.get('error') is None:
# public channel
channel_name = '#' + pub_channel['channel']['name']
elif priv_channel.get('error') is None and pub_channel.get('error') is not None:
# private channel
channel_name = u"\U0001F512" + priv_channel['group']['name']
else:
# something fucking broke but we'll try anyway
channel_name = None
# we only want to forward broadcast messages, so there needs to be filters
matches = []
matches.append(r'(.*)<!here\|@here>(.*)') # active ppl in channel
matches.append(r'(.*)<!channel>(.*)') # all ppl in channel
matches.append(r'(.*)<!everyone>(.*)') # all ppl everywhere
matches.append(r'(.*)<@{}>(.*)'.format(user_id)) # just me
matchcount = 0
for regex in matches:
match = re.match(regex, content)
if match:
content = match.group(1) + '@_some_crap' + match.group(2)
matchcount = 1
continue
if matchcount == 0:
# this item won't be forwarded. yawn.
return
# we have a message to forward
msg = 'ping message from {0} in channel {1}: {2}'.format(sender_name, channel_name, content)
logger.info(msg)
ping = '--------------------\n'
ping += 'CHANNEL: {0} || FROM: {1}\n'.format(channel_name, sender_name)
ping += 'MESSAGE: {0}\n\n'.format(content)
ping = "**[{0}]** | __{1}__\n```css\n{2}```".format(covername, time.strftime("%H:%M:%S %z / %d-%m-%Y", time.localtime(timestamp)), ping)
# send to discord
discord_queue.put(ping)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment