Skip to content

Commit 4a25177

Browse files
author
Ace Nassri
authored
functions: Use Slack client lib for request validation (GoogleCloudPlatform#4369)
* Use Slack client lib for request validation * fix bad validation logic * fix tests * Add clarifying comment * Fix lint * Fix lint, take 2 * rm unused slackeventsapi package
1 parent 2fdb611 commit 4a25177

File tree

3 files changed

+37
-22
lines changed

3 files changed

+37
-22
lines changed

functions/slack/main.py

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,11 @@
1212
# limitations under the License.
1313

1414
# [START functions_slack_setup]
15-
import hashlib
16-
import hmac
1715
import os
1816

1917
from flask import jsonify
2018
import googleapiclient.discovery
19+
from slack.signature import SignatureVerifier
2120

2221

2322
kgsearch = googleapiclient.discovery.build(
@@ -29,19 +28,12 @@
2928

3029

3130
# [START functions_verify_webhook]
32-
# Python 3+ version of https://github.com/slackapi/python-slack-events-api/blob/master/slackeventsapi/server.py
3331
def verify_signature(request):
34-
timestamp = request.headers.get('X-Slack-Request-Timestamp', '')
35-
signature = request.headers.get('X-Slack-Signature', '')
32+
request.get_data() # Decodes received requests into request.data
3633

37-
req = str.encode('v0:{}:'.format(timestamp)) + request.get_data()
38-
request_digest = hmac.new(
39-
str.encode(os.environ['SLACK_SECRET']),
40-
req, hashlib.sha256
41-
).hexdigest()
42-
request_hash = 'v0={}'.format(request_digest)
34+
verifier = SignatureVerifier(os.environ['SLACK_SECRET'])
4335

44-
if not hmac.compare_digest(request_hash, signature):
36+
if not verifier.is_valid_request(request.data, request.headers):
4537
raise ValueError('Invalid request/credentials.')
4638
# [END functions_verify_webhook]
4739

functions/slack/main_test.py

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@
1313

1414
import json
1515
import os
16+
import time
1617

1718
import googleapiclient.discovery
1819
import mock
1920
import pytest
21+
from slack.signature import SignatureVerifier
2022

2123
import main
2224

@@ -28,8 +30,9 @@
2830

2931

3032
class Request(object):
31-
def __init__(self, data=b''):
33+
def __init__(self, data='', headers={}):
3234
self.data = data
35+
self.headers = headers
3336

3437
def get_data(self):
3538
return self.data
@@ -39,19 +42,28 @@ class TestGCFPySlackSample(object):
3942
def test_verify_signature_request_form_empty(self):
4043
with pytest.raises(ValueError):
4144
request = Request()
42-
request.headers = {}
4345
main.verify_signature(request)
4446

4547
def test_verify_signature_token_incorrect(self):
4648
with pytest.raises(ValueError):
47-
request = Request()
48-
request.headers = {'X-Slack-Signature': '12345'}
49+
request = Request(headers={'X-Slack-Signature': '12345'})
4950
main.verify_signature(request)
5051

5152
def test_verify_web_hook_valid_request(self):
5253
request = Request()
54+
request.body = ''
55+
56+
now = str(int(time.time()))
57+
58+
verifier = SignatureVerifier(os.environ['SLACK_SECRET'])
59+
test_signature = verifier.generate_signature(
60+
timestamp=now,
61+
body=''
62+
)
63+
5364
request.headers = {
54-
'X-Slack-Signature': os.environ['SLACK_TEST_SIGNATURE']
65+
'X-Slack-Request-Timestamp': now,
66+
'X-Slack-Signature': test_signature
5567
}
5668
main.verify_signature(request)
5769

@@ -77,14 +89,25 @@ def test_kg_search(self):
7789
entities = main.kgsearch.entities.return_value
7890
search = entities.search.return_value
7991
search.execute.return_value = example_response
92+
8093
request = Request()
81-
request.method = 'POST'
82-
request.headers = {
83-
'X-Slack-Signature': os.environ['SLACK_TEST_SIGNATURE']
84-
}
8594
request.form = {
8695
'text': 'lion'
8796
}
97+
request.data = json.dumps(request.form)
98+
99+
now = str(int(time.time()))
100+
verifier = SignatureVerifier(os.environ['SLACK_SECRET'])
101+
test_signature = verifier.generate_signature(
102+
timestamp=now,
103+
body=request.data
104+
)
105+
106+
request.method = 'POST'
107+
request.headers = {
108+
'X-Slack-Request-Timestamp': now,
109+
'X-Slack-Signature': test_signature
110+
}
88111

89112
with mock.patch('main.jsonify', side_effect=json.dumps):
90113
response = main.kg_search(request)

functions/slack/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
google-api-python-client==1.10.0
22
flask==1.1.2
3-
slackeventsapi==2.2.0
3+
slackclient==2.7.3

0 commit comments

Comments
 (0)