openbadgeslib 0.4.2__tar.gz → 1.1.2__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 (103) hide show
  1. openbadgeslib-1.1.2/Changelog.txt +256 -0
  2. {openbadgeslib-0.4.2 → openbadgeslib-1.1.2}/MANIFEST.in +1 -1
  3. openbadgeslib-1.1.2/PKG-INFO +211 -0
  4. openbadgeslib-1.1.2/README.md +174 -0
  5. openbadgeslib-1.1.2/docs/authors.rst +21 -0
  6. {openbadgeslib-0.4.2 → openbadgeslib-1.1.2}/docs/conf.py +14 -4
  7. openbadgeslib-1.1.2/docs/development.rst +165 -0
  8. openbadgeslib-1.1.2/docs/glossary.rst +147 -0
  9. openbadgeslib-1.1.2/docs/index.rst +30 -0
  10. openbadgeslib-1.1.2/docs/installation.rst +159 -0
  11. openbadgeslib-1.1.2/docs/intro.rst +190 -0
  12. openbadgeslib-1.1.2/docs/userguide.rst +367 -0
  13. openbadgeslib-1.1.2/openbadgeslib/__init__.py +40 -0
  14. openbadgeslib-1.1.2/openbadgeslib/_jws/__init__.py +102 -0
  15. openbadgeslib-1.1.2/openbadgeslib/_jws/exceptions.py +18 -0
  16. openbadgeslib-1.1.2/openbadgeslib/_jws/utils.py +30 -0
  17. openbadgeslib-1.1.2/openbadgeslib/badge.py +12 -0
  18. openbadgeslib-1.1.2/openbadgeslib/baking.py +166 -0
  19. {openbadgeslib-0.4.2 → openbadgeslib-1.1.2}/openbadgeslib/config.ini.example +6 -1
  20. {openbadgeslib-0.4.2 → openbadgeslib-1.1.2}/openbadgeslib/confparser.py +30 -4
  21. {openbadgeslib-0.4.2 → openbadgeslib-1.1.2}/openbadgeslib/errors.py +18 -15
  22. {openbadgeslib-0.4.2 → openbadgeslib-1.1.2}/openbadgeslib/keys.py +58 -27
  23. {openbadgeslib-0.4.2 → openbadgeslib-1.1.2}/openbadgeslib/logs.py +20 -3
  24. {openbadgeslib-0.4.2 → openbadgeslib-1.1.2}/openbadgeslib/mail.py +17 -9
  25. openbadgeslib-1.1.2/openbadgeslib/ob2/__init__.py +36 -0
  26. {openbadgeslib-0.4.2/openbadgeslib → openbadgeslib-1.1.2/openbadgeslib/ob2}/badge.py +90 -104
  27. openbadgeslib-1.1.2/openbadgeslib/ob2/signer.py +152 -0
  28. openbadgeslib-1.1.2/openbadgeslib/ob2/verifier.py +178 -0
  29. {openbadgeslib-0.4.2/openbadgeslib → openbadgeslib-1.1.2/openbadgeslib/ob3}/__init__.py +13 -10
  30. openbadgeslib-1.1.2/openbadgeslib/ob3/credential.py +198 -0
  31. openbadgeslib-1.1.2/openbadgeslib/ob3/signer.py +79 -0
  32. openbadgeslib-1.1.2/openbadgeslib/ob3/verifier.py +196 -0
  33. {openbadgeslib-0.4.2 → openbadgeslib-1.1.2}/openbadgeslib/openbadges_init.py +12 -8
  34. openbadgeslib-1.1.2/openbadgeslib/openbadges_keygenerator.py +117 -0
  35. {openbadgeslib-0.4.2 → openbadgeslib-1.1.2}/openbadgeslib/openbadges_publish.py +51 -33
  36. openbadgeslib-1.1.2/openbadgeslib/openbadges_signer.py +216 -0
  37. openbadgeslib-1.1.2/openbadgeslib/openbadges_verifier.py +197 -0
  38. openbadgeslib-1.1.2/openbadgeslib/signer.py +4 -0
  39. openbadgeslib-1.1.2/openbadgeslib/util.py +111 -0
  40. openbadgeslib-1.1.2/openbadgeslib/verifier.py +4 -0
  41. openbadgeslib-1.1.2/openbadgeslib.egg-info/PKG-INFO +211 -0
  42. openbadgeslib-1.1.2/openbadgeslib.egg-info/SOURCES.txt +73 -0
  43. openbadgeslib-1.1.2/openbadgeslib.egg-info/dependency_links.txt +1 -0
  44. openbadgeslib-1.1.2/openbadgeslib.egg-info/entry_points.txt +6 -0
  45. openbadgeslib-1.1.2/openbadgeslib.egg-info/requires.txt +11 -0
  46. openbadgeslib-1.1.2/openbadgeslib.egg-info/top_level.txt +1 -0
  47. openbadgeslib-1.1.2/pyproject.toml +79 -0
  48. openbadgeslib-1.1.2/setup.cfg +11 -0
  49. {openbadgeslib-0.4.2 → openbadgeslib-1.1.2}/tests/config1.ini +4 -0
  50. openbadgeslib-1.1.2/tests/conftest.py +216 -0
  51. openbadgeslib-1.1.2/tests/logo Python Espa/303/261a.svg" +15 -0
  52. openbadgeslib-1.1.2/tests/runtests.sh +3 -0
  53. openbadgeslib-1.1.2/tests/test_badge_io.py +140 -0
  54. openbadgeslib-1.1.2/tests/test_cli_smoke.py +442 -0
  55. openbadgeslib-1.1.2/tests/test_docs.py +90 -0
  56. openbadgeslib-1.1.2/tests/test_jws.py +180 -0
  57. openbadgeslib-1.1.2/tests/test_key_operation.py +229 -0
  58. openbadgeslib-1.1.2/tests/test_ob3_credential.py +235 -0
  59. openbadgeslib-1.1.2/tests/test_ob3_signer.py +148 -0
  60. openbadgeslib-1.1.2/tests/test_ob3_verifier.py +343 -0
  61. {openbadgeslib-0.4.2 → openbadgeslib-1.1.2}/tests/test_signer_operation.py +186 -66
  62. openbadgeslib-1.1.2/tests/test_util.py +148 -0
  63. openbadgeslib-1.1.2/tests/test_verify_operation.py +239 -0
  64. openbadgeslib-0.4.2/CONTRIBUTORS.txt +0 -5
  65. openbadgeslib-0.4.2/Changelog.txt +0 -81
  66. openbadgeslib-0.4.2/PKG-INFO +0 -20
  67. openbadgeslib-0.4.2/README.txt +0 -2
  68. openbadgeslib-0.4.2/TODO.txt +0 -27
  69. openbadgeslib-0.4.2/docs/authors.rst +0 -17
  70. openbadgeslib-0.4.2/docs/development.rst +0 -19
  71. openbadgeslib-0.4.2/docs/glossary.rst +0 -113
  72. openbadgeslib-0.4.2/docs/index.rst +0 -26
  73. openbadgeslib-0.4.2/docs/installation.rst +0 -148
  74. openbadgeslib-0.4.2/docs/intro.rst +0 -18
  75. openbadgeslib-0.4.2/docs/userguide.rst +0 -89
  76. openbadgeslib-0.4.2/openbadgeslib/3dparty/jws/__init__.py +0 -76
  77. openbadgeslib-0.4.2/openbadgeslib/3dparty/jws/algos.py +0 -192
  78. openbadgeslib-0.4.2/openbadgeslib/3dparty/jws/exceptions.py +0 -11
  79. openbadgeslib-0.4.2/openbadgeslib/3dparty/jws/header.py +0 -67
  80. openbadgeslib-0.4.2/openbadgeslib/3dparty/jws/utils.py +0 -16
  81. openbadgeslib-0.4.2/openbadgeslib/openbadges_keygenerator.py +0 -98
  82. openbadgeslib-0.4.2/openbadgeslib/openbadges_signer.py +0 -150
  83. openbadgeslib-0.4.2/openbadgeslib/openbadges_verifier.py +0 -104
  84. openbadgeslib-0.4.2/openbadgeslib/signer.py +0 -200
  85. openbadgeslib-0.4.2/openbadgeslib/util.py +0 -84
  86. openbadgeslib-0.4.2/openbadgeslib/verifier.py +0 -161
  87. openbadgeslib-0.4.2/setup.cfg +0 -2
  88. openbadgeslib-0.4.2/setup.py +0 -50
  89. openbadgeslib-0.4.2/tests/runtests.sh +0 -4
  90. openbadgeslib-0.4.2/tests/test_common.py +0 -7
  91. openbadgeslib-0.4.2/tests/test_key_operation.py +0 -130
  92. openbadgeslib-0.4.2/tests/test_verify_operation.py +0 -17
  93. {openbadgeslib-0.4.2 → openbadgeslib-1.1.2}/LICENSE.txt +0 -0
  94. {openbadgeslib-0.4.2 → openbadgeslib-1.1.2}/tests/images/sample1.png +0 -0
  95. {openbadgeslib-0.4.2 → openbadgeslib-1.1.2}/tests/images/sample1.svg +0 -0
  96. {openbadgeslib-0.4.2 → openbadgeslib-1.1.2}/tests/images/userimage01.svg +0 -0
  97. {openbadgeslib-0.4.2 → openbadgeslib-1.1.2}/tests/logo Python Espan/314/203a.svg" +0 -0
  98. {openbadgeslib-0.4.2 → openbadgeslib-1.1.2}/tests/test_sign_ecc.pem +0 -0
  99. {openbadgeslib-0.4.2 → openbadgeslib-1.1.2}/tests/test_sign_rsa.pem +0 -0
  100. {openbadgeslib-0.4.2 → openbadgeslib-1.1.2}/tests/test_verify_ecc.pem +0 -0
  101. {openbadgeslib-0.4.2 → openbadgeslib-1.1.2}/tests/test_verify_rsa.pem +0 -0
  102. {openbadgeslib-0.4.2 → openbadgeslib-1.1.2}/tests/withoutxmlheader.svg +0 -0
  103. {openbadgeslib-0.4.2 → openbadgeslib-1.1.2}/tests/withxmlheader.svg +0 -0
@@ -0,0 +1,256 @@
1
+ OpenBadgesLib - Changelog
2
+ =========================
3
+
4
+ Newest first. Dates are ISO 8601 (YYYY-MM-DD).
5
+
6
+
7
+ * v1.1.2 - 2026-06-27
8
+
9
+ - The -d/--debug flag now actually enables DEBUG-level console logging. It was
10
+ previously parsed but ignored in openbadges-signer; it is now wired up and
11
+ also added to openbadges-keygenerator and openbadges-verifier.
12
+
13
+ - Packaging metadata refreshed: README is now Markdown, and the project URLs
14
+ point to the GitHub Wiki (documentation) and the GitHub Pages API reference
15
+ instead of the old homepage.
16
+
17
+ - Docs & infra: the version is single-sourced from util.__version__; CI gates
18
+ catch doc drift (CLI flags, wiki links); an auto-generated pdoc API site and
19
+ an auto-synced wiki were added; Changelog normalised; CONTRIBUTORS.txt
20
+ removed (see docs/authors.rst); pending work is now tracked in GitHub Issues.
21
+
22
+
23
+ * v1.1.1 - 2026-06-27
24
+
25
+ - OB3: recipient identifiers are normalised through one shared helper, fixing
26
+ a DID being corrupted into 'mailto:did:...'; the verifier CLI now delegates
27
+ recipient binding to OB3Verifier.verify() instead of re-implementing it.
28
+
29
+ - OB3: verify() cross-checks the JWT registered claims against the vc body -
30
+ a token whose 'iss'/'sub' disagree with the credential issuer/subject is
31
+ rejected - and OB3VerificationError now inherits from LibOpenBadgesException
32
+ so one except clause covers both OB2 and OB3.
33
+
34
+ - Refactor: shared keys.alg_for_key_type and CLI config helpers
35
+ (read_config_or_exit / resolve_badge_section / _resolve_trusted_pubkey)
36
+ remove the boilerplate duplicated across the entrypoints; first-party code
37
+ imports openbadgeslib.ob2 directly rather than the back-compat shims; the
38
+ oversized verify/main/_verify_ob3 functions were decomposed.
39
+
40
+ - Type hints added on the OB2/core byte-vs-str boundaries.
41
+
42
+ - Tests: OB2 signer CLI, the mail subsystem and read_from_file edge cases are
43
+ now covered; 258 tests, 92% line coverage; the whole repo (source and
44
+ tests) is flake8-clean.
45
+
46
+ - CI: a GitHub Actions workflow runs flake8 and the test suite on Python
47
+ 3.10-3.13 for every push and pull request.
48
+
49
+
50
+ * v1.1.0 - 2026-06-27
51
+
52
+ - SECURITY: signature verification now pins the accepted algorithm to the
53
+ verification key's type instead of trusting the token header. OB3Verifier
54
+ derives the RS*/ES* family from the key and passes it to jwt.decode;
55
+ _jws.verify_block rejects any header alg that doesn't match the key. This
56
+ blocks cross-type confusion and any none/HMAC downgrade.
57
+
58
+ - SECURITY: SVG badge XML is parsed with defusedxml, defusing entity-expansion
59
+ (billion-laughs) DoS on untrusted badges. New defusedxml dependency.
60
+
61
+ - SECURITY: iTXt PNG token extraction caps zlib decompression at 256 KB to
62
+ stop a decompression-bomb DoS during extraction (before verification).
63
+
64
+ - SECURITY: the OB2 verifier CLI now distinguishes a trusted operator key
65
+ (--local/--pubkey) from the badge's own embedded key. Without a trusted key
66
+ it reports the signature as internally-consistent-only, not "[+] correct"
67
+ (the embedded key proves nothing about issuer identity). --pubkey now
68
+ applies to OB2 as well as OB3.
69
+
70
+ - SECURITY: check_revocation guards the issuer / revocation-list downloads and
71
+ JSON parsing, raising a clean VerifierException instead of a raw error.
72
+
73
+ - Fixed: _jws base64url padding (wrong when the length was a multiple of 4);
74
+ BadgeSigned.get_serial_num crashed on badges read from a file (str vs bytes);
75
+ Verifier.check_identity crashed instead of skipping when no identity was
76
+ given; extract_svg_assertion could raise NameError masking the real error;
77
+ unknown key/image types now fail loudly instead of UnboundLocalError.
78
+
79
+ - Refactor: a single keys.key_to_pem() replaces three drifting copies, and a
80
+ new openbadgeslib.baking module is the one home for the SVG/PNG carrier
81
+ format (OB2 and OB3 share it; the OB2 fixed-offset PNG reader is gone in
82
+ favour of the structured iTXt parser).
83
+
84
+ - Cleanup: removed the redundant setup.py, the stale committed dist/ artifacts
85
+ and generated MANIFEST, and several never-raised exception classes; docs now
86
+ cover OB3 on the landing page and document the SMTP/email-badge feature;
87
+ test import hygiene tidied. 236 tests pass, 87% line coverage.
88
+
89
+
90
+ * v1.0.2 - 2026-06-18
91
+
92
+ - SECURITY: OB2 verification now uses the operator-supplied trusted key when
93
+ one is given, instead of always trusting the key the badge points to. A
94
+ forged badge can no longer self-describe its own verification key.
95
+
96
+ - SECURITY: download_file now refuses non-HTTPS URLs by default (the verify
97
+ key is the OB2 root of trust); pass allow_insecure=True to override.
98
+
99
+ - Fixed expiration check: a badge is now considered expired when its
100
+ expiration date is in the past relative to *now*, not relative to its own
101
+ issue date (expired badges were previously reported VALID).
102
+
103
+ - Fixed openbadges-publish: it copied no verify key and stopped after the
104
+ first badge (it read a non-existent [keys] section). It now reads each
105
+ badge's public_key and iterates all badge_* sections.
106
+
107
+ - Fixed SMTP: use_ssl is parsed as a boolean (the string 'False' was truthy);
108
+ connection-level mail errors are caught instead of crashing a successful
109
+ sign; the example config uses 'username' (matching the code), not 'login'.
110
+
111
+ - openbadges-keygenerator now honours a key_type (RSA/ECC) field in the badge
112
+ profile, so ECC key pairs are reachable from the CLI.
113
+
114
+ - OB2 sign log and log files are opened in append mode (were truncated on
115
+ every run).
116
+
117
+ - OB3 credentials use the W3C VC 2.0 data model (validFrom/validUntil,
118
+ /ns/credentials/v2 context); from_jwt_payload still reads VC 1.1 fields.
119
+ OB3Verifier.verify() gained an optional expected_recipient argument and now
120
+ asserts the credential type; PNG token extraction parses the iTXt chunk
121
+ structure instead of a fixed offset.
122
+
123
+ - Robustness: unsigned PNGs raise a clear error instead of crashing;
124
+ read_from_file raises instead of calling sys.exit; identity is normalised to
125
+ bytes; revocation handles issuers without a revocationList.
126
+
127
+ - Tests: added CLI/publish/keygenerator/mail/revocation coverage and removed
128
+ the coverage omit list that hid those modules; expiration tests rewritten to
129
+ model real timestamps.
130
+
131
+
132
+ * v1.0.1 - 2026-04-22
133
+
134
+ - OpenBadges 3.0 support (W3C Verifiable Credentials / JWT-VC):
135
+ new openbadgeslib.ob3 subpackage with OpenBadgeCredential, Issuer,
136
+ Achievement data model; OB3Signer for JWT-VC signing and SVG/PNG
137
+ baking; OB3Verifier for JWT-VC verification and token extraction.
138
+
139
+ - OpenBadges 2.0 implementation moved to openbadgeslib.ob2 subpackage.
140
+ Top-level badge.py / signer.py / verifier.py kept as backward-compatible
141
+ shims so existing code continues to work unchanged.
142
+
143
+ - All CLI tools (openbadges-keygenerator, openbadges-signer,
144
+ openbadges-verifier, openbadges-publish) gained a -V / --ob-version
145
+ flag to select the specification version (2 or 3, default 2).
146
+
147
+ - openbadges-verifier: new -k / --pubkey FILE option to supply the
148
+ public key directly when verifying OB3 badges without a config file.
149
+
150
+ - Python 3.10+ compatibility: removed distutils (dropped in 3.12),
151
+ packaging migrated to pyproject.toml with setuptools.build_meta.
152
+
153
+ - Replaced abandoned pycrypto with pycryptodome >= 3.20.
154
+
155
+ - Replaced custom bundled JWS engine (3dparty/jws/) with PyJWT[crypto]
156
+ algorithm classes (RS256/384/512, ES256/384/512). Internal module
157
+ moved to openbadgeslib/_jws/. Old 3dparty/ directory removed.
158
+
159
+ - TLS security fix: download_file relies on urllib's default TLS context
160
+ (certificate validation on) instead of the deprecated PROTOCOL_TLSv1 /
161
+ CERT_NONE settings.
162
+
163
+ - pypng API update: signature constant renamed, chunk tags now bytes.
164
+
165
+ - Copyright year range updated to 2014-2026 across all source files.
166
+
167
+ - Bug fixes: verifier signature check logic, ECC private-key detection,
168
+ hash_email str/bytes coercion.
169
+
170
+ - Test suite: 203 tests, 89% line coverage.
171
+
172
+
173
+ * v0.4.2
174
+
175
+ - Adding support to verifying external openbadges.
176
+
177
+ - Adding a new parameter to show assertion before verifying.
178
+
179
+ - OpenBadges URLs are verified before the signing process.
180
+
181
+
182
+ * v0.4
183
+
184
+ - Support for PNG. The library can now verify and sign OpenBadges in PNG
185
+ format.
186
+
187
+ - Support for sending badges via mail.
188
+
189
+ - Badge signatures are registered in a log file.
190
+
191
+ - Mail code now supports SMTP auth. The config file needs modifications;
192
+ see the example.
193
+
194
+
195
+ * v0.3
196
+
197
+ - The email is no longer encoded in the filename when creating a new badge.
198
+
199
+ - When creating a badge, "-o" is optional.
200
+
201
+ - When specified, "-o" is supposed to be a directory.
202
+
203
+ - We can specify "-E" or "--no-evidence" when creating a new badge.
204
+
205
+ - When creating a new badge we now need to choose EXPLICITLY between
206
+ providing evidence or not.
207
+
208
+ - Badge sections in the INI file must now be prefixed with "badge_".
209
+ UPGRADE: if your badge is called "ponente2014", rename it to
210
+ "badge_ponente2014".
211
+
212
+ - Each badge can now have a different key.
213
+ UPGRADE: move your current key configuration to the badge section,
214
+ renaming "private" to "private_key" and "public" to "public_key".
215
+ UPGRADE: "openbadges-keygenerator -g" now requires a badge name.
216
+
217
+ - "openbadges-verifier" changes its parameter from "-lk" to "-l" and now
218
+ needs the name of the badge to locate its public key.
219
+
220
+ - "openbadges-verifier" now accepts a parameter -x to specify the expiration
221
+ for a badge.
222
+
223
+ - "openbadges-verifier" now checks the revocation status and the expiration
224
+ dates of badges.
225
+
226
+
227
+ * v0.2.1 - 2014-12-16
228
+
229
+ - config.ini now allows configuring the badge json url and image url.
230
+
231
+ - Signer now uses randomly salted emails by default in assertions.
232
+
233
+ - Compatibility with more SVG formats.
234
+
235
+ - Documentation in the "docs" directory.
236
+
237
+
238
+ * v0.2 - 2014-12-10
239
+
240
+ - "openbadges-init".
241
+
242
+ - New configuration format. If you are using the 0.1 format, you must
243
+ migrate by hand.
244
+
245
+ - Tests.
246
+
247
+ - Use proper logging instead of simple "print" calls.
248
+
249
+ - Massive cleanup of internal imports.
250
+
251
+ - Do not change "sys.path".
252
+
253
+
254
+ * v0.1 - 2014-12-01
255
+
256
+ - Initial release.
@@ -4,4 +4,4 @@ recursive-include openbadgeslib *
4
4
  recursive-include tests *
5
5
  recursive-include docs *
6
6
  global-exclude __pycache__/*
7
- include *.txt MANIFEST.in
7
+ include *.txt *.md MANIFEST.in
@@ -0,0 +1,211 @@
1
+ Metadata-Version: 2.4
2
+ Name: openbadgeslib
3
+ Version: 1.1.2
4
+ Summary: A library to sign and verify OpenBadges
5
+ Author-email: Luis González Fernández <luisgf@luisgf.es>, Jesús Cea Avión <jcea@jcea.es>
6
+ License: LGPLv3
7
+ Project-URL: Homepage, https://github.com/luisgf/openbadgeslib
8
+ Project-URL: Documentation, https://github.com/luisgf/openbadgeslib/wiki
9
+ Project-URL: API Reference, https://luisgf.github.io/openbadgeslib/
10
+ Project-URL: Source, https://github.com/luisgf/openbadgeslib
11
+ Project-URL: Changelog, https://github.com/luisgf/openbadgeslib/blob/master/Changelog.txt
12
+ Keywords: openbadges
13
+ Classifier: Development Status :: 5 - Production/Stable
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Classifier: Natural Language :: English
21
+ Classifier: Natural Language :: Spanish
22
+ Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)
23
+ Requires-Python: >=3.10
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE.txt
26
+ Requires-Dist: pycryptodome>=3.20
27
+ Requires-Dist: ecdsa>=0.19
28
+ Requires-Dist: pypng>=0.20220715.0
29
+ Requires-Dist: PyJWT[crypto]>=2.8
30
+ Requires-Dist: defusedxml>=0.7
31
+ Provides-Extra: dev
32
+ Requires-Dist: pytest>=8.0; extra == "dev"
33
+ Requires-Dist: pytest-cov>=5.0; extra == "dev"
34
+ Requires-Dist: flake8>=7.0; extra == "dev"
35
+ Requires-Dist: pdoc>=14; extra == "dev"
36
+ Dynamic: license-file
37
+
38
+ # OpenBadgesLib
39
+
40
+ [![CI](https://github.com/luisgf/openbadgeslib/actions/workflows/ci.yml/badge.svg)](https://github.com/luisgf/openbadgeslib/actions/workflows/ci.yml)
41
+ [![PyPI](https://img.shields.io/pypi/v/openbadgeslib.svg)](https://pypi.org/project/openbadgeslib/)
42
+ [![Python](https://img.shields.io/badge/python-3.10%E2%80%933.13-blue.svg)](https://github.com/luisgf/openbadgeslib/actions/workflows/ci.yml)
43
+ [![License](https://img.shields.io/badge/license-LGPLv3%20%2F%20BSD-blue.svg)](#license)
44
+
45
+ A Python library and CLI for signing and verifying
46
+ [Open Badges](https://www.imsglobal.org/activity/digital-badges) embedded in SVG
47
+ and PNG image files. It supports both **OpenBadges 2.0** (JWS compact
48
+ serialisation) and **OpenBadges 3.0** (W3C Verifiable Credentials / JWT-VC).
49
+
50
+ ## Features
51
+
52
+ - Sign badge images (SVG and PNG) with a JWS assertion (OB 2.0)
53
+ - Issue and verify OpenBadges 3.0 JWT-VC credentials
54
+ - Bake OB 3.0 JWT tokens into SVG and PNG badge images
55
+ - RSA 2048-bit (RS256) and ECC NIST P-256 (ES256) key support
56
+ - SHA-256 hashed recipient identity with salt (OB 2.0)
57
+ - Expiration and revocation checking
58
+ - Five command-line tools included
59
+
60
+ ## Requirements
61
+
62
+ - Python >= 3.10 (tested on 3.10–3.13)
63
+ - [pycryptodome](https://pypi.org/project/pycryptodome/) >= 3.20
64
+ - [ecdsa](https://pypi.org/project/ecdsa/) >= 0.19
65
+ - [pypng](https://pypi.org/project/pypng/) >= 0.20220715.0
66
+ - [PyJWT[crypto]](https://pypi.org/project/PyJWT/) >= 2.8
67
+ - [defusedxml](https://pypi.org/project/defusedxml/) >= 0.7
68
+
69
+ ## Installation
70
+
71
+ ```bash
72
+ pip install openbadgeslib
73
+ ```
74
+
75
+ All dependencies are installed automatically. For a development checkout with
76
+ the test suite and linters:
77
+
78
+ ```bash
79
+ pip install -e ".[dev]"
80
+ ```
81
+
82
+ ## Quick Start
83
+
84
+ ```bash
85
+ # 1. Initialize a configuration directory
86
+ openbadges-init ./config/
87
+
88
+ # 2. Generate a key pair for a badge
89
+ openbadges-keygenerator -c ./config/config.ini -g 1
90
+
91
+ # 3a. Sign a badge — OpenBadges 2.0 (default)
92
+ openbadges-signer -c ./config/config.ini -b 1 -r recipient@example.com -o /tmp/ -E
93
+
94
+ # 3b. Sign a badge — OpenBadges 3.0
95
+ openbadges-signer -c ./config/config.ini -b 1 -r recipient@example.com -o /tmp/ -E -V 3
96
+
97
+ # 4a. Verify — OpenBadges 2.0 (pin a trusted key with -l/--local or -k/--pubkey)
98
+ openbadges-verifier -i /tmp/badge_1_recipient@example.com.svg \
99
+ -r recipient@example.com -l 1
100
+
101
+ # 4b. Verify — OpenBadges 3.0
102
+ openbadges-verifier -i /tmp/badge_1_recipient@example.com.svg \
103
+ -r recipient@example.com -V 3 -k ./config/keys/verify_rsa_key_1.pem
104
+ ```
105
+
106
+ See the [Quick Start](https://github.com/luisgf/openbadgeslib/wiki/Quick-Start)
107
+ and [CLI Reference](https://github.com/luisgf/openbadgeslib/wiki/CLI-Reference)
108
+ wiki pages for the full walkthrough and every flag.
109
+
110
+ ## Using the library — OpenBadges 2.0
111
+
112
+ ```python
113
+ from openbadgeslib.ob2 import Badge, BadgeImgType, BadgeType, Signer
114
+ from openbadgeslib.keys import KeyType
115
+
116
+ with open('sign.pem', 'rb') as f:
117
+ priv_pem = f.read()
118
+ with open('verify.pem', 'rb') as f:
119
+ pub_pem = f.read()
120
+ with open('badge.svg', 'rb') as f:
121
+ image = f.read()
122
+
123
+ badge = Badge(
124
+ ini_name='my_badge',
125
+ name='My Badge',
126
+ description='Awarded for excellence',
127
+ image_type=BadgeImgType.SVG,
128
+ image=image,
129
+ image_url='https://example.com/badge.svg',
130
+ criteria_url='https://example.com/criteria.html',
131
+ json_url='https://example.com/badge.json',
132
+ verify_key_url='https://example.com/verify.pem',
133
+ key_type=KeyType.RSA,
134
+ privkey_pem=priv_pem,
135
+ pubkey_pem=pub_pem,
136
+ )
137
+
138
+ signer = Signer(identity='recipient@example.com', badge_type=BadgeType.SIGNED)
139
+ signed = signer.sign_badge(badge)
140
+ signed.save_to_file('/tmp/signed_badge.svg')
141
+ ```
142
+
143
+ ## Using the library — OpenBadges 3.0 (JWT-VC)
144
+
145
+ ```python
146
+ from openbadgeslib.ob3 import (
147
+ Issuer, Achievement, OpenBadgeCredential, OB3Signer, OB3Verifier,
148
+ )
149
+
150
+ issuer = Issuer(id='https://example.com/issuer', name='Example Org')
151
+ achievement = Achievement(
152
+ id='https://example.com/achievements/python',
153
+ name='Python Developer',
154
+ description='Awarded for Python proficiency',
155
+ criteria_narrative='Must pass the Python assessment',
156
+ )
157
+ credential = OpenBadgeCredential(
158
+ issuer=issuer,
159
+ recipient_id='mailto:recipient@example.com',
160
+ achievement=achievement,
161
+ )
162
+
163
+ with open('sign.pem', 'rb') as f:
164
+ priv_pem = f.read()
165
+ signer = OB3Signer(privkey_pem=priv_pem, algorithm='RS256')
166
+
167
+ # Bake the signed JWT-VC into a badge image
168
+ with open('badge.svg', 'rb') as f:
169
+ baked_svg = signer.sign_into_svg(credential, f.read())
170
+
171
+ # Verify
172
+ with open('verify.pem', 'rb') as f:
173
+ verifier = OB3Verifier(pubkey_pem=f.read())
174
+ token = OB3Verifier.extract_token_from_svg(baked_svg)
175
+ restored = verifier.verify(token, expected_recipient='recipient@example.com')
176
+ print('Recipient:', restored.recipient_id)
177
+ ```
178
+
179
+ ## Documentation
180
+
181
+ - **User & developer guide** — the project [**Wiki**](https://github.com/luisgf/openbadgeslib/wiki):
182
+ installation, configuration, concepts, the security model, CLI reference and
183
+ how-to guides.
184
+ - **API reference** — generated from the docstrings and published at
185
+ [**luisgf.github.io/openbadgeslib**](https://luisgf.github.io/openbadgeslib/).
186
+
187
+ ## Running the test suite
188
+
189
+ ```bash
190
+ pytest
191
+ pytest --cov=openbadgeslib # with coverage report
192
+ flake8 openbadgeslib tests # lint
193
+ ```
194
+
195
+ ## Changelog
196
+
197
+ See [`Changelog.txt`](Changelog.txt) for the full history, and the
198
+ [GitHub Releases](https://github.com/luisgf/openbadgeslib/releases) page for
199
+ release notes.
200
+
201
+ ## License
202
+
203
+ The **library** (`openbadgeslib/` package) is licensed under the
204
+ [GNU Lesser General Public License v3](https://opensource.org/licenses/lgpl-3.0.html)
205
+ (LGPLv3). The **command-line wrapper tools** are licensed under the
206
+ [BSD 2-Clause](https://opensource.org/licenses/BSD-2-Clause) license.
207
+
208
+ ## Authors
209
+
210
+ - Luis González Fernández <luisgf@luisgf.es>
211
+ - Jesús Cea Avión <jcea@jcea.es>
@@ -0,0 +1,174 @@
1
+ # OpenBadgesLib
2
+
3
+ [![CI](https://github.com/luisgf/openbadgeslib/actions/workflows/ci.yml/badge.svg)](https://github.com/luisgf/openbadgeslib/actions/workflows/ci.yml)
4
+ [![PyPI](https://img.shields.io/pypi/v/openbadgeslib.svg)](https://pypi.org/project/openbadgeslib/)
5
+ [![Python](https://img.shields.io/badge/python-3.10%E2%80%933.13-blue.svg)](https://github.com/luisgf/openbadgeslib/actions/workflows/ci.yml)
6
+ [![License](https://img.shields.io/badge/license-LGPLv3%20%2F%20BSD-blue.svg)](#license)
7
+
8
+ A Python library and CLI for signing and verifying
9
+ [Open Badges](https://www.imsglobal.org/activity/digital-badges) embedded in SVG
10
+ and PNG image files. It supports both **OpenBadges 2.0** (JWS compact
11
+ serialisation) and **OpenBadges 3.0** (W3C Verifiable Credentials / JWT-VC).
12
+
13
+ ## Features
14
+
15
+ - Sign badge images (SVG and PNG) with a JWS assertion (OB 2.0)
16
+ - Issue and verify OpenBadges 3.0 JWT-VC credentials
17
+ - Bake OB 3.0 JWT tokens into SVG and PNG badge images
18
+ - RSA 2048-bit (RS256) and ECC NIST P-256 (ES256) key support
19
+ - SHA-256 hashed recipient identity with salt (OB 2.0)
20
+ - Expiration and revocation checking
21
+ - Five command-line tools included
22
+
23
+ ## Requirements
24
+
25
+ - Python >= 3.10 (tested on 3.10–3.13)
26
+ - [pycryptodome](https://pypi.org/project/pycryptodome/) >= 3.20
27
+ - [ecdsa](https://pypi.org/project/ecdsa/) >= 0.19
28
+ - [pypng](https://pypi.org/project/pypng/) >= 0.20220715.0
29
+ - [PyJWT[crypto]](https://pypi.org/project/PyJWT/) >= 2.8
30
+ - [defusedxml](https://pypi.org/project/defusedxml/) >= 0.7
31
+
32
+ ## Installation
33
+
34
+ ```bash
35
+ pip install openbadgeslib
36
+ ```
37
+
38
+ All dependencies are installed automatically. For a development checkout with
39
+ the test suite and linters:
40
+
41
+ ```bash
42
+ pip install -e ".[dev]"
43
+ ```
44
+
45
+ ## Quick Start
46
+
47
+ ```bash
48
+ # 1. Initialize a configuration directory
49
+ openbadges-init ./config/
50
+
51
+ # 2. Generate a key pair for a badge
52
+ openbadges-keygenerator -c ./config/config.ini -g 1
53
+
54
+ # 3a. Sign a badge — OpenBadges 2.0 (default)
55
+ openbadges-signer -c ./config/config.ini -b 1 -r recipient@example.com -o /tmp/ -E
56
+
57
+ # 3b. Sign a badge — OpenBadges 3.0
58
+ openbadges-signer -c ./config/config.ini -b 1 -r recipient@example.com -o /tmp/ -E -V 3
59
+
60
+ # 4a. Verify — OpenBadges 2.0 (pin a trusted key with -l/--local or -k/--pubkey)
61
+ openbadges-verifier -i /tmp/badge_1_recipient@example.com.svg \
62
+ -r recipient@example.com -l 1
63
+
64
+ # 4b. Verify — OpenBadges 3.0
65
+ openbadges-verifier -i /tmp/badge_1_recipient@example.com.svg \
66
+ -r recipient@example.com -V 3 -k ./config/keys/verify_rsa_key_1.pem
67
+ ```
68
+
69
+ See the [Quick Start](https://github.com/luisgf/openbadgeslib/wiki/Quick-Start)
70
+ and [CLI Reference](https://github.com/luisgf/openbadgeslib/wiki/CLI-Reference)
71
+ wiki pages for the full walkthrough and every flag.
72
+
73
+ ## Using the library — OpenBadges 2.0
74
+
75
+ ```python
76
+ from openbadgeslib.ob2 import Badge, BadgeImgType, BadgeType, Signer
77
+ from openbadgeslib.keys import KeyType
78
+
79
+ with open('sign.pem', 'rb') as f:
80
+ priv_pem = f.read()
81
+ with open('verify.pem', 'rb') as f:
82
+ pub_pem = f.read()
83
+ with open('badge.svg', 'rb') as f:
84
+ image = f.read()
85
+
86
+ badge = Badge(
87
+ ini_name='my_badge',
88
+ name='My Badge',
89
+ description='Awarded for excellence',
90
+ image_type=BadgeImgType.SVG,
91
+ image=image,
92
+ image_url='https://example.com/badge.svg',
93
+ criteria_url='https://example.com/criteria.html',
94
+ json_url='https://example.com/badge.json',
95
+ verify_key_url='https://example.com/verify.pem',
96
+ key_type=KeyType.RSA,
97
+ privkey_pem=priv_pem,
98
+ pubkey_pem=pub_pem,
99
+ )
100
+
101
+ signer = Signer(identity='recipient@example.com', badge_type=BadgeType.SIGNED)
102
+ signed = signer.sign_badge(badge)
103
+ signed.save_to_file('/tmp/signed_badge.svg')
104
+ ```
105
+
106
+ ## Using the library — OpenBadges 3.0 (JWT-VC)
107
+
108
+ ```python
109
+ from openbadgeslib.ob3 import (
110
+ Issuer, Achievement, OpenBadgeCredential, OB3Signer, OB3Verifier,
111
+ )
112
+
113
+ issuer = Issuer(id='https://example.com/issuer', name='Example Org')
114
+ achievement = Achievement(
115
+ id='https://example.com/achievements/python',
116
+ name='Python Developer',
117
+ description='Awarded for Python proficiency',
118
+ criteria_narrative='Must pass the Python assessment',
119
+ )
120
+ credential = OpenBadgeCredential(
121
+ issuer=issuer,
122
+ recipient_id='mailto:recipient@example.com',
123
+ achievement=achievement,
124
+ )
125
+
126
+ with open('sign.pem', 'rb') as f:
127
+ priv_pem = f.read()
128
+ signer = OB3Signer(privkey_pem=priv_pem, algorithm='RS256')
129
+
130
+ # Bake the signed JWT-VC into a badge image
131
+ with open('badge.svg', 'rb') as f:
132
+ baked_svg = signer.sign_into_svg(credential, f.read())
133
+
134
+ # Verify
135
+ with open('verify.pem', 'rb') as f:
136
+ verifier = OB3Verifier(pubkey_pem=f.read())
137
+ token = OB3Verifier.extract_token_from_svg(baked_svg)
138
+ restored = verifier.verify(token, expected_recipient='recipient@example.com')
139
+ print('Recipient:', restored.recipient_id)
140
+ ```
141
+
142
+ ## Documentation
143
+
144
+ - **User & developer guide** — the project [**Wiki**](https://github.com/luisgf/openbadgeslib/wiki):
145
+ installation, configuration, concepts, the security model, CLI reference and
146
+ how-to guides.
147
+ - **API reference** — generated from the docstrings and published at
148
+ [**luisgf.github.io/openbadgeslib**](https://luisgf.github.io/openbadgeslib/).
149
+
150
+ ## Running the test suite
151
+
152
+ ```bash
153
+ pytest
154
+ pytest --cov=openbadgeslib # with coverage report
155
+ flake8 openbadgeslib tests # lint
156
+ ```
157
+
158
+ ## Changelog
159
+
160
+ See [`Changelog.txt`](Changelog.txt) for the full history, and the
161
+ [GitHub Releases](https://github.com/luisgf/openbadgeslib/releases) page for
162
+ release notes.
163
+
164
+ ## License
165
+
166
+ The **library** (`openbadgeslib/` package) is licensed under the
167
+ [GNU Lesser General Public License v3](https://opensource.org/licenses/lgpl-3.0.html)
168
+ (LGPLv3). The **command-line wrapper tools** are licensed under the
169
+ [BSD 2-Clause](https://opensource.org/licenses/BSD-2-Clause) license.
170
+
171
+ ## Authors
172
+
173
+ - Luis González Fernández <luisgf@luisgf.es>
174
+ - Jesús Cea Avión <jcea@jcea.es>
@@ -0,0 +1,21 @@
1
+ Authors
2
+ =======
3
+
4
+ Contributors
5
+ ------------
6
+
7
+ Sorted alphabetically:
8
+
9
+ * Jesús Cea Avión <jcea@jcea.es>
10
+ * Luis González Fernández <luisgf@luisgf.es>
11
+
12
+
13
+ License
14
+ -------
15
+
16
+ The **library** (``openbadgeslib/`` package) is licensed under the terms of
17
+ the :term:`LGPL3`.
18
+
19
+ The **command-line wrapper tools** (``openbadges-init``,
20
+ ``openbadges-keygenerator``, ``openbadges-signer``, ``openbadges-verifier``,
21
+ ``openbadges-publish``) are licensed under the :term:`BSD 2-Clause` licence.