Metadata-Version: 2.4
Name: EmbeddedSigner
Version: 0.1.3.dev7
Summary: Embed XMP metadata and sign media assets using Swarmauri plugins.
License-Expression: Apache-2.0
License-File: LICENSE
Keywords: xmp,signing,swarmauri,metadata,security,digital-rights-management,drm,license-rights,embedded-licensing,tamper-proofing,tamper-evidence,content-protection,png,gif,jpeg,svg,webp,tiff,pdf,mp4,digital-asset-security,metadata-signing,workflow-automation,plugin-orchestration,asyncio,plugin,digital-asset-workflows,cms,pkcs7,cades,jws,openpgp,pdf-signatures,xmldsig
Author: Jacob Stewart
Author-email: jacob@swarmauri.com
Requires-Python: >=3.10,<3.13
Classifier: Development Status :: 1 - Planning
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Natural Language :: English
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Framework :: AsyncIO
Classifier: Topic :: Security :: Cryptography
Classifier: Operating System :: OS Independent
Classifier: Topic :: Multimedia :: Graphics
Classifier: Topic :: Multimedia :: Video
Classifier: Intended Audience :: Developers
Provides-Extra: full
Provides-Extra: local
Provides-Extra: memory
Provides-Extra: signing-all
Provides-Extra: signing-cms
Provides-Extra: signing-jws
Provides-Extra: signing-openpgp
Provides-Extra: signing-pdf
Provides-Extra: signing-xmld
Provides-Extra: xmp-all
Provides-Extra: xmp-gif
Provides-Extra: xmp-jpeg
Provides-Extra: xmp-mp4
Provides-Extra: xmp-pdf
Provides-Extra: xmp-png
Provides-Extra: xmp-svg
Provides-Extra: xmp-tiff
Provides-Extra: xmp-webp
Requires-Dist: EmbedXMP
Requires-Dist: MediaSigner
Requires-Dist: swarmauri_base
Requires-Dist: swarmauri_core
Requires-Dist: swarmauri_keyprovider_inmemory ; extra == "full"
Requires-Dist: swarmauri_keyprovider_inmemory ; extra == "memory"
Requires-Dist: swarmauri_keyprovider_local ; extra == "full"
Requires-Dist: swarmauri_keyprovider_local ; extra == "local"
Requires-Dist: swarmauri_signing_cms ; extra == "full"
Requires-Dist: swarmauri_signing_cms ; extra == "signing-all"
Requires-Dist: swarmauri_signing_cms ; extra == "signing-cms"
Requires-Dist: swarmauri_signing_jws ; extra == "full"
Requires-Dist: swarmauri_signing_jws ; extra == "signing-all"
Requires-Dist: swarmauri_signing_jws ; extra == "signing-jws"
Requires-Dist: swarmauri_signing_openpgp ; extra == "full"
Requires-Dist: swarmauri_signing_openpgp ; extra == "signing-all"
Requires-Dist: swarmauri_signing_openpgp ; extra == "signing-openpgp"
Requires-Dist: swarmauri_signing_pdf ; extra == "full"
Requires-Dist: swarmauri_signing_pdf ; extra == "signing-all"
Requires-Dist: swarmauri_signing_pdf ; extra == "signing-pdf"
Requires-Dist: swarmauri_signing_xmld ; extra == "full"
Requires-Dist: swarmauri_signing_xmld ; extra == "signing-all"
Requires-Dist: swarmauri_signing_xmld ; extra == "signing-xmld"
Requires-Dist: swarmauri_xmp_gif ; extra == "full"
Requires-Dist: swarmauri_xmp_gif ; extra == "xmp-all"
Requires-Dist: swarmauri_xmp_gif ; extra == "xmp-gif"
Requires-Dist: swarmauri_xmp_jpeg ; extra == "full"
Requires-Dist: swarmauri_xmp_jpeg ; extra == "xmp-all"
Requires-Dist: swarmauri_xmp_jpeg ; extra == "xmp-jpeg"
Requires-Dist: swarmauri_xmp_mp4 ; extra == "full"
Requires-Dist: swarmauri_xmp_mp4 ; extra == "xmp-all"
Requires-Dist: swarmauri_xmp_mp4 ; extra == "xmp-mp4"
Requires-Dist: swarmauri_xmp_pdf ; extra == "full"
Requires-Dist: swarmauri_xmp_pdf ; extra == "xmp-all"
Requires-Dist: swarmauri_xmp_pdf ; extra == "xmp-pdf"
Requires-Dist: swarmauri_xmp_png ; extra == "full"
Requires-Dist: swarmauri_xmp_png ; extra == "xmp-all"
Requires-Dist: swarmauri_xmp_png ; extra == "xmp-png"
Requires-Dist: swarmauri_xmp_svg ; extra == "full"
Requires-Dist: swarmauri_xmp_svg ; extra == "xmp-all"
Requires-Dist: swarmauri_xmp_svg ; extra == "xmp-svg"
Requires-Dist: swarmauri_xmp_tiff ; extra == "full"
Requires-Dist: swarmauri_xmp_tiff ; extra == "xmp-all"
Requires-Dist: swarmauri_xmp_tiff ; extra == "xmp-tiff"
Requires-Dist: swarmauri_xmp_webp ; extra == "full"
Requires-Dist: swarmauri_xmp_webp ; extra == "xmp-all"
Requires-Dist: swarmauri_xmp_webp ; extra == "xmp-webp"
Project-URL: Changelog, https://github.com/swarmauri/swarmauri-sdk/releases
Project-URL: Documentation, https://github.com/swarmauri/swarmauri-sdk/tree/main/pkgs/plugins/embedded_signer#readme
Project-URL: Discussions, https://github.com/orgs/swarmauri/discussions
Project-URL: Homepage, https://github.com/swarmauri/swarmauri-sdk
Project-URL: Issues, https://github.com/swarmauri/swarmauri-sdk/issues
Project-URL: Source, https://github.com/swarmauri/swarmauri-sdk/tree/main/pkgs/plugins/embedded_signer
Description-Content-Type: text/markdown

<p align="center">
  <img src="../../../assets/swarmauri.brand.theme.svg" alt="Swarmauri logotype" width="420" />
</p>

<h1 align="center">EmbeddedSigner</h1>

<p align="center">
  <a href="https://img.shields.io/pypi/dm/EmbeddedSigner?style=for-the-badge"><img src="https://img.shields.io/pypi/dm/EmbeddedSigner?style=for-the-badge" alt="PyPI - Downloads" /></a>
  <a href="https://hits.sh/github.com/swarmauri/swarmauri-sdk/tree/main/pkgs/plugins/embedded_signer/"><img src="https://hits.sh/github.com/swarmauri/swarmauri-sdk/tree/main/pkgs/plugins/embedded_signer.svg?style=for-the-badge" alt="Repo views" /></a>
  <a href="https://img.shields.io/pypi/pyversions/EmbeddedSigner?style=for-the-badge"><img src="https://img.shields.io/pypi/pyversions/EmbeddedSigner?style=for-the-badge" alt="Supported Python versions" /></a>
  <a href="https://img.shields.io/pypi/l/EmbeddedSigner?style=for-the-badge"><img src="https://img.shields.io/pypi/l/EmbeddedSigner?style=for-the-badge" alt="License" /></a>
  <a href="https://img.shields.io/pypi/v/EmbeddedSigner?style=for-the-badge"><img src="https://img.shields.io/pypi/v/EmbeddedSigner?style=for-the-badge" alt="Latest release" /></a>
</p>

EmbeddedSigner composes the dynamic XMP embedding utilities from
[`EmbedXMP`](../EmbedXMP) with the signing facade exposed by
[`MediaSigner`](../media_signer). 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`

```bash
uv add EmbeddedSigner
```

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

```bash
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`

```bash
pip install EmbeddedSigner
```

Extras mirror the `uv` workflow:

```bash
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

```python
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:

```python
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:

```python
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:

```bash
# 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:

   ```bash
   uv pip install -e ".[dev]"
   ```

2. Format and lint code with `ruff`:

   ```bash
   uv run ruff format .
   uv run ruff check . --fix
   ```

3. Run the unit tests in isolation:

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

## Project Resources

- Source: <https://github.com/swarmauri/swarmauri-sdk/tree/main/pkgs/plugins/embedded_signer>
- Documentation: <https://github.com/swarmauri/swarmauri-sdk/tree/main/pkgs/plugins/embedded_signer#readme>
- Issues: <https://github.com/swarmauri/swarmauri-sdk/issues>
- Releases: <https://github.com/swarmauri/swarmauri-sdk/releases>
- Discussions: <https://github.com/orgs/swarmauri/discussions>

## License

EmbeddedSigner is released under the Apache 2.0 License. See the
[LICENSE](LICENSE) file for details.

