Spaces:
Running on Zero
Running on Zero
Update utils.py
Browse files
utils.py
CHANGED
|
@@ -1,5 +1,8 @@
|
|
| 1 |
import os
|
| 2 |
import re
|
|
|
|
|
|
|
|
|
|
| 3 |
import gradio as gr
|
| 4 |
from constants import (
|
| 5 |
DIFFUSERS_FORMAT_LORAS,
|
|
@@ -20,7 +23,6 @@ from diffusers.pipelines.pipeline_loading_utils import variant_compatible_siblin
|
|
| 20 |
from stablepy.diffusers_vanilla.utils import checkpoint_model_type
|
| 21 |
from pathlib import PosixPath
|
| 22 |
from unidecode import unidecode
|
| 23 |
-
import urllib.parse
|
| 24 |
import copy
|
| 25 |
import requests
|
| 26 |
from requests.adapters import HTTPAdapter
|
|
@@ -39,8 +41,42 @@ MODEL_ARCH = {
|
|
| 39 |
}
|
| 40 |
|
| 41 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
def read_safetensors_header_from_url(url: str):
|
| 43 |
"""Read safetensors header from a remote Hugging Face file."""
|
|
|
|
| 44 |
meta = get_hf_file_metadata(url)
|
| 45 |
|
| 46 |
# Step 1: first 8 bytes → header length
|
|
@@ -248,7 +284,7 @@ def civ_redirect_down(url, dir_, civitai_api_key, romanize, alternative_name):
|
|
| 248 |
curl_command = (
|
| 249 |
f'curl -L -sI --connect-timeout 5 --max-time 5 '
|
| 250 |
f'-H "Content-Type: application/json" '
|
| 251 |
-
f'-H "Authorization: Bearer {civitai_api_key}"
|
| 252 |
)
|
| 253 |
|
| 254 |
headers = os.popen(curl_command).read()
|
|
@@ -277,7 +313,7 @@ def civ_redirect_down(url, dir_, civitai_api_key, romanize, alternative_name):
|
|
| 277 |
|
| 278 |
wget_command = (
|
| 279 |
f'wget -c -nv '
|
| 280 |
-
f'-O
|
| 281 |
)
|
| 282 |
r_code = os.system(wget_command) # noqa
|
| 283 |
|
|
@@ -303,7 +339,7 @@ def civ_api_down(url, dir_, civitai_api_key, civ_filename):
|
|
| 303 |
if not civ_filename:
|
| 304 |
wget_command = (
|
| 305 |
f'wget -c -nv '
|
| 306 |
-
f'-P
|
| 307 |
)
|
| 308 |
os.system(wget_command)
|
| 309 |
|
|
@@ -313,12 +349,13 @@ def civ_api_down(url, dir_, civitai_api_key, civ_filename):
|
|
| 313 |
if not os.path.exists(output_path):
|
| 314 |
wget_command = (
|
| 315 |
f'wget -c -nv '
|
| 316 |
-
f'-O
|
| 317 |
)
|
| 318 |
os.system(wget_command)
|
| 319 |
|
| 320 |
return output_path
|
| 321 |
|
|
|
|
| 322 |
def drive_down(url, dir_):
|
| 323 |
import gdown
|
| 324 |
|
|
@@ -361,13 +398,13 @@ def hf_down(url, dir_, hf_token, romanize):
|
|
| 361 |
if hf_token:
|
| 362 |
os.system(
|
| 363 |
f'wget -c -nv '
|
| 364 |
-
f'--header="Authorization: Bearer {hf_token}" '
|
| 365 |
-
f'-O
|
| 366 |
)
|
| 367 |
else:
|
| 368 |
os.system(
|
| 369 |
f'wget -c -nv '
|
| 370 |
-
f'-O
|
| 371 |
)
|
| 372 |
|
| 373 |
return output_path
|
|
@@ -375,13 +412,26 @@ def hf_down(url, dir_, hf_token, romanize):
|
|
| 375 |
|
| 376 |
def download_things(directory, url, hf_token="", civitai_api_key="", romanize=False):
|
| 377 |
url = url.strip()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 378 |
downloaded_file_path = None
|
| 379 |
|
| 380 |
-
if "drive.google.com"
|
| 381 |
downloaded_file_path = drive_down(url, directory)
|
| 382 |
-
elif "huggingface.co"
|
| 383 |
downloaded_file_path = hf_down(url, directory, hf_token, romanize)
|
| 384 |
-
elif "civitai."
|
| 385 |
url = url.replace("civitai.red", "civitai.com")
|
| 386 |
if not civitai_api_key:
|
| 387 |
msg = "You need an API key to download Civitai models."
|
|
@@ -407,7 +457,7 @@ def download_things(directory, url, hf_token="", civitai_api_key="", romanize=Fa
|
|
| 407 |
else:
|
| 408 |
os.system(
|
| 409 |
f'wget -c -nv '
|
| 410 |
-
f'-P
|
| 411 |
)
|
| 412 |
|
| 413 |
return downloaded_file_path
|
|
@@ -726,4 +776,4 @@ def html_template_message(msg):
|
|
| 726 |
|
| 727 |
def escape_html(text):
|
| 728 |
"""Escapes HTML special characters in the input text."""
|
| 729 |
-
return text.replace("<", "<").replace(">", ">").replace("\n", "<br>")
|
|
|
|
| 1 |
import os
|
| 2 |
import re
|
| 3 |
+
import ipaddress
|
| 4 |
+
import urllib.parse
|
| 5 |
+
from shlex import quote as shqt
|
| 6 |
import gradio as gr
|
| 7 |
from constants import (
|
| 8 |
DIFFUSERS_FORMAT_LORAS,
|
|
|
|
| 23 |
from stablepy.diffusers_vanilla.utils import checkpoint_model_type
|
| 24 |
from pathlib import PosixPath
|
| 25 |
from unidecode import unidecode
|
|
|
|
| 26 |
import copy
|
| 27 |
import requests
|
| 28 |
from requests.adapters import HTTPAdapter
|
|
|
|
| 41 |
}
|
| 42 |
|
| 43 |
|
| 44 |
+
def validate_url(url: str) -> str:
|
| 45 |
+
"""Validate URL protocol and block SSRF (localhost, private & cloud metadata IPs)."""
|
| 46 |
+
url = url.strip()
|
| 47 |
+
if not url:
|
| 48 |
+
raise ValueError("URL cannot be empty.")
|
| 49 |
+
|
| 50 |
+
parsed = urllib.parse.urlparse(url)
|
| 51 |
+
if parsed.scheme not in ("http", "https"):
|
| 52 |
+
raise ValueError(f"Invalid protocol '{parsed.scheme}'. Only HTTP/HTTPS are allowed.")
|
| 53 |
+
|
| 54 |
+
hostname = (parsed.hostname or "").lower()
|
| 55 |
+
if not hostname:
|
| 56 |
+
raise ValueError("Invalid URL: missing hostname.")
|
| 57 |
+
|
| 58 |
+
# SSRF Protection: Block loopback and local hosts
|
| 59 |
+
if hostname in ("localhost", "0.0.0.0", "127.0.0.1", "::1"):
|
| 60 |
+
raise ValueError("Access to local/loopback address is blocked.")
|
| 61 |
+
|
| 62 |
+
# SSRF Protection: Block private and link-local / cloud metadata IPs (e.g. 169.254.169.254)
|
| 63 |
+
try:
|
| 64 |
+
ip = ipaddress.ip_address(hostname)
|
| 65 |
+
if ip.is_private or ip.is_loopback or ip.is_link_local or ip.is_reserved:
|
| 66 |
+
raise ValueError(f"Access to internal IP ({hostname}) is blocked.")
|
| 67 |
+
except ValueError:
|
| 68 |
+
pass # Standard domain name
|
| 69 |
+
|
| 70 |
+
# Normalize Civitai domain alias
|
| 71 |
+
if hostname == "civitai.red" or hostname.endswith(".civitai.red"):
|
| 72 |
+
url = url.replace("civitai.red", "civitai.com")
|
| 73 |
+
|
| 74 |
+
return url
|
| 75 |
+
|
| 76 |
+
|
| 77 |
def read_safetensors_header_from_url(url: str):
|
| 78 |
"""Read safetensors header from a remote Hugging Face file."""
|
| 79 |
+
url = validate_url(url)
|
| 80 |
meta = get_hf_file_metadata(url)
|
| 81 |
|
| 82 |
# Step 1: first 8 bytes → header length
|
|
|
|
| 284 |
curl_command = (
|
| 285 |
f'curl -L -sI --connect-timeout 5 --max-time 5 '
|
| 286 |
f'-H "Content-Type: application/json" '
|
| 287 |
+
f'-H {shqt(f"Authorization: Bearer {civitai_api_key}")} {shqt(url)}'
|
| 288 |
)
|
| 289 |
|
| 290 |
headers = os.popen(curl_command).read()
|
|
|
|
| 313 |
|
| 314 |
wget_command = (
|
| 315 |
f'wget -c -nv '
|
| 316 |
+
f'-O {shqt(os.path.join(dir_, filename_base))} {shqt(redirect_url)}'
|
| 317 |
)
|
| 318 |
r_code = os.system(wget_command) # noqa
|
| 319 |
|
|
|
|
| 339 |
if not civ_filename:
|
| 340 |
wget_command = (
|
| 341 |
f'wget -c -nv '
|
| 342 |
+
f'-P {shqt(dir_)} {shqt(url_dl)}'
|
| 343 |
)
|
| 344 |
os.system(wget_command)
|
| 345 |
|
|
|
|
| 349 |
if not os.path.exists(output_path):
|
| 350 |
wget_command = (
|
| 351 |
f'wget -c -nv '
|
| 352 |
+
f'-O {shqt(output_path)} {shqt(url_dl)}'
|
| 353 |
)
|
| 354 |
os.system(wget_command)
|
| 355 |
|
| 356 |
return output_path
|
| 357 |
|
| 358 |
+
|
| 359 |
def drive_down(url, dir_):
|
| 360 |
import gdown
|
| 361 |
|
|
|
|
| 398 |
if hf_token:
|
| 399 |
os.system(
|
| 400 |
f'wget -c -nv '
|
| 401 |
+
f'--header={shqt(f"Authorization: Bearer {hf_token}")} '
|
| 402 |
+
f'-O {shqt(output_path)} {shqt(url)}'
|
| 403 |
)
|
| 404 |
else:
|
| 405 |
os.system(
|
| 406 |
f'wget -c -nv '
|
| 407 |
+
f'-O {shqt(output_path)} {shqt(url)}'
|
| 408 |
)
|
| 409 |
|
| 410 |
return output_path
|
|
|
|
| 412 |
|
| 413 |
def download_things(directory, url, hf_token="", civitai_api_key="", romanize=False):
|
| 414 |
url = url.strip()
|
| 415 |
+
if not url:
|
| 416 |
+
return None
|
| 417 |
+
|
| 418 |
+
# SSRF & protocol validation
|
| 419 |
+
try:
|
| 420 |
+
url = validate_url(url)
|
| 421 |
+
except Exception as e:
|
| 422 |
+
msg = f"Download blocked: {e}"
|
| 423 |
+
print(f"\033[91m{msg}\033[0m")
|
| 424 |
+
gr.Warning(msg)
|
| 425 |
+
return None
|
| 426 |
+
|
| 427 |
+
hostname = (urllib.parse.urlparse(url).hostname or "").lower()
|
| 428 |
downloaded_file_path = None
|
| 429 |
|
| 430 |
+
if hostname == "drive.google.com" or hostname.endswith(".drive.google.com"):
|
| 431 |
downloaded_file_path = drive_down(url, directory)
|
| 432 |
+
elif hostname in ("huggingface.co", "hf.co") or hostname.endswith((".huggingface.co", ".hf.co")):
|
| 433 |
downloaded_file_path = hf_down(url, directory, hf_token, romanize)
|
| 434 |
+
elif hostname == "civitai.com" or hostname.endswith(".civitai.com"):
|
| 435 |
url = url.replace("civitai.red", "civitai.com")
|
| 436 |
if not civitai_api_key:
|
| 437 |
msg = "You need an API key to download Civitai models."
|
|
|
|
| 457 |
else:
|
| 458 |
os.system(
|
| 459 |
f'wget -c -nv '
|
| 460 |
+
f'-P {shqt(directory)} {shqt(url)}'
|
| 461 |
)
|
| 462 |
|
| 463 |
return downloaded_file_path
|
|
|
|
| 776 |
|
| 777 |
def escape_html(text):
|
| 778 |
"""Escapes HTML special characters in the input text."""
|
| 779 |
+
return text.replace("<", "<").replace(">", ">").replace("\n", "<br>")
|