mirror of
https://github.com/comfyanonymous/ComfyUI.git
synced 2026-05-29 04:07:32 +08:00
Compare commits
14 Commits
rename-str
...
proxy-widg
| Author | SHA1 | Date | |
|---|---|---|---|
| 6e831a1ab3 | |||
| 7083484a48 | |||
| 4b1444fc7a | |||
| 8cbbea8f6a | |||
| 13917b3880 | |||
| f21f6b2212 | |||
| eb0686bbb6 | |||
| 5de94e70ec | |||
| 76b75f3ad7 | |||
| 0c63b4f6e3 | |||
| 7d437687c2 | |||
| e2ddf28d78 | |||
| 076639fed9 | |||
| 55e6478526 |
36
.github/workflows/release-stable-all.yml
vendored
36
.github/workflows/release-stable-all.yml
vendored
@ -20,29 +20,12 @@ jobs:
|
|||||||
git_tag: ${{ inputs.git_tag }}
|
git_tag: ${{ inputs.git_tag }}
|
||||||
cache_tag: "cu130"
|
cache_tag: "cu130"
|
||||||
python_minor: "13"
|
python_minor: "13"
|
||||||
python_patch: "11"
|
python_patch: "12"
|
||||||
rel_name: "nvidia"
|
rel_name: "nvidia"
|
||||||
rel_extra_name: ""
|
rel_extra_name: ""
|
||||||
test_release: true
|
test_release: true
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
release_nvidia_cu128:
|
|
||||||
permissions:
|
|
||||||
contents: "write"
|
|
||||||
packages: "write"
|
|
||||||
pull-requests: "read"
|
|
||||||
name: "Release NVIDIA cu128"
|
|
||||||
uses: ./.github/workflows/stable-release.yml
|
|
||||||
with:
|
|
||||||
git_tag: ${{ inputs.git_tag }}
|
|
||||||
cache_tag: "cu128"
|
|
||||||
python_minor: "12"
|
|
||||||
python_patch: "10"
|
|
||||||
rel_name: "nvidia"
|
|
||||||
rel_extra_name: "_cu128"
|
|
||||||
test_release: true
|
|
||||||
secrets: inherit
|
|
||||||
|
|
||||||
release_nvidia_cu126:
|
release_nvidia_cu126:
|
||||||
permissions:
|
permissions:
|
||||||
contents: "write"
|
contents: "write"
|
||||||
@ -76,3 +59,20 @@ jobs:
|
|||||||
rel_extra_name: ""
|
rel_extra_name: ""
|
||||||
test_release: false
|
test_release: false
|
||||||
secrets: inherit
|
secrets: inherit
|
||||||
|
|
||||||
|
release_xpu:
|
||||||
|
permissions:
|
||||||
|
contents: "write"
|
||||||
|
packages: "write"
|
||||||
|
pull-requests: "read"
|
||||||
|
name: "Release Intel XPU"
|
||||||
|
uses: ./.github/workflows/stable-release.yml
|
||||||
|
with:
|
||||||
|
git_tag: ${{ inputs.git_tag }}
|
||||||
|
cache_tag: "xpu"
|
||||||
|
python_minor: "13"
|
||||||
|
python_patch: "12"
|
||||||
|
rel_name: "intel"
|
||||||
|
rel_extra_name: ""
|
||||||
|
test_release: true
|
||||||
|
secrets: inherit
|
||||||
|
|||||||
@ -61,6 +61,7 @@ See what ComfyUI can do with the [newer template workflows](https://comfy.org/wo
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
- Nodes/graph/flowchart interface to experiment and create complex Stable Diffusion workflows without needing to code anything.
|
- Nodes/graph/flowchart interface to experiment and create complex Stable Diffusion workflows without needing to code anything.
|
||||||
|
- NOTE: There are many more models supported than the list below, if you want to see what is supported see our templates list inside ComfyUI.
|
||||||
- Image Models
|
- Image Models
|
||||||
- SD1.x, SD2.x ([unCLIP](https://comfyanonymous.github.io/ComfyUI_examples/unclip/))
|
- SD1.x, SD2.x ([unCLIP](https://comfyanonymous.github.io/ComfyUI_examples/unclip/))
|
||||||
- [SDXL](https://comfyanonymous.github.io/ComfyUI_examples/sdxl/), [SDXL Turbo](https://comfyanonymous.github.io/ComfyUI_examples/sdturbo/)
|
- [SDXL](https://comfyanonymous.github.io/ComfyUI_examples/sdxl/), [SDXL Turbo](https://comfyanonymous.github.io/ComfyUI_examples/sdturbo/)
|
||||||
@ -136,7 +137,7 @@ ComfyUI follows a weekly release cycle targeting Monday but this regularly chang
|
|||||||
- Builds a new release using the latest stable core version
|
- Builds a new release using the latest stable core version
|
||||||
|
|
||||||
3. **[ComfyUI Frontend](https://github.com/Comfy-Org/ComfyUI_frontend)**
|
3. **[ComfyUI Frontend](https://github.com/Comfy-Org/ComfyUI_frontend)**
|
||||||
- Weekly frontend updates are merged into the core repository
|
- Every 2+ weeks frontend updates are merged into the core repository
|
||||||
- Features are frozen for the upcoming core release
|
- Features are frozen for the upcoming core release
|
||||||
- Development continues for the next release cycle
|
- Development continues for the next release cycle
|
||||||
|
|
||||||
@ -275,7 +276,7 @@ Nvidia users should install stable pytorch using this command:
|
|||||||
|
|
||||||
This is the command to install pytorch nightly instead which might have performance improvements.
|
This is the command to install pytorch nightly instead which might have performance improvements.
|
||||||
|
|
||||||
```pip install --pre torch torchvision torchaudio --index-url https://download.pytorch.org/whl/nightly/cu130```
|
```pip install --pre torch torchvision torchaudio --index-url https://download.pytorch.org/whl/nightly/cu132```
|
||||||
|
|
||||||
#### Troubleshooting
|
#### Troubleshooting
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -3,12 +3,9 @@ from ..diffusionmodules.openaimodel import Timestep
|
|||||||
import torch
|
import torch
|
||||||
|
|
||||||
class CLIPEmbeddingNoiseAugmentation(ImageConcatWithNoiseAugmentation):
|
class CLIPEmbeddingNoiseAugmentation(ImageConcatWithNoiseAugmentation):
|
||||||
def __init__(self, *args, clip_stats_path=None, timestep_dim=256, **kwargs):
|
def __init__(self, *args, timestep_dim=256, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
if clip_stats_path is None:
|
clip_mean, clip_std = torch.zeros(timestep_dim), torch.ones(timestep_dim)
|
||||||
clip_mean, clip_std = torch.zeros(timestep_dim), torch.ones(timestep_dim)
|
|
||||||
else:
|
|
||||||
clip_mean, clip_std = torch.load(clip_stats_path, map_location="cpu")
|
|
||||||
self.register_buffer("data_mean", clip_mean[None, :], persistent=False)
|
self.register_buffer("data_mean", clip_mean[None, :], persistent=False)
|
||||||
self.register_buffer("data_std", clip_std[None, :], persistent=False)
|
self.register_buffer("data_std", clip_std[None, :], persistent=False)
|
||||||
self.time_embed = Timestep(timestep_dim)
|
self.time_embed = Timestep(timestep_dim)
|
||||||
|
|||||||
@ -1745,6 +1745,8 @@ def load_diffusion_model_state_dict(sd, model_options={}, metadata=None, disable
|
|||||||
temp_sd = comfy.utils.state_dict_prefix_replace(sd, {diffusion_model_prefix: ""}, filter_keys=True)
|
temp_sd = comfy.utils.state_dict_prefix_replace(sd, {diffusion_model_prefix: ""}, filter_keys=True)
|
||||||
if len(temp_sd) > 0:
|
if len(temp_sd) > 0:
|
||||||
sd = temp_sd
|
sd = temp_sd
|
||||||
|
if custom_operations is None:
|
||||||
|
sd, metadata = comfy.utils.convert_old_quants(sd, "", metadata=metadata)
|
||||||
|
|
||||||
parameters = comfy.utils.calculate_parameters(sd)
|
parameters = comfy.utils.calculate_parameters(sd)
|
||||||
weight_dtype = comfy.utils.weight_dtype(sd)
|
weight_dtype = comfy.utils.weight_dtype(sd)
|
||||||
|
|||||||
226
comfy_api_nodes/apis/wan.py
Normal file
226
comfy_api_nodes/apis/wan.py
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
|
||||||
|
class Text2ImageInputField(BaseModel):
|
||||||
|
prompt: str = Field(...)
|
||||||
|
negative_prompt: str | None = Field(None)
|
||||||
|
|
||||||
|
|
||||||
|
class Image2ImageInputField(BaseModel):
|
||||||
|
prompt: str = Field(...)
|
||||||
|
negative_prompt: str | None = Field(None)
|
||||||
|
images: list[str] = Field(..., min_length=1, max_length=2)
|
||||||
|
|
||||||
|
|
||||||
|
class Text2VideoInputField(BaseModel):
|
||||||
|
prompt: str = Field(...)
|
||||||
|
negative_prompt: str | None = Field(None)
|
||||||
|
audio_url: str | None = Field(None)
|
||||||
|
|
||||||
|
|
||||||
|
class Image2VideoInputField(BaseModel):
|
||||||
|
prompt: str = Field(...)
|
||||||
|
negative_prompt: str | None = Field(None)
|
||||||
|
img_url: str = Field(...)
|
||||||
|
audio_url: str | None = Field(None)
|
||||||
|
|
||||||
|
|
||||||
|
class Reference2VideoInputField(BaseModel):
|
||||||
|
prompt: str = Field(...)
|
||||||
|
negative_prompt: str | None = Field(None)
|
||||||
|
reference_video_urls: list[str] = Field(...)
|
||||||
|
|
||||||
|
|
||||||
|
class Txt2ImageParametersField(BaseModel):
|
||||||
|
size: str = Field(...)
|
||||||
|
n: int = Field(1, description="Number of images to generate.") # we support only value=1
|
||||||
|
seed: int = Field(..., ge=0, le=2147483647)
|
||||||
|
prompt_extend: bool = Field(True)
|
||||||
|
watermark: bool = Field(False)
|
||||||
|
|
||||||
|
|
||||||
|
class Image2ImageParametersField(BaseModel):
|
||||||
|
size: str | None = Field(None)
|
||||||
|
n: int = Field(1, description="Number of images to generate.") # we support only value=1
|
||||||
|
seed: int = Field(..., ge=0, le=2147483647)
|
||||||
|
watermark: bool = Field(False)
|
||||||
|
|
||||||
|
|
||||||
|
class Text2VideoParametersField(BaseModel):
|
||||||
|
size: str = Field(...)
|
||||||
|
seed: int = Field(..., ge=0, le=2147483647)
|
||||||
|
duration: int = Field(5, ge=5, le=15)
|
||||||
|
prompt_extend: bool = Field(True)
|
||||||
|
watermark: bool = Field(False)
|
||||||
|
audio: bool = Field(False, description="Whether to generate audio automatically.")
|
||||||
|
shot_type: str = Field("single")
|
||||||
|
|
||||||
|
|
||||||
|
class Image2VideoParametersField(BaseModel):
|
||||||
|
resolution: str = Field(...)
|
||||||
|
seed: int = Field(..., ge=0, le=2147483647)
|
||||||
|
duration: int = Field(5, ge=5, le=15)
|
||||||
|
prompt_extend: bool = Field(True)
|
||||||
|
watermark: bool = Field(False)
|
||||||
|
audio: bool = Field(False, description="Whether to generate audio automatically.")
|
||||||
|
shot_type: str = Field("single")
|
||||||
|
|
||||||
|
|
||||||
|
class Reference2VideoParametersField(BaseModel):
|
||||||
|
size: str = Field(...)
|
||||||
|
duration: int = Field(5, ge=5, le=15)
|
||||||
|
shot_type: str = Field("single")
|
||||||
|
seed: int = Field(..., ge=0, le=2147483647)
|
||||||
|
watermark: bool = Field(False)
|
||||||
|
|
||||||
|
|
||||||
|
class Text2ImageTaskCreationRequest(BaseModel):
|
||||||
|
model: str = Field(...)
|
||||||
|
input: Text2ImageInputField = Field(...)
|
||||||
|
parameters: Txt2ImageParametersField = Field(...)
|
||||||
|
|
||||||
|
|
||||||
|
class Image2ImageTaskCreationRequest(BaseModel):
|
||||||
|
model: str = Field(...)
|
||||||
|
input: Image2ImageInputField = Field(...)
|
||||||
|
parameters: Image2ImageParametersField = Field(...)
|
||||||
|
|
||||||
|
|
||||||
|
class Text2VideoTaskCreationRequest(BaseModel):
|
||||||
|
model: str = Field(...)
|
||||||
|
input: Text2VideoInputField = Field(...)
|
||||||
|
parameters: Text2VideoParametersField = Field(...)
|
||||||
|
|
||||||
|
|
||||||
|
class Image2VideoTaskCreationRequest(BaseModel):
|
||||||
|
model: str = Field(...)
|
||||||
|
input: Image2VideoInputField = Field(...)
|
||||||
|
parameters: Image2VideoParametersField = Field(...)
|
||||||
|
|
||||||
|
|
||||||
|
class Reference2VideoTaskCreationRequest(BaseModel):
|
||||||
|
model: str = Field(...)
|
||||||
|
input: Reference2VideoInputField = Field(...)
|
||||||
|
parameters: Reference2VideoParametersField = Field(...)
|
||||||
|
|
||||||
|
|
||||||
|
class Wan27MediaItem(BaseModel):
|
||||||
|
type: str = Field(...)
|
||||||
|
url: str = Field(...)
|
||||||
|
|
||||||
|
|
||||||
|
class Wan27ReferenceVideoInputField(BaseModel):
|
||||||
|
prompt: str = Field(...)
|
||||||
|
negative_prompt: str | None = Field(None)
|
||||||
|
media: list[Wan27MediaItem] = Field(...)
|
||||||
|
|
||||||
|
|
||||||
|
class Wan27ReferenceVideoParametersField(BaseModel):
|
||||||
|
resolution: str = Field(...)
|
||||||
|
ratio: str | None = Field(None)
|
||||||
|
duration: int = Field(5, ge=2, le=10)
|
||||||
|
watermark: bool = Field(False)
|
||||||
|
seed: int = Field(..., ge=0, le=2147483647)
|
||||||
|
|
||||||
|
|
||||||
|
class Wan27ReferenceVideoTaskCreationRequest(BaseModel):
|
||||||
|
model: str = Field(...)
|
||||||
|
input: Wan27ReferenceVideoInputField = Field(...)
|
||||||
|
parameters: Wan27ReferenceVideoParametersField = Field(...)
|
||||||
|
|
||||||
|
|
||||||
|
class Wan27ImageToVideoInputField(BaseModel):
|
||||||
|
prompt: str | None = Field(None)
|
||||||
|
negative_prompt: str | None = Field(None)
|
||||||
|
media: list[Wan27MediaItem] = Field(...)
|
||||||
|
|
||||||
|
|
||||||
|
class Wan27ImageToVideoParametersField(BaseModel):
|
||||||
|
resolution: str = Field(...)
|
||||||
|
duration: int = Field(5, ge=2, le=15)
|
||||||
|
prompt_extend: bool = Field(True)
|
||||||
|
watermark: bool = Field(False)
|
||||||
|
seed: int = Field(..., ge=0, le=2147483647)
|
||||||
|
|
||||||
|
|
||||||
|
class Wan27ImageToVideoTaskCreationRequest(BaseModel):
|
||||||
|
model: str = Field(...)
|
||||||
|
input: Wan27ImageToVideoInputField = Field(...)
|
||||||
|
parameters: Wan27ImageToVideoParametersField = Field(...)
|
||||||
|
|
||||||
|
|
||||||
|
class Wan27VideoEditInputField(BaseModel):
|
||||||
|
prompt: str = Field(...)
|
||||||
|
media: list[Wan27MediaItem] = Field(...)
|
||||||
|
|
||||||
|
|
||||||
|
class Wan27VideoEditParametersField(BaseModel):
|
||||||
|
resolution: str = Field(...)
|
||||||
|
ratio: str | None = Field(None)
|
||||||
|
duration: int = Field(0)
|
||||||
|
audio_setting: str = Field("auto")
|
||||||
|
watermark: bool = Field(False)
|
||||||
|
seed: int = Field(..., ge=0, le=2147483647)
|
||||||
|
|
||||||
|
|
||||||
|
class Wan27VideoEditTaskCreationRequest(BaseModel):
|
||||||
|
model: str = Field(...)
|
||||||
|
input: Wan27VideoEditInputField = Field(...)
|
||||||
|
parameters: Wan27VideoEditParametersField = Field(...)
|
||||||
|
|
||||||
|
|
||||||
|
class Wan27Text2VideoParametersField(BaseModel):
|
||||||
|
resolution: str = Field(...)
|
||||||
|
ratio: str | None = Field(None)
|
||||||
|
duration: int = Field(5, ge=2, le=15)
|
||||||
|
prompt_extend: bool = Field(True)
|
||||||
|
watermark: bool = Field(False)
|
||||||
|
seed: int = Field(..., ge=0, le=2147483647)
|
||||||
|
|
||||||
|
|
||||||
|
class Wan27Text2VideoTaskCreationRequest(BaseModel):
|
||||||
|
model: str = Field(...)
|
||||||
|
input: Text2VideoInputField = Field(...)
|
||||||
|
parameters: Wan27Text2VideoParametersField = Field(...)
|
||||||
|
|
||||||
|
|
||||||
|
class TaskCreationOutputField(BaseModel):
|
||||||
|
task_id: str = Field(...)
|
||||||
|
task_status: str = Field(...)
|
||||||
|
|
||||||
|
|
||||||
|
class TaskCreationResponse(BaseModel):
|
||||||
|
output: TaskCreationOutputField | None = Field(None)
|
||||||
|
request_id: str = Field(...)
|
||||||
|
code: str | None = Field(None, description="Error code for the failed request.")
|
||||||
|
message: str | None = Field(None, description="Details about the failed request.")
|
||||||
|
|
||||||
|
|
||||||
|
class TaskResult(BaseModel):
|
||||||
|
url: str | None = Field(None)
|
||||||
|
code: str | None = Field(None)
|
||||||
|
message: str | None = Field(None)
|
||||||
|
|
||||||
|
|
||||||
|
class ImageTaskStatusOutputField(TaskCreationOutputField):
|
||||||
|
task_id: str = Field(...)
|
||||||
|
task_status: str = Field(...)
|
||||||
|
results: list[TaskResult] | None = Field(None)
|
||||||
|
|
||||||
|
|
||||||
|
class VideoTaskStatusOutputField(TaskCreationOutputField):
|
||||||
|
task_id: str = Field(...)
|
||||||
|
task_status: str = Field(...)
|
||||||
|
video_url: str | None = Field(None)
|
||||||
|
code: str | None = Field(None)
|
||||||
|
message: str | None = Field(None)
|
||||||
|
|
||||||
|
|
||||||
|
class ImageTaskStatusResponse(BaseModel):
|
||||||
|
output: ImageTaskStatusOutputField | None = Field(None)
|
||||||
|
request_id: str = Field(...)
|
||||||
|
|
||||||
|
|
||||||
|
class VideoTaskStatusResponse(BaseModel):
|
||||||
|
output: VideoTaskStatusOutputField | None = Field(None)
|
||||||
|
request_id: str = Field(...)
|
||||||
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,7 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
from comfy_api.latest import ComfyExtension, io
|
from comfy_api.latest import ComfyExtension, io
|
||||||
from comfy_api.input import CurveInput
|
from comfy_api.input import CurveInput
|
||||||
from typing_extensions import override
|
from typing_extensions import override
|
||||||
@ -32,10 +34,58 @@ class CurveEditor(io.ComfyNode):
|
|||||||
return io.NodeOutput(result, ui=ui) if ui else io.NodeOutput(result)
|
return io.NodeOutput(result, ui=ui) if ui else io.NodeOutput(result)
|
||||||
|
|
||||||
|
|
||||||
|
class ImageHistogram(io.ComfyNode):
|
||||||
|
@classmethod
|
||||||
|
def define_schema(cls):
|
||||||
|
return io.Schema(
|
||||||
|
node_id="ImageHistogram",
|
||||||
|
display_name="Image Histogram",
|
||||||
|
category="utils",
|
||||||
|
inputs=[
|
||||||
|
io.Image.Input("image"),
|
||||||
|
],
|
||||||
|
outputs=[
|
||||||
|
io.Histogram.Output("rgb"),
|
||||||
|
io.Histogram.Output("luminance"),
|
||||||
|
io.Histogram.Output("red"),
|
||||||
|
io.Histogram.Output("green"),
|
||||||
|
io.Histogram.Output("blue"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def execute(cls, image) -> io.NodeOutput:
|
||||||
|
img = image[0].cpu().numpy()
|
||||||
|
img_uint8 = np.clip(img * 255, 0, 255).astype(np.uint8)
|
||||||
|
|
||||||
|
def bincount(data):
|
||||||
|
return np.bincount(data.ravel(), minlength=256)[:256]
|
||||||
|
|
||||||
|
hist_r = bincount(img_uint8[:, :, 0])
|
||||||
|
hist_g = bincount(img_uint8[:, :, 1])
|
||||||
|
hist_b = bincount(img_uint8[:, :, 2])
|
||||||
|
|
||||||
|
# Average of R, G, B histograms (same as Photoshop's RGB composite)
|
||||||
|
rgb = ((hist_r + hist_g + hist_b) // 3).tolist()
|
||||||
|
|
||||||
|
# ITU-R BT.709-6, Item 3.2 (p.6) — Derivation of luminance signal
|
||||||
|
# https://www.itu.int/rec/R-REC-BT.709-6-201506-I/en
|
||||||
|
lum = 0.2126 * img[:, :, 0] + 0.7152 * img[:, :, 1] + 0.0722 * img[:, :, 2]
|
||||||
|
luminance = bincount(np.clip(lum * 255, 0, 255).astype(np.uint8)).tolist()
|
||||||
|
|
||||||
|
return io.NodeOutput(
|
||||||
|
rgb,
|
||||||
|
luminance,
|
||||||
|
hist_r.tolist(),
|
||||||
|
hist_g.tolist(),
|
||||||
|
hist_b.tolist(),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class CurveExtension(ComfyExtension):
|
class CurveExtension(ComfyExtension):
|
||||||
@override
|
@override
|
||||||
async def get_node_list(self):
|
async def get_node_list(self):
|
||||||
return [CurveEditor]
|
return [CurveEditor, ImageHistogram]
|
||||||
|
|
||||||
|
|
||||||
async def comfy_entrypoint():
|
async def comfy_entrypoint():
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
comfyui-frontend-package==1.42.8
|
comfyui-frontend-package==1.42.8
|
||||||
comfyui-workflow-templates==0.9.39
|
comfyui-workflow-templates==0.9.44
|
||||||
comfyui-embedded-docs==0.4.3
|
comfyui-embedded-docs==0.4.3
|
||||||
torch
|
torch
|
||||||
torchsde
|
torchsde
|
||||||
|
|||||||
@ -146,6 +146,10 @@ def is_loopback(host):
|
|||||||
def create_origin_only_middleware():
|
def create_origin_only_middleware():
|
||||||
@web.middleware
|
@web.middleware
|
||||||
async def origin_only_middleware(request: web.Request, handler):
|
async def origin_only_middleware(request: web.Request, handler):
|
||||||
|
if 'Sec-Fetch-Site' in request.headers:
|
||||||
|
sec_fetch_site = request.headers['Sec-Fetch-Site']
|
||||||
|
if sec_fetch_site == 'cross-site':
|
||||||
|
return web.Response(status=403)
|
||||||
#this code is used to prevent the case where a random website can queue comfy workflows by making a POST to 127.0.0.1 which browsers don't prevent for some dumb reason.
|
#this code is used to prevent the case where a random website can queue comfy workflows by making a POST to 127.0.0.1 which browsers don't prevent for some dumb reason.
|
||||||
#in that case the Host and Origin hostnames won't match
|
#in that case the Host and Origin hostnames won't match
|
||||||
#I know the proper fix would be to add a cookie but this should take care of the problem in the meantime
|
#I know the proper fix would be to add a cookie but this should take care of the problem in the meantime
|
||||||
|
|||||||
Reference in New Issue
Block a user