From 6cddd30ff2a64f6a3e509c992684c4a0a357fe71 Mon Sep 17 00:00:00 2001 From: kasium <15907922+kasium@users.noreply.github.com> Date: Tue, 24 Sep 2024 10:30:58 +0200 Subject: [PATCH] Add basic jwcrypto stubs (#12687) --- pyrightconfig.stricter.json | 1 + stubs/jwcrypto/@tests/stubtest_allowlist.txt | 6 + stubs/jwcrypto/METADATA.toml | 3 + stubs/jwcrypto/jwcrypto/__init__.pyi | 0 stubs/jwcrypto/jwcrypto/common.pyi | 48 ++++++++ stubs/jwcrypto/jwcrypto/jwa.pyi | 35 ++++++ stubs/jwcrypto/jwcrypto/jwe.pyi | 51 ++++++++ stubs/jwcrypto/jwcrypto/jwk.pyi | 115 +++++++++++++++++++ stubs/jwcrypto/jwcrypto/jws.pyi | 52 +++++++++ stubs/jwcrypto/jwcrypto/jwt.pyi | 78 +++++++++++++ 10 files changed, 389 insertions(+) create mode 100644 stubs/jwcrypto/@tests/stubtest_allowlist.txt create mode 100644 stubs/jwcrypto/METADATA.toml create mode 100644 stubs/jwcrypto/jwcrypto/__init__.pyi create mode 100644 stubs/jwcrypto/jwcrypto/common.pyi create mode 100644 stubs/jwcrypto/jwcrypto/jwa.pyi create mode 100644 stubs/jwcrypto/jwcrypto/jwe.pyi create mode 100644 stubs/jwcrypto/jwcrypto/jwk.pyi create mode 100644 stubs/jwcrypto/jwcrypto/jws.pyi create mode 100644 stubs/jwcrypto/jwcrypto/jwt.pyi diff --git a/pyrightconfig.stricter.json b/pyrightconfig.stricter.json index 594908d69..6c00f5ed3 100644 --- a/pyrightconfig.stricter.json +++ b/pyrightconfig.stricter.json @@ -57,6 +57,7 @@ "stubs/influxdb-client", "stubs/jmespath", "stubs/jsonschema", + "stubs/jwcrypto", "stubs/ldap3", "stubs/Markdown", "stubs/mysqlclient", diff --git a/stubs/jwcrypto/@tests/stubtest_allowlist.txt b/stubs/jwcrypto/@tests/stubtest_allowlist.txt new file mode 100644 index 000000000..10f855e9e --- /dev/null +++ b/stubs/jwcrypto/@tests/stubtest_allowlist.txt @@ -0,0 +1,6 @@ +# test code does not need type hints +jwcrypto.tests +jwcrypto.tests-cookbook + +# even if the deprecated decorator is applied, the attribute is not present +jwcrypto.jwt.JWTMissingKeyID.__deprecated__ diff --git a/stubs/jwcrypto/METADATA.toml b/stubs/jwcrypto/METADATA.toml new file mode 100644 index 000000000..53d468ec6 --- /dev/null +++ b/stubs/jwcrypto/METADATA.toml @@ -0,0 +1,3 @@ +version = "1.5.*" +upstream_repository = "https://github.com/latchset/jwcrypto" +requires = ["cryptography"] diff --git a/stubs/jwcrypto/jwcrypto/__init__.pyi b/stubs/jwcrypto/jwcrypto/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stubs/jwcrypto/jwcrypto/common.pyi b/stubs/jwcrypto/jwcrypto/common.pyi new file mode 100644 index 000000000..10ee692c3 --- /dev/null +++ b/stubs/jwcrypto/jwcrypto/common.pyi @@ -0,0 +1,48 @@ +from _typeshed import Incomplete +from collections.abc import Iterator, MutableMapping +from typing import Any, NamedTuple + +def base64url_encode(payload: str | bytes) -> str: ... +def base64url_decode(payload: str) -> bytes: ... +def json_encode(string: str | bytes) -> str: ... + +# The function returns json.loads which returns Any +def json_decode(string: str | bytes) -> Any: ... + +class JWException(Exception): ... + +class InvalidJWAAlgorithm(JWException): + def __init__(self, message: str | None = None) -> None: ... + +class InvalidCEKeyLength(JWException): + def __init__(self, expected: int, obtained: int) -> None: ... + +class InvalidJWEOperation(JWException): + def __init__(self, message: str | None = None, exception: BaseException | None = None) -> None: ... + +class InvalidJWEKeyType(JWException): + def __init__(self, expected: int, obtained: int) -> None: ... + +class InvalidJWEKeyLength(JWException): + def __init__(self, expected: int, obtained: int) -> None: ... + +class InvalidJWSERegOperation(JWException): + def __init__(self, message: str | None = None, exception: BaseException | None = None) -> None: ... + +class JWKeyNotFound(JWException): + def __init__(self, message: str | None = None) -> None: ... + +class JWSEHeaderParameter(NamedTuple): + description: str + mustprotect: bool + supported: bool + check_fn: Incomplete | None + +class JWSEHeaderRegistry(MutableMapping[str, JWSEHeaderParameter]): + def __init__(self, init_registry: Incomplete | None = None) -> None: ... + def check_header(self, h: str, value) -> bool: ... + def __getitem__(self, key: str) -> JWSEHeaderParameter: ... + def __iter__(self) -> Iterator[str]: ... + def __delitem__(self, key: str) -> None: ... + def __setitem__(self, h: str, jwse_header_param: JWSEHeaderParameter) -> None: ... + def __len__(self) -> int: ... diff --git a/stubs/jwcrypto/jwcrypto/jwa.pyi b/stubs/jwcrypto/jwcrypto/jwa.pyi new file mode 100644 index 000000000..dc6aff867 --- /dev/null +++ b/stubs/jwcrypto/jwcrypto/jwa.pyi @@ -0,0 +1,35 @@ +from abc import ABCMeta, abstractmethod +from collections.abc import Mapping +from typing import ClassVar + +default_max_pbkdf2_iterations: int + +class JWAAlgorithm(metaclass=ABCMeta): + @property + @abstractmethod + def name(self) -> str: ... + @property + @abstractmethod + def description(self) -> str: ... + @property + @abstractmethod + def keysize(self) -> int: ... + @property + @abstractmethod + def algorithm_usage_location(self) -> str: ... + @property + @abstractmethod + def algorithm_use(self) -> str: ... + @property + def input_keysize(self) -> int: ... + +class JWA: + algorithms_registry: ClassVar[Mapping[str, JWAAlgorithm]] + @classmethod + def instantiate_alg(cls, name: str, use: str | None = None) -> JWAAlgorithm: ... + @classmethod + def signing_alg(cls, name: str) -> JWAAlgorithm: ... + @classmethod + def keymgmt_alg(cls, name: str) -> JWAAlgorithm: ... + @classmethod + def encryption_alg(cls, name: str) -> JWAAlgorithm: ... diff --git a/stubs/jwcrypto/jwcrypto/jwe.pyi b/stubs/jwcrypto/jwcrypto/jwe.pyi new file mode 100644 index 000000000..408b8850d --- /dev/null +++ b/stubs/jwcrypto/jwcrypto/jwe.pyi @@ -0,0 +1,51 @@ +from _typeshed import Incomplete +from collections.abc import Mapping, Sequence + +from jwcrypto import common +from jwcrypto.common import JWException, JWSEHeaderParameter +from jwcrypto.jwk import JWK, JWKSet + +default_max_compressed_size: int +JWEHeaderRegistry: Mapping[str, JWSEHeaderParameter] +default_allowed_algs: Sequence[str] + +class InvalidJWEData(JWException): + def __init__(self, message: str | None = None, exception: BaseException | None = None) -> None: ... + +InvalidCEKeyLength = common.InvalidCEKeyLength +InvalidJWEKeyLength = common.InvalidJWEKeyLength +InvalidJWEKeyType = common.InvalidJWEKeyType +InvalidJWEOperation = common.InvalidJWEOperation + +class JWE: + objects: Incomplete + plaintext: Incomplete + header_registry: Incomplete + cek: Incomplete + decryptlog: Incomplete + def __init__( + self, + plaintext: bytes | None = None, + protected: str | None = None, + unprotected: str | None = None, + aad: bytes | None = None, + algs: Incomplete | None = None, + recipient: str | None = None, + header: Incomplete | None = None, + header_registry: Incomplete | None = None, + ) -> None: ... + @property + def allowed_algs(self): ... + @allowed_algs.setter + def allowed_algs(self, algs) -> None: ... + def add_recipient(self, key, header: Incomplete | None = None) -> None: ... + def serialize(self, compact: bool = False): ... + def decrypt(self, key: JWK | JWKSet) -> None: ... + def deserialize(self, raw_jwe: str | bytes, key: JWK | JWKSet | None = None) -> None: ... + @property + def payload(self): ... + @property + def jose_header(self) -> dict[Incomplete, Incomplete]: ... + @classmethod + def from_jose_token(cls, token: str | bytes) -> JWE: ... + def __eq__(self, other: object) -> bool: ... diff --git a/stubs/jwcrypto/jwcrypto/jwk.pyi b/stubs/jwcrypto/jwcrypto/jwk.pyi new file mode 100644 index 000000000..c86ff358d --- /dev/null +++ b/stubs/jwcrypto/jwcrypto/jwk.pyi @@ -0,0 +1,115 @@ +from _typeshed import Incomplete +from collections.abc import Sequence +from enum import Enum +from typing import Any, NamedTuple + +from cryptography.hazmat.primitives.asymmetric.ed448 import Ed448PrivateKey as Ed448PrivateKey, Ed448PublicKey as Ed448PublicKey +from cryptography.hazmat.primitives.asymmetric.ed25519 import ( + Ed25519PrivateKey as Ed25519PrivateKey, + Ed25519PublicKey as Ed25519PublicKey, +) +from cryptography.hazmat.primitives.asymmetric.x448 import X448PrivateKey as X448PrivateKey, X448PublicKey as X448PublicKey +from cryptography.hazmat.primitives.asymmetric.x25519 import ( + X25519PrivateKey as X25519PrivateKey, + X25519PublicKey as X25519PublicKey, +) +from jwcrypto.common import JWException + +class UnimplementedOKPCurveKey: + @classmethod + def generate(cls) -> None: ... + @classmethod + def from_public_bytes(cls, *args) -> None: ... + @classmethod + def from_private_bytes(cls, *args) -> None: ... + +ImplementedOkpCurves: Sequence[str] +priv_bytes: Incomplete + +JWKTypesRegistry: Incomplete + +class ParmType(Enum): + name: str + b64: str + b64u: str + unsupported: str + +class JWKParameter(NamedTuple): + description: Incomplete + public: Incomplete + required: Incomplete + type: Incomplete + +JWKValuesRegistry: Incomplete +JWKParamsRegistry: Incomplete +JWKEllipticCurveRegistry: Incomplete +JWKUseRegistry: Incomplete +JWKOperationsRegistry: Incomplete +JWKpycaCurveMap: Incomplete +IANANamedInformationHashAlgorithmRegistry: Incomplete + +class InvalidJWKType(JWException): + value: Incomplete + def __init__(self, value: Incomplete | None = None) -> None: ... + +class InvalidJWKUsage(JWException): + value: Incomplete + use: Incomplete + def __init__(self, use, value) -> None: ... + +class InvalidJWKOperation(JWException): + op: Incomplete + values: Incomplete + def __init__(self, operation, values) -> None: ... + +class InvalidJWKValue(JWException): ... + +class JWK(dict[str, Any]): + def __init__(self, **kwargs) -> None: ... + @classmethod + def generate(cls, **kwargs): ... + def generate_key(self, **params) -> None: ... + def import_key(self, **kwargs) -> None: ... + @classmethod + def from_json(cls, key): ... + def export(self, private_key: bool = True, as_dict: bool = False): ... + def export_public(self, as_dict: bool = False): ... + def export_private(self, as_dict: bool = False): ... + def export_symmetric(self, as_dict: bool = False): ... + def public(self): ... + @property + def has_public(self) -> bool: ... + @property + def has_private(self) -> bool: ... + @property + def is_symmetric(self) -> bool: ... + @property + def key_type(self): ... + @property + def key_id(self): ... + @property + def key_curve(self): ... + def get_curve(self, arg): ... + def get_op_key(self, operation: Incomplete | None = None, arg: Incomplete | None = None): ... + def import_from_pyca(self, key) -> None: ... + def import_from_pem(self, data, password: Incomplete | None = None, kid: Incomplete | None = None) -> None: ... + def export_to_pem(self, private_key: bool = False, password: bool = False): ... + @classmethod + def from_pyca(cls, key): ... + @classmethod + def from_pem(cls, data, password: Incomplete | None = None): ... + def thumbprint(self, hashalg=...): ... + def thumbprint_uri(self, hname: str = "sha-256"): ... + @classmethod + def from_password(cls, password): ... + def setdefault(self, key: str, default: Incomplete | None = None): ... + +class JWKSet(dict[str, Any]): + def add(self, elem) -> None: ... + def export(self, private_keys: bool = True, as_dict: bool = False): ... + def import_keyset(self, keyset) -> None: ... + @classmethod + def from_json(cls, keyset): ... + def get_key(self, kid): ... + def get_keys(self, kid): ... + def setdefault(self, key: str, default: Incomplete | None = None): ... diff --git a/stubs/jwcrypto/jwcrypto/jws.pyi b/stubs/jwcrypto/jwcrypto/jws.pyi new file mode 100644 index 000000000..d1bb2f8a2 --- /dev/null +++ b/stubs/jwcrypto/jwcrypto/jws.pyi @@ -0,0 +1,52 @@ +from _typeshed import Incomplete + +from jwcrypto.common import JWException + +JWSHeaderRegistry: Incomplete +default_allowed_algs: Incomplete + +class InvalidJWSSignature(JWException): + def __init__(self, message: str | None = None, exception: BaseException | None = None) -> None: ... + +class InvalidJWSObject(JWException): + def __init__(self, message: str | None = None, exception: BaseException | None = None) -> None: ... + +class InvalidJWSOperation(JWException): + def __init__(self, message: str | None = None, exception: BaseException | None = None) -> None: ... + +class JWSCore: + alg: Incomplete + engine: Incomplete + key: Incomplete + header: Incomplete + protected: Incomplete + payload: Incomplete + def __init__(self, alg, key, header, payload, algs: Incomplete | None = None) -> None: ... + def sign(self): ... + def verify(self, signature): ... + +class JWS: + objects: Incomplete + verifylog: Incomplete + header_registry: Incomplete + def __init__(self, payload: Incomplete | None = None, header_registry: Incomplete | None = None) -> None: ... + @property + def allowed_algs(self): ... + @allowed_algs.setter + def allowed_algs(self, algs) -> None: ... + @property + def is_valid(self): ... + def verify(self, key, alg: Incomplete | None = None, detached_payload: Incomplete | None = None) -> None: ... + def deserialize(self, raw_jws, key: Incomplete | None = None, alg: Incomplete | None = None) -> None: ... + def add_signature( + self, key, alg: Incomplete | None = None, protected: Incomplete | None = None, header: Incomplete | None = None + ) -> None: ... + def serialize(self, compact: bool = False): ... + @property + def payload(self): ... + def detach_payload(self) -> None: ... + @property + def jose_header(self): ... + @classmethod + def from_jose_token(cls, token): ... + def __eq__(self, other: object) -> bool: ... diff --git a/stubs/jwcrypto/jwcrypto/jwt.pyi b/stubs/jwcrypto/jwcrypto/jwt.pyi new file mode 100644 index 000000000..4bd2a5b79 --- /dev/null +++ b/stubs/jwcrypto/jwcrypto/jwt.pyi @@ -0,0 +1,78 @@ +from _typeshed import Incomplete +from collections.abc import Mapping +from typing_extensions import deprecated + +from jwcrypto.common import JWException, JWKeyNotFound +from jwcrypto.jwk import JWK, JWKSet + +JWTClaimsRegistry: Mapping[str, str] +JWT_expect_type: bool + +class JWTExpired(JWException): + def __init__(self, message: str | None = None, exception: BaseException | None = None) -> None: ... + +class JWTNotYetValid(JWException): + def __init__(self, message: str | None = None, exception: BaseException | None = None) -> None: ... + +class JWTMissingClaim(JWException): + def __init__(self, message: str | None = None, exception: BaseException | None = None) -> None: ... + +class JWTInvalidClaimValue(JWException): + def __init__(self, message: str | None = None, exception: BaseException | None = None) -> None: ... + +class JWTInvalidClaimFormat(JWException): + def __init__(self, message: str | None = None, exception: BaseException | None = None) -> None: ... + +@deprecated("") +class JWTMissingKeyID(JWException): + def __init__(self, message: str | None = None, exception: BaseException | None = None) -> None: ... + +class JWTMissingKey(JWKeyNotFound): + def __init__(self, message: str | None = None, exception: BaseException | None = None) -> None: ... + +class JWT: + deserializelog: Incomplete + def __init__( + self, + header: dict[Incomplete, Incomplete] | str | None = None, + claims: dict[Incomplete, Incomplete] | str | None = None, + jwt: Incomplete | None = None, + key: JWK | JWKSet | None = None, + algs: Incomplete | None = None, + default_claims: Incomplete | None = None, + check_claims: Incomplete | None = None, + expected_type: Incomplete | None = None, + ) -> None: ... + @property + def header(self): ... + @header.setter + def header(self, h) -> None: ... + @property + def claims(self): ... + @claims.setter + def claims(self, data) -> None: ... + @property + def token(self): ... + @token.setter + def token(self, t) -> None: ... + @property + def leeway(self): ... + @leeway.setter + def leeway(self, lwy) -> None: ... + @property + def validity(self): ... + @validity.setter + def validity(self, v) -> None: ... + @property + def expected_type(self): ... + @expected_type.setter + def expected_type(self, v) -> None: ... + def norm_typ(self, val): ... + def make_signed_token(self, key) -> None: ... + def make_encrypted_token(self, key) -> None: ... + def validate(self, key) -> None: ... + def deserialize(self, jwt, key: Incomplete | None = None) -> None: ... + def serialize(self, compact: bool = True): ... + @classmethod + def from_jose_token(cls, token): ... + def __eq__(self, other: object) -> bool: ...