Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .kokoro/tests/run_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ source ./testing/test-env.sh
export GOOGLE_APPLICATION_CREDENTIALS=$(pwd)/testing/service-account.json
export GOOGLE_CLIENT_SECRETS=$(pwd)/testing/client-secrets.json
source "${KOKORO_GFILE_DIR}/automl_secrets.txt"
cp "${KOKORO_GFILE_DIR}/functions-slack-config.json" "functions/slack/config.json"

# For Datalabeling samples to hit the testing endpoint
export DATALABELING_ENDPOINT="test-datalabeling.sandbox.googleapis.com:443"
Expand Down
2 changes: 1 addition & 1 deletion functions/slack/config.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"SLACK_TOKEN": "YOUR_SLACK_TOKEN",
"SLACK_SECRET": "YOUR_SLACK_SIGNING_SECRET",
"KG_API_KEY": "YOUR_KG_API_KEY"
}
22 changes: 18 additions & 4 deletions functions/slack/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
# limitations under the License.

# [START functions_slack_setup]
import hashlib
import hmac
import json
import os

Expand All @@ -26,13 +28,25 @@
kgsearch = apiclient.discovery.build(
'kgsearch',
'v1',
developerKey=os.environ['API_KEY'] or config['KG_API_KEY'])
developerKey=os.environ.get('API_KEY') or config.get('KG_API_KEY'),
cache_discovery=False)
# [END functions_slack_setup]


# [START functions_verify_webhook]
def verify_web_hook(form):
if not form or form.get('token') != config['SLACK_TOKEN']:
# Python 3+ version of https://github.com/slackapi/python-slack-events-api/blob/master/slackeventsapi/server.py
def verify_signature(request):
timestamp = request.headers.get('X-Slack-Request-Timestamp', '')
signature = request.headers.get('X-Slack-Signature', '')

req = str.encode('v0:{}:'.format(timestamp)) + request.get_data()
request_digest = hmac.new(
str.encode(config['SLACK_SECRET']),
req, hashlib.sha256
).hexdigest()
request_hash = 'v0={}'.format(request_digest)

if not hmac.compare_digest(request_hash, signature):
raise ValueError('Invalid request/credentials.')
# [END functions_verify_webhook]

Expand Down Expand Up @@ -92,7 +106,7 @@ def kg_search(request):
if request.method != 'POST':
return 'Only POST requests are accepted', 405

verify_web_hook(request.form)
verify_signature(request)
kg_search_response = make_search_request(request.form['text'])
return jsonify(kg_search_response)
# [END functions_slack_search]
27 changes: 19 additions & 8 deletions functions/slack/main_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,30 @@


class Request(object):
def __init__(self):
pass
def __init__(self, data=b''):
self.data = data

def get_data(self):
return self.data


class TestGCFPySlackSample(object):
def test_verify_web_hook_request_form_empty(self):
def test_verify_signature_request_form_empty(self):
with pytest.raises(ValueError):
main.verify_web_hook({})
request = Request()
request.headers = {}
main.verify_signature(request)

def test_verify_web_hook_token_incorrect(self):
def test_verify_signature_token_incorrect(self):
with pytest.raises(ValueError):
main.verify_web_hook({'token': 123})
request = Request()
request.headers = {'X-Slack-Signature': '12345'}
main.verify_signature(request)

def test_verify_web_hook_valid_request(self):
main.verify_web_hook({'token': config['SLACK_TOKEN']})
request = Request()
request.headers = {'X-Slack-Signature': os.environ['SLACK_TEST_SIGNATURE']}
main.verify_signature(request)

def test_format_slack_message(self):
message = main.format_slack_message('lion', example_response)
Expand All @@ -72,8 +81,10 @@ def test_kg_search(self):
search.execute.return_value = example_response
request = Request()
request.method = 'POST'
request.headers = {
'X-Slack-Signature': os.environ['SLACK_TEST_SIGNATURE']
}
request.form = {
'token': config['SLACK_TOKEN'],
'text': 'lion'
}

Expand Down
2 changes: 2 additions & 0 deletions functions/slack/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
google-api-python-client==1.7.11
flask==1.1.1
oauth2client==4.1.3
slackeventsapi==2.1.0
Binary file modified testing/secrets.tar.enc
Binary file not shown.