feat: add Nox-API upstream support

This commit is contained in:
liumangmang
2026-06-30 11:22:38 +08:00
parent 9600e4ceba
commit a914d3d222
8 changed files with 189 additions and 33 deletions
+28 -5
View File
@@ -137,6 +137,8 @@ def _unwrap_list(value: Any) -> Optional[list[dict[str, Any]]]:
if isinstance(value, list):
return _normalize(value)
if isinstance(value, dict) and not _is_success_response(value):
raise UpstreamError(_response_message(value, "upstream API returned success=false"))
if isinstance(value, dict):
for key in ("data", "items", "groups", "available_groups", "availableGroups"):
nested = value.get(key)
@@ -145,8 +147,11 @@ def _unwrap_list(value: Any) -> Optional[list[dict[str, Any]]]:
elif isinstance(nested, dict):
# Handle /api/user/self/groups where data is a dict of group_name -> { desc, ratio }
out = []
for k in nested.keys():
out.append({"id": k, "name": k})
for k, item in nested.items():
row = {"id": k, "name": k}
if isinstance(item, dict):
row.update(item)
out.append(row)
return out
return None
@@ -316,9 +321,16 @@ class UpstreamClient:
bool(self.auth_config.get("new_api_user"))
or login_path == "/api/user/login"
or self.auth_type == "cookie"
or self.auth_type == "nox_token"
)
)
def _user_header_value(self) -> str:
return _clean_auth_header_value(
self.auth_config.get("user_id", "") or self.auth_config.get("new_api_user", ""),
"User header",
)
def _headers(self, auth: bool = True) -> dict[str, str]:
headers: dict[str, str] = {
"Accept": "application/json",
@@ -330,6 +342,13 @@ class UpstreamClient:
token = _clean_auth_header_value(self.auth_config.get("token", ""), "Bearer token")
if token:
headers["Authorization"] = f"Bearer {token}"
elif self.auth_type == "nox_token":
token = _clean_auth_header_value(self.auth_config.get("token", ""), "Nox access token")
user_id = self._user_header_value()
if token:
headers["Authorization"] = f"Bearer {token}"
if user_id:
headers["Nox-Api-User"] = user_id
elif self.auth_type == "api_key":
key = _clean_auth_header_value(self.auth_config.get("key", ""), "API key")
header = self.auth_config.get("header", "Authorization")
@@ -339,20 +358,24 @@ class UpstreamClient:
cookie_str = _clean_auth_header_value(self.auth_config.get("cookie_string", ""), "Cookie")
if cookie_str:
headers["Cookie"] = cookie_str
new_api_user = _clean_auth_header_value(self.auth_config.get("new_api_user", ""), "New-Api-User")
if new_api_user:
headers["New-Api-User"] = new_api_user
user_id = self._user_header_value()
if user_id:
headers["New-Api-User"] = user_id
headers["Nox-Api-User"] = user_id
elif self.auth_type == "login_password" and self._token:
token = _clean_auth_header_value(self._token, "Login token")
if token:
headers["Authorization"] = f"Bearer {token}"
if self.auth_type == "login_password" and self._new_api_user:
headers["New-Api-User"] = self._new_api_user
headers["Nox-Api-User"] = self._new_api_user
return headers
def _request(self, method: str, path: str, body: Any = None, auth: bool = True) -> Any:
if auth and self.auth_type == "cookie" and "user/self" in path and not self.auth_config.get("new_api_user"):
raise UpstreamError("New-API user endpoint requires New-Api-User; re-extract the session cookie after login and save the upstream")
if auth and self.auth_type == "nox_token" and "user/self" in path and not self._user_header_value():
raise UpstreamError("Nox-API endpoint requires Nox-Api-User; please fill user id and retry")
url = self._url(path)
if body is not None:
resp = self._client.request(