Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/api/endpoints/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ def get_config_id(catalog) -> str | None:


async def _manifest_handler(response: Response, token: str):
response.headers["Cache-Control"] = "public, max-age=7200"
response.headers["Cache-Control"] = "no-cache"

if not token:
raise HTTPException(status_code=401, detail="Missing token. Please reconfigure the addon.")
Expand Down
2 changes: 1 addition & 1 deletion app/core/version.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.1.3"
__version__ = "1.1.4"
29 changes: 28 additions & 1 deletion app/services/token_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def _ensure_secure_salt(self) -> None:
if not settings.TOKEN_SALT or settings.TOKEN_SALT == "change-me":
logger.error("Refusing to store credentials because TOKEN_SALT is unset or using the insecure default.")
raise RuntimeError(
"Server misconfiguration: TOKEN_SALT must be set to a non-default value before storing credentials."
"Server misconfiguration: TOKEN_SALT must be set to a non-default value before storing" " credentials."
)

def _get_cipher(self) -> Fernet:
Expand Down Expand Up @@ -145,6 +145,20 @@ async def store_user_data(self, user_id: str, payload: dict[str, Any]) -> str:
else:
await client.set(key, json_str)

# Invalidate async LRU cache for fresh reads on subsequent requests
try:
# bound method supports targeted invalidation by argument(s)
self.get_user_data.cache_invalidate(token)
except KeyError:
# The token was not in the cache, no action needed.
pass
except Exception as e:
logger.warning(f"Targeted cache invalidation failed: {e}. Falling back to clearing cache.")
try:
self.get_user_data.cache_clear()
except Exception as e_clear:
logger.error(f"Error while clearing cache: {e_clear}")

# Ensure we remove from negative cache so new value is read next time
try:
if token in self._missing_tokens:
Expand Down Expand Up @@ -194,6 +208,19 @@ async def delete_token(self, token: str = None, key: str = None) -> None:
client = await self._get_client()
await client.delete(key)

# Invalidate async LRU cache so future reads reflect deletion
try:
if token:
self.get_user_data.cache_invalidate(token)
else:
# If only key is provided, clear cache entirely to be safe
self.get_user_data.cache_clear()
except KeyError:
# The token was not in the cache, no action needed.
pass
except Exception as e:
logger.warning(f"Failed to invalidate user data cache during token deletion: {e}")

# Remove from negative cache as token is deleted
try:
if token and token in self._missing_tokens:
Expand Down