Critical security fixes ----------------------- - Sandbox Jinja2 in template_render + prompt_template_render (was RCE via shared workflows) - Drop user home dir from filesystem allow-list (was arbitrary delete/overwrite) - Confine save_image_with_manifest + sanitize filename basename - SSRF block on http_get/http_post/notify_webhook (catches 169.254.169.254 metadata) - Case-insensitive path confinement on Windows Critical correctness/perf ------------------------- - halftone_dots: O(N^2) -> O(cells*36); was freezing worker on 1024+ images - Preserve latent dict keys (noise_mask, batch_index) in latent_math/noise/upscale - Preserve alpha channel in invert + threshold_binary on RGBA inputs - Force odd kernel in mask_erode/mask_dilate to prevent H+1 shape mismatch - Snap aspect_ratio_pick output to multiples of 8 (was crashing SD UNet) Theme engine (JS) ----------------- - Hoist window.matchMedia() out of per-frame hot path -> recovers 200 FPS from 25 - Wrap-once draw method to stop stomping other extensions wrappers - nodeRemoved hook + WeakMap groups + in-place canvas reuse -> three memory leaks closed - Wire thickness now uses connections_width (the wrap was a no-op vs LiteGraph) - onGroupAdded auto-themes new groups; budget change triggers redraw - Gradient caching in synthwave/glassmorphic New ops (10) ------------ - json_path (programming): dotted/bracketed path extract - latent_nan_guard, latent_pad_crop (mask_latent) - mask_from_depth, mask_invert (mask_latent) - color_match_histogram, image_composite_over (image_pro/value) - frequency_separation (image_pro/style) - pad_to_multiple (image_pro/spatial) - save_images_zip (io_workflow) - llm_enhance_prompt via Ollama / LM Studio / llama.cpp (prompt) Theme UX -------- - Right-click "Theme..." submenu on every node (including vanilla ComfyUI nodes) - Auto-contrast title text (WCAG AA-based flip) Tests: 373 Python + 33 JS = 406 passing (added 33 new tests for security + features). Full review notes in CHANGELOG.md.
108 lines
3.6 KiB
JavaScript
108 lines
3.6 KiB
JavaScript
/**
|
|
* Wire (link/connection) theming.
|
|
*
|
|
* 1. Per-data-type color palette: mutate `app.canvas.default_connection_color_byType`
|
|
* and store originals so we can restore on theme removal.
|
|
* 2. Render mode (bezier/straight/linear/manhattan): set `app.canvas.links_render_mode`.
|
|
* 3. Thickness: scale LiteGraph's native `connections_width` property. (v0.2.x
|
|
* tried to mutate `ctx.lineWidth` inside a renderLink wrap, but LiteGraph
|
|
* overwrites lineWidth from connections_width inside the original
|
|
* renderLink anyway, so the wrap was a no-op.)
|
|
* 4. Opacity: wrap renderLink to scale globalAlpha. There is no native
|
|
* LiteGraph property for link opacity, so a wrap is necessary here.
|
|
*
|
|
* Verified against existing packs:
|
|
* - ComfyUI-Custom-Scripts mutates `links_render_mode`.
|
|
* - ComfyUI-KJNodes mutates `default_connection_color_byType` and wraps `renderLink`.
|
|
*/
|
|
|
|
let _originalColorByType = null;
|
|
let _originalConnectionsWidth = null;
|
|
let _renderLinkPatched = false;
|
|
let _wireState = {
|
|
thickness: 1.0, // multiplier on connections_width
|
|
opacity: 1.0, // ctx.globalAlpha multiplier (applied in wrap)
|
|
};
|
|
|
|
|
|
export function applyWirePalette(app, palette) {
|
|
if (!app?.canvas) return;
|
|
if (!_originalColorByType) {
|
|
_originalColorByType = { ...(app.canvas.default_connection_color_byType || {}) };
|
|
}
|
|
if (!palette) {
|
|
app.canvas.default_connection_color_byType = { ..._originalColorByType };
|
|
return;
|
|
}
|
|
// Apply theme palette merged over originals — unknown link types keep
|
|
// their original colors.
|
|
app.canvas.default_connection_color_byType = {
|
|
..._originalColorByType,
|
|
...palette,
|
|
};
|
|
}
|
|
|
|
|
|
/**
|
|
* Set the link render mode globally.
|
|
* 1 = Straight, 2 = Linear, 3 = Spline/Bezier, 4 = L-Shape (ComfyUI Manhattan).
|
|
* null = leave ComfyUI's user setting alone.
|
|
*/
|
|
export function applyWireRenderMode(app, mode) {
|
|
if (!app?.canvas) return;
|
|
if (mode !== null && mode !== undefined) {
|
|
app.canvas.links_render_mode = Number(mode);
|
|
app.canvas.setDirty?.(true, true);
|
|
}
|
|
}
|
|
|
|
|
|
/** Scale LiteGraph's native connections_width by `multiplier`. */
|
|
export function applyWireThickness(app, multiplier) {
|
|
_wireState.thickness = Number(multiplier) || 1.0;
|
|
if (!app?.canvas) return;
|
|
if (_originalConnectionsWidth === null) {
|
|
// LiteGraph defaults to 3 in modern builds; snapshot whatever is live.
|
|
_originalConnectionsWidth = app.canvas.connections_width ?? 3;
|
|
}
|
|
app.canvas.connections_width = _originalConnectionsWidth * _wireState.thickness;
|
|
app.canvas.setDirty?.(true, false);
|
|
}
|
|
|
|
|
|
export function setWireOpacity(alpha) {
|
|
_wireState.opacity = Math.max(0, Math.min(1, Number(alpha) || 1.0));
|
|
}
|
|
|
|
|
|
/**
|
|
* Install a one-time wrapper around LGraphCanvas.prototype.renderLink that
|
|
* applies the live opacity setting. Thickness is handled by mutating
|
|
* `connections_width` (see applyWireThickness) and does NOT require a wrap.
|
|
*/
|
|
export function ensureRenderLinkWrapped(LGraphCanvas) {
|
|
if (_renderLinkPatched || !LGraphCanvas?.prototype?.renderLink) return;
|
|
const original = LGraphCanvas.prototype.renderLink;
|
|
LGraphCanvas.prototype.renderLink = function (...args) {
|
|
if (_wireState.opacity === 1.0) {
|
|
return original.apply(this, args);
|
|
}
|
|
const ctx = args[0];
|
|
const prev = ctx.globalAlpha ?? 1;
|
|
ctx.globalAlpha = prev * _wireState.opacity;
|
|
const result = original.apply(this, args);
|
|
ctx.globalAlpha = prev;
|
|
return result;
|
|
};
|
|
_renderLinkPatched = true;
|
|
}
|
|
|
|
|
|
/** For tests only. */
|
|
export function _resetForTests() {
|
|
_originalColorByType = null;
|
|
_originalConnectionsWidth = null;
|
|
_renderLinkPatched = false;
|
|
_wireState = { thickness: 1.0, opacity: 1.0 };
|
|
}
|