Skip to content
This repository was archived by the owner on Jun 26, 2025. It is now read-only.

Commit 337a424

Browse files
authored
Merge pull request #130 from davidalbertonogueira/master
Fix deprecated Google certificates & add MediaResponse
2 parents 004fccc + 9e474b2 commit 337a424

File tree

5 files changed

+101
-26
lines changed

5 files changed

+101
-26
lines changed

flask_assistant/core.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,11 @@ def _set_user_profile(self):
395395
from flask_assistant.utils import decode_token
396396

397397
token = self.user["idToken"]
398-
profile_payload = decode_token(token, self.client_id)
398+
decode_resp = decode_token(token, self.client_id)
399+
if decode_resp["status"]=="BAD":
400+
return
401+
else: #decode_resp["status"]=="OK"
402+
profile_payload = decode_resp["output"]
399403
for k in ["sub", "iss", "aud", "iat", "exp"]:
400404
profile_payload.pop(k)
401405

flask_assistant/response.py

Lines changed: 65 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ def __init__(self, speech, display_text=None, is_ssml=False):
1111
self._display_text = display_text
1212
self._integrations = current_app.config.get("INTEGRATIONS", [])
1313
self._messages = [{"text": {"text": [speech]}}]
14-
14+
self._is_ssml = is_ssml
1515
self._response = {
1616
"fulfillmentText": speech,
1717
"fulfillmentMessages": self._messages,
@@ -197,6 +197,49 @@ def build_carousel(self, items=None):
197197
)
198198
return carousel
199199

200+
def add_media(self, url, name, description=None, icon_url=None, icon_alt=None):
201+
"""Adds a Media Card Response
202+
203+
Media responses let your Actions play audio content with a
204+
playback duration longer than the 240-second limit of SSML.
205+
206+
Can be included with ask and tell responses.
207+
If added to an `ask` response, suggestion chips
208+
209+
Arguments:
210+
url {str} -- Required. Url where the media is stored
211+
name {str} -- Name of media card.
212+
213+
Optional:
214+
description {str} -- A description of the item (default: {None})
215+
icon_url {str} -- Url of icon image
216+
icon_alt {str} -- Accessibility text for icon image
217+
218+
example usage:
219+
220+
resp = ask("Check out this tune")
221+
resp = resp.add_media(url, "Jazzy Tune")
222+
return resp_with_media.suggest("Next Song", "Done")
223+
224+
225+
"""
226+
media_object = {"contentUrl": url, "name": name}
227+
if description:
228+
media_object["description"] = description
229+
230+
if icon_url:
231+
media_object["largeImage"] = {}
232+
media_object["largeImage"]["imageUri"] = icon_url
233+
media_object["largeImage"]["accessibilityText"] = icon_alt or name
234+
235+
self._messages.append(
236+
{
237+
"platform": "ACTIONS_ON_GOOGLE",
238+
"mediaContent": {"mediaObjects": [media_object], "mediaType": "AUDIO",},
239+
}
240+
)
241+
return self
242+
200243

201244
def build_item(
202245
title, key=None, synonyms=None, description=None, img_url=None, alt_text=None
@@ -307,10 +350,12 @@ def __init__(self, speech, display_text=None, is_ssml=False):
307350
self._response["payload"]["google"]["expect_user_response"] = True
308351

309352
def reprompt(self, prompt):
310-
self._response["payload"]["google"]["no_input_prompts"] = [
311-
{"text_to_speech": prompt}
312-
]
313-
353+
repromtKey = "text_to_speech"
354+
if self._is_ssml:
355+
repromtKey = "ssml"
356+
repromtResponse = {}
357+
repromtResponse[repromtKey] = prompt
358+
self._response["payload"]["google"]["no_input_prompts"] = [repromtResponse]
314359
return self
315360

316361

@@ -367,18 +412,26 @@ class sign_in(_Response):
367412
with the `user.profile` local
368413
369414
In order to complete the sign in process, you will need to create an intent with
370-
the `actions_intent_SIGN)IN` event
415+
the `actions_intent_SIGN_IN` event
371416
"""
372417

418+
# Payload according to https://developers.google.com/assistant/conversational/helpers#account_sign-in
373419
def __init__(self, reason=None):
374420
super(sign_in, self).__init__(speech=None)
375421

376422
self._messages[:] = []
377-
self._response["payload"]["google"]["systemIntent"] = {
378-
"intent": "actions.intent.SIGN_IN",
379-
"data": {
380-
"optContext": reason,
381-
"@type": "type.googleapis.com/google.actions.v2.SignInValueSpec",
382-
},
423+
self._response = {
424+
"payload": {
425+
"google": {
426+
"expectUserResponse": True,
427+
"systemIntent": {
428+
"intent": "actions.intent.SIGN_IN",
429+
"data": {
430+
"@type": "type.googleapis.com/google.actions.v2.SignInValueSpec"
431+
},
432+
},
433+
}
434+
}
383435
}
384436

437+

flask_assistant/utils.py

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,10 @@
66
from google.auth import jwt
77
from flask_assistant.core import Assistant
88
from . import logger
9-
9+
import requests
1010

1111
logger.setLevel(logging.INFO)
1212

13-
GOOGLE_PUBLIC_KEY = {
14-
"ee4dbd06c06683cb48dddca6b88c3e473b6915b9": "-----BEGIN CERTIFICATE-----\nMIIDJjCCAg6gAwIBAgIIXlp0tU/OdR8wDQYJKoZIhvcNAQEFBQAwNjE0MDIGA1UE\nAxMrZmVkZXJhdGVkLXNpZ25vbi5zeXN0ZW0uZ3NlcnZpY2VhY2NvdW50LmNvbTAe\nFw0xOTEwMDMxNDQ5MzRaFw0xOTEwMjAwMzA0MzRaMDYxNDAyBgNVBAMTK2ZlZGVy\nYXRlZC1zaWdub24uc3lzdGVtLmdzZXJ2aWNlYWNjb3VudC5jb20wggEiMA0GCSqG\nSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC41NLGPK9PRi0KjFTIQ9qEirje2IrmWSwZ\n7lmgTzwA4mpc4tqDn7AfUTHmuyhDrbweGq2wQeYJDbBPT5uX86XcQgAcu4IzSuZG\nJZ68ASYOWWlKV0vYjf6W/9v73sGJFxbkoAB8X7QH/fN80QYoXvSX+IwNnePnoikM\nnAsNiZrkLoqHuv5+ahOgpBN5qyvKglasNiXGpv8EL96CKb+nmMudzpypjbQHJUp2\nmfDvOiTX6IuSXyeYRkyzOeX7wqpV1l+TU3A8orMylNe8e+oL/2mAYVzCC9Wk1nq2\nGT4vRRmzrr2GW4eKr9525JQe7BKBKkC2WWhKE+EmqPm2ZFnQ/frlAgMBAAGjODA2\nMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQMMAoGCCsG\nAQUFBwMCMA0GCSqGSIb3DQEBBQUAA4IBAQA+mwyWb+SZMLOiQS1lUgN6iXO2JZm+\nq6rmSYnpLP5nCtwKjHbGSw0DoUchem2g0AYsB/HqNl5zLvJb5CXlP79sTO6Ot7sX\nHI3Mtqw4Fe1QFCC5QVhudpMNKNQYq8P45SrfwMW1qSYYsMXbpmNkIPbFvxib1L0l\niUfnjCXFB4XiDa80Cb73cxmU7a24/j03o42kjcRX2BtXs6jhP7z8BxnDCjybjlLT\no5gBombtlPKgOTdcF+eKdaO1LLQ+9LmueiZH/HCsvAmmxLT9g1XZCEFg5zttdetT\nVV+03sFBGhoJPbChiOJMdH8IQVEdtpvnAiYyVBYEUSj7CWSZEI50syL2\n-----END CERTIFICATE-----\n",
15-
"8c58e138614bd58742172bd5080d197d2b2dd2f3": "-----BEGIN CERTIFICATE-----\nMIIDJjCCAg6gAwIBAgIIFqFLh91FQ0kwDQYJKoZIhvcNAQEFBQAwNjE0MDIGA1UE\nAxMrZmVkZXJhdGVkLXNpZ25vbi5zeXN0ZW0uZ3NlcnZpY2VhY2NvdW50LmNvbTAe\nFw0xOTA5MjUxNDQ5MzRaFw0xOTEwMTIwMzA0MzRaMDYxNDAyBgNVBAMTK2ZlZGVy\nYXRlZC1zaWdub24uc3lzdGVtLmdzZXJ2aWNlYWNjb3VudC5jb20wggEiMA0GCSqG\nSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJ/fKZfxfVD68YAuMfl5bnoNBjZ4kyhXMi\nffkizGpJGkMR2gL6ansSYLrd94Gn/W5FH0hMLCWK41gBXXI6alI6y0YNGSeGnmbO\nZz8Si+oMfiPAj9NaawMwNnusdMqrkMUrMBUmWSTzk4ttu3U9TVkIXZ5i0LNvntJO\nuG+Ga4A+CaipE6Y1QoXkFwFDDum8qpXYKMlF0pSbGz/Nb2o1RjINlo9gx+KWgaPK\n2wWw+n6XJDLFtcmhRtQPuMDpxRveY63OlE4CCRhnJLvjSD4ZlxUtqmoDALpRnGUI\n36VdsZpvtz5CsIy8PB+7ZTcBBK8jfy73kxpuuMdlaxZEJuolV8cjAgMBAAGjODA2\nMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQMMAoGCCsG\nAQUFBwMCMA0GCSqGSIb3DQEBBQUAA4IBAQCY7YX8EDcPQGFpklGVtqN7tlfm+Gi8\n0v3E9WoQUiMQJ9Mt34ixd3zPjMeKOtVxj6BZzHrpyR6rM9lB4nzoyCWf9K86HaWS\nuxtAACj7yovKAh2x5pFwEB014qNdG03YYQFy8MvDxegaL4soWqCa2UfEK4vdWyJi\nZKM0iT6s78VY6vOWxK+z1IC/6AYbyskzv57T+dBUwGcwQEf0yBeu89tR7LFSaVV/\n6A+dTGyFlHysR6dddwJvzl7jG83RQs2L58qIISD+6RdRxcD02h388YhhMy9Nrpmo\nZeXouJ7YLsHGFkn3yfWi3KWYVdTGbd/9BQPBjhKzS93SxdolTKKVOI/7\n-----END CERTIFICATE-----\n",
16-
"3db3ed6b9574ee3fcd9f149e59ff0eef4f932153": "-----BEGIN CERTIFICATE-----\nMIIDJjCCAg6gAwIBAgIIeBPD3wqfL6EwDQYJKoZIhvcNAQEFBQAwNjE0MDIGA1UE\nAxMrZmVkZXJhdGVkLXNpZ25vbi5zeXN0ZW0uZ3NlcnZpY2VhY2NvdW50LmNvbTAe\nFw0xOTEwMTExNDQ5MzRaFw0xOTEwMjgwMzA0MzRaMDYxNDAyBgNVBAMTK2ZlZGVy\nYXRlZC1zaWdub24uc3lzdGVtLmdzZXJ2aWNlYWNjb3VudC5jb20wggEiMA0GCSqG\nSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDYpym/gLFOh4IoQhfOeGo+DbUyEIA/0Odf\nmzb9R1nVvM5WFHyqKiT8/yPvLxgXYzYlzyvZu18KAkYWWNuS21Vzhe+d4949P6EZ\n/096QjVFSHvKTo94bSQImeZxZiBhfFcvw/RMM0eTeZZPgOXI3YIJyWjAZ9FUslt7\nWoLU0HZFc/JyPRF8M2kinkdYxnzA+MjzCetXlqmhAr+wLPg/QLKwACyRIF2FJHgf\nPsvqaeF7JXo0zHPcGuHUOqXCHon6KiHZF7OC4bzTuTEzVipJTLYy9QUyL4M2L8bQ\nu1ISUSaXhj+i1WT0RDJwqpioOFprVFqqkVvbUW0nXD/x1UA4nvf7AgMBAAGjODA2\nMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQMMAoGCCsG\nAQUFBwMCMA0GCSqGSIb3DQEBBQUAA4IBAQBr5+4ZvfhP436NdJgN0Jn7iwwVArus\nXUn0hfuBbCoj1DhuRkP9wyLCpOo6cQS0T5bURVZzirsKc5sXP4fNYXqbfLaBpc7n\njTUtTOIqoA4LKPU7/FH6Qt/UfZ4DQIsKaD3087KdY3ePatSn/HTxvT8Ghqy/JGjf\nLXZehQnlyyCRaCMqv1gEOMiY/8LG3d1hLL7CMphnb4ASk0YMKrWkKhIoa6NWU2Rd\nqp01F4iG44ABpea+ymXAGmWBVPnep51kr/wIPIzr9WvNFAAZW2Enk3+kUWNupuz+\npdXq9KnegVsCs4G7QcTPqwc/vMu7uGq/pruDEOYVOd9Rm+rr0wlMgkcf\n-----END CERTIFICATE-----\n",
17-
}
18-
19-
2013
def import_with_3(module_name, path):
2114
import importlib.util
2215

@@ -49,6 +42,31 @@ def get_assistant(filename):
4942

5043

5144
def decode_token(token, client_id):
52-
decoded = jwt.decode(token, certs=GOOGLE_PUBLIC_KEY, verify=True, audience=client_id)
53-
return decoded
54-
45+
r = requests.get('https://accounts.google.com/.well-known/openid-configuration')
46+
if(r.status_code != 200):
47+
print("status_code != 200; status_code =", r.status_code)
48+
print(r)
49+
try:
50+
return {'status':'BAD','error':r.status_code, "output": r.text}
51+
except requests.exceptions.RequestException as e:
52+
return {'status':'BAD','error':r.status_code}
53+
54+
if "jwks_uri" not in r.json():
55+
error_message = "Missing jwks_uri in 'https://accounts.google.com/.well-known/openid-configuration'"
56+
print(error_message)
57+
return {'status':'BAD','error':error_message}
58+
59+
googleapis_certs = r.json()["jwks_uri"].replace("/v3/", "/v1/")
60+
r = requests.get(googleapis_certs)
61+
if(r.status_code != 200):
62+
print("status_code != 200; status_code =", r.status_code)
63+
print(r)
64+
try:
65+
return {'status':'BAD','error':r.status_code, "output": r.text}
66+
except requests.exceptions.RequestException as e:
67+
return {'status':'BAD','error':r.status_code}
68+
else:
69+
public_keys = r.json()
70+
decoded = jwt.decode(token, certs=public_keys, verify=True, audience=client_id)
71+
return {'status':'OK','output': decoded}
72+

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ cachetools==3.1.1
33
certifi==2018.11.29
44
chardet==3.0.4
55
click==7.0
6-
flask==1.0.2
6+
flask==1.1.1
77
google-auth==1.6.3
88
idna==2.8
99
itsdangerous==1.1.0

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
setup(
1313
name="Flask-Assistant",
14-
version="0.4.1",
14+
version="0.5.0",
1515
url="https://github.com/treethought/flask-assistant",
1616
license="Apache 2.0",
1717
author="Cam Sweeney",

0 commit comments

Comments
 (0)