* v1.1.1 - 20260627

  - 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 - 20260627

  - 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 - 20260618

  - 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 - 20260422

  - 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 verifing
 - OpenBadges URLs are verified before the signing process

* v0.4
 - Support for PNG!. Now the library is capable of verify and sign OpenBadges
   in PNG format.

 - Support for sendmails badges via mail.

 - Badge signes are registered in a log file.

 - Mail code now supports SMTP auth. The config file need modifications.
   See the example.

* v0.3

  - The email is not encoded anymore in the filename, when creating
    a new badge.

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

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

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

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

  - Now badge sections in the INI file must be prefixed with "badge_".

    UPGRADE: If your badge is called "ponente2014", rename it to
    "badge_ponente2014".

  - Now each badge can 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: Now "openbadges-keygenerator -g" requires a badge name.

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

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

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

* v0.2.1 - 20141216

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

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

  - Compatibility with more SVG formats.

  - Documentation in "docs" directory.

* v0.2 - 20141210

  - "openbadges-init".

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

  - Tests!.

  - Use proper logging instead of simple "prints".

  - Massive cleanup of internal imports.

  - Do not change "sys.path".

* v0.1 - 20141201

  - Initial release.

