fix: restore ingredient thumbnails with c2pa-web#389
Conversation
|
This update prioritizes the signed ingredient's own c2pa.thumbnail.claim, if present, When no claim thumbnail is available for an ingredient, we fall back to It solves this kind of issue: |
|
@andyparsons I synced this with main after #388 merged, and just updated c2pa-web to 0.9.0. |
|
Not a JS expert but looks good to me. |
| @@ -0,0 +1,66 @@ | |||
| // Copyright 2021-2024 Adobe, Copyright 2025 The C2PA Contributors | |||
There was a problem hiding this comment.
If this is a new file this can be Copyright 2026 The C2PA contributors
There was a problem hiding this comment.
@MassivaM Can this be // Copyright 2021-2024 Adobe, Copyright 2026 The C2PA Contributors instead? There is an eslint header rule that enforces this format.
There was a problem hiding this comment.
Ah yes I forgot we had that linter , we'll want to change this eventually but yes that's okay for now!
| // untrusted, we suppress the thumbnail so an untrusted signer can't force a false | ||
| // thumbnail to display for an ingredient that has no claim thumbnail of its own. A | ||
| // signed ingredient's own claim thumbnail is still shown when present (untrusted | ||
| // state is flagged in the UI). |
There was a problem hiding this comment.
/**
* The code prioritizes the signed ingredient's own c2pa.thumbnail.claim, if present,
* over the c2pa.thumbnail.ingredient assertion that the consuming manifest's signer
* references via ingredient.thumbnail. When a signed ingredient already provides
* its own claim thumbnail, a consuming signer's separate ingredient assertion
* thumbnail could be an intentional override pointing at a misleading image. The
* claim thumbnail more faithfully represents the ingredient.
*
* When no claim thumbnail is available for an ingredient, we fall back to
* c2pa.thumbnail.ingredient only if the containing manifest is trusted. If it is
* untrusted, we suppress the thumbnail so an untrusted signer can't force a false
* thumbnail to display for an ingredient that has no claim thumbnail of its own. A
* signed ingredient's own claim thumbnail is still shown when present (untrusted
* state is flagged in the UI)
*/
Can we use a multiline comment here to make it more readable
| const containingManifestUntrusted = (runtimeValidationStatuses[containingManifestLabel] ?? []) | ||
| .some((s) => s.code.includes('signingCredential.untrusted') || s.code.includes('signingCredential.invalid')); | ||
|
|
||
| const thumbnail = ingredientManifestLabel && ingredientManifest?.thumbnail |
There was a problem hiding this comment.
Are null guards needed here, in that chain of calls to set that variable?
There was a problem hiding this comment.
Hey @tmathern,
const containingManifestUntrusted = (runtimeValidationStatuses[containingManifestLabel] ?? [])
.some((s) => s.code.includes('signingCredential.untrusted') || s.code.includes('signingCredential.invalid'));
This is protected by the ?? []
const thumbnail = ingredientManifestLabel && ingredientManifest?.thumbnail
? await lookupThumbnail(ingredientManifest.thumbnail, ingredientManifestLabel) // branch A
: !containingManifestUntrusted
? await lookupThumbnail(ingredient.thumbnail, containingManifestLabel) // branch B
: await loadThumbnail(undefined, undefined); // branch C
When this code runs, we already know that ingredient is not null. Branch A is guarded by ingredientManifestLabel && ingredientManifest?.thumbnail. On branch C, the existing loadThumbnail() is designed to accept undefined. I followed that same pattern in lookupThumbnail(). So in branch B, ingredient.thumbnail could be undefined, but lookupThumbnail() is null safe. It gets caught there by ref?.identifier.


Overview
Restores ingredient thumbnail rendering. The c2pa-web SDK exposes raw resource bytes via
reader.resourceToBytes()and we need to fetch and assign thumbnails explicitly.resolveThumbnailshelper that walks the manifest store and fetches embedded thumbnail bytes, keyed by absolute JUMBF identifier.c2pa.thumbnail.claimassertion.c2pa.thumbnail.ingredientassertion on the containing manifest, if present.