(20241203) Cleaning-up the callback-handling blueprint.
This commit is contained in:
@@ -40,7 +40,7 @@ sys.path.append(".")
|
|||||||
sys.path.append("..")
|
sys.path.append("..")
|
||||||
|
|
||||||
# For using Quart:
|
# For using Quart:
|
||||||
from quart import Blueprint, current_app, request, render_template
|
from quart import Blueprint, current_app, g, request, render_template
|
||||||
|
|
||||||
# My utils:
|
# My utils:
|
||||||
from utils_v2.string import json
|
from utils_v2.string import json
|
||||||
@@ -108,6 +108,81 @@ def init(blueprint_setup_state):
|
|||||||
# ---------------------------------------------------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
async def handle_gmail_callback():
|
||||||
|
|
||||||
|
"""
|
||||||
|
To handle the callbacks from GMail specifically. Refer to the individual comments to check what hap[pens at each
|
||||||
|
step of the process.
|
||||||
|
:return: A rendered template of the final status of the authorization.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Start by assuming failure:
|
||||||
|
tokens_saved = False
|
||||||
|
|
||||||
|
# In case the user cancelled halfway through (on Google's screen):
|
||||||
|
if g.inbound_data.get("error") == "access_denied": return await render_template(
|
||||||
|
"/mail/oauth/oauth_cancelled_v2.html",
|
||||||
|
mail_client = g.mail_client.title()
|
||||||
|
)
|
||||||
|
|
||||||
|
# Generate the tokens from the callback. Google sends all the needed params in the callback as the URL's query
|
||||||
|
# params. We can simply use the exact URL that was hit to generate the tokens. In Quart (and Flask) this can be
|
||||||
|
# achieved by 'request.url' like this:
|
||||||
|
tokens = await current_app.gmail_client.get_authorization_tokens(
|
||||||
|
redirect_url = request.url,
|
||||||
|
scopes = g.inbound_data["scope"]
|
||||||
|
)
|
||||||
|
|
||||||
|
if tokens:
|
||||||
|
|
||||||
|
# Get the e-mail id that granted authorization. We will be comparing this to the e-mail id that had been given
|
||||||
|
# to us when the authorization was initiated. We don't mind any e-mail id being used, but we need them to be the
|
||||||
|
# same at both ends:
|
||||||
|
user_profile = await current_app.gmail_client.get_user_profile(tokens = tokens)
|
||||||
|
tokens.email = user_profile.data["emailAddress"] if user_profile.success else None
|
||||||
|
|
||||||
|
# Here's where we do the checking of the e-mails,
|
||||||
|
# if they don't match, we reject the authorization:
|
||||||
|
placeholder_token = await current_app.mail_oauth_model.get_token(
|
||||||
|
mongo_conn = current_app.data_mongo,
|
||||||
|
account_identifier = g.inbound_data["state"]
|
||||||
|
)
|
||||||
|
if (
|
||||||
|
(not placeholder_token) or
|
||||||
|
placeholder_token["clientUserId"] != str(tokens.email)
|
||||||
|
): return await render_template(
|
||||||
|
"/mail/oauth/oauth_failure_v2.html",
|
||||||
|
mail_client = g.mail_client.title(),
|
||||||
|
failure_hint = f"We were expecting authorization from '{placeholder_token['clientUserId']['email']}' but got authorization from '{tokens.email}' instead."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Now that we have passed the check,
|
||||||
|
# we save the tokens to the database:
|
||||||
|
tokens_saved = await current_app.mail_oauth_model.set_token(
|
||||||
|
db_conn = current_app.sql_writer,
|
||||||
|
mongo_conn = current_app.data_mongo,
|
||||||
|
session_token = g.inbound_headers.get("X-Session-Token"),
|
||||||
|
account_identifier = g.inbound_data["state"],
|
||||||
|
token = tokens.model_dump()
|
||||||
|
)
|
||||||
|
|
||||||
|
# Return an HTML response for success:
|
||||||
|
if tokens_saved: return await render_template(
|
||||||
|
"/mail/oauth/oauth_success_v2.html",
|
||||||
|
mail_client = g.mail_client.title()
|
||||||
|
)
|
||||||
|
|
||||||
|
# Return an HTML response for failure:
|
||||||
|
else: return await render_template(
|
||||||
|
"/mail/oauth/oauth_failure_v2.html",
|
||||||
|
mail_client = g.mail_client.title(),
|
||||||
|
failure_hint = f"Unknown error. Please use log-id '{g.log_id}' to check with the support team."
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
@mail_callback_bp.route("/callback/<mail_client>", methods = ["POST", "GET"])
|
@mail_callback_bp.route("/callback/<mail_client>", methods = ["POST", "GET"])
|
||||||
@set_api_version(api_version = "1.0.0")
|
@set_api_version(api_version = "1.0.0")
|
||||||
@read_input(sanitize_headers = False, sanitize_data = False)
|
@read_input(sanitize_headers = False, sanitize_data = False)
|
||||||
@@ -141,86 +216,30 @@ async def mail_callback(
|
|||||||
:return: A standard response structure.
|
:return: A standard response structure.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Start by assuming failure:
|
# ┓┏ ┓┓ ┓┏ • ┓ ┓
|
||||||
tokens_saved = False
|
# ┣┫┏┓┏┓┏┫┃┏┓ ┃┃┏┓┏┓┓┏┓┣┓┃┏┓┏
|
||||||
|
# ┛┗┗┻┛┗┗┻┗┗ ┗┛┗┻┛ ┗┗┻┗┛┗┗ ┛
|
||||||
|
|
||||||
# ┏┓ ┏┓┳┳┓ •┓
|
# Here we make various variables available in the scope of the current request through 'g':
|
||||||
# ┣ ┏┓┏┓ ┃┓┃┃┃┏┓┓┃
|
g.log_id = kwargs.get("log_id")
|
||||||
# ┻ ┗┛┛ ┗┛┛ ┗┗┻┗┗
|
g.inbound_headers = inbound_headers
|
||||||
|
g.inbound_data = inbound_data
|
||||||
|
g.mail_client = mail_client
|
||||||
|
|
||||||
if mail_client == "gmail":
|
# ┓┏ ┓┓ ┏┓ ┓┓┓ ┓
|
||||||
|
# ┣┫┏┓┏┓┏┫┃┏┓ ┃ ┏┓┃┃┣┓┏┓┏┃┏┏
|
||||||
|
# ┛┗┗┻┛┗┗┻┗┗ ┗┛┗┻┗┗┗┛┗┻┗┛┗┛
|
||||||
|
|
||||||
# In case the user cancelled halfway through (on Google's screen):
|
if mail_client == "gmail": return await handle_gmail_callback()
|
||||||
if inbound_data.get("error") == "access_denied": return await render_template(
|
|
||||||
"/mail/oauth/oauth_cancelled_v2.html",
|
|
||||||
mail_client = mail_client.title()
|
|
||||||
)
|
|
||||||
|
|
||||||
# Generate the tokens from the callback:
|
# ┓┏ ┓┓ ┳ ┓• ┓ ┏┓┓•
|
||||||
tokens = await current_app.gmail_client.get_authorization_tokens(
|
# ┣┫┏┓┏┓┏┫┃┏┓ ┃┏┓┓┏┏┓┃┓┏┫ ┃ ┃┓┏┓┏┓╋
|
||||||
redirect_url = request.url,
|
# ┛┗┗┻┛┗┗┻┗┗ ┻┛┗┗┛┗┻┗┗┗┻ ┗┛┗┗┗ ┛┗┗
|
||||||
scopes = inbound_data["scope"]
|
|
||||||
)
|
|
||||||
|
|
||||||
if tokens:
|
|
||||||
|
|
||||||
# Get the e-mail id that granted authorization:
|
|
||||||
user_profile = await current_app.gmail_client.get_user_profile(tokens = tokens)
|
|
||||||
tokens.email = user_profile.data["emailAddress"] if user_profile.success else None
|
|
||||||
|
|
||||||
# The e-mail id that we requested access to and the one that granted us access should be the same:
|
|
||||||
placeholder_token = await current_app.mail_oauth_model.get_token(
|
|
||||||
mongo_conn = current_app.data_mongo,
|
|
||||||
account_identifier = inbound_data["state"]
|
|
||||||
)
|
|
||||||
if (
|
|
||||||
(not placeholder_token) or
|
|
||||||
placeholder_token["clientUserId"] != str(tokens.email)
|
|
||||||
): return await render_template(
|
|
||||||
"/mail/oauth/oauth_failure_v2.html",
|
|
||||||
mail_client = mail_client.title(),
|
|
||||||
failure_hint = f"We were expecting authorization from '{placeholder_token['clientUserId']}' but got authorization from '{tokens.email}' instead."
|
|
||||||
)
|
|
||||||
|
|
||||||
# Save the tokens to the database
|
|
||||||
tokens_saved = await current_app.mail_oauth_model.set_token(
|
|
||||||
db_conn = current_app.sql_writer,
|
|
||||||
mongo_conn = current_app.data_mongo,
|
|
||||||
session_token = inbound_headers.get("X-Session-Token"),
|
|
||||||
account_identifier = inbound_data["state"],
|
|
||||||
token = tokens.model_dump()
|
|
||||||
)
|
|
||||||
|
|
||||||
# tokens_saved = False
|
|
||||||
|
|
||||||
# ┳┓
|
|
||||||
# ┣┫┏┓┏┏┓┏┓┏┓┏┏┓
|
|
||||||
# ┛┗┗ ┛┣┛┗┛┛┗┛┗
|
|
||||||
# ┛
|
|
||||||
|
|
||||||
# # Return a JSON response:
|
|
||||||
# return ResponseModel(
|
|
||||||
# status_code = StatusCodes.OK if tokens_saved else StatusCodes.FAILED,
|
|
||||||
# http_code = HttpCodes.SUCCESS if tokens_saved else HttpCodes.INTERNAL_SERVER_ERROR,
|
|
||||||
# data = {
|
|
||||||
# "mailClient": mail_client,
|
|
||||||
# "authorized": True
|
|
||||||
# }
|
|
||||||
# )
|
|
||||||
|
|
||||||
# Return an HTML response for success:
|
|
||||||
if tokens_saved:
|
|
||||||
return await render_template(
|
|
||||||
"/mail/oauth/oauth_success_v2.html",
|
|
||||||
mail_client = mail_client.title()
|
|
||||||
)
|
|
||||||
|
|
||||||
# Return an HTML response for failure:
|
|
||||||
else:
|
|
||||||
return await render_template(
|
return await render_template(
|
||||||
"/mail/oauth/oauth_failure_v2.html",
|
"/mail/oauth/oauth_failure_v2.html",
|
||||||
mail_client = mail_client.title(),
|
mail_client = mail_client.title(),
|
||||||
failure_hint = f"Unknown error. Please use log-id '{kwargs['logId']}' to check with the support team."
|
failure_hint = f"Invalid client '{mail_client}' selected. Please use log-id '{g.log_id}' to check with the support team."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user