@@ -23,9 +23,42 @@ def _normalize_base(api_url: str) -> str:
2323 return (api_url or "" ).strip ().rstrip ("/" )
2424
2525
26+ def normalize_authorization_token (header_value : str , header_name : str = "Authorization Token" ) -> str :
27+ normalized_value = (header_value or "" ).strip ()
28+ if not normalized_value :
29+ raise ValueError (f"{ header_name } 不能为空" )
30+ try :
31+ normalized_value .encode ("ascii" )
32+ except UnicodeEncodeError as exc :
33+ raise ValueError (f"{ header_name } 包含非 ASCII 字符,请确认填写的是实际令牌而不是中文说明" ) from exc
34+ if any (ord (ch ) < 32 or ord (ch ) == 127 for ch in normalized_value ):
35+ raise ValueError (f"{ header_name } 包含非法控制字符" )
36+ return normalized_value
37+
38+
39+ def _mask_header_value (header_value : str , keep : int = 4 ) -> str :
40+ """
41+ Mask a sensitive header value for safe logging.
42+
43+ The strategy is:
44+ - If the value is empty, return an empty string.
45+ - If the length is <= keep, fully mask it (no characters revealed).
46+ - Otherwise, reveal only the last `keep` characters and mask the rest.
47+ """
48+ if not header_value :
49+ return ""
50+
51+ length = len (header_value )
52+ if length <= keep :
53+ return "*" * length
54+
55+ masked_prefix = "*" * (length - keep )
56+ visible_suffix = header_value [- keep :]
57+ return masked_prefix + visible_suffix
2658def _build_headers (api_key : str ) -> dict :
59+ safe_api_key = normalize_authorization_token (api_key )
2760 return {
28- "Authorization" : f"Bearer { api_key } " ,
61+ "Authorization" : f"Bearer { safe_api_key } " ,
2962 "New-Api-User" : "1" ,
3063 "Content-Type" : "application/json" ,
3164 }
@@ -68,7 +101,7 @@ def upload_to_newapi(
68101 "auto_ban" : 1 ,
69102 "name" : account .email or "" ,
70103 "type" : resolved_channel_type ,
71- "key" : json .dumps ({"access_token" : account .access_token or "" , "account_id" : account_name }, ensure_ascii = False ),
104+ "key" : json .dumps ({"access_token" : account .access_token or "" , "account_id" : account_name }, ensure_ascii = True ),
72105 "base_url" : resolved_channel_base_url ,
73106 "models" : resolved_channel_models ,
74107 "multi_key_mode" : "random" ,
@@ -79,10 +112,20 @@ def upload_to_newapi(
79112 }
80113
81114 try :
115+ payload = json .dumps ({"mode" : "single" , "channel" : channel }, ensure_ascii = True )
116+ headers = _build_headers (api_key )
117+ headers ["Content-Type" ] = "application/json; charset=utf-8"
118+
119+ logger .info ("NEWAPI 上传 URL: %s" , url )
120+ safe_headers = dict (headers )
121+ if "Authorization" in safe_headers :
122+ safe_headers ["Authorization" ] = "REDACTED"
123+ logger .debug ("NEWAPI 请求头: %s" , safe_headers )
124+
82125 resp = cffi_requests .post (
83126 url ,
84- headers = _build_headers ( api_key ) ,
85- json = { "mode" : "single" , "channel" : channel } ,
127+ headers = headers ,
128+ data = payload . encode ( "utf-8" ) ,
86129 proxies = None ,
87130 timeout = 30 ,
88131 impersonate = "chrome110" ,
0 commit comments