Commit Graph
4153 Commits
Author SHA1 Message Date
Dylan M. Taylor 2e2faec1a3 security(raw): cap lossless-JPEG Huffman table builds
Each DHT definition for table id 0..3 calls Huffman::new, which
allocates and fills a ~48 KiB lookup pair. A stream repeating DHT
definitions (and DNG tiles referencing such a stream) could rebuild
tables thousands of times, multiplying header-processing cost and
memory churn while producing little output.

A real lossless JPEG uses a handful of Huffman tables; cap cumulative
table builds per stream at 64 and reject streams that exceed it.

Finding: 7a31b581-d1b7-4f9c-91e5-ce42b47db87f (CWE-400)
2026-10-22 07:10:24 -04:00
Dylan M. Taylor 8c0a9cb185 security(raw): bound cumulative retained tile memory
read_plane decodes every tile in parallel and retains all decoded tile
buffers in  before assembly copies only the useful pixels. Each
tile is charged individually, but file-controlled padding and repeated
source ranges can make the cumulative retained samples far exceed both
the input and the useful image.

Sum the padded tile samples (two bytes each) and reject the plane before
decoding when that total exceeds max_alloc.

Finding: e66981b1-0d7a-4738-a64c-37b5e8bf28d1 (CWE-770)
2026-10-22 07:10:19 -04:00
Dylan M. Taylor 0e1a7a8b2a security(io): bound PDN layer-name copies
PDN conversion copied a referenced name into an owned String for every
output layer, while the NRBF budget charged the shared string only once.
Repeated references to one large name could multiply a small document
into gigabytes of retained metadata.

Cap each layer name at 64 KiB and the aggregate copied name bytes at
4 MiB, checked before each copy.

Finding: fd77f4b2-39a2-48b5-b9d8-4ad69cf69469 (CWE-770)
2026-10-22 07:10:15 -04:00
Dylan M. Taylor bd109515a9 security(io): bound XCF copied layer metadata
The XCF importer reparses every layer offset and allocates a new owned
name and item path per reference. Repeated offsets referencing one
record with a large name or path could retain gigabytes of metadata,
which the per-field and per-layer limits did not bound in aggregate.

Add a document-wide metadata budget (32 MiB) to the Image reader and
charge each copied layer name and item path against it, erroring when
exhausted.

Finding: 1631d2df-fe8f-4734-b14e-380db11afb26 (CWE-789)
2026-10-22 07:10:12 -04:00
Dylan M. Taylor 7016152f22 security(compose): bound dense mask working set
build_mask derives its working area from sparse mask geometry grown by
feather, so two distant changed pixels could span a canvas-sized
rectangle. It then allocated f32 planes (coverage, pixel-mask values,
blur scratch) over that area, gigabytes during even a one-pixel render.

Check the estimated working bytes before the dense allocation and fall
back to the constant default mask above 512 MiB, so pathological
geometry degrades feather detail instead of exhausting memory.

Finding: 8c04c5ef-a5bd-48f4-bfcf-83615bcf11c0 (CWE-770)
2026-10-22 07:10:08 -04:00
Dylan M. Taylor f65832931b security(compose): cap uncached pattern conversion
When a pattern exceeded the preparation cache budget, every lookup still
called Tile::new_in, expanding the whole sparse pattern into RGBA floats
on each output tile (and possibly concurrently). The cache budget only
controlled retained entries, not this conversion work.

Reject patterns whose full RGBA conversion would exceed an absolute
256 MiB cap on the uncached path, so oversized patterns are skipped
instead of re-expanded per tile. The cap is independent of the cache
budget, so small patterns still convert on demand when nothing is cached.

Finding: cc0b2f77-5578-48ed-aba0-1f3beccd21cd (CWE-400)
2026-10-22 07:10:03 -04:00
BFlat 2438d38084 Merge pull request #8514 from storytold/readme/app-icon
README: the app icon above the title
2026-10-22 18:02:22 +07:00
bflatastic d2e349ee6c README: the app icon above the title 2026-10-22 17:58:16 +07:00
aiongg 78b46b1a99 Merge pull request #3283 from abc2cb/codex/github-smart-filters-usability-20261011
Smart Filters: distinct editors, shared disclosure and stable alpha
2026-10-22 00:26:00 -04:00
aiongg 3458eee861 Merge main into #3283
dialogs.rs: main's Displace-map prompt runs before the fallible confirm_command. filter_dialog.rs: main's ask_displace_map uses the new confirm_command signature; SMART_FILTER_SET_PARAMS stays for main's uses; a smart-filter edit without a "layer" param previews the active layer, as the command runs it (main's smart_displace_preview_uses_the_map_document).
2026-10-22 02:16:49 +00:00
Zuujis 38bc5e916c refactor(atn): build the clipping-mask and three adjustment events with macros (#8401)
Create/Release Clipping Mask and Brightness/Contrast, Black & White and
Gradient Map were written out by hand with the same body as
adjustment_event! or each other, which SonarCloud counts as duplicated new
code (photocraft's quality gate fails on 9.8% duplication from the GrpL
entry). adjustment_event! takes an optional command id, and clipping_event!
builds the two clipping events. The mapping table is unchanged.
2026-10-21 20:28:12 -04:00
Dylan M. Taylor f4bc90b93f ci: pin GitHub Actions to full commit SHA (SonarCloud githubactions:S7637) (#8368)
Pin third-party actions to full-length commit SHAs (with version comments)
instead of mutable tags/branches to prevent supply-chain tampering via
retagged releases. Resolves SonarCloud rule githubactions:S7637.
2026-10-21 20:12:22 -04:00
Dylan M. Taylor 3ec52a9ff1 security: enforce HTTPS on curl downloads (SonarCloud S6506) (#8369)
Add --proto '=https' to curl invocations so redirects cannot downgrade to
plaintext HTTP. Resolves SonarCloud S6506 (shell/docker/githubactions).
2026-10-21 20:11:03 -04:00
Dylan M. Taylor 9b18f57344 test: use tokio::time::sleep in async test poll loop (SonarCloud rust:S7488) (#8373)
The multi-thread #[tokio::test] polled with a blocking std::thread::sleep,
stalling a runtime worker. Use tokio::time::sleep(..).await instead.
2026-10-21 19:35:38 -04:00
aiongg ad694eb17d Merge pull request #8370 from storytold/sonar-fix/actions-script-injection
security: prevent script injection in fuzz workflow (SonarCloud S7630)
2026-10-21 19:26:09 -04:00
aiongg ba40dffb25 Merge pull request #8355 from aiongg/integration-10
Integration batch: #8229, David's follow-ups and 85 FredApps-approved PRs on main
2026-10-21 19:02:54 -04:00
aiongg ce85a5ae78 Merge PR #8229: Integration batch: 8 PRs on main 2026-10-21 22:30:00 +00:00
aiongg 33214b70f4 Merge PR #6708: Paths: the path selected in the Paths panel is drawn on the canvas (#6550) 2026-10-21 22:30:00 +00:00
aiongg 989a685b3f Merge PR #6208: Preferences: Save in Background off saves in the foreground (#6207) 2026-10-21 22:29:59 +00:00
aiongg 3b04ff873c Merge PR #5840: Export As: Resample menu, incl. Nearest Neighbor (#5838) 2026-10-21 22:29:59 +00:00
abc2cbandClaude Opus 5.5 08fa0ed4fb Smart Filters: keep main's thumbnail scaling tests test-only
The merge of main kept `#[cfg(test)]` on `mod editor_tests;` only, so
`layer_thumbnail_scaling_tests` (which uses the dev-only egui_kittest)
was compiled into normal builds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 01:13:10 +03:00
abc2cbandClaude Opus 5.5 a335b58e21 Merge upstream/main 43b14883 into the Smart Filters branch
#3289, #3974 and #3975 landed in main, so the Smart Filters row code meets
#3974's thumbnail geometry.

Conflicts:
- smart_ui.rs: the rows keep our layout (separate name and Blending
  Options targets, shared disclosure, real mask thumbnail) and take
  #3974's geometry: the header height and the shared-mask side come from
  smart_filters_header_geometry, sub-rows are SUB_ROW_H, the mask is
  hidden at None and the header name follows it. #3974's own
  drag_started and selection handling is dropped, ours already covers
  both through the name target. #3974's scaling test module is kept
  next to editor_tests.
- All 20 i18n catalogs: both sides appended rows at the end; kept both,
  exact duplicates dropped, dupscan reports 0 problems.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 01:12:29 +03:00
aiongg f32f882f3a Merge main into integration-10
# Conflicts:
#	apps/photocraft-web/src/web.rs
#	apps/photocraft/src/services.rs
#	crates/engine/src/file_cmds/tests.rs
#	crates/engine/src/float_cmds.rs
#	crates/engine/src/float_cmds/tests.rs
#	xtask/src/corpus.rs
#	xtask/src/corpus_pins.rs
#	xtask/src/main.rs
2026-10-21 21:56:26 +00:00
aiongg 21a952698a Integration: Lens Flare and the render filters' colours read with main's double and typed enum_name helpers, for #6160 2026-10-21 21:56:22 +00:00
aiongg 1a388f8ba7 Merge PR #8229: Integration batch: 8 PRs on main
# Conflicts:
#	crates/io/src/smart_map.rs
#	docs/file-format-parity.md
2026-10-21 21:56:22 +00:00
aiongg 64d042aef5 Integration: Create Clipping Mask also maps the GrpL code and a named-layer target, for #6881 and #4496 2026-10-21 21:56:21 +00:00
aiongg 0e9cbbc88e Integration: one tools.setColors and one clipping-mask mapping in .atn export, for #6881 and #4496 2026-10-21 21:56:21 +00:00
aiongg 719fb44d42 Merge PR #6881: Actions: .atn Select Subject, Select and Mask, Color Range, clipping and layer masks, colours map to commands (part of #6745) 2026-10-21 21:56:21 +00:00
aiongg 3b16c2bc98 Merge PR #5729: Move tool: ΔX/ΔY readout beside the pointer while dragging (#5727) 2026-10-21 21:56:21 +00:00
aiongg bd133eee81 Merge PR #5855: Displace: OK asks for the displacement map, as in Photoshop (#5806) 2026-10-21 21:56:21 +00:00
aiongg 43e9587590 Merge PR #6363: New Document: Color Profile, the working space or another profile of the mode (#321) 2026-10-21 21:56:21 +00:00
aiongg 20adb5f1d7 Merge PR #6410: Artboards: layers outside the boards stay visible over the pasteboard (#5712) 2026-10-21 21:56:21 +00:00
aiongg 1bc45862cb Merge PR #6813: A layer that doesn't fit in GPU memory no longer breaks GPU drawing: older pages are freed and the layer is retried 2026-10-21 21:56:21 +00:00
aiongg 64526a6c28 Merge PR #7904: Filter Gallery › Halftone Pattern: a tone-keeping screen at 45° 2026-10-21 21:56:21 +00:00
aiongg f97c28828d Merge PR #6873: HEIF: honour the nclx colour description; HLG/PQ HEICs open as linear BT.2020 32-bit (#6752) 2026-10-21 21:56:21 +00:00
aiongg 1837a19362 Merge PR #6908: Background redraw: keep the last finished composites, so a solo's restore uploads instead of recompositing (part of #6528) 2026-10-21 21:56:21 +00:00
aiongg 29388de427 Merge PR #6919: Selections don't mark a document modified (#6865) 2026-10-21 21:56:21 +00:00
aiongg c71322043c Merge PR #7941: Light themes outline the slider knob (UI-217-11, #7927) 2026-10-21 21:56:21 +00:00
aiongg e4a413241a Merge PR #8004: Windows on ARM: auto picks DirectX 12 for Qualcomm graphics (#7537) 2026-10-21 21:56:21 +00:00
aiongg 403dc5043a Merge PR #8096: CodeRabbit follow-ups for the #8095 batch 2026-10-21 21:56:21 +00:00
aiongg 07e4020360 Merge PR #8098: PSD layer comps: an entry without enab inherits the previous visibility, as in Photoshop (#8093) 2026-10-21 21:56:21 +00:00
aiongg 3b6fabb04a Merge PR #6801: Actions that start with Deselect play on when nothing is selected 2026-10-21 21:56:21 +00:00
aiongg a06c4639f6 Merge PR #5590: Warp: apply a large layer's warp in the background, with progress and Esc to cancel (#1015) 2026-10-21 21:56:21 +00:00
aiongg 7b81efddcb Merge PR #5436: IO: open .psd through the PSD reader, not codecs (#5258) 2026-10-21 21:56:21 +00:00
aiongg dd83f87d3c Merge PR #5581: Layers: Group Layers creates the group collapsed (#5571) 2026-10-21 21:56:20 +00:00
aiongg 0fe1d3233d Merge PR #5907: Text: apply anti-alias mode shaping when rasterizing type (#5902) 2026-10-21 21:56:20 +00:00
aiongg c865e3b93b Merge PR #5928: BMP export: Indexed Color documents save as palette BMPs 2026-10-21 21:56:20 +00:00
aiongg b9b97f15ff Merge PR #6243: GPU: pin the keep-overlap ordering with a tile-growth regression test 2026-10-21 21:56:20 +00:00
aiongg 5eada4996a Merge PR #7219: Actions: record File › Export › Export As and replay it with its settings (#7207) 2026-10-21 21:56:20 +00:00
aiongg abfb8cce96 Merge PR #8042: Codecs: Fix corrupted CMYK JPEG exports (#8008) 2026-10-21 21:56:11 +00:00