From 1f33262e9053a42d250d34dfa4a8981ce0c51592 Mon Sep 17 00:00:00 2001 From: Casey Wittrock Date: Sun, 2 Nov 2025 20:46:50 -0600 Subject: [PATCH] add whitelist proxy request method for external api calls --- custom_ui/api/__init__.py | 0 custom_ui/api/proxy.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 custom_ui/api/__init__.py create mode 100644 custom_ui/api/proxy.py diff --git a/custom_ui/api/__init__.py b/custom_ui/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/custom_ui/api/proxy.py b/custom_ui/api/proxy.py new file mode 100644 index 0000000..bfa25d9 --- /dev/null +++ b/custom_ui/api/proxy.py @@ -0,0 +1,32 @@ +import frappe +import requests +from urllib.parse import urlparse + +allowed_hosts = ["api.zippopotam.us"] # Update this list with trusted domains as needed + +@frappe.whitelist(allow_guest=True) +def proxy_request(url, method="GET", data=None, headers=None): + """ + Generic proxy for external API requests. + WARNING: Only allow requests to trusted domains. + """ + parsed_url = urlparse(url) + if parsed_url.hostname not in allowed_hosts: + frappe.throw(f"Rquests to {parsed_url.hostname} are not allowed.", frappe.PermissionError) + + try: + resp = requests.request( + method=method.upper(), + url=url, + json=frappe.parse_json(data) if data else None, + headers=frappe.parse_json(headers) if headers else None, + timeout=10 + ) + resp.raise_for_status() + try: + return resp.json() + except ValueError: + return {"text": resp.text} + except requests.exceptions.RequestException as e: + frappe.log_error(message=str(e), title="Proxy Request Failed") + frappe.throw("Failed to fetch data from external API.") \ No newline at end of file