openbadgeslib 3.1.1__tar.gz → 3.3.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.
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/Changelog.txt +63 -0
- {openbadgeslib-3.1.1/openbadgeslib.egg-info → openbadgeslib-3.3.0}/PKG-INFO +84 -24
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/README.md +80 -22
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/baking.py +29 -5
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/config.ini.example +4 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/confparser.py +19 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/ob1/badge.py +19 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/ob3/__init__.py +11 -1
- openbadgeslib-3.3.0/openbadgeslib/ob3/contexts/__init__.py +127 -0
- openbadgeslib-3.3.0/openbadgeslib/ob3/contexts/credentials-v2.json +340 -0
- openbadgeslib-3.3.0/openbadgeslib/ob3/contexts/ob-v3p0-context-3.0.1.json +447 -0
- openbadgeslib-3.3.0/openbadgeslib/ob3/contexts/ob-v3p0-context-3.0.2.json +431 -0
- openbadgeslib-3.3.0/openbadgeslib/ob3/contexts/ob-v3p0-context-3.0.3.json +452 -0
- openbadgeslib-3.3.0/openbadgeslib/ob3/contexts/security-data-integrity-v2.json +81 -0
- openbadgeslib-3.3.0/openbadgeslib/ob3/contexts/security-multikey-v1.json +35 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/ob3/credential.py +25 -6
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/ob3/did.py +113 -2
- openbadgeslib-3.3.0/openbadgeslib/ob3/ldp.py +565 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/ob3/verifier.py +76 -34
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/openbadges_signer.py +92 -12
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/openbadges_verifier.py +40 -10
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/util.py +1 -1
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0/openbadgeslib.egg-info}/PKG-INFO +84 -24
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib.egg-info/SOURCES.txt +20 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib.egg-info/requires.txt +3 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/pyproject.toml +11 -2
- openbadgeslib-3.3.0/tests/fixtures/vc_di_eddsa/README.md +13 -0
- openbadgeslib-3.3.0/tests/fixtures/vc_di_eddsa/credentials-examples-v2.json +5 -0
- openbadgeslib-3.3.0/tests/fixtures/vc_di_eddsa/doc-hash.txt +1 -0
- openbadgeslib-3.3.0/tests/fixtures/vc_di_eddsa/key-pair.json +4 -0
- openbadgeslib-3.3.0/tests/fixtures/vc_di_eddsa/proof-config-hash.txt +1 -0
- openbadgeslib-3.3.0/tests/fixtures/vc_di_eddsa/signed-credential.json +27 -0
- openbadgeslib-3.3.0/tests/ldp_helpers.py +55 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_confparser.py +25 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_ob1_badge_io.py +28 -0
- openbadgeslib-3.3.0/tests/test_ob3_contexts.py +76 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_ob3_credential.py +32 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_ob3_did.py +126 -0
- openbadgeslib-3.3.0/tests/test_ob3_ldp.py +292 -0
- openbadgeslib-3.3.0/tests/test_ob3_ldp_cli.py +166 -0
- openbadgeslib-3.3.0/tests/test_ob3_ldp_sign.py +292 -0
- openbadgeslib-3.3.0/tests/test_ob3_signer_cli_ldp.py +231 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/LICENSE.txt +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/MANIFEST.in +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/docs/README.md +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/__init__.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/_jws/__init__.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/_jws/exceptions.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/_jws/utils.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/badge.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/errors.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/keys.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/logs.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/mail.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/ob1/__init__.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/ob1/signer.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/ob1/verifier.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/ob2/__init__.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/ob2/models.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/ob2/signer.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/ob2/verifier.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/ob3/signer.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/ob3/status.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/ob3/status_list.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/ob3/status_registry.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/openbadges_init.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/openbadges_keygenerator.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/openbadges_publish.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/py.typed +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/signer.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib/verifier.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib.egg-info/dependency_links.txt +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib.egg-info/entry_points.txt +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/openbadgeslib.egg-info/top_level.txt +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/setup.cfg +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/config1.ini +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/conftest.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/images/sample1.png +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/images/sample1.svg +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/images/userimage01.svg +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/logo Python Espan/314/203a.svg" +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/logo Python Espa/303/261a.svg" +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/runtests.sh +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_cli_json.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_cli_smoke.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_docs.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_eddsa.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_jws.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_key_operation.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_ob1_signer.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_ob1_verifier.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_ob2_cli.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_ob2_models.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_ob2_signer.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_ob2_verifier.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_ob3_did_doc.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_ob3_publish_cli.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_ob3_signer.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_ob3_status.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_ob3_status_list.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_ob3_status_registry.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_ob3_verifier.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_sign_ecc.pem +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_sign_rsa.pem +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_util.py +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_verify_ecc.pem +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/test_verify_rsa.pem +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/withoutxmlheader.svg +0 -0
- {openbadgeslib-3.1.1 → openbadgeslib-3.3.0}/tests/withxmlheader.svg +0 -0
|
@@ -4,6 +4,69 @@ OpenBadgesLib - Changelog
|
|
|
4
4
|
Newest first. Dates are ISO 8601 (YYYY-MM-DD).
|
|
5
5
|
|
|
6
6
|
|
|
7
|
+
* v3.3.0 - 2026-07-04
|
|
8
|
+
|
|
9
|
+
- feat(ob3): issuance of OB 3.0 credentials secured with a W3C Data
|
|
10
|
+
Integrity proof (eddsa-rdfc-2022) — new `OB3LdpSigner` and low-level
|
|
11
|
+
`add_data_integrity_proof`, the signing counterparts of the verifiers
|
|
12
|
+
shipped in 3.2.0, sharing their canonicalization core and reproducing
|
|
13
|
+
the official W3C vc-di-eddsa test vector byte for byte. Ed25519 keys
|
|
14
|
+
only; requires the `[ldp]` extra, which now covers both directions.
|
|
15
|
+
|
|
16
|
+
- feat(cli): `openbadges-signer -P/--proof-format {vc-jwt,ldp}` (OB3
|
|
17
|
+
only) plus an optional per-badge `proof_format` config key (flag wins;
|
|
18
|
+
default vc-jwt). With `[issuer] did` configured the proof names the
|
|
19
|
+
`did:web:...#badge_N` verification method `openbadges-publish -V 3`
|
|
20
|
+
publishes (trusted via `--resolve-did`); otherwise it falls back to a
|
|
21
|
+
self-asserted did:key derived from the signing key and tells the
|
|
22
|
+
operator so. LDP-signed badges are tagged `PROOF ldp` in the signer
|
|
23
|
+
audit log. Status lists stay VC-JWT regardless of the badge's proof
|
|
24
|
+
format.
|
|
25
|
+
|
|
26
|
+
- feat(ob3): multikey/did:key encoders in `ob3.did` —
|
|
27
|
+
`multikey_from_pem` (publicKeyMultibase) and `did_key_from_pem`,
|
|
28
|
+
the exact inverses of the resolvers, for Ed25519 and NIST P-256.
|
|
29
|
+
|
|
30
|
+
- fix(cli): `Badge.create_from_conf` rejected `key_type = ED25519`
|
|
31
|
+
outright, so the CLI could never sign with the keys
|
|
32
|
+
`openbadges-keygenerator -t ED25519` produces; Ed25519 key material
|
|
33
|
+
now loads, and the legacy OB 1.0 path (`-V 1`) refuses non-RSA/ECC
|
|
34
|
+
keys with a clean message instead of failing mid-JWS.
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
* v3.2.0 - 2026-07-03
|
|
38
|
+
|
|
39
|
+
- feat(ob3): verification of OB 3.0 credentials secured with a W3C Data
|
|
40
|
+
Integrity proof (the Linked Data Proof format), cryptosuite
|
|
41
|
+
eddsa-rdfc-2022 — new `OB3LdpVerifier` and low-level
|
|
42
|
+
`verify_data_integrity_proof`, validated against the official W3C
|
|
43
|
+
vc-di-eddsa test vectors. Verify-only: issuing stays JWT-VC. Requires
|
|
44
|
+
the new optional extra: `pip install "openbadgeslib[ldp]"` (pyld);
|
|
45
|
+
everything else works without it.
|
|
46
|
+
|
|
47
|
+
- feat(ob3): JSON-LD @context documents are never fetched from the
|
|
48
|
+
network — the exact context files ship pinned inside the wheel behind
|
|
49
|
+
an exact-match allowlist (fail-closed on unknown contexts), and Data
|
|
50
|
+
Integrity documents are capped at 256 KiB before canonicalization.
|
|
51
|
+
|
|
52
|
+
- feat(ob3): `resolve_verification_method` resolves the exact
|
|
53
|
+
verificationMethod URL a proof names (did:key fragment validation;
|
|
54
|
+
did:web entry selected by id, fail-closed on no match).
|
|
55
|
+
|
|
56
|
+
- feat(baking): OB 3.0 §5.3 text-content carrier for Data Integrity
|
|
57
|
+
credentials — `bake_svg(..., as_text=True)` and an opt-in
|
|
58
|
+
`extract_svg(..., text_fallback=True)`; the OB3 extraction returns
|
|
59
|
+
either a compact JWT or the credential JSON. PNG needed no change.
|
|
60
|
+
|
|
61
|
+
- feat(cli): `openbadges-verifier -V 3` autodetects the baked payload
|
|
62
|
+
(JWT-VC vs Data Integrity) with the same trust flags, reports
|
|
63
|
+
`proof_format` in `--json`, and hints at the missing `[ldp]` extra.
|
|
64
|
+
|
|
65
|
+
- feat(api): `OpenBadgeCredential.from_vc_document` reconstructs a
|
|
66
|
+
credential from its JSON-LD document shape (same validation as the
|
|
67
|
+
JWT payload path).
|
|
68
|
+
|
|
69
|
+
|
|
7
70
|
* v3.1.1 - 2026-07-03
|
|
8
71
|
|
|
9
72
|
- docs(packaging): discoverability metadata — a descriptive PyPI summary,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: openbadgeslib
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.3.0
|
|
4
4
|
Summary: Production-ready Python library & CLI for Open Badges 3.0 (W3C Verifiable Credentials): issue, verify, and revoke JWT-VC credentials with Bitstring Status Lists and did:web — plus strict OB 2.0 and legacy OB 1.0.
|
|
5
5
|
Author-email: Luis González Fernández <luisgf@luisgf.es>, Jesús Cea Avión <jcea@jcea.es>
|
|
6
6
|
License: LGPLv3
|
|
@@ -9,7 +9,7 @@ Project-URL: Documentation, https://github.com/luisgf/openbadgeslib/wiki
|
|
|
9
9
|
Project-URL: API Reference, https://luisgf.github.io/openbadgeslib/
|
|
10
10
|
Project-URL: Source, https://github.com/luisgf/openbadgeslib
|
|
11
11
|
Project-URL: Changelog, https://github.com/luisgf/openbadgeslib/blob/master/Changelog.txt
|
|
12
|
-
Keywords: openbadges,open-badges,verifiable-credentials,vc-jwt,w3c-vc,digital-credentials,did,did-web,bitstring-status-list,revocation,ob3,credentials,ed25519,cryptography
|
|
12
|
+
Keywords: openbadges,open-badges,verifiable-credentials,vc-jwt,w3c-vc,digital-credentials,did,did-web,bitstring-status-list,revocation,ob3,credentials,ed25519,cryptography,data-integrity,eddsa
|
|
13
13
|
Classifier: Development Status :: 5 - Production/Stable
|
|
14
14
|
Classifier: Intended Audience :: Developers
|
|
15
15
|
Classifier: Intended Audience :: Education
|
|
@@ -34,6 +34,8 @@ Requires-Dist: pypng>=0.20220715.0
|
|
|
34
34
|
Requires-Dist: PyJWT[crypto]>=2.8
|
|
35
35
|
Requires-Dist: cryptography>=42
|
|
36
36
|
Requires-Dist: defusedxml>=0.7
|
|
37
|
+
Provides-Extra: ldp
|
|
38
|
+
Requires-Dist: pyld>=2.0.4; extra == "ldp"
|
|
37
39
|
Provides-Extra: dev
|
|
38
40
|
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
39
41
|
Requires-Dist: pytest-cov>=5.0; extra == "dev"
|
|
@@ -52,7 +54,8 @@ Dynamic: license-file
|
|
|
52
54
|
|
|
53
55
|
**A production-ready Python library & CLI for the full Open Badges 3.0 issuer
|
|
54
56
|
lifecycle** — issue [W3C Verifiable Credentials](https://www.w3.org/TR/vc-data-model-2.0/)
|
|
55
|
-
as JWT-VC, bake them into SVG/PNG, verify them,
|
|
57
|
+
as JWT-VC or W3C Data Integrity (LDP) proofs, bake them into SVG/PNG, verify them,
|
|
58
|
+
and **revoke or suspend** them
|
|
56
59
|
with W3C Bitstring Status Lists and `did:web`. It also ships strict
|
|
57
60
|
**OpenBadges 2.0** (JWS / hosted assertions) and a frozen **OpenBadges 1.0**
|
|
58
61
|
legacy format, selected with `-V {1,2,3}` (default `3`).
|
|
@@ -61,12 +64,14 @@ legacy format, selected with `-V {1,2,3}` (default `3`).
|
|
|
61
64
|
|
|
62
65
|
- Sign badge images (SVG and PNG) as strict OB 2.0 JWS / hosted assertions (with a frozen OB 1.0 legacy format)
|
|
63
66
|
- Issue and verify OpenBadges 3.0 JWT-VC credentials
|
|
64
|
-
- Bake OB 3.0 JWT
|
|
67
|
+
- Bake OB 3.0 credentials (JWT-VC or Data Integrity JSON-LD) into SVG and PNG badge images
|
|
65
68
|
- RSA 2048-bit (RS256), ECC NIST P-256 (ES256), and Ed25519 (EdDSA) key support
|
|
66
69
|
- SHA-256 hashed recipient identity with salt (OB 2.0)
|
|
67
70
|
- Expiration and revocation checking
|
|
68
71
|
- Issuer-side OB 3.0 revocation and suspension: W3C Bitstring Status List
|
|
69
72
|
publication and `--revoke` / `--suspend` / `--unsuspend` management
|
|
73
|
+
- Issue and verify OB 3.0 W3C Data Integrity credentials (`eddsa-rdfc-2022`,
|
|
74
|
+
optional `[ldp]` extra) in addition to JWT-VC
|
|
70
75
|
- did:web issuer identity: `did.json` generation and DID resolution
|
|
71
76
|
- Five command-line tools included
|
|
72
77
|
|
|
@@ -75,8 +80,10 @@ legacy format, selected with `-V {1,2,3}` (default `3`).
|
|
|
75
80
|
- **The complete OB 3.0 issuer lifecycle in Python** — not just issuing, but
|
|
76
81
|
publishing trust artefacts (`did:web`) and revoking/suspending credentials via
|
|
77
82
|
Bitstring Status Lists, driven from the CLI or the library.
|
|
78
|
-
- **Native VC-JWT
|
|
79
|
-
(EdDSA)
|
|
83
|
+
- **Native VC-JWT signing** with RSA (RS256), ECC P-256 (ES256) and Ed25519
|
|
84
|
+
(EdDSA) — *plus* native **W3C Data Integrity / LDP** signing
|
|
85
|
+
(`eddsa-rdfc-2022`, Ed25519, optional `[ldp]` extra). Both proof formats
|
|
86
|
+
issue *and* verify offline, no external service.
|
|
80
87
|
- **Lean and typed** — `mypy --strict`, CI on Python 3.10–3.13, a small
|
|
81
88
|
dependency set, dataclasses + explicit validation (no Pydantic).
|
|
82
89
|
- **Dual-licensed** LGPLv3 (library) / BSD-2-Clause (CLI tools).
|
|
@@ -84,23 +91,39 @@ legacy format, selected with `-V {1,2,3}` (default `3`).
|
|
|
84
91
|
### How it compares
|
|
85
92
|
|
|
86
93
|
Best-effort comparison from each project's public documentation as of July 2026;
|
|
87
|
-
"not documented" is shown as `—`. Corrections welcome via issue/PR.
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
|
95
|
-
|
|
|
96
|
-
|
|
|
97
|
-
|
|
|
98
|
-
|
|
|
99
|
-
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
94
|
+
"not documented" is shown as `—`. Corrections welcome via issue/PR. The Python
|
|
95
|
+
Open Badges landscape splits into three groups: 1EdTech's **verify-only** OB 2.0
|
|
96
|
+
reference validator, heavyweight **Django server platforms** (the Badgr lineage),
|
|
97
|
+
and a thin tail of **standalone libraries** — of which openbadgeslib is the only
|
|
98
|
+
actively-maintained, pip-installable, offline one that covers all three OB
|
|
99
|
+
versions and both OB 3.0 proof formats.
|
|
100
|
+
|
|
101
|
+
| Capability | **openbadgeslib** | [validator-core](https://github.com/1EdTech/openbadges-validator-core) | [Badgr / mint-o-badges](https://github.com/mint-o-badges/badgr-server) (a) | [pyopenbadges](https://github.com/CoopCodeCommun/pyopenbadges) | [didkit](https://github.com/spruceid/didkit-python) (b) |
|
|
102
|
+
| --- | --- | --- | --- | --- | --- |
|
|
103
|
+
| Open Badges versions | 1.0, 2.0, **3.0** | 0.5–2.0 | 1.1, 2.0, 3.0 | 3.0 only | generic VC |
|
|
104
|
+
| Issue / verify | ✅ both | verify only | issue; partial verify | both | both (VC + VP) |
|
|
105
|
+
| OB 3.0 proof: VC-JWT (JOSE) | ✅ RS/ES/EdDSA | — | — | roadmap | ✅ not OB-aware |
|
|
106
|
+
| OB 3.0 proof: Data Integrity / LDP | ✅ issue + verify (`eddsa-rdfc-2022`) | — | issue only (Ed25519) | home-grown, non-conformant | older suites; no `rdfc-2022` in wheel |
|
|
107
|
+
| Revocation / suspension | ✅ W3C Bitstring Status List | hosted check | `1EdTechRevocationList` | ad-hoc flag | — |
|
|
108
|
+
| `did:web` (generate + resolve) | ✅ | — | — | — | resolve only |
|
|
109
|
+
| Image baking (SVG + PNG) | ✅ | unbake only | ✅ | — | — |
|
|
110
|
+
| Form factor | library + 5 CLI tools | library + CLI | Django server | library | binding |
|
|
111
|
+
| Typing / CI | `mypy --strict`, CI 3.10–3.13 | — | — | Pydantic | — |
|
|
112
|
+
| License | LGPLv3 / BSD-2 | Apache-2.0 | AGPL-3.0 | MIT/LGPL | Apache-2.0 |
|
|
113
|
+
|
|
114
|
+
(a) The actively-maintained community fork (open-educational-badges): it
|
|
115
|
+
genuinely issues OB 3.0 Data Integrity credentials, but only as a server (not a
|
|
116
|
+
pip library) and only with Ed25519 (no VC-JWT). The classic Concentric Sky
|
|
117
|
+
`badgr-server` is OB 2.0 and its canonical repo is gone; SURF's
|
|
118
|
+
`edubadges-server` delegates OB 3.0 signing to external agents.
|
|
119
|
+
(b) Generic W3C VC/DID toolkit (Rust `ssi` bindings), not Open Badges-aware, and
|
|
120
|
+
archived (read-only since July 2025).
|
|
121
|
+
|
|
122
|
+
For authoritative OB 2.0 *validation* semantics, 1EdTech's Python
|
|
123
|
+
[`openbadges-validator-core`](https://github.com/1EdTech/openbadges-validator-core)
|
|
124
|
+
and Node [`openbadges-validator`](https://github.com/1EdTech/openbadges-validator)
|
|
125
|
+
remain the reference; openbadgeslib focuses on the full issuer lifecycle across
|
|
126
|
+
all three OB versions.
|
|
104
127
|
|
|
105
128
|
## Requirements
|
|
106
129
|
|
|
@@ -187,7 +210,15 @@ with open('/tmp/signed_badge.svg', 'wb') as f:
|
|
|
187
210
|
|
|
188
211
|
For the frozen OpenBadges 1.0 legacy API (`Badge` / `Signer` / `Verifier`), import from `openbadgeslib.ob1` instead.
|
|
189
212
|
|
|
190
|
-
## Using the library — OpenBadges 3.0
|
|
213
|
+
## Using the library — OpenBadges 3.0
|
|
214
|
+
|
|
215
|
+
OB 3.0 credentials can be secured with either of the two proof formats the
|
|
216
|
+
spec allows: a compact **VC-JWT** (`OB3Signer`, RS256/ES256/EdDSA) or an
|
|
217
|
+
embedded **Data Integrity** proof (`OB3LdpSigner`, cryptosuite
|
|
218
|
+
`eddsa-rdfc-2022`, Ed25519 only — needs the `[ldp]` extra). Both bake into
|
|
219
|
+
the same SVG/PNG carriers and the verifier auto-detects the format.
|
|
220
|
+
|
|
221
|
+
### VC-JWT (JOSE)
|
|
191
222
|
|
|
192
223
|
```python
|
|
193
224
|
from openbadgeslib.ob3 import (
|
|
@@ -223,6 +254,35 @@ restored = verifier.verify(token, expected_recipient='recipient@example.com')
|
|
|
223
254
|
print('Recipient:', restored.recipient_id)
|
|
224
255
|
```
|
|
225
256
|
|
|
257
|
+
### Data Integrity (LDP)
|
|
258
|
+
|
|
259
|
+
Same credential, an embedded JSON-LD proof instead of a JWT. Requires an
|
|
260
|
+
Ed25519 signing key and the `[ldp]` extra (`pip install openbadgeslib[ldp]`).
|
|
261
|
+
Reuse the `credential` built above:
|
|
262
|
+
|
|
263
|
+
```python
|
|
264
|
+
from openbadgeslib.ob3 import OB3LdpSigner, OB3LdpVerifier
|
|
265
|
+
|
|
266
|
+
with open('sign_ed25519.pem', 'rb') as f:
|
|
267
|
+
priv_pem = f.read()
|
|
268
|
+
|
|
269
|
+
# Bake a credential carrying an eddsa-rdfc-2022 DataIntegrityProof into an SVG
|
|
270
|
+
signer = OB3LdpSigner(priv_pem)
|
|
271
|
+
with open('badge.svg', 'rb') as f:
|
|
272
|
+
baked_svg = signer.sign_into_svg(credential, f.read())
|
|
273
|
+
|
|
274
|
+
# Verify (the LDP credential travels as JSON in the baked image)
|
|
275
|
+
with open('verify_ed25519.pem', 'rb') as f:
|
|
276
|
+
verifier = OB3LdpVerifier(pubkey_pem=f.read())
|
|
277
|
+
document = OB3Verifier.extract_token_from_svg(baked_svg)
|
|
278
|
+
restored = verifier.verify(document, expected_recipient='recipient@example.com')
|
|
279
|
+
print('Recipient:', restored.recipient_id)
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
From the CLI, select the format with `openbadges-signer -P ldp` (OB 3.0 only),
|
|
283
|
+
or set `proof_format = ldp` in the badge's INI section; the default stays
|
|
284
|
+
`vc-jwt`. Status lists remain VC-JWT regardless of the badge's proof format.
|
|
285
|
+
|
|
226
286
|
## Documentation
|
|
227
287
|
|
|
228
288
|
- **User & developer guide** — the project [**Wiki**](https://github.com/luisgf/openbadgeslib/wiki):
|
|
@@ -7,7 +7,8 @@
|
|
|
7
7
|
|
|
8
8
|
**A production-ready Python library & CLI for the full Open Badges 3.0 issuer
|
|
9
9
|
lifecycle** — issue [W3C Verifiable Credentials](https://www.w3.org/TR/vc-data-model-2.0/)
|
|
10
|
-
as JWT-VC, bake them into SVG/PNG, verify them,
|
|
10
|
+
as JWT-VC or W3C Data Integrity (LDP) proofs, bake them into SVG/PNG, verify them,
|
|
11
|
+
and **revoke or suspend** them
|
|
11
12
|
with W3C Bitstring Status Lists and `did:web`. It also ships strict
|
|
12
13
|
**OpenBadges 2.0** (JWS / hosted assertions) and a frozen **OpenBadges 1.0**
|
|
13
14
|
legacy format, selected with `-V {1,2,3}` (default `3`).
|
|
@@ -16,12 +17,14 @@ legacy format, selected with `-V {1,2,3}` (default `3`).
|
|
|
16
17
|
|
|
17
18
|
- Sign badge images (SVG and PNG) as strict OB 2.0 JWS / hosted assertions (with a frozen OB 1.0 legacy format)
|
|
18
19
|
- Issue and verify OpenBadges 3.0 JWT-VC credentials
|
|
19
|
-
- Bake OB 3.0 JWT
|
|
20
|
+
- Bake OB 3.0 credentials (JWT-VC or Data Integrity JSON-LD) into SVG and PNG badge images
|
|
20
21
|
- RSA 2048-bit (RS256), ECC NIST P-256 (ES256), and Ed25519 (EdDSA) key support
|
|
21
22
|
- SHA-256 hashed recipient identity with salt (OB 2.0)
|
|
22
23
|
- Expiration and revocation checking
|
|
23
24
|
- Issuer-side OB 3.0 revocation and suspension: W3C Bitstring Status List
|
|
24
25
|
publication and `--revoke` / `--suspend` / `--unsuspend` management
|
|
26
|
+
- Issue and verify OB 3.0 W3C Data Integrity credentials (`eddsa-rdfc-2022`,
|
|
27
|
+
optional `[ldp]` extra) in addition to JWT-VC
|
|
25
28
|
- did:web issuer identity: `did.json` generation and DID resolution
|
|
26
29
|
- Five command-line tools included
|
|
27
30
|
|
|
@@ -30,8 +33,10 @@ legacy format, selected with `-V {1,2,3}` (default `3`).
|
|
|
30
33
|
- **The complete OB 3.0 issuer lifecycle in Python** — not just issuing, but
|
|
31
34
|
publishing trust artefacts (`did:web`) and revoking/suspending credentials via
|
|
32
35
|
Bitstring Status Lists, driven from the CLI or the library.
|
|
33
|
-
- **Native VC-JWT
|
|
34
|
-
(EdDSA)
|
|
36
|
+
- **Native VC-JWT signing** with RSA (RS256), ECC P-256 (ES256) and Ed25519
|
|
37
|
+
(EdDSA) — *plus* native **W3C Data Integrity / LDP** signing
|
|
38
|
+
(`eddsa-rdfc-2022`, Ed25519, optional `[ldp]` extra). Both proof formats
|
|
39
|
+
issue *and* verify offline, no external service.
|
|
35
40
|
- **Lean and typed** — `mypy --strict`, CI on Python 3.10–3.13, a small
|
|
36
41
|
dependency set, dataclasses + explicit validation (no Pydantic).
|
|
37
42
|
- **Dual-licensed** LGPLv3 (library) / BSD-2-Clause (CLI tools).
|
|
@@ -39,23 +44,39 @@ legacy format, selected with `-V {1,2,3}` (default `3`).
|
|
|
39
44
|
### How it compares
|
|
40
45
|
|
|
41
46
|
Best-effort comparison from each project's public documentation as of July 2026;
|
|
42
|
-
"not documented" is shown as `—`. Corrections welcome via issue/PR.
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
|
50
|
-
|
|
|
51
|
-
|
|
|
52
|
-
|
|
|
53
|
-
|
|
|
54
|
-
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
47
|
+
"not documented" is shown as `—`. Corrections welcome via issue/PR. The Python
|
|
48
|
+
Open Badges landscape splits into three groups: 1EdTech's **verify-only** OB 2.0
|
|
49
|
+
reference validator, heavyweight **Django server platforms** (the Badgr lineage),
|
|
50
|
+
and a thin tail of **standalone libraries** — of which openbadgeslib is the only
|
|
51
|
+
actively-maintained, pip-installable, offline one that covers all three OB
|
|
52
|
+
versions and both OB 3.0 proof formats.
|
|
53
|
+
|
|
54
|
+
| Capability | **openbadgeslib** | [validator-core](https://github.com/1EdTech/openbadges-validator-core) | [Badgr / mint-o-badges](https://github.com/mint-o-badges/badgr-server) (a) | [pyopenbadges](https://github.com/CoopCodeCommun/pyopenbadges) | [didkit](https://github.com/spruceid/didkit-python) (b) |
|
|
55
|
+
| --- | --- | --- | --- | --- | --- |
|
|
56
|
+
| Open Badges versions | 1.0, 2.0, **3.0** | 0.5–2.0 | 1.1, 2.0, 3.0 | 3.0 only | generic VC |
|
|
57
|
+
| Issue / verify | ✅ both | verify only | issue; partial verify | both | both (VC + VP) |
|
|
58
|
+
| OB 3.0 proof: VC-JWT (JOSE) | ✅ RS/ES/EdDSA | — | — | roadmap | ✅ not OB-aware |
|
|
59
|
+
| OB 3.0 proof: Data Integrity / LDP | ✅ issue + verify (`eddsa-rdfc-2022`) | — | issue only (Ed25519) | home-grown, non-conformant | older suites; no `rdfc-2022` in wheel |
|
|
60
|
+
| Revocation / suspension | ✅ W3C Bitstring Status List | hosted check | `1EdTechRevocationList` | ad-hoc flag | — |
|
|
61
|
+
| `did:web` (generate + resolve) | ✅ | — | — | — | resolve only |
|
|
62
|
+
| Image baking (SVG + PNG) | ✅ | unbake only | ✅ | — | — |
|
|
63
|
+
| Form factor | library + 5 CLI tools | library + CLI | Django server | library | binding |
|
|
64
|
+
| Typing / CI | `mypy --strict`, CI 3.10–3.13 | — | — | Pydantic | — |
|
|
65
|
+
| License | LGPLv3 / BSD-2 | Apache-2.0 | AGPL-3.0 | MIT/LGPL | Apache-2.0 |
|
|
66
|
+
|
|
67
|
+
(a) The actively-maintained community fork (open-educational-badges): it
|
|
68
|
+
genuinely issues OB 3.0 Data Integrity credentials, but only as a server (not a
|
|
69
|
+
pip library) and only with Ed25519 (no VC-JWT). The classic Concentric Sky
|
|
70
|
+
`badgr-server` is OB 2.0 and its canonical repo is gone; SURF's
|
|
71
|
+
`edubadges-server` delegates OB 3.0 signing to external agents.
|
|
72
|
+
(b) Generic W3C VC/DID toolkit (Rust `ssi` bindings), not Open Badges-aware, and
|
|
73
|
+
archived (read-only since July 2025).
|
|
74
|
+
|
|
75
|
+
For authoritative OB 2.0 *validation* semantics, 1EdTech's Python
|
|
76
|
+
[`openbadges-validator-core`](https://github.com/1EdTech/openbadges-validator-core)
|
|
77
|
+
and Node [`openbadges-validator`](https://github.com/1EdTech/openbadges-validator)
|
|
78
|
+
remain the reference; openbadgeslib focuses on the full issuer lifecycle across
|
|
79
|
+
all three OB versions.
|
|
59
80
|
|
|
60
81
|
## Requirements
|
|
61
82
|
|
|
@@ -142,7 +163,15 @@ with open('/tmp/signed_badge.svg', 'wb') as f:
|
|
|
142
163
|
|
|
143
164
|
For the frozen OpenBadges 1.0 legacy API (`Badge` / `Signer` / `Verifier`), import from `openbadgeslib.ob1` instead.
|
|
144
165
|
|
|
145
|
-
## Using the library — OpenBadges 3.0
|
|
166
|
+
## Using the library — OpenBadges 3.0
|
|
167
|
+
|
|
168
|
+
OB 3.0 credentials can be secured with either of the two proof formats the
|
|
169
|
+
spec allows: a compact **VC-JWT** (`OB3Signer`, RS256/ES256/EdDSA) or an
|
|
170
|
+
embedded **Data Integrity** proof (`OB3LdpSigner`, cryptosuite
|
|
171
|
+
`eddsa-rdfc-2022`, Ed25519 only — needs the `[ldp]` extra). Both bake into
|
|
172
|
+
the same SVG/PNG carriers and the verifier auto-detects the format.
|
|
173
|
+
|
|
174
|
+
### VC-JWT (JOSE)
|
|
146
175
|
|
|
147
176
|
```python
|
|
148
177
|
from openbadgeslib.ob3 import (
|
|
@@ -178,6 +207,35 @@ restored = verifier.verify(token, expected_recipient='recipient@example.com')
|
|
|
178
207
|
print('Recipient:', restored.recipient_id)
|
|
179
208
|
```
|
|
180
209
|
|
|
210
|
+
### Data Integrity (LDP)
|
|
211
|
+
|
|
212
|
+
Same credential, an embedded JSON-LD proof instead of a JWT. Requires an
|
|
213
|
+
Ed25519 signing key and the `[ldp]` extra (`pip install openbadgeslib[ldp]`).
|
|
214
|
+
Reuse the `credential` built above:
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
from openbadgeslib.ob3 import OB3LdpSigner, OB3LdpVerifier
|
|
218
|
+
|
|
219
|
+
with open('sign_ed25519.pem', 'rb') as f:
|
|
220
|
+
priv_pem = f.read()
|
|
221
|
+
|
|
222
|
+
# Bake a credential carrying an eddsa-rdfc-2022 DataIntegrityProof into an SVG
|
|
223
|
+
signer = OB3LdpSigner(priv_pem)
|
|
224
|
+
with open('badge.svg', 'rb') as f:
|
|
225
|
+
baked_svg = signer.sign_into_svg(credential, f.read())
|
|
226
|
+
|
|
227
|
+
# Verify (the LDP credential travels as JSON in the baked image)
|
|
228
|
+
with open('verify_ed25519.pem', 'rb') as f:
|
|
229
|
+
verifier = OB3LdpVerifier(pubkey_pem=f.read())
|
|
230
|
+
document = OB3Verifier.extract_token_from_svg(baked_svg)
|
|
231
|
+
restored = verifier.verify(document, expected_recipient='recipient@example.com')
|
|
232
|
+
print('Recipient:', restored.recipient_id)
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
From the CLI, select the format with `openbadges-signer -P ldp` (OB 3.0 only),
|
|
236
|
+
or set `proof_format = ldp` in the badge's INI section; the default stays
|
|
237
|
+
`vc-jwt`. Status lists remain VC-JWT regardless of the badge's proof format.
|
|
238
|
+
|
|
181
239
|
## Documentation
|
|
182
240
|
|
|
183
241
|
- **User & developer guide** — the project [**Wiki**](https://github.com/luisgf/openbadgeslib/wiki):
|
|
@@ -75,16 +75,26 @@ def _bounded_inflate(data: bytes, limit: int = MAX_ITXT_DECOMPRESSED) -> bytes:
|
|
|
75
75
|
# ── SVG ─────────────────────────────────────────────────────────────────────
|
|
76
76
|
|
|
77
77
|
def bake_svg(image_bytes: bytes, token: str, comment: Optional[str] = None, *,
|
|
78
|
-
element: str = SVG_ELEMENT, namespace: str = SVG_NS
|
|
78
|
+
element: str = SVG_ELEMENT, namespace: str = SVG_NS,
|
|
79
|
+
as_text: bool = False) -> bytes:
|
|
79
80
|
"""Return *image_bytes* with an ``<element verify=token>`` node (and an
|
|
80
81
|
optional XML comment) appended to the root ``<svg>``. *element*/*namespace*
|
|
81
|
-
default to the OB 2.0 identifiers; OB 3.0 passes its own.
|
|
82
|
+
default to the OB 2.0 identifiers; OB 3.0 passes its own.
|
|
83
|
+
|
|
84
|
+
With ``as_text=True`` the token is stored as the element's text content
|
|
85
|
+
instead of the ``verify`` attribute — the OB 3.0 carrier for credentials
|
|
86
|
+
secured with a Data Integrity proof, whose payload is a JSON document
|
|
87
|
+
rather than a compact JWT (OB 3.0 §5.3).
|
|
88
|
+
"""
|
|
82
89
|
svg_doc = parseString(image_bytes)
|
|
83
90
|
try:
|
|
84
91
|
svg_tag = svg_doc.getElementsByTagName('svg').item(0)
|
|
85
92
|
node = svg_doc.createElement(element)
|
|
86
93
|
node.attributes['xmlns:openbadges'] = namespace
|
|
87
|
-
|
|
94
|
+
if as_text:
|
|
95
|
+
node.appendChild(svg_doc.createTextNode(token))
|
|
96
|
+
else:
|
|
97
|
+
node.attributes['verify'] = token
|
|
88
98
|
svg_tag.appendChild(node)
|
|
89
99
|
if comment:
|
|
90
100
|
svg_tag.appendChild(svg_doc.createComment(comment))
|
|
@@ -102,12 +112,18 @@ def has_svg(image_bytes: bytes, *, element: str = SVG_ELEMENT) -> bool:
|
|
|
102
112
|
svg_doc.unlink()
|
|
103
113
|
|
|
104
114
|
|
|
105
|
-
def extract_svg(image_bytes: bytes, *, element: str = SVG_ELEMENT
|
|
115
|
+
def extract_svg(image_bytes: bytes, *, element: str = SVG_ELEMENT,
|
|
116
|
+
text_fallback: bool = False) -> Optional[str]:
|
|
106
117
|
"""Return the embedded token string, or None if the badge carries no token.
|
|
107
118
|
|
|
108
119
|
None covers both a missing *element* node and a present element with no
|
|
109
120
|
``verify`` attribute (a well-formed SVG that simply isn't a signed badge).
|
|
110
121
|
Malformed XML still raises (left to the caller to map to its own error type).
|
|
122
|
+
|
|
123
|
+
With ``text_fallback=True``, an element without a ``verify`` attribute
|
|
124
|
+
falls back to its text content — where OB 3.0 §5.3 bakes a credential
|
|
125
|
+
secured with a Data Integrity proof (a JSON document, not a compact JWT).
|
|
126
|
+
An empty/whitespace-only text content still yields None.
|
|
111
127
|
"""
|
|
112
128
|
svg_doc = None
|
|
113
129
|
try:
|
|
@@ -116,7 +132,15 @@ def extract_svg(image_bytes: bytes, *, element: str = SVG_ELEMENT) -> Optional[s
|
|
|
116
132
|
if not nodes:
|
|
117
133
|
return None
|
|
118
134
|
attrs = nodes[0].attributes
|
|
119
|
-
|
|
135
|
+
if 'verify' in attrs:
|
|
136
|
+
return attrs['verify'].nodeValue
|
|
137
|
+
if not text_fallback:
|
|
138
|
+
return None
|
|
139
|
+
text = ''.join(
|
|
140
|
+
child.data for child in nodes[0].childNodes
|
|
141
|
+
if child.nodeType in (child.TEXT_NODE, child.CDATA_SECTION_NODE)
|
|
142
|
+
).strip()
|
|
143
|
+
return text or None
|
|
120
144
|
finally:
|
|
121
145
|
if svg_doc is not None:
|
|
122
146
|
svg_doc.unlink()
|
|
@@ -58,6 +58,10 @@ private_key = ${paths:base_key}/sign_rsa_key_1.pem
|
|
|
58
58
|
public_key = ${paths:base_key}/verify_rsa_key_1.pem
|
|
59
59
|
; key_type selects the algorithm for openbadges-keygenerator: RSA (default), ECC, or ED25519
|
|
60
60
|
key_type = RSA
|
|
61
|
+
; OpenBadges 3.0 proof format: vc-jwt (compact JWT-VC, the default) or ldp
|
|
62
|
+
; (embedded W3C Data Integrity proof, cryptosuite eddsa-rdfc-2022). ldp needs
|
|
63
|
+
; key_type = ED25519 and the [ldp] extra (pip install openbadgeslib[ldp]).
|
|
64
|
+
;proof_format = vc-jwt
|
|
61
65
|
; OpenBadges 3.0 credential status (opt-in). When set, openbadges-signer -V 3
|
|
62
66
|
; attaches credentialStatus entries for these purposes (comma-separated subset
|
|
63
67
|
; of: revocation, suspension) and openbadges-publish -V 3 generates the signed
|
|
@@ -79,6 +79,25 @@ def ob3_issuer_id(conf: ConfigParser) -> str:
|
|
|
79
79
|
"[issuer] did must be 'auto' or a did:... identifier, got %r" % did)
|
|
80
80
|
|
|
81
81
|
|
|
82
|
+
#: Proof formats an OB3 credential can be issued with — the same vocabulary
|
|
83
|
+
#: openbadges-verifier reports in its JSON output.
|
|
84
|
+
OB3_PROOF_FORMATS = ('vc-jwt', 'ldp')
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def ob3_proof_format(conf: ConfigParser, badge_section: str) -> str:
|
|
88
|
+
"""Return the proof format OB3 credentials of *badge_section* use:
|
|
89
|
+
``vc-jwt`` (compact JWT-VC, the default) or ``ldp`` (embedded Data
|
|
90
|
+
Integrity proof, cryptosuite eddsa-rdfc-2022 — needs an Ed25519 key and
|
|
91
|
+
the [ldp] extra). Raises ValueError for anything else.
|
|
92
|
+
"""
|
|
93
|
+
value = (conf[badge_section].get('proof_format') or 'vc-jwt').strip()
|
|
94
|
+
if value in OB3_PROOF_FORMATS:
|
|
95
|
+
return value
|
|
96
|
+
raise ValueError(
|
|
97
|
+
"[%s] proof_format must be one of %s, got %r"
|
|
98
|
+
% (badge_section, ', '.join(OB3_PROOF_FORMATS), value))
|
|
99
|
+
|
|
100
|
+
|
|
82
101
|
@dataclass
|
|
83
102
|
class OB3StatusConfig:
|
|
84
103
|
"""Resolved per-badge OB3 credential status configuration."""
|
|
@@ -145,6 +145,25 @@ class Badge():
|
|
|
145
145
|
self.priv_key = SigningKey.from_pem(self.privkey_pem)
|
|
146
146
|
except Exception as exc:
|
|
147
147
|
raise PrivateKeyReadError('Unable to read ECC private key: %s' % exc) from exc
|
|
148
|
+
elif self.key_type is KeyType.ED25519:
|
|
149
|
+
from cryptography.hazmat.primitives.serialization import (
|
|
150
|
+
load_pem_private_key, load_pem_public_key)
|
|
151
|
+
if self.pubkey_pem:
|
|
152
|
+
try:
|
|
153
|
+
pub_pem = self.pubkey_pem.encode('utf-8') \
|
|
154
|
+
if isinstance(self.pubkey_pem, str) else self.pubkey_pem
|
|
155
|
+
self.pub_key = load_pem_public_key(pub_pem)
|
|
156
|
+
except Exception as exc:
|
|
157
|
+
raise PublicKeyReadError(
|
|
158
|
+
'Unable to read Ed25519 public key: %s' % exc) from exc
|
|
159
|
+
if self.privkey_pem:
|
|
160
|
+
try:
|
|
161
|
+
priv_pem = self.privkey_pem.encode('utf-8') \
|
|
162
|
+
if isinstance(self.privkey_pem, str) else self.privkey_pem
|
|
163
|
+
self.priv_key = load_pem_private_key(priv_pem, password=None)
|
|
164
|
+
except Exception as exc:
|
|
165
|
+
raise PrivateKeyReadError(
|
|
166
|
+
'Unable to read Ed25519 private key: %s' % exc) from exc
|
|
148
167
|
elif self.key_type is not None:
|
|
149
168
|
# key_type=None is a valid "no key material yet" state; any other
|
|
150
169
|
# value is an unsupported key type and must fail loudly.
|
|
@@ -23,26 +23,36 @@
|
|
|
23
23
|
from .credential import Achievement, Issuer, OpenBadgeCredential
|
|
24
24
|
from .signer import OB3Signer
|
|
25
25
|
from .verifier import OB3VerificationError, OB3Verifier
|
|
26
|
+
from .ldp import (OB3LdpSigner, OB3LdpVerifier, add_data_integrity_proof,
|
|
27
|
+
verify_data_integrity_proof)
|
|
26
28
|
from .status import check_credential_status
|
|
27
29
|
from .status_list import (build_status_list_credential, encode_bitstring,
|
|
28
30
|
sign_status_list_credential, status_entry)
|
|
29
31
|
from .status_registry import StatusRegistry
|
|
30
|
-
from .did import build_did_document, did_web_from_url,
|
|
32
|
+
from .did import (build_did_document, did_key_from_pem, did_web_from_url,
|
|
33
|
+
multikey_from_pem, resolve_did, resolve_verification_method)
|
|
31
34
|
|
|
32
35
|
__all__ = [
|
|
33
36
|
'Achievement',
|
|
34
37
|
'Issuer',
|
|
35
38
|
'OpenBadgeCredential',
|
|
39
|
+
'OB3LdpSigner',
|
|
40
|
+
'OB3LdpVerifier',
|
|
36
41
|
'OB3Signer',
|
|
37
42
|
'OB3Verifier',
|
|
38
43
|
'OB3VerificationError',
|
|
44
|
+
'add_data_integrity_proof',
|
|
45
|
+
'verify_data_integrity_proof',
|
|
39
46
|
'StatusRegistry',
|
|
40
47
|
'build_did_document',
|
|
41
48
|
'build_status_list_credential',
|
|
42
49
|
'check_credential_status',
|
|
50
|
+
'did_key_from_pem',
|
|
43
51
|
'did_web_from_url',
|
|
44
52
|
'encode_bitstring',
|
|
53
|
+
'multikey_from_pem',
|
|
45
54
|
'resolve_did',
|
|
55
|
+
'resolve_verification_method',
|
|
46
56
|
'sign_status_list_credential',
|
|
47
57
|
'status_entry',
|
|
48
58
|
]
|