-from flask import current_app
-from slack import WebClient
-from slack.errors import SlackApiError
-from slack.signature import SignatureVerifier
+import hashlib
+import hmac
import os
-import requests
+import boto3
-slack_signing_secret = os.environ['SLACK_SIGNING_SECRET']
-slack_bot_token = os.environ['SLACK_BOT_TOKEN']
+if 'SLACK_SIGNING_SECRET' in os.environ:
+ slack_signing_secret = os.environ['SLACK_SIGNING_SECRET']
+else:
+ ssm = boto3.client('ssm')
+ response = ssm.get_parameter(Name='SLACK_SIGNING_SECRET',
+ WithDecryption=True)
+ slack_signing_secret = response['Parameter']['Value']
+ os.environ['SLACK_SIGNING_SECRET'] = slack_signing_secret
-signature_verifier = SignatureVerifier(slack_signing_secret)
-slack_client = WebClient(slack_bot_token)
+slack_signing_secret = bytes(os.environ['SLACK_SIGNING_SECRET'], 'utf-8')
-def slack_is_valid_request(request):
- """Returns true if request actually came from Slack.
+def slack_is_valid_request(slack_signature, timestamp, body):
+ """Returns True if the timestamp and body correspond to signature.
- By means of checking the requests signature together with the slack
- signing key.
+ This implements the Slack signature verification using the slack
+ signing secret (obtained via an SSM parameter in code above)."""
- Note: If flask is in debug mode, this function will always return true."""
+ content = "v0:{}:{}".format(timestamp, body).encode('utf-8')
- if current_app.debug:
- return True
-
- data = request.get_data()
- headers = request.headers
-
- return signature_verifier.is_valid_request(data, headers)
-
-def slack_send_reply(request, text):
- """Send a Slack message as a reply to a specified request.
-
- If the request is associated with a direct message, the reply is
- made by using the "response_url" from the request. Otherwise, the
- reply will be sent to the channel associated with the request.
-
- Note: If flask is in debug mode, this function will just print the
- text to stdout."""
+ signature = 'v0=' + hmac.new(slack_signing_secret,
+ content,
+ hashlib.sha256).hexdigest()
- app = current_app
- channel_name = request.form.get('channel_name')
- response_url = request.form.get('response_url')
- channel = request.form.get('channel_id')
-
- if (app.debug):
- print("Sending message to channel '{}': {}".format(channel, text))
- return
-
- if (channel_name == "directmessage"):
- resp = requests.post(response_url,
- json = {"text": text},
- headers = {"Content-type": "application/json"})
- if (resp.status_code != 200):
- app.logger.error("Error posting request to Slack: " + resp.text)
+ if hmac.compare_digest(signature, slack_signature):
+ return True
else:
- slack_send_message(channel, text)
-
-def slack_send_message(channel, text):
- """Send a Slack message to a specified channel."""
-
- slack_client.chat_postMessage(channel=channel, text=text)
-
+ print("Bad signature: {} != {}".format(signature, slack_signature))
+ return False
+
+def slack_channel_members(slack_client, channel_id):
+ members = []
+
+ cursor = None
+ while True:
+ if cursor:
+ response = slack_client.conversations_members(channel=channel_id,
+ cursor=cursor)
+ else:
+ response = slack_client.conversations_members(channel=channel_id)
+
+ if response['ok']:
+ members += response['members']
+ else:
+ print("Error querying members of channel {}: {}"
+ .format(channel_id, response['error']))
+ return members
+
+ cursor = None
+ if 'next_cursor' in response['response_metadata']:
+ cursor = response['response_metadata']['next_cursor']
+
+ if not cursor or cursor == '':
+ break
+
+ return members
+
+def slack_send_message(slack_client, channel_id, text):
+ slack_client.chat_postMessage(channel=channel_id, text=text)