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.
Files changed (22) hide show
  1. {c2pa_python-0.24.1/src/c2pa_python.egg-info → c2pa_python-0.25.0}/PKG-INFO +1 -1
  2. {c2pa_python-0.24.1 → c2pa_python-0.25.0}/pyproject.toml +1 -1
  3. {c2pa_python-0.24.1 → c2pa_python-0.25.0}/src/c2pa/c2pa.py +51 -0
  4. {c2pa_python-0.24.1 → c2pa_python-0.25.0/src/c2pa_python.egg-info}/PKG-INFO +1 -1
  5. {c2pa_python-0.24.1 → c2pa_python-0.25.0}/tests/test_unit_tests.py +88 -0
  6. {c2pa_python-0.24.1 → c2pa_python-0.25.0}/LICENSE-APACHE +0 -0
  7. {c2pa_python-0.24.1 → c2pa_python-0.25.0}/LICENSE-MIT +0 -0
  8. {c2pa_python-0.24.1 → c2pa_python-0.25.0}/MANIFEST.in +0 -0
  9. {c2pa_python-0.24.1 → c2pa_python-0.25.0}/README.md +0 -0
  10. {c2pa_python-0.24.1 → c2pa_python-0.25.0}/requirements.txt +0 -0
  11. {c2pa_python-0.24.1 → c2pa_python-0.25.0}/scripts/download_artifacts.py +0 -0
  12. {c2pa_python-0.24.1 → c2pa_python-0.25.0}/setup.cfg +0 -0
  13. {c2pa_python-0.24.1 → c2pa_python-0.25.0}/setup.py +0 -0
  14. {c2pa_python-0.24.1 → c2pa_python-0.25.0}/src/c2pa/__init__.py +0 -0
  15. {c2pa_python-0.24.1 → c2pa_python-0.25.0}/src/c2pa/build.py +0 -0
  16. {c2pa_python-0.24.1 → c2pa_python-0.25.0}/src/c2pa/lib.py +0 -0
  17. {c2pa_python-0.24.1 → c2pa_python-0.25.0}/src/c2pa_python.egg-info/SOURCES.txt +0 -0
  18. {c2pa_python-0.24.1 → c2pa_python-0.25.0}/src/c2pa_python.egg-info/dependency_links.txt +0 -0
  19. {c2pa_python-0.24.1 → c2pa_python-0.25.0}/src/c2pa_python.egg-info/entry_points.txt +0 -0
  20. {c2pa_python-0.24.1 → c2pa_python-0.25.0}/src/c2pa_python.egg-info/requires.txt +0 -0
  21. {c2pa_python-0.24.1 → c2pa_python-0.25.0}/src/c2pa_python.egg-info/top_level.txt +0 -0
  22. {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.24.1
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.24.1"
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.24.1
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