Initial public commit
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
"""Offline signature verification — the bulk of the value of the SDK."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import uuid
|
||||
from dataclasses import dataclass
|
||||
|
||||
from cryptography.exceptions import InvalidSignature
|
||||
|
||||
from .errors import LicensingError
|
||||
from .key import LicensePayload, parse_license_key
|
||||
from .pubkey import PublicKey
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class VerifyOk:
|
||||
"""Result of a successful offline `Verifier.verify()` call."""
|
||||
|
||||
license_id: uuid.UUID
|
||||
product_id: uuid.UUID
|
||||
issued_at: int
|
||||
expires_at: int # 0 = perpetual
|
||||
is_trial: bool
|
||||
is_fingerprint_bound: bool
|
||||
fingerprint_hash: bytes # 32 bytes; all-zero if unbound
|
||||
entitlements: list[str]
|
||||
payload: LicensePayload # the full parsed payload
|
||||
|
||||
|
||||
class Verifier:
|
||||
"""Offline license-key verifier.
|
||||
|
||||
Given the issuer's PEM-encoded public key, verifies the cryptographic
|
||||
integrity of a license key string with no network access. Suitable
|
||||
for boot-time license checks where the licensing server may be
|
||||
unreachable.
|
||||
|
||||
Usage::
|
||||
|
||||
verifier = Verifier(PublicKey.from_pem(ISSUER_PUBKEY_PEM))
|
||||
ok = verifier.verify(key_from_user)
|
||||
# raises LicensingError on bad signature / bad format
|
||||
|
||||
For revocation and fingerprint binding, layer the online
|
||||
`Client.validate(...)` on top of this — but only AFTER offline
|
||||
verification has passed.
|
||||
"""
|
||||
|
||||
def __init__(self, public_key: PublicKey):
|
||||
self._pubkey = public_key
|
||||
|
||||
def verify(self, key: str) -> VerifyOk:
|
||||
"""Verify a `LIC1-...-...` key.
|
||||
|
||||
On success, returns a `VerifyOk` with all parsed fields. On
|
||||
failure, raises `LicensingError`:
|
||||
|
||||
- `kind="bad_format"`: the key string is malformed.
|
||||
- `kind="bad_signature"`: signature didn't verify against
|
||||
the issuer's public key (key was edited, fabricated, or
|
||||
issued by a different server).
|
||||
"""
|
||||
parsed = parse_license_key(key)
|
||||
try:
|
||||
self._pubkey.underlying.verify(parsed.signature, parsed.payload_bytes)
|
||||
except InvalidSignature as e:
|
||||
raise LicensingError(
|
||||
"bad_signature",
|
||||
"signature did not verify against the issuer's public key",
|
||||
) from e
|
||||
p = parsed.payload
|
||||
return VerifyOk(
|
||||
license_id=p.license_id,
|
||||
product_id=p.product_id,
|
||||
issued_at=p.issued_at,
|
||||
expires_at=p.expires_at,
|
||||
is_trial=p.is_trial,
|
||||
is_fingerprint_bound=p.is_fingerprint_bound,
|
||||
fingerprint_hash=p.fingerprint_hash,
|
||||
entitlements=list(p.entitlements),
|
||||
payload=p,
|
||||
)
|
||||
Reference in New Issue
Block a user