Skip to main content

Embed XMP metadata and sign media assets using Swarmauri plugins.

Project description

Swarmauri logotype

EmbeddedSigner

PyPI - Downloads Repo views Supported Python versions License Latest release

EmbeddedSigner composes the dynamic XMP embedding utilities from EmbedXMP with the signing facade exposed by MediaSigner. It embeds metadata into media assets and then routes signing requests to the appropriate media-aware signer in either attached or detached mode. The class orchestrates key provider plugins so that opaque key references can be resolved automatically before signatures are produced.

Features

  • One-shot embed & sign – inject XMP metadata and produce signatures with a single call.
  • Media-aware detection – delegates to all registered EmbedXmpBase handlers so PNG, GIF, JPEG, SVG, WEBP, TIFF, PDF, and MP4 assets are processed consistently.
  • Pluggable signers – forwards signing requests to every SigningBase registered with MediaSigner, including CMS, JWS, OpenPGP, PDF, and XMLDSig providers.
  • Key provider integration – loads providers from the swarmauri.key_providers entry point group and resolves opaque key reference strings (e.g. local://kid@2) before invoking a signer.
  • Attached or detached output – toggle between embedded signatures or detached artifacts via a simple flag.
  • File and byte workflows – operate on in-memory payloads or update files on disk with helpers for embedding, reading, removing, and signing.
  • Command line tooling – bundle a ready-to-use embedded-signer CLI for ad-hoc embedding, signing, and combined workflows.

Installation

Using uv

uv add EmbeddedSigner

Optional dependencies align with the available key providers, EmbedXMP handlers, and MediaSigner backends:

uv add "EmbeddedSigner[local]"      # enable LocalKeyProvider resolution
uv add "EmbeddedSigner[memory]"     # enable InMemoryKeyProvider resolution
uv add "EmbeddedSigner[xmp_png]"    # add PNG embedding support
uv add "EmbeddedSigner[xmp_all]"    # install every EmbedXMP handler
uv add "EmbeddedSigner[signing_pdf]"  # enable PDF signer backend
uv add "EmbeddedSigner[signing_all]"  # install every MediaSigner backend
uv add "EmbeddedSigner[full]"       # bring in all extras and key providers

Using pip

pip install EmbeddedSigner

Extras mirror the uv workflow:

pip install "EmbeddedSigner[local]"
pip install "EmbeddedSigner[memory]"
pip install "EmbeddedSigner[xmp_png]"
pip install "EmbeddedSigner[xmp_all]"
pip install "EmbeddedSigner[signing_pdf]"
pip install "EmbeddedSigner[signing_all]"
pip install "EmbeddedSigner[full]"

Extras overview

Extra name Purpose
local / memory Enable Swarmauri key provider resolution for local filesystem and in-memory secrets.
xmp_gif, xmp_jpeg, xmp_png, xmp_svg, xmp_webp, xmp_tiff, xmp_pdf, xmp_mp4 Pull in the corresponding swarmauri_xmp_* handler so EmbedXMP can embed metadata for that media format.
xmp_all Install every EmbedXMP media handler dependency at once.
signing_cms, signing_jws, signing_openpgp, signing_pdf, signing_xmld Add the matching MediaSigner backend plugin for CMS, JWS, OpenPGP, PDF, or XMLDSig signing.
signing_all Install all MediaSigner backends together.
full Bring in every key provider, EmbedXMP handler, and MediaSigner backend for maximum coverage.

Usage

import asyncio
from pathlib import Path

from EmbeddedSigner import EmbedSigner

xmp_xml = """
<x:xmpmeta xmlns:x="adobe:ns:meta/">
  <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
    <rdf:Description rdf:about=""/>
  </rdf:RDF>
</x:xmpmeta>
""".strip()

async def embed_and_sign() -> None:
    signer = EmbedSigner()
    media_bytes = Path("image.png").read_bytes()
    embedded, signatures = await signer.embed_and_sign_bytes(
        media_bytes,
        fmt="JWSSigner",
        xmp_xml=xmp_xml,
        key={"kind": "raw", "key": b"\x00" * 32},
        path="image.png",
        attached=True,
        signer_opts={"alg": "HS256"},
    )
    Path("image.signed.png").write_bytes(embedded)
    print(signatures[0].mode)  # "attached"

asyncio.run(embed_and_sign())

Key provider integration

When you install a key provider plugin such as swarmauri_keyprovider_local, EmbeddedSigner can resolve string key references on the fly:

signer = EmbedSigner(key_provider_name="LocalKeyProvider")
embedded, signatures = await signer.embed_and_sign_file(
    Path("report.pdf"),
    fmt="PDFSigner",
    xmp_xml=xmp_xml,
    key="LocalKeyProvider://a1b2c3@1",
    attached=False,
    signer_opts={"alg": "SHA256"},
)

EmbeddedSigner parses the opaque reference, looks up the provider by name, and retrieves the specified key version using the provider's asynchronous API.

File helpers

EmbedSigner offers mirrored helpers that operate on file paths when you need to persist updates directly on disk:

signer = EmbedSigner()

# Embed metadata into a file and write it back in place.
signer.embed_file("image.png", xmp_xml)

# Read embedded metadata without materialising the bytes in memory.
print(signer.read_xmp_file("image.png"))

# Remove metadata and persist the stripped bytes to a new path.
signer.remove_xmp_file("image.png", write_back=True)

# Sign file contents without manual IO boilerplate.
signatures = asyncio.run(
    signer.sign_file(
        "image.png",
        fmt="JWSSigner",
        key="LocalKeyProvider://img-key",
        attached=True,
    )
)

Command line interface

Installing the package exposes an embedded-signer executable that wraps the most common workflows:

# Embed metadata from a file into an image in place.
embedded-signer embed example.png --xmp-file metadata.xmp

# Read metadata to stdout (non-zero exit if none is embedded).
embedded-signer read example.png

# Remove metadata and write the result to a new file.
embedded-signer remove example.png --output clean.png

# Sign using a key reference exposed by a provider plugin.
embedded-signer sign example.png --format JWSSigner --key-ref local://img-key

# Embed and sign in one step, writing signatures to JSON.
embedded-signer embed-sign example.png \
  --xmp-file metadata.xmp \
  --format JWSSigner \
  --key-ref local://img-key \
  --signature-output signatures.json

Development

  1. Install development dependencies:

    uv pip install -e ".[dev]"
    
  2. Format and lint code with ruff:

    uv run ruff format .
    uv run ruff check . --fix
    
  3. Run the unit tests in isolation:

    uv run --package EmbeddedSigner --directory plugins/embedded_signer pytest
    

Project Resources

License

EmbeddedSigner is released under the Apache 2.0 License. See the LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

embeddedsigner-0.1.2.dev1.tar.gz (13.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

embeddedsigner-0.1.2.dev1-py3-none-any.whl (15.0 kB view details)

Uploaded Python 3

File details

Details for the file embeddedsigner-0.1.2.dev1.tar.gz.

File metadata

  • Download URL: embeddedsigner-0.1.2.dev1.tar.gz
  • Upload date:
  • Size: 13.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.27 {"installer":{"name":"uv","version":"0.9.27","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for embeddedsigner-0.1.2.dev1.tar.gz
Algorithm Hash digest
SHA256 265807bd69cd4aed5196424bd3c124631601511f17578ed17ce946f8a6ded41e
MD5 e734f4f96e03940ce61082df66e58800
BLAKE2b-256 b659a8e181078d9bd4a43ad1462ca22e5fdbe560ad200b5a4108ee0ebe1f97e8

See more details on using hashes here.

File details

Details for the file embeddedsigner-0.1.2.dev1-py3-none-any.whl.

File metadata

  • Download URL: embeddedsigner-0.1.2.dev1-py3-none-any.whl
  • Upload date:
  • Size: 15.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.9.27 {"installer":{"name":"uv","version":"0.9.27","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for embeddedsigner-0.1.2.dev1-py3-none-any.whl
Algorithm Hash digest
SHA256 b005bb54fa8d376f8976ed697851331d0aea089a7b8a536d5d3f5c91cae48c84
MD5 b2bf298245d6ce9009fe69d306402df7
BLAKE2b-256 34ce025f0adb2baf8482c6d19c08806b4532a94b1e558d70a08d628650c60146

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page