mirror of
https://github.com/nirvana-7777/script.service.ultimate.git
synced 2026-09-23 01:22:17 +02:00
Fix get_manifest
This commit is contained in:
@@ -233,6 +233,7 @@ class Magenta2Provider(StreamingProvider):
|
||||
|
||||
# Initialize auth tokens (lazy - populated on first use)
|
||||
self.device_token = None
|
||||
self._persona_cache = None
|
||||
|
||||
logger.info("Magenta2 provider initialization completed successfully")
|
||||
|
||||
@@ -469,15 +470,18 @@ class Magenta2Provider(StreamingProvider):
|
||||
return False
|
||||
|
||||
def get_persona_token(self, force_refresh: bool = False) -> str:
|
||||
"""
|
||||
Get persona token - ONLY authentication entry point
|
||||
|
||||
Raises:
|
||||
Exception: If persona token cannot be obtained
|
||||
"""
|
||||
"""Get persona token with simple provider-level caching"""
|
||||
if not self.authenticator.token_flow_manager:
|
||||
raise Exception("TokenFlowManager not initialized")
|
||||
|
||||
# Optional: Add simple time-based caching at provider level
|
||||
if not force_refresh and hasattr(self, '_persona_cache'):
|
||||
cache_time, cached_token = self._persona_cache
|
||||
# Cache for 5 minutes at provider level (TokenFlowManager has proper JWT expiry)
|
||||
if time.time() - cache_time < 300:
|
||||
return cached_token
|
||||
|
||||
# Get from TokenFlowManager (which has proper JWT expiry caching)
|
||||
persona_result = self.authenticator.token_flow_manager.get_persona_token(
|
||||
force_refresh=force_refresh
|
||||
)
|
||||
@@ -485,6 +489,12 @@ class Magenta2Provider(StreamingProvider):
|
||||
if not persona_result.success:
|
||||
raise Exception(f"Failed to get persona token: {persona_result.error}")
|
||||
|
||||
# Optional: Cache in provider (simple time-based)
|
||||
if not hasattr(self, '_persona_cache'):
|
||||
self._persona_cache = (time.time(), persona_result.persona_token)
|
||||
else:
|
||||
self._persona_cache = (time.time(), persona_result.persona_token)
|
||||
|
||||
return persona_result.persona_token
|
||||
|
||||
def _ensure_authenticated(self) -> str:
|
||||
|
||||
@@ -14,7 +14,6 @@ from ...base.utils.logger import logger
|
||||
from ...base.auth.session_manager import SessionManager
|
||||
from .sam3_client import Sam3Client
|
||||
from .taa_client import TaaClient
|
||||
from .token_utils import PersonaTokenComposer
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -87,62 +86,114 @@ class TokenFlowManager:
|
||||
logger.debug(f"TokenFlowManager initialized for {provider_name}" +
|
||||
(f" ({country})" if country else ""))
|
||||
|
||||
@staticmethod
|
||||
def _compose_persona_token(access_token: str) -> Optional[str]:
|
||||
return PersonaTokenComposer.compose_from_jwt(
|
||||
jwt_token=access_token,
|
||||
fallback_account_uri=MAGENTA2_FALLBACK_ACCOUNT_URI
|
||||
)
|
||||
|
||||
def get_persona_token(self, force_refresh: bool = False) -> PersonaResult:
|
||||
"""
|
||||
Get persona token - compose from successful yo_digital token result
|
||||
"""
|
||||
"""Get persona token with proper JWT expiry caching"""
|
||||
logger.debug("=== GET_PERSONA_TOKEN START ===")
|
||||
|
||||
# Get TokenFlowResult from existing method
|
||||
token_result = self.get_yo_digital_token(force_refresh)
|
||||
logger.debug(f"token_result.success: {token_result.success}")
|
||||
logger.debug(f"token_result.access_token present: {bool(token_result.access_token)}")
|
||||
# Check for cached persona token with proper expiry validation
|
||||
if not force_refresh:
|
||||
cached_result = self._get_cached_persona_token()
|
||||
if cached_result.success:
|
||||
logger.debug("=== GET_PERSONA_TOKEN SUCCESS (cached) ===")
|
||||
return cached_result
|
||||
|
||||
# If it failed, return the failure
|
||||
if not token_result.success:
|
||||
# Get the yo_digital token
|
||||
token_result = self.get_yo_digital_token(force_refresh)
|
||||
|
||||
if not token_result.success or not token_result.access_token:
|
||||
logger.debug("=== GET_PERSONA_TOKEN FAILED (token_result failed) ===")
|
||||
return PersonaResult(
|
||||
success=False,
|
||||
error=token_result.error,
|
||||
error=token_result.error or "No access token"
|
||||
)
|
||||
|
||||
# We have success - extract access_token and compose persona_token
|
||||
access_token = token_result.access_token
|
||||
# Compose persona token with expiry information using existing method
|
||||
from .token_utils import PersonaTokenComposer
|
||||
composition_result = PersonaTokenComposer.compose_from_jwt(
|
||||
token_result.access_token,
|
||||
MAGENTA2_FALLBACK_ACCOUNT_URI
|
||||
)
|
||||
|
||||
if not access_token:
|
||||
logger.debug("=== GET_PERSONA_TOKEN FAILED (no access_token) ===")
|
||||
return PersonaResult(
|
||||
success=False,
|
||||
error="Failed to get yo_digital access token"
|
||||
)
|
||||
|
||||
logger.debug(f"About to call _compose_persona_token with access_token: {access_token[:50]}...")
|
||||
|
||||
# Compose persona_token
|
||||
persona_token = self._compose_persona_token(access_token)
|
||||
|
||||
logger.debug(f"_compose_persona_token returned: {persona_token is not None}")
|
||||
|
||||
if not persona_token:
|
||||
if not composition_result:
|
||||
logger.debug("=== GET_PERSONA_TOKEN FAILED (composition failed) ===")
|
||||
return PersonaResult(
|
||||
success=False,
|
||||
error="Failed to compose persona token"
|
||||
)
|
||||
|
||||
# Cache with the correct expiry (from persona JWT)
|
||||
self._cache_persona_composition(composition_result)
|
||||
|
||||
logger.debug("=== GET_PERSONA_TOKEN SUCCESS ===")
|
||||
return PersonaResult(
|
||||
success=True,
|
||||
persona_token=persona_token
|
||||
persona_token=composition_result.persona_token
|
||||
)
|
||||
|
||||
def _get_cached_persona_token(self) -> PersonaResult:
|
||||
"""Check for cached persona token using the actual persona JWT expiry"""
|
||||
try:
|
||||
persona_data = self.session_manager.load_scoped_token(
|
||||
self.provider_name,
|
||||
'persona',
|
||||
self.country
|
||||
)
|
||||
|
||||
if (persona_data and
|
||||
'persona_token' in persona_data and
|
||||
'persona_jwt' in persona_data and
|
||||
'expires_at' in persona_data):
|
||||
|
||||
current_time = time.time()
|
||||
expires_at = persona_data['expires_at']
|
||||
|
||||
# Check if cached token is still valid using the actual persona JWT expiry
|
||||
if current_time < (expires_at - 300): # 5-minute buffer
|
||||
logger.debug(f"Using cached persona token (expires at {time.ctime(expires_at)})")
|
||||
return PersonaResult(
|
||||
success=True,
|
||||
persona_token=persona_data['persona_token']
|
||||
)
|
||||
else:
|
||||
logger.debug(f"Cached persona token expired at {time.ctime(expires_at)}")
|
||||
|
||||
except Exception as e:
|
||||
logger.debug(f"Error checking cached persona token: {e}")
|
||||
|
||||
return PersonaResult(success=False, error="No valid cached token")
|
||||
|
||||
def _cache_persona_composition(self, composition_result) -> None:
|
||||
"""Cache persona composition with proper expiry"""
|
||||
persona_data = {
|
||||
'persona_token': composition_result.persona_token,
|
||||
'persona_jwt': composition_result.persona_jwt, # Store for validation
|
||||
'expires_at': composition_result.expires_at,
|
||||
'composed_at': composition_result.composed_at
|
||||
}
|
||||
|
||||
success = self.session_manager.save_scoped_token(
|
||||
self.provider_name,
|
||||
'persona',
|
||||
persona_data,
|
||||
self.country
|
||||
)
|
||||
|
||||
if success:
|
||||
logger.debug(f"✓ Persona token cached until {time.ctime(composition_result.expires_at)}")
|
||||
else:
|
||||
logger.debug("✗ Failed to cache persona token")
|
||||
|
||||
# Keep the existing _compose_persona_token method for backward compatibility
|
||||
@staticmethod
|
||||
def _compose_persona_token(access_token: str) -> Optional[str]:
|
||||
"""Backward compatibility method - delegates to new composition"""
|
||||
from .token_utils import PersonaTokenComposer
|
||||
result = PersonaTokenComposer.compose_from_jwt(
|
||||
access_token,
|
||||
MAGENTA2_FALLBACK_ACCOUNT_URI
|
||||
)
|
||||
return result.persona_token if result else None
|
||||
|
||||
def get_yo_digital_token(self, force_refresh: bool = False) -> TokenFlowResult:
|
||||
"""
|
||||
Get yo_digital access token following the complete hierarchy
|
||||
|
||||
@@ -7,6 +7,7 @@ Consolidates all JWT parsing and persona token composition logic
|
||||
|
||||
import base64
|
||||
import json
|
||||
import time
|
||||
from typing import Dict, Any, Optional
|
||||
from dataclasses import dataclass
|
||||
|
||||
@@ -181,105 +182,91 @@ class JWTParser:
|
||||
logger.debug(f"Failed to extract raw JWT claims: {e}")
|
||||
return None
|
||||
|
||||
@dataclass
|
||||
class PersonaCompositionResult:
|
||||
persona_token: str
|
||||
persona_jwt: str # The actual dc_cts_personaToken JWT
|
||||
expires_at: float # Expiry from persona JWT
|
||||
composed_at: float
|
||||
|
||||
def __init__(self, persona_token: str, persona_jwt: str, expires_at: float):
|
||||
self.persona_token = persona_token
|
||||
self.persona_jwt = persona_jwt
|
||||
self.expires_at = expires_at
|
||||
self.composed_at = time.time()
|
||||
|
||||
class PersonaTokenComposer:
|
||||
"""Unified persona token composition"""
|
||||
|
||||
@staticmethod
|
||||
def compose_from_jwt(jwt_token: str,
|
||||
fallback_account_uri: Optional[str] = None) -> Optional[str]:
|
||||
"""
|
||||
Compose persona token from JWT access token
|
||||
|
||||
This is the PRIMARY method for persona token composition.
|
||||
Format: Base64(account_uri + ":" + dc_cts_persona_token)
|
||||
|
||||
Args:
|
||||
jwt_token: JWT access token containing persona claims
|
||||
fallback_account_uri: Optional fallback account URI if not in JWT
|
||||
|
||||
Returns:
|
||||
Base64-encoded persona token or None
|
||||
"""
|
||||
def compose_from_jwt(jwt_token: str, fallback_account_uri: str = None) -> Optional[PersonaCompositionResult]:
|
||||
"""Compose persona token and return with expiry information"""
|
||||
try:
|
||||
# Parse JWT to extract claims
|
||||
claims = JWTParser.parse(jwt_token)
|
||||
if not claims:
|
||||
logger.error("Failed to parse JWT for persona token composition")
|
||||
return None
|
||||
|
||||
# Get persona JWT token (the nested JWT)
|
||||
# Extract the dc_cts_personaToken (this is the actual persona JWT)
|
||||
persona_jwt = claims.dc_cts_persona_token
|
||||
if not persona_jwt:
|
||||
logger.error("No dc_cts_persona_token found in JWT claims")
|
||||
logger.warning("JWT missing dc_cts_personaToken")
|
||||
return None
|
||||
|
||||
# Get account URI (prefer JWT, then fallback)
|
||||
# Get account_uri from claims or use fallback
|
||||
account_uri = claims.account_uri or fallback_account_uri
|
||||
if not account_uri:
|
||||
logger.error("No account_uri available for persona token composition")
|
||||
logger.warning("JWT missing account_uri and no fallback provided")
|
||||
return None
|
||||
|
||||
# Compose raw token
|
||||
raw_token = f"{account_uri}:{persona_jwt}"
|
||||
# Compose the persona token
|
||||
composed_token = PersonaTokenComposer._compose_token(account_uri, persona_jwt)
|
||||
if not composed_token:
|
||||
return None
|
||||
|
||||
# Base64 encode
|
||||
persona_token = base64.b64encode(
|
||||
raw_token.encode('utf-8')
|
||||
).decode('utf-8')
|
||||
# Extract expiry from the PERSONA JWT (dc_cts_personaToken), not the original JWT
|
||||
persona_expiry = PersonaTokenComposer._get_jwt_expiry(persona_jwt)
|
||||
if not persona_expiry:
|
||||
logger.warning("Could not extract expiry from persona JWT")
|
||||
return None
|
||||
|
||||
logger.info("✓ Persona token composed successfully")
|
||||
logger.debug(f"Account URI: {account_uri}")
|
||||
logger.debug(f"Persona token length: {len(persona_token)}")
|
||||
logger.debug(f"Persona token preview: {persona_token[:50]}...")
|
||||
|
||||
return persona_token
|
||||
return PersonaCompositionResult(
|
||||
persona_token=composed_token,
|
||||
persona_jwt=persona_jwt,
|
||||
expires_at=persona_expiry
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to compose persona token from JWT: {e}")
|
||||
logger.error(f"Error composing persona token: {e}")
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def compose_from_components(account_uri: str,
|
||||
dc_cts_persona_token: str) -> Optional[str]:
|
||||
"""
|
||||
Compose persona token from explicit components
|
||||
|
||||
Use this when you already have extracted components.
|
||||
|
||||
Args:
|
||||
account_uri: Account URI (e.g., "http://access.auth.theplatform.com/...")
|
||||
dc_cts_persona_token: The persona JWT token
|
||||
|
||||
Returns:
|
||||
Base64-encoded persona token or None
|
||||
"""
|
||||
def _get_jwt_expiry(jwt_token: str) -> Optional[float]:
|
||||
"""Extract expiry from any JWT token using existing JWTParser"""
|
||||
try:
|
||||
if not account_uri or not dc_cts_persona_token:
|
||||
logger.warning(
|
||||
f"Cannot compose persona token - "
|
||||
f"account_uri: {bool(account_uri)}, "
|
||||
f"dc_cts_persona_token: {bool(dc_cts_persona_token)}"
|
||||
)
|
||||
return None
|
||||
|
||||
# Compose raw token
|
||||
raw_token = f"{account_uri}:{dc_cts_persona_token}"
|
||||
|
||||
# Base64 encode
|
||||
persona_token = base64.b64encode(
|
||||
raw_token.encode('utf-8')
|
||||
).decode('utf-8')
|
||||
|
||||
logger.info("✓ Persona token composed from components")
|
||||
logger.debug(f"Composed token preview: {persona_token[:50]}...")
|
||||
|
||||
return persona_token
|
||||
|
||||
claims = JWTParser.parse(jwt_token)
|
||||
if claims and claims.raw_claims and 'exp' in claims.raw_claims:
|
||||
return float(claims.raw_claims['exp'])
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to compose persona token from components: {e}")
|
||||
logger.debug(f"Failed to extract expiry from JWT: {e}")
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def _compose_token(account_uri: str, persona_jwt: str) -> Optional[str]:
|
||||
"""Compose the actual persona token (base64 encoded)"""
|
||||
try:
|
||||
import base64
|
||||
# Format: account_uri:persona_jwt
|
||||
token_string = f"{account_uri}:{persona_jwt}"
|
||||
# Base64 encode
|
||||
encoded = base64.b64encode(token_string.encode('utf-8')).decode('utf-8')
|
||||
return encoded
|
||||
except Exception as e:
|
||||
logger.error(f"Error composing token: {e}")
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def compose_from_components(account_uri: str, dc_cts_persona_token: str) -> Optional[str]:
|
||||
"""Original method - for backward compatibility"""
|
||||
return PersonaTokenComposer._compose_token(account_uri, dc_cts_persona_token)
|
||||
|
||||
@staticmethod
|
||||
def extract_components_from_persona_token(persona_token: str) -> Optional[Dict[str, str]]:
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user