c2pa-python 0.24.1__tar.gz → 0.25.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {c2pa_python-0.24.1/src/c2pa_python.egg-info → c2pa_python-0.25.0}/PKG-INFO +1 -1
- {c2pa_python-0.24.1 → c2pa_python-0.25.0}/pyproject.toml +1 -1
- {c2pa_python-0.24.1 → c2pa_python-0.25.0}/src/c2pa/c2pa.py +51 -0
- {c2pa_python-0.24.1 → c2pa_python-0.25.0/src/c2pa_python.egg-info}/PKG-INFO +1 -1
- {c2pa_python-0.24.1 → c2pa_python-0.25.0}/tests/test_unit_tests.py +88 -0
- {c2pa_python-0.24.1 → c2pa_python-0.25.0}/LICENSE-APACHE +0 -0
- {c2pa_python-0.24.1 → c2pa_python-0.25.0}/LICENSE-MIT +0 -0
- {c2pa_python-0.24.1 → c2pa_python-0.25.0}/MANIFEST.in +0 -0
- {c2pa_python-0.24.1 → c2pa_python-0.25.0}/README.md +0 -0
- {c2pa_python-0.24.1 → c2pa_python-0.25.0}/requirements.txt +0 -0
- {c2pa_python-0.24.1 → c2pa_python-0.25.0}/scripts/download_artifacts.py +0 -0
- {c2pa_python-0.24.1 → c2pa_python-0.25.0}/setup.cfg +0 -0
- {c2pa_python-0.24.1 → c2pa_python-0.25.0}/setup.py +0 -0
- {c2pa_python-0.24.1 → c2pa_python-0.25.0}/src/c2pa/__init__.py +0 -0
- {c2pa_python-0.24.1 → c2pa_python-0.25.0}/src/c2pa/build.py +0 -0
- {c2pa_python-0.24.1 → c2pa_python-0.25.0}/src/c2pa/lib.py +0 -0
- {c2pa_python-0.24.1 → c2pa_python-0.25.0}/src/c2pa_python.egg-info/SOURCES.txt +0 -0
- {c2pa_python-0.24.1 → c2pa_python-0.25.0}/src/c2pa_python.egg-info/dependency_links.txt +0 -0
- {c2pa_python-0.24.1 → c2pa_python-0.25.0}/src/c2pa_python.egg-info/entry_points.txt +0 -0
- {c2pa_python-0.24.1 → c2pa_python-0.25.0}/src/c2pa_python.egg-info/requires.txt +0 -0
- {c2pa_python-0.24.1 → c2pa_python-0.25.0}/src/c2pa_python.egg-info/top_level.txt +0 -0
- {c2pa_python-0.24.1 → c2pa_python-0.25.0}/tests/test_unit_tests_threaded.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: c2pa-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.25.0
|
|
4
4
|
Summary: Python bindings for the C2PA Content Authenticity Initiative (CAI) library
|
|
5
5
|
Author-email: Gavin Peacock <gvnpeacock@adobe.com>, Tania Mathern <mathern@adobe.com>
|
|
6
6
|
Maintainer-email: Gavin Peacock <gpeacock@adobe.com>
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "c2pa-python"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.25.0"
|
|
8
8
|
requires-python = ">=3.10"
|
|
9
9
|
description = "Python bindings for the C2PA Content Authenticity Initiative (CAI) library"
|
|
10
10
|
readme = { file = "README.md", content-type = "text/markdown" }
|
|
@@ -64,6 +64,8 @@ _REQUIRED_FUNCTIONS = [
|
|
|
64
64
|
'c2pa_free_string_array',
|
|
65
65
|
'c2pa_reader_supported_mime_types',
|
|
66
66
|
'c2pa_builder_supported_mime_types',
|
|
67
|
+
'c2pa_reader_is_embedded',
|
|
68
|
+
'c2pa_reader_remote_url',
|
|
67
69
|
]
|
|
68
70
|
|
|
69
71
|
# TODO Bindings:
|
|
@@ -369,6 +371,16 @@ _setup_function(
|
|
|
369
371
|
[ctypes.POINTER(ctypes.c_size_t)],
|
|
370
372
|
ctypes.POINTER(ctypes.c_char_p)
|
|
371
373
|
)
|
|
374
|
+
_setup_function(
|
|
375
|
+
_lib.c2pa_reader_is_embedded,
|
|
376
|
+
[ctypes.POINTER(C2paReader)],
|
|
377
|
+
ctypes.c_bool
|
|
378
|
+
)
|
|
379
|
+
_setup_function(
|
|
380
|
+
_lib.c2pa_reader_remote_url,
|
|
381
|
+
[ctypes.POINTER(C2paReader)],
|
|
382
|
+
ctypes.c_void_p
|
|
383
|
+
)
|
|
372
384
|
|
|
373
385
|
# Set up Builder function prototypes
|
|
374
386
|
_setup_function(
|
|
@@ -1662,6 +1674,45 @@ class Reader:
|
|
|
1662
1674
|
|
|
1663
1675
|
return result
|
|
1664
1676
|
|
|
1677
|
+
def is_embedded(self) -> bool:
|
|
1678
|
+
"""Check if the reader was created from an embedded manifest.
|
|
1679
|
+
This method determines whether the C2PA manifest is embedded directly
|
|
1680
|
+
in the asset file or stored remotely.
|
|
1681
|
+
Returns:
|
|
1682
|
+
True if the reader was created from an embedded manifest,
|
|
1683
|
+
False if it was created from a remote manifest
|
|
1684
|
+
Raises:
|
|
1685
|
+
C2paError: If there was an error checking the embedded status
|
|
1686
|
+
"""
|
|
1687
|
+
self._ensure_valid_state()
|
|
1688
|
+
|
|
1689
|
+
result = _lib.c2pa_reader_is_embedded(self._reader)
|
|
1690
|
+
|
|
1691
|
+
return bool(result)
|
|
1692
|
+
|
|
1693
|
+
def get_remote_url(self) -> Optional[str]:
|
|
1694
|
+
"""Get the remote URL of the manifest if it was obtained remotely.
|
|
1695
|
+
This method returns the URL from which the C2PA manifest was fetched
|
|
1696
|
+
if the reader was created from a remote manifest. If the manifest
|
|
1697
|
+
is embedded in the asset, this will return None.
|
|
1698
|
+
Returns:
|
|
1699
|
+
The remote URL as a string if the manifest was obtained remotely,
|
|
1700
|
+
None if the manifest is embedded or no remote URL is available
|
|
1701
|
+
Raises:
|
|
1702
|
+
C2paError: If there was an error getting the remote URL
|
|
1703
|
+
"""
|
|
1704
|
+
self._ensure_valid_state()
|
|
1705
|
+
|
|
1706
|
+
result = _lib.c2pa_reader_remote_url(self._reader)
|
|
1707
|
+
|
|
1708
|
+
if result is None:
|
|
1709
|
+
# No remote URL set (manifest is embedded)
|
|
1710
|
+
return None
|
|
1711
|
+
|
|
1712
|
+
# Convert the C string to Python string
|
|
1713
|
+
url_str = _convert_to_py_string(result)
|
|
1714
|
+
return url_str
|
|
1715
|
+
|
|
1665
1716
|
|
|
1666
1717
|
class Signer:
|
|
1667
1718
|
"""High-level wrapper for C2PA Signer operations."""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: c2pa-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.25.0
|
|
4
4
|
Summary: Python bindings for the C2PA Content Authenticity Initiative (CAI) library
|
|
5
5
|
Author-email: Gavin Peacock <gvnpeacock@adobe.com>, Tania Mathern <mathern@adobe.com>
|
|
6
6
|
Maintainer-email: Gavin Peacock <gpeacock@adobe.com>
|
|
@@ -342,6 +342,94 @@ class TestReader(unittest.TestCase):
|
|
|
342
342
|
with self.assertRaises(Error):
|
|
343
343
|
reader.json()
|
|
344
344
|
|
|
345
|
+
def test_reader_is_embedded(self):
|
|
346
|
+
"""Test the is_embedded method returns correct values for embedded and remote manifests."""
|
|
347
|
+
|
|
348
|
+
# Test with a fixture which has an embedded manifest
|
|
349
|
+
with open(self.testPath, "rb") as file:
|
|
350
|
+
reader = Reader("image/jpeg", file)
|
|
351
|
+
self.assertTrue(reader.is_embedded())
|
|
352
|
+
reader.close()
|
|
353
|
+
|
|
354
|
+
# Test with cloud.jpg fixture which has a remote manifest (not embedded)
|
|
355
|
+
cloud_fixture_path = os.path.join(self.data_dir, "cloud.jpg")
|
|
356
|
+
with Reader("image/jpeg", cloud_fixture_path) as reader:
|
|
357
|
+
self.assertFalse(reader.is_embedded())
|
|
358
|
+
|
|
359
|
+
def test_sign_and_read_is_not_embedded(self):
|
|
360
|
+
"""Test the is_embedded method returns correct values for remote manifests."""
|
|
361
|
+
|
|
362
|
+
with open(os.path.join(self.data_dir, "es256_certs.pem"), "rb") as cert_file:
|
|
363
|
+
certs = cert_file.read()
|
|
364
|
+
with open(os.path.join(self.data_dir, "es256_private.key"), "rb") as key_file:
|
|
365
|
+
key = key_file.read()
|
|
366
|
+
|
|
367
|
+
# Create signer info and signer
|
|
368
|
+
signer_info = C2paSignerInfo(
|
|
369
|
+
alg=b"es256",
|
|
370
|
+
sign_cert=certs,
|
|
371
|
+
private_key=key,
|
|
372
|
+
ta_url=b"http://timestamp.digicert.com"
|
|
373
|
+
)
|
|
374
|
+
signer = Signer.from_info(signer_info)
|
|
375
|
+
|
|
376
|
+
# Define a simple manifest
|
|
377
|
+
manifest_definition = {
|
|
378
|
+
"claim_generator": "python_test",
|
|
379
|
+
"claim_generator_info": [{
|
|
380
|
+
"name": "python_test",
|
|
381
|
+
"version": "0.0.1",
|
|
382
|
+
}],
|
|
383
|
+
"format": "image/jpeg",
|
|
384
|
+
"title": "Python Test Image",
|
|
385
|
+
"ingredients": [],
|
|
386
|
+
"assertions": [
|
|
387
|
+
{
|
|
388
|
+
"label": "c2pa.actions",
|
|
389
|
+
"data": {
|
|
390
|
+
"actions": [
|
|
391
|
+
{
|
|
392
|
+
"action": "c2pa.opened"
|
|
393
|
+
}
|
|
394
|
+
]
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
]
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
# Create a temporary directory for the signed file
|
|
401
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
402
|
+
temp_file_path = os.path.join(temp_dir, "signed_test_file_no_embed.jpg")
|
|
403
|
+
|
|
404
|
+
with open(self.testPath, "rb") as file:
|
|
405
|
+
builder = Builder(manifest_definition)
|
|
406
|
+
# Direct the Builder not to embed the manifest into the asset
|
|
407
|
+
builder.set_no_embed()
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
with open(temp_file_path, "wb") as temp_file:
|
|
411
|
+
manifest_data = builder.sign(
|
|
412
|
+
signer, "image/jpeg", file, temp_file)
|
|
413
|
+
|
|
414
|
+
with Reader("image/jpeg", temp_file_path, manifest_data) as reader:
|
|
415
|
+
self.assertFalse(reader.is_embedded())
|
|
416
|
+
|
|
417
|
+
def test_reader_get_remote_url(self):
|
|
418
|
+
"""Test the get_remote_url method returns correct values for embedded and remote manifests."""
|
|
419
|
+
|
|
420
|
+
# Test get_remote_url for file with embedded manifest (should return None)
|
|
421
|
+
with open(self.testPath, "rb") as file:
|
|
422
|
+
reader = Reader("image/jpeg", file)
|
|
423
|
+
self.assertIsNone(reader.get_remote_url())
|
|
424
|
+
reader.close()
|
|
425
|
+
|
|
426
|
+
# Test remote manifest using cloud.jpg fixture which has a remote URL
|
|
427
|
+
cloud_fixture_path = os.path.join(self.data_dir, "cloud.jpg")
|
|
428
|
+
with Reader("image/jpeg", cloud_fixture_path) as reader:
|
|
429
|
+
remote_url = reader.get_remote_url()
|
|
430
|
+
self.assertEqual(remote_url, "https://cai-manifests.adobe.com/manifests/adobe-urn-uuid-5f37e182-3687-462e-a7fb-573462780391")
|
|
431
|
+
self.assertFalse(reader.is_embedded())
|
|
432
|
+
|
|
345
433
|
# TODO: Unskip once fixed configuration to read data is clarified
|
|
346
434
|
# def test_read_cawg_data_file(self):
|
|
347
435
|
# """Test reading C2PA metadata from C_with_CAWG_data.jpg file."""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|