Skip to content

Commit 9d832a1

Browse files
committed
fix: accept civitai.red as an allowed CivitAI host
civitai.red is an official Civitai domain (NSFW-inclusive front door to the same accounts, database, and REST API as civitai.com). Previously the host allowlist only matched civitai.com, so the configured CivitAI API token was never attached to civitai.red downloads and gated content failed with 401. Lift the allowed hosts to a single CIVITAI_ALLOWED_HOSTS constant in constants.py and use it for both exact-match and subdomain-suffix checks. Adding future Civitai TLDs is now a one-line change. Anti-spoofing semantics (e.g. evilcivitai.red, civitai.red.evil.com) are preserved. Signed-off-by: Alexander Piskun <bigcat88@icloud.com>
1 parent f33bdad commit 9d832a1

3 files changed

Lines changed: 39 additions & 1 deletion

File tree

comfy_cli/command/models/models.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
workspace_manager = WorkspaceManager()
2222
config_manager = ConfigManager()
2323

24+
_CIVITAI_SUBDOMAIN_SUFFIXES = tuple(f".{h}" for h in constants.CIVITAI_ALLOWED_HOSTS)
25+
2426

2527
model_path_map = {
2628
"lora": "loras",
@@ -99,7 +101,7 @@ def check_civitai_url(url: str) -> tuple[bool, bool, int | None, int | None]:
99101
try:
100102
parsed = urlparse(url)
101103
host = (parsed.hostname or "").lower()
102-
if host != "civitai.com" and not host.endswith(".civitai.com"):
104+
if host not in constants.CIVITAI_ALLOWED_HOSTS and not host.endswith(_CIVITAI_SUBDOMAIN_SUFFIXES):
103105
return False, False, None, None
104106
p_parts = [p for p in parsed.path.split("/") if p]
105107
query = parse_qs(parsed.query)

comfy_cli/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ class PROC(str, Enum):
4747

4848
CIVITAI_API_TOKEN_KEY = "civitai_api_token"
4949
CIVITAI_API_TOKEN_ENV_KEY = "CIVITAI_API_TOKEN"
50+
CIVITAI_ALLOWED_HOSTS: tuple[str, ...] = ("civitai.com", "civitai.red")
5051
HF_API_TOKEN_KEY = "hf_api_token"
5152
HF_API_TOKEN_ENV_KEY = "HF_API_TOKEN"
5253

tests/comfy_cli/command/models/test_models.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,41 @@ def test_non_evil_civitai_url():
244244
assert check_civitai_url(url) == (False, False, None, None)
245245

246246

247+
def test_valid_model_url_red_domain():
248+
url = "https://civitai.red/models/43331"
249+
assert check_civitai_url(url) == (True, False, 43331, None)
250+
251+
252+
def test_valid_model_url_red_with_query():
253+
url = "https://civitai.red/models/43331?modelVersionId=485088"
254+
assert check_civitai_url(url) == (True, False, 43331, 485088)
255+
256+
257+
def test_valid_api_download_url_red_domain():
258+
url = "https://civitai.red/api/download/models/1617665?type=Model&format=SafeTensor"
259+
assert check_civitai_url(url) == (False, True, None, 1617665)
260+
261+
262+
def test_valid_api_v1_model_versions_url_red_domain():
263+
url = "https://civitai.red/api/v1/model-versions/1617665"
264+
assert check_civitai_url(url) == (False, True, None, 1617665)
265+
266+
267+
def test_www_subdomain_red_is_accepted():
268+
url = "https://www.civitai.red/models/43331?version=12345"
269+
assert check_civitai_url(url) == (True, False, 43331, 12345)
270+
271+
272+
def test_non_evil_civitai_red_url():
273+
url = "https://evilcivitai.red/models/43331?version=12345"
274+
assert check_civitai_url(url) == (False, False, None, None)
275+
276+
277+
def test_red_as_spoofed_subdomain_of_other_tld():
278+
url = "https://civitai.red.evil.com/models/43331"
279+
assert check_civitai_url(url) == (False, False, None, None)
280+
281+
247282
def test_valid_huggingface_url():
248283
url = "https://huggingface.co/CompVis/stable-diffusion-v1-4/resolve/main/sd-v1-4.ckpt"
249284
assert check_huggingface_url(url) == (True, "CompVis/stable-diffusion-v1-4", "sd-v1-4.ckpt", None, "main")

0 commit comments

Comments
 (0)