Attaching and signing a manifest
- JavaScript
- Python
- Node.js
- C++
- Rust
You can't currently attach a manifest to an asset and sign the claim using the JavaScript library. You need to use a language that runs on the "back-end," such as Python, Node.js, C++, or Rust.
This is an example of how to assign a manifest to an asset and sign the claim using Python.
Use a Builder
object to add a manifest to an asset.
try:
# Define a function to sign the claim bytes.
# In this case we are using a pre-defined sign_ps256 method, passing in our private cert.
# Normally this cert would be kept safe in some other location.
def private_sign(data: bytes) -> bytes:
return sign_ps256(data, "tests/fixtures/ps256.pem")
# Read our public certs into memory.
certs = open(data_dir + "ps256.pub", "rb").read()
# Create a signer from the private signer, certs and a time stamp service URL.
signer = create_signer(private_sign, SigningAlg.PS256, certs, "http://timestamp.digicert.com")
# Create a builder add a thumbnail resource and an ingredient file.
builder = Builder(manifest_json)
# Add the resource from a stream.
a_thumbnail_jpg_stream = open("tests/fixtures/A_thumbnail.jpg", "rb")
builder.add_resource("image/jpeg", a_thumbnail_jpg_stream)
# Add the resource from a file.
# The URI provided here, "thumbnail", must match an identifier in the manifest definition.
builder.add_resource_file("thumbnail", "tests/fixtures/A_thumbnail.jpg")
# Define an ingredient, in this case a parent ingredient named A.jpg, with a thumbnail.
ingredient_json = {
"title": "A.jpg",
"relationship": "parentOf", # "parentOf", "componentOf" or "inputTo"
"thumbnail": {
"identifier": "thumbnail",
"format": "image/jpeg"
}
}
# Add the ingredient from a stream.
a_jpg_stream = open("tests/fixtures/A.jpg", "rb")
builder.add_ingredient("image/jpeg", a_jpg_stream)
# At this point archive or unarchive Builder to continue later.
# This example uses a bytearray for the archive stream.
# All ingredients and resources are saved in the archive.
archive = io.BytesIO(bytearray())
builder.to_archive(archive)
archive.seek()
builder = builder.from_archive(archive)
# Sign the builder with a stream and output it to a stream.
# This returns the binary manifest data that could be uploaded to cloud storage.
input_stream = open("tests/fixtures/A.jpg", "rb")
output_stream = open("target/out.jpg", "wb")
c2pa_data = builder.sign(signer, "image/jpeg", input_stream, output_stream)
except Exception as err:
print(err)
note
The Node.js library is being revised. The documentation will be updated as soon as possible with the latest changes.
This is an example of how to assign a manifest to an asset and sign the claim using C++:
const std::string manifest_json = R"{
"claim_generator": "c2pa_c_test/0.1",
"claim_generator_info": [
{
"name": "c2pa-c test",
"version": "0.1"
}
],
"assertions": [
{
"label": "c2pa.training-mining",
"data": {
"entries": {
"c2pa.ai_generative_training": { "use": "notAllowed" },
"c2pa.ai_inference": { "use": "notAllowed" },
"c2pa.ai_training": { "use": "notAllowed" },
"c2pa.data_mining": { "use": "notAllowed" }
}
}
}
]
};
auto builder = Builder(manifest_json);
This is an example of how to assign a manifest to an asset and sign the claim using Rust.
This example is from c2pa-rs/sdk/examples/v2api.rs
:
let json = manifest_def(title, format);
let mut builder = Builder::from_json(&json)?;
builder.add_ingredient_from_stream(
json!({
"title": parent_name,
"relationship": "parentOf"
})
.to_string(),
format,
&mut source,
)?;
let thumb_uri = builder
.definition
.thumbnail
.as_ref()
.map(|t| t.identifier.clone());
// add a manifest thumbnail ( just reuse the image for now )
if let Some(uri) = thumb_uri {
if !uri.starts_with("self#jumbf") {
source.rewind()?;
builder.add_resource(&uri, &mut source)?;
}
}
// write the manifest builder to a zipped stream
let mut zipped = Cursor::new(Vec::new());
builder.to_archive(&mut zipped)?;
// unzip the manifest builder from the zipped stream
zipped.rewind()?;
let ed_signer =
|_context: *const (), data: &[u8]| CallbackSigner::ed25519_sign(data, PRIVATE_KEY);
let signer = CallbackSigner::new(ed_signer, SigningAlg::Ed25519, CERTS);
let mut builder = Builder::from_archive(&mut zipped)?;
// sign the ManifestStoreBuilder and write it to the output stream
let mut dest = Cursor::new(Vec::new());
builder.sign(&signer, format, &mut source, &mut dest)?;