Process 1 build 0203261953

This commit is contained in:
2026-03-02 19:54:14 +13:00
parent b0ef455498
commit 9c69d9fd17
22 changed files with 672 additions and 279 deletions

View File

@@ -18,7 +18,6 @@ from ..db import (
get_user_by_username,
get_users_by_username_ci,
set_user_password,
set_jellyfin_auth_cache,
set_user_jellyseerr_id,
set_user_auth_provider,
get_signup_invite_by_code,
@@ -35,13 +34,14 @@ from ..db import (
get_global_request_leader,
get_global_request_total,
get_setting,
sync_jellyfin_password_state,
)
from ..runtime import get_runtime_settings
from ..clients.jellyfin import JellyfinClient
from ..clients.jellyseerr import JellyseerrClient
from ..security import create_access_token, verify_password
from ..security import create_stream_token
from ..auth import get_current_user
from ..auth import get_current_user, normalize_user_auth_provider, resolve_user_auth_provider
from ..config import settings
from ..services.user_cache import (
build_jellyseerr_candidate_map,
@@ -599,7 +599,7 @@ async def jellyfin_login(request: Request, form_data: OAuth2PasswordRequestForm
save_jellyfin_users_cache(users)
except Exception:
pass
set_jellyfin_auth_cache(canonical_username, password)
sync_jellyfin_password_state(canonical_username, password)
if user and user.get("jellyseerr_user_id") is None and candidate_map:
matched_id = match_jellyseerr_user_id(canonical_username, candidate_map)
if matched_id is not None:
@@ -781,7 +781,7 @@ async def signup(payload: dict) -> dict:
if jellyfin_client.configured():
logger.info("signup provisioning jellyfin username=%s", username)
auth_provider = "jellyfin"
local_password_value = "jellyfin-user"
local_password_value = password_value
try:
await jellyfin_client.create_user_with_password(username, password_value)
except httpx.HTTPStatusError as exc:
@@ -838,7 +838,7 @@ async def signup(payload: dict) -> dict:
increment_signup_invite_use(int(invite["id"]))
created_user = get_user_by_username(username)
if auth_provider == "jellyfin":
set_jellyfin_auth_cache(username, password_value)
sync_jellyfin_password_state(username, password_value)
if (
created_user
and created_user.get("jellyseerr_user_id") is None
@@ -1129,16 +1129,20 @@ async def change_password(payload: dict, current_user: dict = Depends(get_curren
status_code=status.HTTP_400_BAD_REQUEST, detail="Password must be at least 8 characters."
)
username = str(current_user.get("username") or "").strip()
auth_provider = str(current_user.get("auth_provider") or "local").lower()
if not username:
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid user")
new_password_clean = new_password.strip()
stored_user = normalize_user_auth_provider(get_user_by_username(username))
auth_provider = resolve_user_auth_provider(stored_user or current_user)
logger.info("password change requested username=%s provider=%s", username, auth_provider)
if auth_provider == "local":
user = verify_user_password(username, current_password)
if not user:
logger.warning("password change rejected username=%s provider=local reason=invalid-current-password", username)
raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Current password is incorrect")
set_user_password(username, new_password_clean)
logger.info("password change completed username=%s provider=local", username)
return {"status": "ok", "provider": "local"}
if auth_provider == "jellyfin":
@@ -1152,6 +1156,7 @@ async def change_password(payload: dict, current_user: dict = Depends(get_curren
try:
auth_result = await client.authenticate_by_name(username, current_password)
if not isinstance(auth_result, dict) or not auth_result.get("User"):
logger.warning("password change rejected username=%s provider=jellyfin reason=invalid-current-password", username)
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, detail="Current password is incorrect"
)
@@ -1159,6 +1164,7 @@ async def change_password(payload: dict, current_user: dict = Depends(get_curren
raise
except Exception as exc:
detail = _extract_http_error_detail(exc)
logger.warning("password change validation failed username=%s provider=jellyfin detail=%s", username, detail)
if isinstance(exc, httpx.HTTPStatusError) and exc.response is not None and exc.response.status_code in {401, 403}:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED, detail="Current password is incorrect"
@@ -1176,13 +1182,15 @@ async def change_password(payload: dict, current_user: dict = Depends(get_curren
await client.set_user_password(user_id, new_password_clean)
except Exception as exc:
detail = _extract_http_error_detail(exc)
logger.warning("password change update failed username=%s provider=jellyfin detail=%s", username, detail)
raise HTTPException(
status_code=status.HTTP_502_BAD_GATEWAY,
detail=f"Jellyfin password update failed: {detail}",
) from exc
# Keep Magent's Jellyfin auth cache in sync for faster subsequent sign-ins.
set_jellyfin_auth_cache(username, new_password_clean)
# Keep Magent's password hash and Jellyfin auth cache aligned with Jellyfin.
sync_jellyfin_password_state(username, new_password_clean)
logger.info("password change completed username=%s provider=jellyfin", username)
return {"status": "ok", "provider": "jellyfin"}
raise HTTPException(