Skip to content

Commit a957727

Browse files
committed
Update example
1 parent 4eaae87 commit a957727

File tree

1 file changed

+52
-54
lines changed

1 file changed

+52
-54
lines changed

docs/usage.md

Lines changed: 52 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,18 @@ manifest_json = json.dumps({
3636

3737
## Signing function
3838

39-
The `sign_ps256` function is [defined in the library](https://github.com/contentauth/c2pa-python/blob/main/c2pa/c2pa_api/c2pa_api.py#L209) is used in both file-based and stream-based methods and is reproduced here to show how signing is performed.
39+
The `sign_ps256` function is [defined in the library](https://github.com/contentauth/c2pa-python/blob/main/c2pa/c2pa_api/c2pa_api.py#L244) and used in both file-based and stream-based methods. It's reproduced here to show how signing is performed.
4040

4141
```py
4242
# Example of using Python crypto to sign data using openssl with Ps256
4343
from cryptography.hazmat.primitives import hashes, serialization
4444
from cryptography.hazmat.primitives.asymmetric import padding
4545

46-
def sign_ps256(data: bytes, key_path: str) -> bytes:
47-
with open(key_path, "rb") as key_file:
48-
private_key = serialization.load_pem_private_key(
49-
key_file.read(),
50-
password=None,
51-
)
46+
def sign_ps256(data: bytes, key: bytes) -> bytes:
47+
private_key = serialization.load_pem_private_key(
48+
key,
49+
password=None,
50+
)
5251
signature = private_key.sign(
5352
data,
5453
padding.PSS(
@@ -78,7 +77,7 @@ try:
7877
reader = c2pa.Reader.from_file("path/to/media_file.jpg")
7978

8079
# Print the JSON for a manifest.
81-
print("manifest store:", reader.json())
80+
print("Manifest store:", reader.json())
8281

8382
# Get the active manifest.
8483
manifest = reader.get_active_manifest()
@@ -99,52 +98,51 @@ except Exception as err:
9998
Use a `Builder` to add a manifest to an asset:
10099

101100
```py
102-
try:
103-
# Define a function to sign the claim bytes
104-
# In this case we are using a pre-defined sign_ps256 method, passing in our private cert
105-
# Normally this cert would be kept safe in some other location
106-
def private_sign(data: bytes) -> bytes:
107-
return sign_ps256(data, "tests/fixtures/ps256.pem")
108-
109-
# read our public certs into memory
110-
certs = open(data_dir + "ps256.pub", "rb").read()
111-
112-
# Create a signer from the private signer, certs and a time stamp service url
113-
signer = create_signer(private_sign, SigningAlg.PS256, certs, "http://timestamp.digicert.com")
114-
115-
# Create a builder add a thumbnail resource and an ingredient file.
116-
builder = Builder(manifest_json)
117-
118-
# The uri provided here "thumbnail" must match an identifier in the manifest definition.
119-
builder.add_resource_file("thumbnail", "tests/fixtures/A_thumbnail.jpg")
120-
121-
# Define an ingredient, in this case a parent ingredient named A.jpg, with a thumbnail
122-
ingredient_json = {
123-
"title": "A.jpg",
124-
"relationship": "parentOf", # "parentOf", "componentOf" or "inputTo"
125-
"thumbnail": {
126-
"identifier": "thumbnail",
127-
"format": "image/jpeg"
128-
}
129-
}
130-
131-
# Add the ingredient to the builder loading information from a source file.
132-
builder.add_ingredient_file(ingredient_json, "tests/fixtures/A.jpg")
133-
134-
# At this point we could archive or unarchive our Builder to continue later.
135-
# In this example we use a bytearray for the archive stream.
136-
# all ingredients and resources will be saved in the archive
137-
archive = io.BytesIO(bytearray())
138-
builder.to_archive(archive)
139-
archive.seek()
140-
builder = builder.from_archive(archive)
141-
142-
# Sign and add our manifest to a source file, writing it to an output file.
143-
# This returns the binary manifest data that could be uploaded to cloud storage.
144-
c2pa_data = builder.sign_file(signer, "tests/fixtures/A.jpg", "target/out.jpg")
145-
146-
except Exception as err:
147-
print(err)
101+
def test_v2_sign(self):
102+
# Define source folder for any assets being read.
103+
data_dir = "tests/fixtures/"
104+
try:
105+
key = open(data_dir + "ps256.pem", "rb").read()
106+
def sign(data: bytes) -> bytes:
107+
return sign_ps256(data, key)
108+
109+
certs = open(data_dir + "ps256.pub", "rb").read()
110+
# Create a local signer from a certificate pem file.
111+
signer = create_signer(sign, SigningAlg.PS256, certs, "http://timestamp.digicert.com")
112+
113+
builder = Builder(manifest_def)
114+
115+
builder.add_ingredient_file(ingredient_def, data_dir + "A.jpg")
116+
117+
builder.add_resource_file("A.jpg", data_dir + "A.jpg")
118+
119+
builder.to_archive(open("target/archive.zip", "wb"))
120+
121+
builder = Builder.from_archive(open("target/archive.zip", "rb"))
122+
123+
with tempfile.TemporaryDirectory() as output_dir:
124+
output_path = output_dir + "out.jpg"
125+
if os.path.exists(output_path):
126+
os.remove(output_path)
127+
c2pa_data = builder.sign_file(signer, data_dir + "A.jpg", output_dir + "out.jpg")
128+
assert len(c2pa_data) > 0
129+
130+
reader = Reader.from_file(output_dir + "out.jpg")
131+
print(reader.json())
132+
manifest_store = json.loads(reader.json())
133+
manifest = manifest_store["manifests"][manifest_store["active_manifest"]]
134+
assert "python_test" in manifest["claim_generator"]
135+
# Check custom title and format.
136+
assert manifest["title"]== "My Title"
137+
assert manifest,["format"] == "image/jpeg"
138+
# There should be no validation status errors.
139+
assert manifest.get("validation_status") == None
140+
assert manifest["ingredients"][0]["relationship"] == "parentOf"
141+
assert manifest["ingredients"][0]["title"] == "A.jpg"
142+
143+
except Exception as e:
144+
print("Failed to sign manifest store: " + str(e))
145+
exit(1)
148146
```
149147

150148
## Stream-based operation

0 commit comments

Comments
 (0)