npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

c2pa-node

v0.5.23

Published

Node.js bindings for C2PA

Downloads

2,226

Readme

C2PA Node.js

The c2pa-node repository implements a Node.js API that can:

WARNING: This is an early prerelease version of this library. There may be bugs and unimplemented features, and the API is subject to change.

Contents:

Installation

Prerequisites

You must install:

If you need to manage multiple versions of Node on your machine, use a tool such as nvm.

Installing for use in a client app

Using npm:

$ npm install c2pa-node

Using Yarn:

$ yarn add c2pa-node

Using pnpm:

$ pnpm add c2pa-node

This command will download precompiled binaries for the following systems:

  • Linux x86_64
  • Linux aarch64 (ARM)
  • macOS aarch64 (Apple Silicon)
  • macOS x86_64 (Intel Mac)
  • Windows x86
  • Windows ARM

For all other platforms, you will need Rust installed on your system, as the postinstall step will attempt to build our Rust SDK into a native Node.js module on your machine.

Building custom binaries

For platforms or architectures that do not have a precompiled binaries or Rust tooling installed, you may need to build custom binaries. To pre-build a binary, install the Rust toolchain and then run the following commands on the target system or VM:

$ cd c2pa-node
$ pnpm install
$ pnpm build:rust

Then, you can copy the binary to a place that is accessible by your application (in this example, it is /path/to/my/application/resources) and set the path to the c2pa.node module via the C2PA_LIBRARY_PATH environment variable. Enter these commands:

$ cd /path/to/my/application
$ mkdir resources
$ cp /path/to/c2pa-node/generated/c2pa.node resources/c2pa.node
$ export C2PA_LIBRARY_PATH=resources/c2pa.node
$ npm install c2pa-node
$ npm start

Important: C2PA_LIBRARY_PATH must be set while both installing or adding c2pa-node to your app to avoid building the Rust code. It must also be set while running your app so that it loads the bindings from the correct location.

Installing for project contributions

If you want to contribute to this project, install the project with npm. In the project directory, enter these commands:

# Switch to the supported version of Node.js for building
$ nvm use
# Install pnpm
$ npm install -g pnpm
# Install dependencies
$ pnpm install
# Build the SDK
$ pnpm run build

Testing

After installation, run the test suite by entering this command:

$ pnpm test

In case the tests don't run, you may need to run a build first:

$ pnpm build

Usage

Creating a c2pa object

Instantiate a c2pa object by using createC2pa():

import { createC2pa } from 'c2pa-node';

const c2pa = createC2pa();

Reading a manifest

Use the c2pa.read() function to read a manifest; for example:

import { createC2pa } from 'c2pa-node';
import { readFile } from 'node:fs/promises';

const c2pa = createC2pa();

async function read(path, mimeType) {
  const buffer = await readFile(path);
  const result = await c2pa.read({ buffer, mimeType });

  if (result) {
    const { active_manifest, manifests, validation_status } = result;
    console.log(active_manifest);
  } else {
    console.log('No claim found');
  }
}

await read('my-c2pa-file.jpg', 'image/jpeg');

Creating a manifest

To create a manifest, pass the claim information to the ManifestBuilder object constructor; for example:

import { ManifestBuilder } from 'c2pa-node';

const manifest = new ManifestBuilder({
  claim_generator: 'my-app/1.0.0',
  format: 'image/jpeg',
  title: 'node_test_local_signer.jpg',
  assertions: [
    {
      label: 'c2pa.actions',
      data: {
        actions: [
          {
            action: 'c2pa.created',
          },
        ],
      },
    },
    {
      label: 'com.custom.my-assertion',
      data: {
        description: 'My custom test assertion',
        version: '1.0.0',
      },
    },
  ],
});

Adding an ingredient

Use c2pa.createIngredient() to load ingredient data for inclusion into a manifest. You can store the ingredient data on the backend and load it at signing time if necessary (for example if the original ingredient is no longer available); for example:

// Create the ingredient asset from a buffer
const ingredientAssetFromBuffer = {
  buffer: await readFile('my-ingredient.jpg'),
  mimeType: 'image/jpeg',
};
// Or load from a file
const ingredientAssetFromFile = {
  path: resolve('my-ingredient.jpg'),
};

// Create the ingredient
const ingredient = await c2pa.createIngredient({
  asset: ingredientAssetFromBuffer,
  title: 'ingredient.jpg',
});
// Add it to the manifest
manifest.addIngredient(ingredient);

Signing a manifest

Use the c2pa.sign() method to sign an ingredient, either locally if you have a signing certificate and key available, or by using a remote signing API.

Signing buffers

If you have an asset file's data loaded into memory, you can sign the the asset using a buffer.

NOTE: Signing using a buffer is currently supported only for image/jpeg and image/png data. For all other file types, use the file-based approach .

import { readFile } from 'node:fs/promises';
import { createC2pa, createTestSigner } from 'c2pa-node';

async function sign(asset, manifest) {
  const buffer = await readFile('to-be-signed.jpg');
  const asset: Asset = { buffer, mimeType: 'image/jpeg' };
  const signer = await createTestSigner();
  const c2pa = createC2pa({
    signer,
  });

  const { signedAsset, signedManifest } = await c2pa.sign({
    asset,
    manifest,
  });
}

sign(asset, manifest);

Signing files

To avoid loading the entire asset into memory (or for file types other than JPEG and PNG that don't support in-memory signing), pass in the file path to the asset file to sign it; for example:

import { resolve } from 'node:path';
import { createC2pa, createTestSigner } from 'c2pa-node';

async function sign(asset, manifest) {
  const asset = {
    path: resolve('to-be-signed.jpg'),
  };
  const outputPath = resolve('signed.jpg');
  const signer = await createTestSigner();
  const c2pa = createC2pa({
    signer,
  });

  const { signedAsset, signedManifest } = await c2pa.sign({
    manifest,
    asset,
    options: {
      outputPath,
    },
  });
}

sign(asset, manifest);

Local signing

If you have a signing certificate and key, you can sign locally using a local signer. This is fine during development, but doing it in production may be insecure. Instead use a Key Management Service (KMS) or a hardware security module (HSM) to access them; for example as show in the C2PA Python Example.

For example:

import { readFile } from 'node:fs/promises';
import { SigningAlgorithm } from 'c2pa-node';

async function createLocalSigner() {
  const [certificate, privateKey] = await Promise.all([
    readFile('tests/fixtures/certs/es256.pem'),
    readFile('tests/fixtures/certs/es256.pub'),
  ]);

  return {
    type: 'local',
    certificate,
    privateKey,
    algorithm: SigningAlgorithm.ES256,
    tsaUrl: 'http://timestamp.digicert.com',
  };
}

async function sign(asset, manifest) {
  const buffer = await readFile('to-be-signed.jpg');
  const asset: Asset = { buffer, mimeType: 'image/jpeg' };
  const signer = await createLocalSigner();
  const c2pa = createC2pa({
    signer,
  });

  const { signedAsset, signedManifest } = await c2pa.sign({
    asset,
    manifest,
  });
}

sign(asset, manifest);

Remote signing

If you have access to a web service that performs signing, you can use it to sign remotely; for example:

import { readFile } from 'node:fs/promises';
import { fetch, Headers } from 'node-fetch';
import { createC2pa, SigningAlgorithm } from 'c2pa-node';

function createRemoteSigner() {
  return {
    type: 'remote',
    async reserveSize() {
      const url = `https://my.signing.service/box-size`;
      const res = await fetch(url);
      const data = (await res.json()) as { boxSize: number };
      return data.boxSize;
    },
    async sign({ reserveSize, toBeSigned }) {
      const url = `https://my.signing.service/sign?boxSize=${reserveSize}`;
      const res = await fetch(url, {
        method: 'POST',
        headers: new Headers({
          'Content-Type': 'application/octet-stream',
        }),
        body: toBeSigned,
      });
      return res.buffer();
    },
  };
}

async function sign(asset, manifest) {
  const buffer = await readFile('to-be-signed.jpg');
  const asset: Asset = { buffer, mimeType: 'image/jpeg' };
  const signer = createRemoteSigner();
  const c2pa = createC2pa({
    signer,
  });

  const { signedAsset, signedManifest } = await c2pa.sign({
    asset,
    manifest,
  });
}

sign(asset, manifest);

API documentation

For the API documentation, see the /docs/ directory.

WARNING: The API is subject to change in this early prerelease library.