Created
February 7, 2019 05:10
-
-
Save jowrjowr/116edefd87d1362c7bcd362111504e95 to your computer and use it in GitHub Desktop.
slack forwarding
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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