EmbeddedSigner 0.1.4.dev19__py3-none-any.whl → 0.11.0.dev1__py3-none-any.whl
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.
- EmbeddedSigner/_embed_signer.py +48 -15
- EmbeddedSigner/cli.py +39 -13
- {embeddedsigner-0.1.4.dev19.dist-info → embeddedsigner-0.11.0.dev1.dist-info}/METADATA +27 -162
- embeddedsigner-0.11.0.dev1.dist-info/RECORD +8 -0
- {embeddedsigner-0.1.4.dev19.dist-info → embeddedsigner-0.11.0.dev1.dist-info}/WHEEL +1 -1
- embeddedsigner-0.1.4.dev19.dist-info/RECORD +0 -8
- {embeddedsigner-0.1.4.dev19.dist-info → embeddedsigner-0.11.0.dev1.dist-info}/entry_points.txt +0 -0
- {embeddedsigner-0.1.4.dev19.dist-info → embeddedsigner-0.11.0.dev1.dist-info}/licenses/LICENSE +0 -0
EmbeddedSigner/_embed_signer.py
CHANGED
|
@@ -53,7 +53,9 @@ class EmbedSigner:
|
|
|
53
53
|
self._default_provider = key_provider
|
|
54
54
|
self._default_provider_name = key_provider.__class__.__name__
|
|
55
55
|
elif key_provider_name is not None:
|
|
56
|
-
self._default_provider = self._instantiate_provider(
|
|
56
|
+
self._default_provider = self._instantiate_provider(
|
|
57
|
+
key_provider_name
|
|
58
|
+
)
|
|
57
59
|
self._default_provider_name = key_provider_name
|
|
58
60
|
|
|
59
61
|
provider_for_signer = self._default_provider
|
|
@@ -78,7 +80,9 @@ class EmbedSigner:
|
|
|
78
80
|
Exception
|
|
79
81
|
): # pragma: no cover - defensive against broken entry points
|
|
80
82
|
continue
|
|
81
|
-
if not inspect.isclass(provider_cls) and not callable(
|
|
83
|
+
if not inspect.isclass(provider_cls) and not callable(
|
|
84
|
+
provider_cls
|
|
85
|
+
):
|
|
82
86
|
continue
|
|
83
87
|
factories[entry.name] = provider_cls
|
|
84
88
|
return factories
|
|
@@ -104,9 +108,16 @@ class EmbedSigner:
|
|
|
104
108
|
if self._default_provider_name is not None:
|
|
105
109
|
return self._instantiate_provider(self._default_provider_name)
|
|
106
110
|
raise ValueError(
|
|
107
|
-
|
|
111
|
+
(
|
|
112
|
+
"No default key provider configured; include a provider "
|
|
113
|
+
"name "
|
|
114
|
+
"in the key reference."
|
|
115
|
+
)
|
|
108
116
|
)
|
|
109
|
-
if
|
|
117
|
+
if (
|
|
118
|
+
name == self._default_provider_name
|
|
119
|
+
and self._default_provider is not None
|
|
120
|
+
):
|
|
110
121
|
return self._default_provider
|
|
111
122
|
return self._instantiate_provider(name)
|
|
112
123
|
|
|
@@ -142,7 +153,9 @@ class EmbedSigner:
|
|
|
142
153
|
) from exc
|
|
143
154
|
if not kid:
|
|
144
155
|
raise ValueError("Key reference must include a key identifier")
|
|
145
|
-
return _ParsedKeyRef(
|
|
156
|
+
return _ParsedKeyRef(
|
|
157
|
+
provider=provider_name, kid=kid, version=version_number
|
|
158
|
+
)
|
|
146
159
|
|
|
147
160
|
async def _resolve_key(
|
|
148
161
|
self, key: KeyRef | Mapping[str, Any] | str
|
|
@@ -155,10 +168,14 @@ class EmbedSigner:
|
|
|
155
168
|
ref = self._parse_key_reference(key)
|
|
156
169
|
provider = self._get_provider(ref.provider)
|
|
157
170
|
try:
|
|
158
|
-
resolved = await provider.get_key_by_ref(
|
|
171
|
+
resolved = await provider.get_key_by_ref(
|
|
172
|
+
ref.kid, include_secret=True
|
|
173
|
+
)
|
|
159
174
|
except NotImplementedError:
|
|
160
175
|
resolved = None
|
|
161
|
-
except
|
|
176
|
+
except (
|
|
177
|
+
AttributeError
|
|
178
|
+
): # pragma: no cover - provider without method
|
|
162
179
|
resolved = None
|
|
163
180
|
if resolved is None:
|
|
164
181
|
resolved = await provider.get_key(
|
|
@@ -166,7 +183,10 @@ class EmbedSigner:
|
|
|
166
183
|
)
|
|
167
184
|
return resolved
|
|
168
185
|
raise TypeError(
|
|
169
|
-
|
|
186
|
+
(
|
|
187
|
+
"key must be a Mapping, KeyRef, or string reference "
|
|
188
|
+
"understood by EmbedSigner"
|
|
189
|
+
)
|
|
170
190
|
)
|
|
171
191
|
|
|
172
192
|
# ------------------------------------------------------------------
|
|
@@ -178,13 +198,17 @@ class EmbedSigner:
|
|
|
178
198
|
ref = str(path) if path is not None else None
|
|
179
199
|
return self._embedder.embed(data, xmp_xml, ref)
|
|
180
200
|
|
|
181
|
-
def read_xmp(
|
|
201
|
+
def read_xmp(
|
|
202
|
+
self, data: bytes, *, path: str | Path | None = None
|
|
203
|
+
) -> str | None:
|
|
182
204
|
"""Read XMP metadata from *data* using the configured handlers."""
|
|
183
205
|
|
|
184
206
|
ref = str(path) if path is not None else None
|
|
185
207
|
return self._embedder.read(data, ref)
|
|
186
208
|
|
|
187
|
-
def remove_xmp(
|
|
209
|
+
def remove_xmp(
|
|
210
|
+
self, data: bytes, *, path: str | Path | None = None
|
|
211
|
+
) -> bytes:
|
|
188
212
|
"""Remove XMP metadata from *data* using the configured handlers."""
|
|
189
213
|
|
|
190
214
|
ref = str(path) if path is not None else None
|
|
@@ -201,7 +225,9 @@ class EmbedSigner:
|
|
|
201
225
|
"""Embed XMP metadata directly into a file on disk."""
|
|
202
226
|
|
|
203
227
|
file_path = Path(path)
|
|
204
|
-
updated = self.embed_bytes(
|
|
228
|
+
updated = self.embed_bytes(
|
|
229
|
+
file_path.read_bytes(), xmp_xml, path=file_path
|
|
230
|
+
)
|
|
205
231
|
target = Path(output) if output is not None else file_path
|
|
206
232
|
if write_back:
|
|
207
233
|
target.write_bytes(updated)
|
|
@@ -220,7 +246,9 @@ class EmbedSigner:
|
|
|
220
246
|
write_back: bool = False,
|
|
221
247
|
output: str | Path | None = None,
|
|
222
248
|
) -> bytes:
|
|
223
|
-
"""
|
|
249
|
+
"""
|
|
250
|
+
Remove XMP metadata from a file, optionally persisting the result.
|
|
251
|
+
"""
|
|
224
252
|
|
|
225
253
|
file_path = Path(path)
|
|
226
254
|
updated = self.remove_xmp(file_path.read_bytes(), path=file_path)
|
|
@@ -240,7 +268,9 @@ class EmbedSigner:
|
|
|
240
268
|
alg: Optional[str] = None,
|
|
241
269
|
signer_opts: Optional[Mapping[str, Any]] = None,
|
|
242
270
|
) -> Sequence[Signature]:
|
|
243
|
-
"""
|
|
271
|
+
"""
|
|
272
|
+
Produce signatures for *payload* using the requested signer format.
|
|
273
|
+
"""
|
|
244
274
|
|
|
245
275
|
resolved_key = await self._resolve_key(key)
|
|
246
276
|
opts: dict[str, Any] = dict(signer_opts or {})
|
|
@@ -286,7 +316,9 @@ class EmbedSigner:
|
|
|
286
316
|
signer_opts: Optional[Mapping[str, Any]] = None,
|
|
287
317
|
write_back: bool = False,
|
|
288
318
|
) -> tuple[bytes, Sequence[Signature]]:
|
|
289
|
-
"""
|
|
319
|
+
"""
|
|
320
|
+
Embed metadata into *path* and optionally persist the signed bytes.
|
|
321
|
+
"""
|
|
290
322
|
|
|
291
323
|
file_path = Path(path)
|
|
292
324
|
embedded, signatures = await self.embed_and_sign_bytes(
|
|
@@ -336,6 +368,7 @@ class EmbedSigner:
|
|
|
336
368
|
)
|
|
337
369
|
|
|
338
370
|
def supported_signers(self) -> Sequence[str]:
|
|
339
|
-
"""Expose signer formats advertised by the underlying
|
|
371
|
+
"""Expose signer formats advertised by the underlying
|
|
372
|
+
:class:`MediaSigner`."""
|
|
340
373
|
|
|
341
374
|
return tuple(self._signer.supported_formats())
|
EmbeddedSigner/cli.py
CHANGED
|
@@ -30,14 +30,18 @@ def _resolve_key_argument(args: argparse.Namespace) -> Any:
|
|
|
30
30
|
if value is not None
|
|
31
31
|
]
|
|
32
32
|
if len(provided) != 1:
|
|
33
|
-
raise SystemExit(
|
|
33
|
+
raise SystemExit(
|
|
34
|
+
"Provide exactly one of --key-ref, --key-json, or --key-file."
|
|
35
|
+
)
|
|
34
36
|
if args.key_ref:
|
|
35
37
|
return args.key_ref
|
|
36
38
|
if args.key_json:
|
|
37
39
|
try:
|
|
38
40
|
return json.loads(args.key_json)
|
|
39
41
|
except json.JSONDecodeError as exc: # pragma: no cover - defensive
|
|
40
|
-
raise SystemExit(
|
|
42
|
+
raise SystemExit(
|
|
43
|
+
f"Invalid JSON passed to --key-json: {exc}"
|
|
44
|
+
) from exc
|
|
41
45
|
if args.key_file:
|
|
42
46
|
return json.loads(Path(args.key_file).read_text(encoding="utf-8"))
|
|
43
47
|
raise SystemExit("A key reference or JSON description must be supplied.")
|
|
@@ -120,7 +124,9 @@ def _command_sign(args: argparse.Namespace) -> int:
|
|
|
120
124
|
for token in args.option:
|
|
121
125
|
name, _, value = token.partition("=")
|
|
122
126
|
if not name:
|
|
123
|
-
raise SystemExit(
|
|
127
|
+
raise SystemExit(
|
|
128
|
+
"Signer options must use the form name=value."
|
|
129
|
+
)
|
|
124
130
|
opts[name] = value
|
|
125
131
|
signatures = asyncio.run(
|
|
126
132
|
_async_sign(
|
|
@@ -180,7 +186,9 @@ def _command_embed_sign(args: argparse.Namespace) -> int:
|
|
|
180
186
|
for token in args.option:
|
|
181
187
|
name, _, value = token.partition("=")
|
|
182
188
|
if not name:
|
|
183
|
-
raise SystemExit(
|
|
189
|
+
raise SystemExit(
|
|
190
|
+
"Signer options must use the form name=value."
|
|
191
|
+
)
|
|
184
192
|
opts[name] = value
|
|
185
193
|
output_path = Path(args.output) if args.output else None
|
|
186
194
|
signatures = asyncio.run(
|
|
@@ -206,7 +214,9 @@ def _command_embed_sign(args: argparse.Namespace) -> int:
|
|
|
206
214
|
|
|
207
215
|
|
|
208
216
|
def build_parser() -> argparse.ArgumentParser:
|
|
209
|
-
parser = argparse.ArgumentParser(
|
|
217
|
+
parser = argparse.ArgumentParser(
|
|
218
|
+
description="Embed XMP metadata and sign media."
|
|
219
|
+
)
|
|
210
220
|
parser.add_argument(
|
|
211
221
|
"--key-provider",
|
|
212
222
|
dest="key_provider",
|
|
@@ -217,11 +227,17 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
217
227
|
embed_parser = subparsers.add_parser("embed", help="Embed XMP into a file")
|
|
218
228
|
embed_parser.add_argument("input", help="Path to the media file")
|
|
219
229
|
embed_parser.add_argument("--xmp", help="Inline XMP XML payload")
|
|
220
|
-
embed_parser.add_argument(
|
|
221
|
-
|
|
230
|
+
embed_parser.add_argument(
|
|
231
|
+
"--xmp-file", help="Read the XMP payload from a file"
|
|
232
|
+
)
|
|
233
|
+
embed_parser.add_argument(
|
|
234
|
+
"--output", help="Write the embedded media to this path"
|
|
235
|
+
)
|
|
222
236
|
embed_parser.set_defaults(func=_command_embed)
|
|
223
237
|
|
|
224
|
-
read_parser = subparsers.add_parser(
|
|
238
|
+
read_parser = subparsers.add_parser(
|
|
239
|
+
"read", help="Read XMP metadata from a file"
|
|
240
|
+
)
|
|
225
241
|
read_parser.add_argument("input", help="Path to the media file")
|
|
226
242
|
read_parser.set_defaults(func=_command_read)
|
|
227
243
|
|
|
@@ -229,13 +245,21 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
229
245
|
"remove", help="Strip XMP metadata from a file"
|
|
230
246
|
)
|
|
231
247
|
remove_parser.add_argument("input", help="Path to the media file")
|
|
232
|
-
remove_parser.add_argument(
|
|
248
|
+
remove_parser.add_argument(
|
|
249
|
+
"--output", help="Write the stripped media to this path"
|
|
250
|
+
)
|
|
233
251
|
remove_parser.set_defaults(func=_command_remove)
|
|
234
252
|
|
|
235
|
-
sign_parser = subparsers.add_parser(
|
|
253
|
+
sign_parser = subparsers.add_parser(
|
|
254
|
+
"sign", help="Generate signatures for a file"
|
|
255
|
+
)
|
|
236
256
|
sign_parser.add_argument("input", help="Path to the media file")
|
|
237
|
-
sign_parser.add_argument(
|
|
238
|
-
|
|
257
|
+
sign_parser.add_argument(
|
|
258
|
+
"--format", required=True, help="MediaSigner format name"
|
|
259
|
+
)
|
|
260
|
+
sign_parser.add_argument(
|
|
261
|
+
"--key-ref", dest="key_ref", help="Key reference string"
|
|
262
|
+
)
|
|
239
263
|
sign_parser.add_argument(
|
|
240
264
|
"--key-json",
|
|
241
265
|
dest="key_json",
|
|
@@ -291,7 +315,9 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
291
315
|
action="append",
|
|
292
316
|
help="Additional signer option in the form name=value",
|
|
293
317
|
)
|
|
294
|
-
embed_sign_parser.add_argument(
|
|
318
|
+
embed_sign_parser.add_argument(
|
|
319
|
+
"--alg", help="Explicit algorithm identifier"
|
|
320
|
+
)
|
|
295
321
|
embed_sign_parser.add_argument(
|
|
296
322
|
"--detached",
|
|
297
323
|
action="store_true",
|
|
@@ -1,28 +1,30 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: EmbeddedSigner
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.11.0.dev1
|
|
4
4
|
Summary: Embed XMP metadata and sign media assets using Swarmauri plugins.
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
License-File: LICENSE
|
|
7
7
|
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
|
|
8
8
|
Author: Jacob Stewart
|
|
9
9
|
Author-email: jacob@swarmauri.com
|
|
10
|
-
Requires-Python: >=3.10,<3.
|
|
10
|
+
Requires-Python: >=3.10,<3.15
|
|
11
11
|
Classifier: Development Status :: 1 - Planning
|
|
12
12
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
13
|
Classifier: Natural Language :: English
|
|
14
|
-
Classifier: Programming Language :: Python
|
|
15
|
-
Classifier: Programming Language :: Python :: 3
|
|
16
|
-
Classifier: Programming Language :: Python :: 3 :: Only
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
20
14
|
Classifier: Framework :: AsyncIO
|
|
21
15
|
Classifier: Topic :: Security :: Cryptography
|
|
22
16
|
Classifier: Operating System :: OS Independent
|
|
23
17
|
Classifier: Topic :: Multimedia :: Graphics
|
|
24
18
|
Classifier: Topic :: Multimedia :: Video
|
|
25
19
|
Classifier: Intended Audience :: Developers
|
|
20
|
+
Classifier: Programming Language :: Python
|
|
21
|
+
Classifier: Programming Language :: Python :: 3
|
|
22
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
26
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
27
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
26
28
|
Provides-Extra: full
|
|
27
29
|
Provides-Extra: local
|
|
28
30
|
Provides-Extra: memory
|
|
@@ -96,160 +98,21 @@ Project-URL: Issues, https://github.com/swarmauri/swarmauri-sdk/issues
|
|
|
96
98
|
Project-URL: Source, https://github.com/swarmauri/swarmauri-sdk/tree/main/pkgs/plugins/embedded_signer
|
|
97
99
|
Description-Content-Type: text/markdown
|
|
98
100
|
|
|
99
|
-
|
|
100
|
-
<img src="../../../assets/swarmauri.brand.theme.svg" alt="Swarmauri logotype" width="420" />
|
|
101
|
-
</p>
|
|
102
|
-
|
|
103
|
-
<h1 align="center">EmbeddedSigner</h1>
|
|
101
|
+

|
|
104
102
|
|
|
105
103
|
<p align="center">
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
EmbeddedSigner
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
opaque key references can be resolved automatically before signatures are
|
|
119
|
-
produced.
|
|
120
|
-
|
|
121
|
-
## Features
|
|
122
|
-
|
|
123
|
-
- **One-shot embed & sign** – inject XMP metadata and produce signatures with a
|
|
124
|
-
single call.
|
|
125
|
-
- **Media-aware detection** – delegates to all registered `EmbedXmpBase`
|
|
126
|
-
handlers so PNG, GIF, JPEG, SVG, WEBP, TIFF, PDF, and MP4 assets are
|
|
127
|
-
processed consistently.
|
|
128
|
-
- **Pluggable signers** – forwards signing requests to every
|
|
129
|
-
`SigningBase` registered with `MediaSigner`, including CMS, JWS, OpenPGP, PDF,
|
|
130
|
-
and XMLDSig providers.
|
|
131
|
-
- **Key provider integration** – loads providers from the
|
|
132
|
-
`swarmauri.key_providers` entry point group and resolves opaque key reference
|
|
133
|
-
strings (e.g. `local://kid@2`) before invoking a signer.
|
|
134
|
-
- **Attached or detached output** – toggle between embedded signatures or
|
|
135
|
-
detached artifacts via a simple flag.
|
|
136
|
-
- **File and byte workflows** – operate on in-memory payloads or update files
|
|
137
|
-
on disk with helpers for embedding, reading, removing, and signing.
|
|
138
|
-
- **Command line tooling** – bundle a ready-to-use `embedded-signer` CLI for
|
|
139
|
-
ad-hoc embedding, signing, and combined workflows.
|
|
140
|
-
|
|
141
|
-
## Installation
|
|
142
|
-
|
|
143
|
-
### Using `uv`
|
|
144
|
-
|
|
145
|
-
```bash
|
|
146
|
-
uv add EmbeddedSigner
|
|
147
|
-
```
|
|
148
|
-
|
|
149
|
-
Optional dependencies align with the available key providers, EmbedXMP handlers,
|
|
150
|
-
and MediaSigner backends:
|
|
151
|
-
|
|
152
|
-
```bash
|
|
153
|
-
uv add "EmbeddedSigner[local]" # enable LocalKeyProvider resolution
|
|
154
|
-
uv add "EmbeddedSigner[memory]" # enable InMemoryKeyProvider resolution
|
|
155
|
-
uv add "EmbeddedSigner[xmp_png]" # add PNG embedding support
|
|
156
|
-
uv add "EmbeddedSigner[xmp_all]" # install every EmbedXMP handler
|
|
157
|
-
uv add "EmbeddedSigner[signing_pdf]" # enable PDF signer backend
|
|
158
|
-
uv add "EmbeddedSigner[signing_all]" # install every MediaSigner backend
|
|
159
|
-
uv add "EmbeddedSigner[full]" # bring in all extras and key providers
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
### Using `pip`
|
|
163
|
-
|
|
164
|
-
```bash
|
|
165
|
-
pip install EmbeddedSigner
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
Extras mirror the `uv` workflow:
|
|
169
|
-
|
|
170
|
-
```bash
|
|
171
|
-
pip install "EmbeddedSigner[local]"
|
|
172
|
-
pip install "EmbeddedSigner[memory]"
|
|
173
|
-
pip install "EmbeddedSigner[xmp_png]"
|
|
174
|
-
pip install "EmbeddedSigner[xmp_all]"
|
|
175
|
-
pip install "EmbeddedSigner[signing_pdf]"
|
|
176
|
-
pip install "EmbeddedSigner[signing_all]"
|
|
177
|
-
pip install "EmbeddedSigner[full]"
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
### Extras overview
|
|
181
|
-
|
|
182
|
-
| Extra name | Purpose |
|
|
183
|
-
| --- | --- |
|
|
184
|
-
| `local` / `memory` | Enable Swarmauri key provider resolution for local filesystem and in-memory secrets. |
|
|
185
|
-
| `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. |
|
|
186
|
-
| `xmp_all` | Install every EmbedXMP media handler dependency at once. |
|
|
187
|
-
| `signing_cms`, `signing_jws`, `signing_openpgp`, `signing_pdf`, `signing_xmld` | Add the matching MediaSigner backend plugin for CMS, JWS, OpenPGP, PDF, or XMLDSig signing. |
|
|
188
|
-
| `signing_all` | Install all MediaSigner backends together. |
|
|
189
|
-
| `full` | Bring in every key provider, EmbedXMP handler, and MediaSigner backend for maximum coverage. |
|
|
190
|
-
|
|
191
|
-
## Usage
|
|
192
|
-
|
|
193
|
-
```python
|
|
194
|
-
import asyncio
|
|
195
|
-
from pathlib import Path
|
|
196
|
-
|
|
197
|
-
from EmbeddedSigner import EmbedSigner
|
|
198
|
-
|
|
199
|
-
xmp_xml = """
|
|
200
|
-
<x:xmpmeta xmlns:x="adobe:ns:meta/">
|
|
201
|
-
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
|
202
|
-
<rdf:Description rdf:about=""/>
|
|
203
|
-
</rdf:RDF>
|
|
204
|
-
</x:xmpmeta>
|
|
205
|
-
""".strip()
|
|
206
|
-
|
|
207
|
-
async def embed_and_sign() -> None:
|
|
208
|
-
signer = EmbedSigner()
|
|
209
|
-
media_bytes = Path("image.png").read_bytes()
|
|
210
|
-
embedded, signatures = await signer.embed_and_sign_bytes(
|
|
211
|
-
media_bytes,
|
|
212
|
-
fmt="JWSSigner",
|
|
213
|
-
xmp_xml=xmp_xml,
|
|
214
|
-
key={"kind": "raw", "key": b"\x00" * 32},
|
|
215
|
-
path="image.png",
|
|
216
|
-
attached=True,
|
|
217
|
-
signer_opts={"alg": "HS256"},
|
|
218
|
-
)
|
|
219
|
-
Path("image.signed.png").write_bytes(embedded)
|
|
220
|
-
print(signatures[0].mode) # "attached"
|
|
221
|
-
|
|
222
|
-
asyncio.run(embed_and_sign())
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
### Key provider integration
|
|
226
|
-
|
|
227
|
-
When you install a key provider plugin such as
|
|
228
|
-
`swarmauri_keyprovider_local`, EmbeddedSigner can resolve string key references
|
|
229
|
-
on the fly:
|
|
230
|
-
|
|
231
|
-
```python
|
|
232
|
-
signer = EmbedSigner(key_provider_name="LocalKeyProvider")
|
|
233
|
-
embedded, signatures = await signer.embed_and_sign_file(
|
|
234
|
-
Path("report.pdf"),
|
|
235
|
-
fmt="PDFSigner",
|
|
236
|
-
xmp_xml=xmp_xml,
|
|
237
|
-
key="LocalKeyProvider://a1b2c3@1",
|
|
238
|
-
attached=False,
|
|
239
|
-
signer_opts={"alg": "SHA256"},
|
|
240
|
-
)
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
EmbeddedSigner parses the opaque reference, looks up the provider by name, and
|
|
244
|
-
retrieves the specified key version using the provider's asynchronous API.
|
|
245
|
-
|
|
246
|
-
### File helpers
|
|
247
|
-
|
|
248
|
-
`EmbedSigner` offers mirrored helpers that operate on file paths when you need
|
|
249
|
-
to persist updates directly on disk:
|
|
250
|
-
|
|
251
|
-
```python
|
|
252
|
-
signer = EmbedSigner()
|
|
104
|
+
<a href="https://pepy.tech/project/EmbeddedSigner/">
|
|
105
|
+
<img src="https://static.pepy.tech/badge/EmbeddedSigner/month" alt="PyPI - Downloads"/></a>
|
|
106
|
+
<a href="https://hits.sh/github.com/swarmauri/swarmauri-sdk/tree/master/pkgs/plugins/embedded_signer/">
|
|
107
|
+
<img alt="Hits" src="https://hits.sh/github.com/swarmauri/swarmauri-sdk/tree/master/pkgs/plugins/embedded_signer.svg"/></a>
|
|
108
|
+
<a href="https://pypi.org/project/EmbeddedSigner/">
|
|
109
|
+
<img src="https://img.shields.io/badge/python-3.10%20%7C%203.11%20%7C%203.12%20%7C%203.13%20%7C%203.14-blue" alt="PyPI - Python Version"/></a>
|
|
110
|
+
<a href="https://pypi.org/project/EmbeddedSigner/">
|
|
111
|
+
<img src="https://img.shields.io/pypi/l/EmbeddedSigner" alt="PyPI - License"/></a>
|
|
112
|
+
<a href="https://pypi.org/project/EmbeddedSigner/">
|
|
113
|
+
<img src="https://img.shields.io/pypi/v/EmbeddedSigner?label=EmbeddedSigner&color=green" alt="PyPI - EmbeddedSigner"/></a>
|
|
114
|
+
<a href="https://discord.gg/N4UpBuQv8T">
|
|
115
|
+
<img src="https://img.shields.io/badge/Discord-Join%20Chat-5865F2?logo=discord&logoColor=white" alt="Discord"/></a></p>
|
|
253
116
|
|
|
254
117
|
# Embed metadata into a file and write it back in place.
|
|
255
118
|
signer.embed_file("image.png", xmp_xml)
|
|
@@ -320,8 +183,8 @@ embedded-signer embed-sign example.png \
|
|
|
320
183
|
|
|
321
184
|
## Project Resources
|
|
322
185
|
|
|
323
|
-
- Source: <https://github.com/swarmauri/swarmauri-sdk/tree/
|
|
324
|
-
- Documentation: <https://github.com/swarmauri/swarmauri-sdk/tree/
|
|
186
|
+
- Source: <https://github.com/swarmauri/swarmauri-sdk/tree/master/pkgs/plugins/embedded_signer>
|
|
187
|
+
- Documentation: <https://github.com/swarmauri/swarmauri-sdk/tree/master/pkgs/plugins/embedded_signer#readme>
|
|
325
188
|
- Issues: <https://github.com/swarmauri/swarmauri-sdk/issues>
|
|
326
189
|
- Releases: <https://github.com/swarmauri/swarmauri-sdk/releases>
|
|
327
190
|
- Discussions: <https://github.com/orgs/swarmauri/discussions>
|
|
@@ -331,3 +194,5 @@ embedded-signer embed-sign example.png \
|
|
|
331
194
|
EmbeddedSigner is released under the Apache 2.0 License. See the
|
|
332
195
|
[LICENSE](LICENSE) file for details.
|
|
333
196
|
|
|
197
|
+
|
|
198
|
+
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
EmbeddedSigner/__init__.py,sha256=PTcO_55bD8K70SqZmI0KzgYjkqmhI7rLpHdQTwvOCbU,119
|
|
2
|
+
EmbeddedSigner/_embed_signer.py,sha256=dtgOwTwX0e3ewG_uacUdivg5p3K_xUJzZJAMo9lYVX4,12984
|
|
3
|
+
EmbeddedSigner/cli.py,sha256=V6RIE1evkMmJKVwqBF1GvUnXrGyhzjPFJXE3S258wN8,10791
|
|
4
|
+
embeddedsigner-0.11.0.dev1.dist-info/METADATA,sha256=g7zfYpIqh-357eQYSYKHajRv-PxYaJRUhQY-8JbSur4,8520
|
|
5
|
+
embeddedsigner-0.11.0.dev1.dist-info/WHEEL,sha256=eY7nduwzv-ldUxpzbRlxwvC693Hg6PX8bWDjEHjZ_dk,88
|
|
6
|
+
embeddedsigner-0.11.0.dev1.dist-info/entry_points.txt,sha256=EwpGp4nYOLoLHwGiNMGvCjOb6RmHd3kOnKcV40Ce6kM,59
|
|
7
|
+
embeddedsigner-0.11.0.dev1.dist-info/licenses/LICENSE,sha256=djUXOlCxLVszShEpZXshZ7v33G-2qIC_j9KXpWKZSzQ,11359
|
|
8
|
+
embeddedsigner-0.11.0.dev1.dist-info/RECORD,,
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
EmbeddedSigner/__init__.py,sha256=PTcO_55bD8K70SqZmI0KzgYjkqmhI7rLpHdQTwvOCbU,119
|
|
2
|
-
EmbeddedSigner/_embed_signer.py,sha256=rorOvU5Bp9u6chWmRvOYxNinpXmMWpaOuXJcmwGyjb4,12547
|
|
3
|
-
EmbeddedSigner/cli.py,sha256=3xRzdMkrjA5NQ1QAutwxTSWWGMxsSrsBYAJ2aOn913k,10537
|
|
4
|
-
embeddedsigner-0.1.4.dev19.dist-info/METADATA,sha256=ogb5u_-6k1GAshdkb5_WpXxzMEAIuVR9sYynQKnlJ3w,13295
|
|
5
|
-
embeddedsigner-0.1.4.dev19.dist-info/WHEEL,sha256=kJCRJT_g0adfAJzTx2GUMmS80rTJIVHRCfG0DQgLq3o,88
|
|
6
|
-
embeddedsigner-0.1.4.dev19.dist-info/entry_points.txt,sha256=EwpGp4nYOLoLHwGiNMGvCjOb6RmHd3kOnKcV40Ce6kM,59
|
|
7
|
-
embeddedsigner-0.1.4.dev19.dist-info/licenses/LICENSE,sha256=djUXOlCxLVszShEpZXshZ7v33G-2qIC_j9KXpWKZSzQ,11359
|
|
8
|
-
embeddedsigner-0.1.4.dev19.dist-info/RECORD,,
|
{embeddedsigner-0.1.4.dev19.dist-info → embeddedsigner-0.11.0.dev1.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{embeddedsigner-0.1.4.dev19.dist-info → embeddedsigner-0.11.0.dev1.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|