返回提交历史
Modified
g4f/api/__init__.py
+3
-1
Modified
g4f/gui/server/backend_api.py
+21
-19
Modified
g4f/mcp/server.py
+1
-1
XFEstudio/gpt4free
fix(security): sanitize exception messages across API, GUI backend, and MCP to prevent stack trace exposure
ab2e5e92
代码差异
3 个文件
+25
-21
@@ -2345,8 +2345,10 @@ def format_exception(
2345
2345
model = config.model
2346
2346
if isinstance(e, str):
2347
2347
message = e
2348
else:
2348
elif isinstance(e, (ModelNotFoundError, ProviderNotFoundError, MissingAuthError)):
2349
2349
message = f"{e.__class__.__name__}: {e}"
2350
else:
2351
message = f"{e.__class__.__name__}: Request failed"
2350
2352
return json.dumps(
2351
2353
{
2352
2354
"error": {"message": message},
@@ -195,7 +195,7 @@ class Backend_Api(Api):
195
195
return jsonify(listing)
196
196
except Exception as e:
197
197
logger.exception(e)
198
return jsonify({"error": {"message": f"{type(e).__name__}: {e}"}}), 500
198
return jsonify({"error": {"message": "Failed to list providers"}}), 500
199
199
task = asyncio.create_task(fetch_providers())
200
200
return jsonify(saved) if saved is not None else await task
201
201
@@ -211,10 +211,10 @@ class Backend_Api(Api):
211
211
if response is None:
212
212
return jsonify({"error": {"message": "Provider not found"}}), 404
213
213
except MissingAuthError as e:
214
return jsonify({"error": {"message": f"{type(e).__name__}: {e}"}}), 401
214
return jsonify({"error": {"message": "Authentication required"}}), 401
215
215
except Exception as e:
216
216
logger.exception(e)
217
return jsonify({"error": {"message": f"{type(e).__name__}: {e}"}}), 500
217
return jsonify({"error": {"message": "Failed to get provider models"}}), 500
218
218
return jsonify(response)
219
219
220
220
@app.route("/backend-api/v2/providers", methods=["GET"])
@@ -238,7 +238,7 @@ class Backend_Api(Api):
238
238
try:
239
239
provider_class = AbstractClientFactory.create_provider(None, provider)
240
240
except ProviderNotFoundError as e:
241
return jsonify({"error": {"message": str(e)}}), 404
241
return jsonify({"error": {"message": "Provider not found"}}), 404
242
242
243
243
if request.method == "GET":
244
244
data = request.args.to_dict() or {}
@@ -254,7 +254,7 @@ class Backend_Api(Api):
254
254
return jsonify(result), 200
255
255
except Exception as e:
256
256
logger.exception(e)
257
return jsonify({"error": {"message": str(e)}}), 500
257
return jsonify({"error": {"message": "Authentication start failed"}}), 500
258
258
259
259
if hasattr(provider_class, "oauth_poll") and action == "poll":
260
260
device_code = data.get("device_code")
@@ -274,7 +274,7 @@ class Backend_Api(Api):
274
274
return jsonify(result), 200
275
275
except Exception as e:
276
276
logger.exception(e)
277
return jsonify({"error": {"message": str(e)}}), 500
277
return jsonify({"error": {"message": "OAuth poll failed"}}), 500
278
278
279
279
# Fallback: provider.login (blocking) for interactive login flows
280
280
if hasattr(provider_class, "login"):
@@ -283,7 +283,7 @@ class Backend_Api(Api):
283
283
return jsonify({"status": "success"}), 200
284
284
except Exception as e:
285
285
logger.exception(e)
286
return jsonify({"error": {"message": str(e)}}), 500
286
return jsonify({"error": {"message": "Login failed"}}), 500
287
287
288
288
return (
289
289
jsonify(
@@ -370,7 +370,7 @@ class Backend_Api(Api):
370
370
None, kwargs.pop("provider", None)
371
371
)
372
372
except ProviderNotFoundError as e:
373
return jsonify({"error": {"message": str(e)}}), 404
373
return jsonify({"error": {"message": "Provider not found"}}), 404
374
374
return self.app.response_class(
375
375
safe_iter_generator(
376
376
self._create_response_stream(
@@ -602,7 +602,7 @@ class Backend_Api(Api):
602
602
try:
603
603
provider_handler = AbstractClientFactory.create_provider(None, provider)
604
604
except ProviderNotFoundError as e:
605
return jsonify({"error": {"message": str(e)}}), 404
605
return jsonify({"error": {"message": "Provider not found"}}), 404
606
606
if not hasattr(provider_handler, "get_quota"):
607
607
return (
608
608
jsonify(
@@ -620,12 +620,12 @@ class Backend_Api(Api):
620
620
response.headers["cache-control"] = "public, max-age=3600"
621
621
return response
622
622
except MissingAuthError as e:
623
return jsonify({"error": {"message": f"{type(e).__name__}: {e}"}}), 401
623
return jsonify({"error": {"message": "Authentication required"}}), 401
624
624
except NotImplementedError as e:
625
return jsonify({"error": {"message": f"{type(e).__name__}: {e}"}}), 501
625
return jsonify({"error": {"message": "Quota check not supported"}}), 501
626
626
except Exception as e:
627
627
logger.exception(e)
628
return jsonify({"error": {"message": f"{type(e).__name__}: {e}"}}), 500
628
return jsonify({"error": {"message": "Failed to retrieve quota"}}), 500
629
629
630
630
@app.route("/backend-api/v2/log", methods=["POST"])
631
631
def add_log():
@@ -793,14 +793,14 @@ class Backend_Api(Api):
793
793
)
794
794
return Response(response, mimetype="text/plain")
795
795
except (ModelNotFoundError, ProviderNotFoundError) as e:
796
return jsonify({"error": {"message": f"{type(e).__name__}: {e}"}}), 404
796
return jsonify({"error": {"message": "Model or provider not found"}}), 404
797
797
except MissingAuthError as e:
798
return jsonify({"error": {"message": f"{type(e).__name__}: {e}"}}), 401
798
return jsonify({"error": {"message": "Authentication required"}}), 401
799
799
except RateLimitError as e:
800
return jsonify({"error": {"message": f"{type(e).__name__}: {e}"}}), 429
800
return jsonify({"error": {"message": "Rate limit exceeded"}}), 429
801
801
except Exception as e:
802
802
logger.exception(e)
803
return jsonify({"error": {"message": f"{type(e).__name__}: {e}"}}), 500
803
return jsonify({"error": {"message": "An error occurred during request generation"}}), 500
804
804
805
805
@app.route("/backend-api/v2/files/<bucket_id>/stream", methods=["GET"])
806
806
def stream_files(bucket_id: str, event_stream=True):
@@ -822,14 +822,16 @@ class Backend_Api(Api):
822
822
shutil.rmtree(bucket_dir)
823
823
return jsonify({"message": "Bucket deleted successfully"}), 200
824
824
except OSError as e:
825
logger.exception(e)
825
826
return (
826
827
jsonify(
827
{"error": {"message": f"Error deleting bucket: {str(e)}"}}
828
{"error": {"message": "Error deleting bucket"}}
828
829
),
829
830
500,
830
831
)
831
832
except Exception as e:
832
return jsonify({"error": {"message": str(e)}}), 500
833
logger.exception(e)
834
return jsonify({"error": {"message": "Failed to delete bucket"}}), 500
833
835
834
836
delete_files = request.args.get("delete_files", True)
835
837
refine_chunks_with_spacy = request.args.get(
@@ -1060,7 +1062,7 @@ class Backend_Api(Api):
1060
1062
try:
1061
1063
provider_handler = AbstractClientFactory.create_provider(None, provider)
1062
1064
except ProviderNotFoundError as e:
1063
return jsonify({"error": {"message": str(e)}}), 404
1065
return jsonify({"error": {"message": "Provider not found"}}), 404
1064
1066
if not hasattr(provider_handler, "synthesize"):
1065
1067
return (
1066
1068
jsonify({"error": {"message": "Provider doesn't support synthesize"}}),
@@ -436,7 +436,7 @@ class MCPServer:
436
436
)
437
437
except Exception as e:
438
438
sys.stderr.write(f"Synthesize error: {e}\n")
439
return web.Response(status=500, text=f"Synthesize error: {str(e)}")
439
return web.Response(status=500, text="Synthesize error: An internal error occurred")
440
440
441
441
_WORKSPACE_SAFE_TYPES: Dict[str, str] = {
442
442
"html": "text/html; charset=utf-8",