mirror of
https://github.com/nirvana-7777/script.service.ultimate.git
synced 2026-09-28 03:52:32 +02:00
Fix save refresh token
This commit is contained in:
@@ -992,69 +992,15 @@ class Magenta2Provider(StreamingProvider):
|
||||
"""
|
||||
Return a valid tvhubs-scoped access_token for use as Bearer.
|
||||
|
||||
The tvhubs token has audience "https://tvhubs.telekom.de" and is what
|
||||
the real device sends in Authorization: Bearer for all tvhubs/wcps calls.
|
||||
|
||||
If the stored token is expired, refreshes it automatically using the
|
||||
shared refresh_token via sam3_client.refresh_access_token("tvhubs").
|
||||
Falls back to None if unavailable (caller falls back to persona_jwt).
|
||||
Delegates entirely to TokenFlowManager.get_tvhubs_token() which owns
|
||||
the full lifecycle: cache check → refresh → full re-auth chain.
|
||||
No token logic lives here.
|
||||
"""
|
||||
import time as _time
|
||||
try:
|
||||
tfm = self.authenticator.token_flow_manager
|
||||
token_data = tfm.session_manager.load_scoped_token(
|
||||
self.provider_name, "tvhubs", self.country
|
||||
)
|
||||
if not token_data or not token_data.get("access_token"):
|
||||
return None
|
||||
|
||||
# Check if expired
|
||||
issued_at = token_data.get("issued_at", 0)
|
||||
expires_in = token_data.get("expires_in", 7200)
|
||||
if _time.time() < issued_at + expires_in - 60:
|
||||
# Still valid (with 60s safety margin)
|
||||
return token_data["access_token"]
|
||||
|
||||
# Expired — refresh using the shared refresh_token.
|
||||
# The refresh_token lives in top-level session data (shared across
|
||||
# all subordinate tokens: tvhubs, taa, yo_digital).
|
||||
logger.debug("tvhubs token expired, refreshing via sam3_client")
|
||||
sam3 = tfm.sam3_client
|
||||
|
||||
# Load shared refresh_token from session storage if not on instance
|
||||
shared_rt = (
|
||||
sam3.refresh_token
|
||||
if sam3 and sam3.refresh_token
|
||||
else (
|
||||
(tfm.session_manager.load_session(self.provider_name, self.country) or {})
|
||||
.get("refresh_token")
|
||||
)
|
||||
)
|
||||
if not shared_rt:
|
||||
logger.warning("Cannot refresh tvhubs token: no shared refresh_token found")
|
||||
return None
|
||||
|
||||
# Inject into sam3_client so refresh_access_token can use it
|
||||
sam3.refresh_token = shared_rt
|
||||
new_token = sam3.refresh_access_token("tvhubs")
|
||||
if new_token:
|
||||
# Persist the refreshed token
|
||||
tfm._save_tvhubs_token({
|
||||
"access_token": new_token,
|
||||
"token_type": "Bearer",
|
||||
"expires_in": 7200,
|
||||
})
|
||||
# ✅ ADD THIS — sam3 already has the new RT on its instance after get_token()
|
||||
if sam3.refresh_token:
|
||||
tfm._save_refresh_token(sam3.refresh_token)
|
||||
logger.debug("tvhubs refresh_token updated in session after refresh")
|
||||
logger.debug("tvhubs token refreshed successfully")
|
||||
return new_token
|
||||
|
||||
logger.warning("tvhubs token refresh failed")
|
||||
return self.authenticator.token_flow_manager.get_tvhubs_token()
|
||||
except Exception as exc:
|
||||
logger.debug(f"Could not load/refresh tvhubs token: {exc}")
|
||||
return None
|
||||
logger.debug(f"Could not obtain tvhubs token: {exc}")
|
||||
return None
|
||||
|
||||
def _vod_auth_headers(self) -> Dict[str, str]:
|
||||
"""
|
||||
|
||||
@@ -820,6 +820,101 @@ class TokenFlowManager:
|
||||
)
|
||||
logger.debug("tvhubs token saved")
|
||||
|
||||
# ========================================================================
|
||||
# Public API - tvhubs token (centralized lifecycle)
|
||||
# ========================================================================
|
||||
|
||||
def get_tvhubs_token(self) -> Optional[str]:
|
||||
"""
|
||||
Return a valid tvhubs-scoped access_token, managing the full lifecycle:
|
||||
|
||||
1. Cached token still valid? → return it
|
||||
2. Expired + shared refresh_token? → refresh tvhubs, save both
|
||||
access_token and refresh_token
|
||||
3. Refresh token dead/missing? → clear stale state, fall through
|
||||
to the full re-auth chain
|
||||
(line_auth → remote_login)
|
||||
4. Full chain succeeded? → tvhubs token now in session,
|
||||
return it
|
||||
|
||||
This is the single place that owns tvhubs token lifecycle at runtime.
|
||||
provider.py must never inline refresh/save logic — call this instead.
|
||||
"""
|
||||
# Step 1: valid cached token
|
||||
try:
|
||||
token_data = self.session_manager.load_scoped_token(
|
||||
self.provider_name, "tvhubs", self.country
|
||||
)
|
||||
if token_data and token_data.get("access_token"):
|
||||
if not self._is_token_expired(token_data):
|
||||
logger.debug("tvhubs token: using valid cached token")
|
||||
return token_data["access_token"]
|
||||
except Exception as exc:
|
||||
logger.debug(f"tvhubs token: error reading cache: {exc}")
|
||||
|
||||
# Step 2: try refreshing via shared refresh_token
|
||||
try:
|
||||
session_data = self.session_manager.load_session(self.provider_name, self.country) or {}
|
||||
shared_rt = self.sam3_client.refresh_token or session_data.get("refresh_token")
|
||||
|
||||
if shared_rt:
|
||||
logger.debug("tvhubs token: expired, attempting refresh")
|
||||
self.sam3_client.refresh_token = shared_rt
|
||||
new_access_token = self.sam3_client.refresh_access_token("tvhubs")
|
||||
|
||||
if new_access_token:
|
||||
# Persist the new access_token
|
||||
self._save_tvhubs_token({
|
||||
"access_token": new_access_token,
|
||||
"token_type": "Bearer",
|
||||
"expires_in": 7200,
|
||||
})
|
||||
# Persist the new refresh_token — the old one is now invalid
|
||||
if self.sam3_client.refresh_token:
|
||||
self._save_refresh_token(self.sam3_client.refresh_token)
|
||||
logger.debug("tvhubs token: refresh_token updated in session")
|
||||
logger.debug("tvhubs token: refreshed successfully")
|
||||
return new_access_token
|
||||
|
||||
# Refresh call failed → the refresh_token is dead; clear it so
|
||||
# downstream steps don't waste a round-trip attempting it again.
|
||||
logger.warning(
|
||||
"tvhubs token: refresh failed — shared refresh_token likely invalidated; "
|
||||
"clearing and falling back to full re-auth chain"
|
||||
)
|
||||
if "refresh_token" in session_data:
|
||||
del session_data["refresh_token"]
|
||||
self.session_manager.save_session(self.provider_name, session_data, self.country)
|
||||
self.sam3_client.refresh_token = None
|
||||
else:
|
||||
logger.debug("tvhubs token: no shared refresh_token available, skipping refresh")
|
||||
|
||||
except Exception as exc:
|
||||
logger.warning(f"tvhubs token: error during refresh attempt: {exc}")
|
||||
|
||||
# Step 3/4: fall back to the full re-auth chain (steps 5/6 in
|
||||
# get_yo_digital_token: line_auth → remote_login). We call
|
||||
# get_yo_digital_token with force_refresh=True so it skips the
|
||||
# yo_digital / taa checks (already known stale) and goes straight
|
||||
# to the login flows which re-acquire tvhubs + refresh_token as a
|
||||
# side effect.
|
||||
logger.info("tvhubs token: entering full re-auth chain")
|
||||
result = self.get_yo_digital_token(force_refresh=True)
|
||||
if result.success:
|
||||
# The chain saved a fresh tvhubs token as a side effect — return it.
|
||||
try:
|
||||
token_data = self.session_manager.load_scoped_token(
|
||||
self.provider_name, "tvhubs", self.country
|
||||
)
|
||||
if token_data and token_data.get("access_token"):
|
||||
logger.debug("tvhubs token: obtained via full re-auth chain")
|
||||
return token_data["access_token"]
|
||||
except Exception as exc:
|
||||
logger.debug(f"tvhubs token: error reading token after re-auth: {exc}")
|
||||
|
||||
logger.warning("tvhubs token: all acquisition attempts failed")
|
||||
return None
|
||||
|
||||
def _save_refresh_token(self, refresh_token: str) -> None:
|
||||
"""Save shared refresh_token at provider level"""
|
||||
session_data = self.session_manager.load_session(self.provider_name, self.country) or {}
|
||||
@@ -899,4 +994,4 @@ class TokenFlowManager:
|
||||
if not session_data or "refresh_token" not in session_data:
|
||||
return {"exists": False}
|
||||
|
||||
return {"exists": True, "has_refresh_token": True}
|
||||
return {"exists": True, "has_refresh_token": True}
|
||||
Reference in New Issue
Block a user