Skip to content

Pure TypeScript implementation of C2PA manifest reading, validation, and creation

License

Notifications You must be signed in to change notification settings

TrustNXT/c2pa-ts

Repository files navigation

c2pa-ts

About

c2pa-ts is a pure TypeScript implementation of Coalition for Content Provenance and Authenticity (C2PA) according to specification version 2.0.

It does not use any native binaries or WebAssembly and is therefore truly platform independent. In modern browsers as well as Node.js it should run out of the box. In mobile apps or other environments lacking browser APIs, some external code may be necessary (see below for details).

Developed and curated by TrustNXT in Hamburg, Germany and licensed under the Apache 2.0 License. Contributions welcome!

(back to top)

Roadmap and current status

This library is under active development and not fully functional yet. Proceed with caution!

Anything that's not listed below is not currently planned to be implemented.

Overall functionality

  • ✅ Reading manifests
  • 🚧 Validating manifests (mostly implemented except chain of trust validation)
  • ✅ Creating manifests

ℹ️ On C2PA versions: The library is targeted at C2PA specification 2.0, however data structures from older versions of the specification are also supported for backwards compatibility.

ℹ️ Although it is a separate project from C2PA, the library also includes support for several CAWG assertions.

Asset file formats

  • ✅ JPEG
  • ✅ PNG
  • ✅ HEIC/HEIF
  • ❌ GIF
  • ❌ TIFF
  • ❌ WebP

Supported assertions

  • ✅ Data Hash
  • ✅ BMFF-Based Hash (except Merkle tree hashing)
  • ❌ General Boxes Hash
  • ✅ Thumbnail
  • ✅ Actions (except action templates and metadata)
  • ✅ Ingredient
  • ✅ Metadata (specialized, common, generic, and CAWG variants)
  • ✅ Creative Work
  • ✅ Training and Data Mining (C2PA and CAWG variants)
  • ❌ CAWG Identity

JUMBF boxes

  • ✅ CBOR boxes
  • ✅ JSON boxes
  • ✅ Codestream boxes
  • ✅ Embedded file boxes
  • ✅ UUID boxes
  • ✅ C2PA salt boxes
  • ❌ Compressed boxes

(back to top)

Usage examples

Reading and validating a manifest

Example usage in a Node.js environment:

import * as fs from 'node:fs/promises';
import { MalformedContentError } from '@trustnxt/c2pa-ts';
import { Asset, BMFF, JPEG, PNG } from '@trustnxt/c2pa-ts/asset';
import { SuperBox } from '@trustnxt/c2pa-ts/jumbf';
import { ManifestStore, ValidationResult, ValidationStatusCode } from '@trustnxt/c2pa-ts/manifest';

if (process.argv.length < 3) {
    console.error('Missing filename');
    process.exit(1);
}

const buf = await fs.readFile(process.argv[2]);

// Read the asset file and dump some information about its structure
let asset: Asset;
if (JPEG.canRead(buf)) {
    asset = new JPEG(buf);
} else if (PNG.canRead(buf)) {
    asset = new PNG(buf);
} else if (BMFF.canRead(buf)) {
    asset = new BMFF(buf);
} else {
    console.error('Unknown file format');
    process.exit(1);
}
console.log(asset.dumpInfo());

// Extract the C2PA manifest store in binary JUMBF format
const jumbf = asset.getManifestJUMBF();

if (jumbf) {
    let validationResult: ValidationResult;

    try {
        // Deserialize the JUMBF box structure
        const superBox = SuperBox.fromBuffer(jumbf);
        console.log('JUMBF structure:');
        console.log(superBox.toString());

        // Read the manifest store from the JUMBF container
        const manifests = ManifestStore.read(superBox);

        // Validate the active manifest
        validationResult = await manifests.validate(asset);
    } catch (e) {
        // Gracefully handle any exceptions to make sure we get a well-formed validation result
        validationResult = ValidationResult.fromError(e as Error);
    }

    console.log('Validation result', validationResult);
}
Creating a manifest

This still needs proper example code (issue #58). For now, you can check jpeg-signing.test.ts.

(back to top)

Usage in constrained environments

Usage with JavaScript engines that lack WebCrypto and other browser APIs (such as JavaScriptCore on iOS) is entirely possible but will require some additional code. In particular, a custom CryptoProvider will need to be created and some polyfills might be required.

For more information or a reference iOS implementation, contact us.

(back to top)

Contributing

Contributions are welcome!

When you're done with your changes, we use changesets to manage release notes. Run npm run changeset to autogenerate notes to be appended to your pull request.

(back to top)

License

Distributed under the Apache 2.0 License. See LICENSE.md for more information.

(back to top)

Contact

Created and curated by TrustNXT GmbH, a proud member of CAI and C2PA.

This project is not affiliated with or endorsed by CAI, C2PA, CAWG, or any other organization except TrustNXT.

(back to top)

Acknowledgments

The following resources were helpful during creation of this library:

Thank you for providing them and keeping open source alive!

(back to top)