(20241127) Testing GMail auth.

This commit is contained in:
2024-11-27 20:14:04 +05:30
parent 269e36ec27
commit 2e7f1cb626
9 changed files with 336 additions and 238 deletions
+89 -40
View File
@@ -6,11 +6,12 @@
DATE:
Monday, 25th Nov., 2024
Wednesday, 27th Nov., 2024
OBJECTIVE:
To receive callbacks (webhooks).
To receive authorization requests (OAuth2.0) for various mail providers and accordingly respond with the
authorization request URLs.
REFERENCES:
@@ -62,6 +63,15 @@ from utils_v2.api.async_quart import (
# Common:
from shared import constants
# Behaviour Models:
from models.behaviour.mail.oauth import MailOAuthModel
# Data Models:
from models.data.mail.oauth import (
OAuthMailAuthorizationRequestHeaders,
OAuthMailAuthorizationRequestData
)
# For asynchronous activities:
import asyncio
@@ -74,7 +84,7 @@ import asyncio
# Related to Quart:
mail_callback_bp = Blueprint("mail_cb", __name__)
mail_oauth_bp = Blueprint("mail_oauth", __name__)
# *****************************************************************************************************************
@@ -94,7 +104,7 @@ mail_callback_bp = Blueprint("mail_cb", __name__)
# *****************************************************************************************************************
@mail_callback_bp.record_once
@mail_oauth_bp.record_once
def init(blueprint_setup_state):
# This gets called when the blueprint is registered.
@@ -105,30 +115,38 @@ def init(blueprint_setup_state):
# ---------------------------------------------------------------------------------------------------------------------
@mail_callback_bp.route("/callback/gmail", methods = ["POST", "GET"])
@mail_oauth_bp.route("/auth/oauth/url/request", methods = ["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,
log_type = constants.MODULE_NAME,
operation = "gmailCllBckApi",
operation = "mailOAuthUrlReqApi",
log_input = True,
log_output = True,
sensitive_keys = None
sensitive_keys = ["sessionToken"]
)
@log_chain_to_mongo(attr_name = "logs_mongo")
@should_not_be_under_maintenance(attr_name = "is_under_maintenance")
@validate_input(
header_validator = lambda x: OAuthMailAuthorizationRequestHeaders(**x).model_dump(),
data_validator = lambda x: OAuthMailAuthorizationRequestData(**x)
)
@handle_cancelled_request()
async def mail_callback(
inbound_headers: dict = None,
inbound_data: dict = None,
async def request_oauth_authorization_url(
inbound_headers: dict | OAuthMailAuthorizationRequestHeaders = None,
inbound_data: dict | OAuthMailAuthorizationRequestData = None,
inbound_files: dict = None,
**kwargs
):
"""
Use this when authorizing access to someone's GMail account. This can be used to capture the authentication token.
Use this when requesting access to someone's GMail account. This API should be used from the UI. A button click
"Connect to GMail" should hit this API, which will generate a request to gain access to the user's GMail account.
When the URL is hit, it opens Google's own UI, and, when the user clicks "Continue", Google hits your 'redirect_url'
to inform you about the user's action.
:param inbound_headers: auto-extracted by the decorators.
:param inbound_data: auto-extracted by the decorators.
:param inbound_files: auto-extracted by the decorators.
@@ -136,39 +154,70 @@ async def mail_callback(
:return: A standard response structure.
"""
# Construct a message:
message = "🪝 *WEBHOOK/CALLBACK ALERT!* 🪝\n\n"
message += f"Method: *{request.method}*\nLog Id.: `{kwargs.get('log_id')}`\n\n"
message += "*Headers:*\n```json\n"
message += json.to_string({k: v for k, v in request.headers.items()})
message += "\n```\n"
message += "*Query Args:*\n```json\n"
message += json.to_string(request.args.to_dict())
message += "\n```\n"
message += "*JSON:*\n```json\n"
message += json.to_string(await request.get_json())
message += "\n```\n"
message += "*Form-Data:*\n```json\n"
message += json.to_string((await request.form).to_dict())
message += "\n```\n"
message += "*Form-Files:*\n```json\n"
message += json.to_string(inbound_files, default = str)
message += "\n```\n"
# ┏┓
# ┃┃┏┓┏┓┏┓┏┓┏┓┏┏┓┏┏
# ┣┛┛ ┗ ┣┛┛ ┗┛┗┗ ┛┛
# ┛
# Send a message on Telegram:
api_response = await current_app.http_client.post(
url = current_app.script_data["alerts"]["url"],
json = {
"message": message,
"type": "info",
"chatId": "1275560043" # ... KPS
}
# If the session token is invalid/expired:
if kwargs.get("session_info") is None:
return ResponseModel(
status_code = StatusCodes.FAILED,
http_code = HttpCodes.UNAUTHORIZED
)
# Start by assuming failure:
auth_url = None
# ┳ ┓ •┏ ┳┳
# ┃┏┫┏┓┏┓╋┓╋┓┏ ┃┃┏┏┓┏┓
# ┻┗┻┗ ┛┗┗┗┛┗┫ ┗┛┛┗ ┛
# ┛
# Make a user identifier from the session info:
user_identifier = await MailOAuthModel.get_id(
db_conn = current_app.data_mongo,
user_info = kwargs["session_info"],
service_type = "email",
service_client = inbound_data.mailClient,
auth_type = "oauth"
)
if user_identifier is None:
return ResponseModel(
status_code = StatusCodes.FAILED,
http_code = HttpCodes.INTERNAL_SERVER_ERROR,
message = "failed to generate user identifier"
)
user_identifier = str(user_identifier)
# Return a success response:
# ┏┓ ┏┓┳┳┓ •┓
# ┣ ┏┓┏┓ ┃┓┃┃┃┏┓┓┃
# ┻ ┗┛┛ ┗┛┛ ┗┗┻┗┗
if inbound_data.mailClient == "gmail":
# Get the authorization URL:
auth_url = await current_app.gmail_client.get_authorization_url(
state = user_identifier,
access_type = "offline",
approval_prompt = "force",
include_granted_scopes = "true",
user_email = None
)
# ┳┓
# ┣┫┏┓┏┏┓┏┓┏┓┏┏┓
# ┛┗┗ ┛┣┛┗┛┛┗┛┗
# ┛
# Done here:
return ResponseModel(
status_code = StatusCodes.OK,
data = {"accepted": True}
status_code = StatusCodes.OK if auth_url else StatusCodes.FAILED,
http_code = HttpCodes.SUCCESS if auth_url else HttpCodes.INTERNAL_SERVER_ERROR,
data = {
"mailClient": inbound_data.mailClient,
"authorizationUrl": auth_url
}
)