You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
57 lines
2.1 KiB
57 lines
2.1 KiB
import os |
|
import json |
|
import time |
|
import uuid |
|
import hmac |
|
import base64 |
|
import hashlib |
|
from urllib.parse import quote |
|
|
|
from flask import Blueprint, session, redirect, url_for, flash |
|
|
|
portal_service_launch_bp = Blueprint("portal_service_launch", __name__) |
|
|
|
def _b64url_encode(data: bytes) -> str: |
|
return base64.urlsafe_b64encode(data).rstrip(b"=").decode("utf-8") |
|
|
|
def _sign_payload(payload: dict, secret: str) -> str: |
|
payload_json = json.dumps(payload, separators=(",", ":"), sort_keys=True).encode("utf-8") |
|
payload_b64 = _b64url_encode(payload_json) |
|
sig = hmac.new(secret.encode("utf-8"), payload_b64.encode("utf-8"), hashlib.sha256).digest() |
|
sig_b64 = _b64url_encode(sig) |
|
return f"{payload_b64}.{sig_b64}" |
|
|
|
@portal_service_launch_bp.route("/portal/services/follow-me-launch") |
|
def portal_follow_me_launch(): |
|
portal_client_id = session.get("portal_client_id") |
|
portal_email = session.get("portal_email") |
|
|
|
if not portal_client_id or not portal_email: |
|
flash("Please sign in to launch Follow-me.", "warning") |
|
return redirect(url_for("portal_login")) |
|
|
|
secret = os.getenv("FMV2_HANDOFF_SECRET", "").strip() |
|
base_url = os.getenv("FMV2_BASE_URL", "https://follow-me.outsidethebox.top").strip().rstrip("/") |
|
ttl_seconds = int(os.getenv("FMV2_HANDOFF_TTL_SECONDS", "300")) |
|
|
|
if not secret: |
|
flash("Follow-me launch is not configured. Missing FMV2_HANDOFF_SECRET.", "danger") |
|
return redirect(url_for("portal_services.portal_services_home")) |
|
|
|
now = int(time.time()) |
|
payload = { |
|
"iss": "otb-billing", |
|
"aud": "fmv2", |
|
"jti": str(uuid.uuid4()), |
|
"iat": now, |
|
"exp": now + ttl_seconds, |
|
"portal_client_id": int(portal_client_id), |
|
"portal_email": portal_email, |
|
"portal_contact_name": session.get("portal_contact_name", ""), |
|
"portal_company_name": session.get("portal_company_name", ""), |
|
"return_to": "/dashboard", |
|
} |
|
|
|
token = _sign_payload(payload, secret) |
|
target = f"{base_url}/auth/portal-handoff?token={quote(token)}" |
|
return redirect(target)
|
|
|