(20241209) Standardizing the data models for the database. Started with mail authentication.
This commit is contained in:
@@ -138,36 +138,38 @@ async def handle_gmail_callback() -> render_template:
|
||||
# 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(
|
||||
google_tokens = await current_app.gmail_client.get_authorization_tokens(
|
||||
redirect_url = request.url,
|
||||
# scopes = g.inbound_data["scope"].split(" ")
|
||||
scopes = None
|
||||
)
|
||||
|
||||
if tokens:
|
||||
if google_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)
|
||||
user_profile = await current_app.gmail_client.get_user_profile(tokens = google_tokens)
|
||||
if user_profile.success:
|
||||
tokens.email = user_profile.data["emailAddress"]
|
||||
tokens.displayName = user_profile.data["displayName"]
|
||||
tokens.displayPictureUrl = user_profile.data["displayPictureUrl"]
|
||||
google_tokens.email = user_profile.data["emailAddress"]
|
||||
google_tokens.displayName = user_profile.data["displayName"]
|
||||
google_tokens.displayPictureUrl = user_profile.data["displayPictureUrl"]
|
||||
|
||||
# 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(
|
||||
auth_token = await current_app.mail_oauth_model.get_token(
|
||||
mongo_conn = current_app.data_mongo,
|
||||
token_id = g.inbound_data["state"]
|
||||
)
|
||||
if (
|
||||
(not placeholder_token) or
|
||||
placeholder_token["clientUserId"]["email"] != str(tokens.email)
|
||||
(not auth_token) or
|
||||
auth_token.clientUserId["email"] != str(google_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."
|
||||
failure_hint = (
|
||||
f"We were expecting authorization from '{auth_token.clientUserId['email']}', "
|
||||
f"but got authorization from '{google_tokens.email}' instead."
|
||||
)
|
||||
)
|
||||
|
||||
# We create standard labels that we will use:
|
||||
@@ -190,7 +192,7 @@ async def handle_gmail_callback() -> render_template:
|
||||
]
|
||||
tasks = [
|
||||
current_app.gmail_client.create_label(
|
||||
tokens = tokens,
|
||||
tokens = google_tokens,
|
||||
label_name = label["name"],
|
||||
label_visibility = "labelShow",
|
||||
message_visibility = "show",
|
||||
@@ -201,18 +203,20 @@ async def handle_gmail_callback() -> render_template:
|
||||
client_responses = await asyncio.gather(*tasks)
|
||||
|
||||
# Add the labels to the tokens data:
|
||||
client_response = await current_app.gmail_client.list_labels(tokens = tokens)
|
||||
tokens.labels = client_response.data if client_response.success else None
|
||||
client_response = await current_app.gmail_client.list_labels(tokens = google_tokens)
|
||||
google_tokens.labels = client_response.data if client_response.success else None
|
||||
|
||||
# Now that we have passed the check,
|
||||
# we save the tokens to the database:
|
||||
auth_token.clientUserId = google_tokens.client_user_id
|
||||
auth_token.token = google_tokens.model_dump()
|
||||
auth_token.status = "active"
|
||||
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"),
|
||||
token_id = g.inbound_data["state"],
|
||||
client_user_id = tokens.client_user_id,
|
||||
token = tokens.model_dump()
|
||||
auth_token = auth_token
|
||||
)
|
||||
|
||||
# Return an HTML response for success:
|
||||
@@ -294,7 +298,10 @@ async def mail_auth_callback(
|
||||
return await render_template(
|
||||
"/mail/oauth/oauth_failure_v2.html",
|
||||
mail_client = mail_client.title(),
|
||||
failure_hint = f"Invalid client '{mail_client}' selected. Please use log-id '{g.log_id}' 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."
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ from models.data.api.mail.oauth import (
|
||||
OAuthMailAuthorizationRequestHeaders,
|
||||
OAuthMailAuthorizationRequestData
|
||||
)
|
||||
from models.data.core.auth_token import CoreAuthTokenModel
|
||||
|
||||
# For asynchronous activities:
|
||||
import asyncio
|
||||
@@ -169,22 +170,24 @@ async def request_oauth_authorization_url(
|
||||
# Start by assuming failure:
|
||||
auth_url = None
|
||||
|
||||
# ┳ ┓ •┏ ┳┳
|
||||
# ┃┏┫┏┓┏┓╋┓╋┓┏ ┃┃┏┏┓┏┓
|
||||
# ┻┗┻┗ ┛┗┗┗┛┗┫ ┗┛┛┗ ┛
|
||||
# ┛
|
||||
# ┏┓ ┏┳┓ ┓ ┳ ┓
|
||||
# ┃┓┏┓┏┓┏┓┏┓┏┓╋┏┓ ┃ ┏┓┃┏┏┓┏┓ ┃┏┫
|
||||
# ┗┛┗ ┛┗┗ ┛ ┗┻┗┗ ┻ ┗┛┛┗┗ ┛┗ ┻┗┻
|
||||
|
||||
# Make a user identifier from the session info:
|
||||
token_id = await current_app.mail_oauth_model.get_token_id(
|
||||
db_conn = current_app.sql_writer,
|
||||
mongo_conn = current_app.data_mongo,
|
||||
session_token = inbound_headers["X-Session-Token"],
|
||||
user_info = kwargs["session_info"],
|
||||
client_user_id = {"email": inbound_data.mailId},
|
||||
auth = None,
|
||||
service_client = inbound_data.mailClient,
|
||||
auth_type = "oauth",
|
||||
sync_freq = inbound_data.syncFreq
|
||||
auth_token = CoreAuthTokenModel(
|
||||
serviceType = "email",
|
||||
client = inbound_data.mailClient,
|
||||
authType = "oauth",
|
||||
user = kwargs["session_info"],
|
||||
clientUserId = {"email": inbound_data.mailId},
|
||||
status = "pending",
|
||||
syncFreq = inbound_data.syncFreq,
|
||||
),
|
||||
session_token = inbound_headers["X-Session-Token"]
|
||||
)
|
||||
if token_id is None:
|
||||
return ResponseModel(
|
||||
|
||||
@@ -111,6 +111,7 @@ def init(blueprint_setup_state):
|
||||
@test_callback_bp.route("/callback", methods = ["POST", "GET"])
|
||||
@set_api_version(api_version = "1.0.0")
|
||||
@read_input(sanitize_headers = False, sanitize_data = False)
|
||||
@get_session_info(key = "X-Session-Token", session_coro = "get_session")
|
||||
@log_request_to_mongo(
|
||||
attr_name = "logs_mongo",
|
||||
project = constants.PROJECT_NAME,
|
||||
@@ -118,7 +119,7 @@ def init(blueprint_setup_state):
|
||||
operation = "testCllBckApi",
|
||||
log_input = True,
|
||||
log_output = True,
|
||||
sensitive_keys = None
|
||||
sensitive_keys = ["sessionToken", "X-Session-Token"]
|
||||
)
|
||||
@log_chain_to_mongo(attr_name = "logs_mongo")
|
||||
@should_not_be_under_maintenance(attr_name = "is_under_maintenance")
|
||||
@@ -130,6 +131,8 @@ async def callback_test(
|
||||
**kwargs
|
||||
):
|
||||
|
||||
print("SESSION INFO:", kwargs.get("session_info"))
|
||||
|
||||
# Return a random page:
|
||||
return await render_template(
|
||||
random.choice([
|
||||
|
||||
Reference in New Issue
Block a user