Skip to content

feat: Migrate to c2pa-web SDK, introduce Conformant vs Legacy verification, and add CPL Integration#384

Merged
andyparsons merged 14 commits into
contentauth:mainfrom
sherifhanna-google:sherifhanna-google/c2pa-web-updates
Apr 30, 2026
Merged

feat: Migrate to c2pa-web SDK, introduce Conformant vs Legacy verification, and add CPL Integration#384
andyparsons merged 14 commits into
contentauth:mainfrom
sherifhanna-google:sherifhanna-google/c2pa-web-updates

Conversation

@sherifhanna-google
Copy link
Copy Markdown
Contributor

@sherifhanna-google sherifhanna-google commented Apr 29, 2026

Summary

This PR migrates the verification engine to the modern @contentauth/c2pa-web (v0.17.x) SDK and introduces a major overhaul to how C2PA trust, provenance, and actions are visualized in the UI.

Key Improvements

1. Modern SDK Migration

  • Upgraded from the legacy c2pa package to the modern @contentauth/c2pa-web SDK, optimizing memory usage and utilizing the new WASM bindings.

2. Zero-Trust C2PA Verification (Conformant vs. Legacy)

  • Implemented a strict dual-pass validation engine that evaluates assets against both the C2PA Trust List and the legacy Interim Trust List (ITL).
  • Assets are now explicitly classified as coming from Conformant (laddering up to C2PA Trust List) products or products with Legacy trust in the UI.

3. C2PA Conforming Products List (CPL) Integration

  • Conformant assets now feature a lookup link in the 'Issued By' section.
  • Extracts the X.509 Certificate's Distinguished Name fields (CN, O) to reactively build a URI-encoded query for the C2PA Conformance Explorer. Note:: need SDK to add support for C and OU value as well.

4. "Captured Media" Provenance Engine

  • Added strict detection for pure native captures (Smartphones, Cameras, Microphones).
  • Identifies assets containing a single c2pa.created action with matching IPTC tags (digitalCapture, computationalCapture, compositeCapture).
  • Renders a dedicated "This is captured media." banner to distinguish native hardware provenance from AI generation.

Additional Fixes

  • Generative AI False Positives: Re-wrote the AI detection selector to accurately read IPTC algorithmicMedia strings, preventing native assets from being falsely flagged as AI.
  • CDN Icon Synchronization: Expanded the C2PA Action Dictionary to support legacy beta names and wired it to the CAI S3 CDN for 100% accurate Spectrum icon mapping.
  • Un-manifested Fallbacks: Added a Blob URL fallback generator to successfully render the source file in the UI when thumbnail manifests are missing.

- Replaces legacy c2pa SDK with @contentauth/c2pa-web
- Implements native crJSON mapping layer in asset.ts
- Updates all local UI selectors to consume snake_case properties
- Fixes V3 validation status mapping for OpenAI/Google test assets
- Adds case-insensitive timestamp filtering
- Adds E2E tests for V2 and V3 manifest topologies
- Splits SDK loaders into `getOfficialToolkitSettings` and `getLegacyToolkitSettings`
- Implements Pass 1 (Official) vs Pass 2 (Legacy) validation engine in the C2PA reader store
- Resolves crJSON V2/V3 structural differences for deep ingredient tagging
- Applies strictly positive cryptographic proofing to eliminate false-positive trust tags
- Adds "Legacy trust" warning UI to main header, sidebar thumbnails, and center tree view
- Bypasses Tailwind config constraints using JIT arbitrary classes for legacy UI
- Updates E2E test suite to include verified Adobe legacy asset
- Adds 'Conformant' label for fully verified standard assets
- Implements Root Trust Inheritance to automatically tag deep ingredients as official when the root passes
- Refactors Center Canvas (`TreeL1`) to natively support legacy/conformant background styling
- Restores standard layout metrics to Main Header and Sidebar views
- Consolidates App/Device and Certificate Subject into a single "Issued by" layout for officially trusted assets
- Hides redundant "App or device used" block from the Process section for conformant implementations
- Updates crjson.ts polyfill to explicitly parse the Organization (O) field from X.509 certificates
- Applies strict Design System typography tokens (text-generalSm) to ensure 16px scaling without arbitrary CSS hacks
- Refactors AboutSection to route raw CN and Issuer fields separately
- Ensures Legacy assets strictly display the Certificate Issuer (Company) instead of the App Name
- Applies text-generalSm (16px) design token to legacy text for visual consistency
…ations, not the assets

- Moves trust validation UI indicators out of the asset-level views (Main Header, Sidebar, Center Canvas)
- Injects Conformant and Legacy Trust badges directly beneath the 'Issued by' identity block
- Removes redundant timestamps from the Main Header to focus purely on Organizational identity
- Resolves fatal UI hydration failure caused by JS SDK structural changes (Map vs Array)
- Adds support for new `c2pa.actions.v2` schema labels
- Fixes fatal UI crash when parsing deep leaf-node ingredients without sub-manifest arrays
- Expands Action dictionary to support full C2PA 1.4 vocabulary (Resized, Placed, Format Converted, etc.)
- Corrects English localized strings to match official C2PA specifications
- Rewires all action icons to fetch directly from the verified Adobe CAI S3 Bucket using exact Spectrum key mappings
…sitives

- Expands the Action mapping to support the exhaustive C2PA v2.2 Specification (Redacted, Transcoded, Watermarked, etc.)
- Adds historical aliases for pre-standardization CAI tags (appliedFilter, adjustedColor, imported, etc.)
- Resolves a major false-positive in the Generative AI parser that incorrectly flagged standard camera captures (c2pa.created) as AI agents
- Refactors AI parser to strictly require the IPTC 'algorithmicMedia' metadata tag
- Fixes UI localization crashes by passing short IPTC slugs to the translation engine instead of absolute URIs
…e image rendering

- Security: Refactored C2PA ingredient validation to abolish implicit Root Trust Inheritance. Ingredients now enforce a strict Zero-Trust model, explicitly checking the local sub-manifest (validation_results.activeManifest.failure) along with V2 pointers and V3 root deltas. Resolves conformity bypass for forged historical sub-manifests.
- Performance: Stripped out the heavy WASM memory sniffer and deep-tree recursion to unblock the iteration loop and restore high UI responsiveness.
- UX: Added native Blob URL fallback for main file rendering, ensuring un-manifested files and manifests lacking cover thumbnails successfully display the source image.
- Extracts CN (Common Name) and O (Organization) fields from the X.509 certificate signature info
- Reactively builds standard URI-encoded query parameters for the official C2PA Conforming Products List
- Adds a dedicated lookup link beneath the 'Conformant' badge for officially trusted assets, improving discoverability of the CPL
- Implements strict detection engine in asset.ts to identify pure analog-to-digital captures (Cameras, Microphones)
- Validates provenance chain based on MIME-type (image/audio), single-action history (c2pa.created), and strict IPTC digitalSourceType tags (digitalCapture, computationalCapture, compositeCapture)
- Updates ContentSummarySection to display a dedicated 'This is captured media.' banner, distinct from AI disclosures
@sherifhanna-google sherifhanna-google force-pushed the sherifhanna-google/c2pa-web-updates branch from 9fb14ae to 53e2695 Compare April 29, 2026 10:22
Copy link
Copy Markdown

@darrellkindred darrellkindred left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have not done a full review (and I'm not really qualified to), but I noticed a few things.

Comment thread src/lib/selectors/doNotTrain.ts
Comment thread src/lib/selectors/editsAndActivity.ts Outdated
results.push({ id: action, label: 'Color adjustments', description: 'Changes made to tone, saturation, or exposure.', icon: `${baseUrl}/color-palette-dark.svg` });
break;
case 'c2pa.cropped':
results.push({ id: action, label: 'Cropped', description: 'The asset was cropped.', icon: `${baseUrl}/crop-dark.svg` });
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these descriptions use the language from the spec?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are the existing strings from the older version of the app I believe, but I will double-check.

@andyparsons andyparsons self-requested a review April 30, 2026 11:40
- Fix selectValidationResult regression: general.error is a side-effect
  of signingCredential.untrusted and must not independently trigger
  hasError/statusCode 'invalid' — preserves the pre-migration behaviour
- Fix timeStamp.* codes being counted as hard errors; an untrusted
  timestamp should suppress the date display but not downgrade the badge
- Update existing selectValidationResult tests to include the new
  hasUntrustedTimestamp field; add dedicated timestamp detection tests
- Add src/lib/crjson.spec.ts (19 tests) covering isCrJson, assertion
  helpers, getSignatureInfo, getClaimInfo,
  getActiveManifestValidationStatus, and legacyToCrJson
- Fix copy-paste bug in legacyManifestToCrJsonEntry: instanceID was
  assigned m.instance_id ?? m.instance_id (both sides identical)
- Remove console.log debug statement from c2paReader.ts
- Delete e2e/css-debug.spec.ts, screenshot-debug.spec.ts, and the
  legacy_header_debug.png artefact (scratch files not intended to ship)
- Rewrite e2e/c2pa-migration-test.spec.ts to use the fixtures server
  (CAICAI.jpg) instead of hardcoded developer machine paths; gate the
  legacy-trust test behind TEST_LEGACY_IMAGE_PATH so CI passes cleanly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread src/lib/selectors/doNotTrain.ts
Comment thread src/lib/crjson.ts
...(validationResults && { validationResults: validationResults as CrJsonValidationResults }),
...(validationStatus && { validationStatus: validationStatus as Record<string, unknown> })
}
}
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why was it necessary to add crJSON support to address urgent issues?

@andyparsons andyparsons merged commit 234dbff into contentauth:main Apr 30, 2026
3 of 4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants