-
Notifications
You must be signed in to change notification settings - Fork 286
Expand file tree
/
Copy pathmain.py
More file actions
130 lines (102 loc) · 4.32 KB
/
main.py
File metadata and controls
130 lines (102 loc) · 4.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# Copyright 2017 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# pylint: disable=invalid-name
"""
Simple Google Chat app that responds to events and
messages from a space.
"""
import logging
from flask import Flask, render_template, request, json
from google.oauth2 import id_token
from google.auth.transport import requests
# Authentication audience (either APP_URL or PROJECT_NUMBER)
AUDIENCE_TYPE = "AUDIENCE_TYPE"
# Intended audience of the token:
# - The URL of the app when AUDIENCE_TYPE is set to APP_URL
# - The project number when AUDIENCE_TYPE is set to PROJECT_NUMBER
AUDIENCE = "AUDIENCE"
app = Flask(__name__)
@app.route('/', methods=['POST'])
def home_post():
"""Respond to POST requests to this endpoint.
All requests sent to this endpoint from Google Chat are POST
requests.
"""
data = request.get_json()
resp_dict = format_response(data)
return json.jsonify(resp_dict)
def format_response(event):
"""Determine what response to provide based upon event data.
Args:
event: A dictionary with the event data.
"""
text = ""
authorization = request.headers.get('Authorization')
if verify_chat_app_request(authorization[len("Bearer "):]) != True:
text = 'Failed verification!'
# Case 1: The app was added to a space
elif event['type'] == 'ADDED_TO_SPACE' and event['space']['type'] == 'ROOM':
text = 'Thanks for adding me to "%s"!' % event['space']['displayName']
# Case 2: The app was added to a DM
elif event['type'] == 'ADDED_TO_SPACE' and event['space']['type'] == 'DM':
text = 'Thanks for adding me to a DM, %s!' % event['user']['displayName']
elif event['type'] == 'MESSAGE':
text = 'Your message: "%s"' % event['message']['text']
elif event['type'] == 'REMOVED_FROM_SPACE':
logging.info('App removed from a space')
return {'text': text}
def verify_chat_app_request(bearer):
"""Determine whether a Google Chat request is legitimate.
Args:
bearer: The bearer value sent in the request.
"""
if AUDIENCE_TYPE == "APP_URL":
# [START chat_request_verification_app_url]
# Bearer Tokens received by apps will always specify this issuer.
CHAT_ISSUER = 'chat@system.gserviceaccount.com'
try:
# Verify valid token, signed by CHAT_ISSUER, intended for a third party.
request = requests.Request()
token = id_token.verify_oauth2_token(bearer, request, AUDIENCE)
return token['email'] == CHAT_ISSUER
except:
return False
# [END chat_request_verification_app_url]
elif AUDIENCE_TYPE == "PROJECT_NUMBER":
# [START chat_request_verification_project_number]
# Bearer Tokens received by apps will always specify this issuer.
CHAT_ISSUER = 'chat@system.gserviceaccount.com'
try:
# Verify valid token, signed by CHAT_ISSUER, intended for a third party.
request = requests.Request()
certs_url = 'https://www.googleapis.com/service_accounts/v1/metadata/x509/' + CHAT_ISSUER
token = id_token.verify_token(bearer, request, AUDIENCE, certs_url)
return token['iss'] == CHAT_ISSUER
except:
return False
# [END chat_request_verification_project_number]
# Skip verification if AUDIENCE_TYPE is not set with supported value
return True;
@app.route('/', methods=['GET'])
def home_get():
"""Respond to GET requests to this endpoint.
This function responds to requests with a simple HTML landing page for this
App Engine instance.
"""
return render_template('home.html')
if __name__ == '__main__':
# This is used when running locally. Gunicorn is used to run the
# application on Google App Engine. See entrypoint in app.yaml.
app.run(host='127.0.0.1', port=8080, debug=True)