OpenBadgesLib - Changelog
=========================

Newest first. Dates are ISO 8601 (YYYY-MM-DD).


* v1.1.4 - 2026-06-29

  - SECURITY: harden OB3 JWT-VC parsing. OpenBadgeCredential.from_jwt_payload
    now validates the structure of the untrusted "vc" claim explicitly (every
    required object/field is checked, dates must be valid ISO 8601,
    credentialSubject may be an object or non-empty array) and raises a clear
    OB3VerificationError naming the offending field instead of surfacing a raw
    KeyError/TypeError.

  - fix: the OB3 verifier's iss/sub cross-check now normalises an array-form
    credentialSubject to its first element, so a validly-signed token carrying
    credentialSubject as an array no longer escapes verify() with a raw
    AttributeError; it verifies (or fails) as an OB3VerificationError.

  - packaging: advertise Python 3.13 support (add the trove classifier; it was
    already tested in CI and stated in the README).


* v1.1.3 - 2026-06-29

  - Typing: the package now ships a py.typed marker (PEP 561) and is fully
    annotated. mypy (disallow_untyped_defs) runs clean and is enforced in CI,
    so downstream type checkers can consume openbadgeslib's types.

  - Docs: fixed stale wiki references surfaced by an audit (OB2 verifier uses
    -r/--receptor; baking.py is a shared top-level module; dev extras and the CI
    gate now list mypy/pdoc).


* v1.1.2 - 2026-06-27

  - The -d/--debug flag now actually enables DEBUG-level console logging. It was
    previously parsed but ignored in openbadges-signer; it is now wired up and
    also added to openbadges-keygenerator and openbadges-verifier.

  - Packaging metadata refreshed: README is now Markdown, and the project URLs
    point to the GitHub Wiki (documentation) and the GitHub Pages API reference
    instead of the old homepage.

  - Docs & infra: the version is single-sourced from util.__version__; CI gates
    catch doc drift (CLI flags, wiki links); an auto-generated pdoc API site and
    an auto-synced wiki were added; Changelog normalised; CONTRIBUTORS.txt
    removed (see docs/authors.rst); pending work is now tracked in GitHub Issues.


* v1.1.1 - 2026-06-27

  - OB3: recipient identifiers are normalised through one shared helper, fixing
    a DID being corrupted into 'mailto:did:...'; the verifier CLI now delegates
    recipient binding to OB3Verifier.verify() instead of re-implementing it.

  - OB3: verify() cross-checks the JWT registered claims against the vc body -
    a token whose 'iss'/'sub' disagree with the credential issuer/subject is
    rejected - and OB3VerificationError now inherits from LibOpenBadgesException
    so one except clause covers both OB2 and OB3.

  - Refactor: shared keys.alg_for_key_type and CLI config helpers
    (read_config_or_exit / resolve_badge_section / _resolve_trusted_pubkey)
    remove the boilerplate duplicated across the entrypoints; first-party code
    imports openbadgeslib.ob2 directly rather than the back-compat shims; the
    oversized verify/main/_verify_ob3 functions were decomposed.

  - Type hints added on the OB2/core byte-vs-str boundaries.

  - Tests: OB2 signer CLI, the mail subsystem and read_from_file edge cases are
    now covered; 258 tests, 92% line coverage; the whole repo (source and
    tests) is flake8-clean.

  - CI: a GitHub Actions workflow runs flake8 and the test suite on Python
    3.10-3.13 for every push and pull request.


* v1.1.0 - 2026-06-27

  - SECURITY: signature verification now pins the accepted algorithm to the
    verification key's type instead of trusting the token header. OB3Verifier
    derives the RS*/ES* family from the key and passes it to jwt.decode;
    _jws.verify_block rejects any header alg that doesn't match the key. This
    blocks cross-type confusion and any none/HMAC downgrade.

  - SECURITY: SVG badge XML is parsed with defusedxml, defusing entity-expansion
    (billion-laughs) DoS on untrusted badges. New defusedxml dependency.

  - SECURITY: iTXt PNG token extraction caps zlib decompression at 256 KB to
    stop a decompression-bomb DoS during extraction (before verification).

  - SECURITY: the OB2 verifier CLI now distinguishes a trusted operator key
    (--local/--pubkey) from the badge's own embedded key. Without a trusted key
    it reports the signature as internally-consistent-only, not "[+] correct"
    (the embedded key proves nothing about issuer identity). --pubkey now
    applies to OB2 as well as OB3.

  - SECURITY: check_revocation guards the issuer / revocation-list downloads and
    JSON parsing, raising a clean VerifierException instead of a raw error.

  - Fixed: _jws base64url padding (wrong when the length was a multiple of 4);
    BadgeSigned.get_serial_num crashed on badges read from a file (str vs bytes);
    Verifier.check_identity crashed instead of skipping when no identity was
    given; extract_svg_assertion could raise NameError masking the real error;
    unknown key/image types now fail loudly instead of UnboundLocalError.

  - Refactor: a single keys.key_to_pem() replaces three drifting copies, and a
    new openbadgeslib.baking module is the one home for the SVG/PNG carrier
    format (OB2 and OB3 share it; the OB2 fixed-offset PNG reader is gone in
    favour of the structured iTXt parser).

  - Cleanup: removed the redundant setup.py, the stale committed dist/ artifacts
    and generated MANIFEST, and several never-raised exception classes; docs now
    cover OB3 on the landing page and document the SMTP/email-badge feature;
    test import hygiene tidied. 236 tests pass, 87% line coverage.


* v1.0.2 - 2026-06-18

  - SECURITY: OB2 verification now uses the operator-supplied trusted key when
    one is given, instead of always trusting the key the badge points to. A
    forged badge can no longer self-describe its own verification key.

  - SECURITY: download_file now refuses non-HTTPS URLs by default (the verify
    key is the OB2 root of trust); pass allow_insecure=True to override.

  - Fixed expiration check: a badge is now considered expired when its
    expiration date is in the past relative to *now*, not relative to its own
    issue date (expired badges were previously reported VALID).

  - Fixed openbadges-publish: it copied no verify key and stopped after the
    first badge (it read a non-existent [keys] section). It now reads each
    badge's public_key and iterates all badge_* sections.

  - Fixed SMTP: use_ssl is parsed as a boolean (the string 'False' was truthy);
    connection-level mail errors are caught instead of crashing a successful
    sign; the example config uses 'username' (matching the code), not 'login'.

  - openbadges-keygenerator now honours a key_type (RSA/ECC) field in the badge
    profile, so ECC key pairs are reachable from the CLI.

  - OB2 sign log and log files are opened in append mode (were truncated on
    every run).

  - OB3 credentials use the W3C VC 2.0 data model (validFrom/validUntil,
    /ns/credentials/v2 context); from_jwt_payload still reads VC 1.1 fields.
    OB3Verifier.verify() gained an optional expected_recipient argument and now
    asserts the credential type; PNG token extraction parses the iTXt chunk
    structure instead of a fixed offset.

  - Robustness: unsigned PNGs raise a clear error instead of crashing;
    read_from_file raises instead of calling sys.exit; identity is normalised to
    bytes; revocation handles issuers without a revocationList.

  - Tests: added CLI/publish/keygenerator/mail/revocation coverage and removed
    the coverage omit list that hid those modules; expiration tests rewritten to
    model real timestamps.


* v1.0.1 - 2026-04-22

  - OpenBadges 3.0 support (W3C Verifiable Credentials / JWT-VC):
    new openbadgeslib.ob3 subpackage with OpenBadgeCredential, Issuer,
    Achievement data model; OB3Signer for JWT-VC signing and SVG/PNG
    baking; OB3Verifier for JWT-VC verification and token extraction.

  - OpenBadges 2.0 implementation moved to openbadgeslib.ob2 subpackage.
    Top-level badge.py / signer.py / verifier.py kept as backward-compatible
    shims so existing code continues to work unchanged.

  - All CLI tools (openbadges-keygenerator, openbadges-signer,
    openbadges-verifier, openbadges-publish) gained a -V / --ob-version
    flag to select the specification version (2 or 3, default 2).

  - openbadges-verifier: new -k / --pubkey FILE option to supply the
    public key directly when verifying OB3 badges without a config file.

  - Python 3.10+ compatibility: removed distutils (dropped in 3.12),
    packaging migrated to pyproject.toml with setuptools.build_meta.

  - Replaced abandoned pycrypto with pycryptodome >= 3.20.

  - Replaced custom bundled JWS engine (3dparty/jws/) with PyJWT[crypto]
    algorithm classes (RS256/384/512, ES256/384/512). Internal module
    moved to openbadgeslib/_jws/. Old 3dparty/ directory removed.

  - TLS security fix: download_file relies on urllib's default TLS context
    (certificate validation on) instead of the deprecated PROTOCOL_TLSv1 /
    CERT_NONE settings.

  - pypng API update: signature constant renamed, chunk tags now bytes.

  - Copyright year range updated to 2014-2026 across all source files.

  - Bug fixes: verifier signature check logic, ECC private-key detection,
    hash_email str/bytes coercion.

  - Test suite: 203 tests, 89% line coverage.


* v0.4.2

  - Adding support to verifying external openbadges.

  - Adding a new parameter to show assertion before verifying.

  - OpenBadges URLs are verified before the signing process.


* v0.4

  - Support for PNG. The library can now verify and sign OpenBadges in PNG
    format.

  - Support for sending badges via mail.

  - Badge signatures are registered in a log file.

  - Mail code now supports SMTP auth. The config file needs modifications;
    see the example.


* v0.3

  - The email is no longer encoded in the filename when creating a new badge.

  - When creating a badge, "-o" is optional.

  - When specified, "-o" is supposed to be a directory.

  - We can specify "-E" or "--no-evidence" when creating a new badge.

  - When creating a new badge we now need to choose EXPLICITLY between
    providing evidence or not.

  - Badge sections in the INI file must now be prefixed with "badge_".
    UPGRADE: if your badge is called "ponente2014", rename it to
    "badge_ponente2014".

  - Each badge can now have a different key.
    UPGRADE: move your current key configuration to the badge section,
    renaming "private" to "private_key" and "public" to "public_key".
    UPGRADE: "openbadges-keygenerator -g" now requires a badge name.

  - "openbadges-verifier" changes its parameter from "-lk" to "-l" and now
    needs the name of the badge to locate its public key.

  - "openbadges-verifier" now accepts a parameter -x to specify the expiration
    for a badge.

  - "openbadges-verifier" now checks the revocation status and the expiration
    dates of badges.


* v0.2.1 - 2014-12-16

  - config.ini now allows configuring the badge json url and image url.

  - Signer now uses randomly salted emails by default in assertions.

  - Compatibility with more SVG formats.

  - Documentation in the "docs" directory.


* v0.2 - 2014-12-10

  - "openbadges-init".

  - New configuration format. If you are using the 0.1 format, you must
    migrate by hand.

  - Tests.

  - Use proper logging instead of simple "print" calls.

  - Massive cleanup of internal imports.

  - Do not change "sys.path".


* v0.1 - 2014-12-01

  - Initial release.
