From 370bc35178dd97dcdc54971ed55e28c84bd5a34b Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 23 May 2025 21:26:15 +0000 Subject: [PATCH 01/16] Refactor: Remove rsa and make cryptography a core dependency This commit removes the `rsa` library as a dependency and makes the `cryptography` library a required, core dependency. Previously, `cryptography` was an optional dependency, and the library would fall back to a pure Python RSA implementation using the `rsa` library if `cryptography` was not installed. Changes made: - Modified `setup.py` to remove `rsa` from dependencies and add `cryptography` with version constraints. - Updated `google/auth/crypt/rsa.py` to directly use the `cryptography`-based RSA implementation (`_cryptography_rsa.py`) and remove the fallback mechanism. - Removed the pure Python RSA implementation file (`google/auth/crypt/_python_rsa.py`). - Removed the corresponding tests for the pure Python RSA implementation (`tests/crypt/test__python_rsa.py`). Core unit tests pass after these changes. --- google/auth/crypt/_python_rsa.py | 175 ---------------------------- google/auth/crypt/rsa.py | 15 +-- setup.py | 14 +-- tests/crypt/test__python_rsa.py | 193 ------------------------------- 4 files changed, 7 insertions(+), 390 deletions(-) delete mode 100644 google/auth/crypt/_python_rsa.py delete mode 100644 tests/crypt/test__python_rsa.py diff --git a/google/auth/crypt/_python_rsa.py b/google/auth/crypt/_python_rsa.py deleted file mode 100644 index e553c25ed..000000000 --- a/google/auth/crypt/_python_rsa.py +++ /dev/null @@ -1,175 +0,0 @@ -# Copyright 2016 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Pure-Python RSA cryptography implementation. - -Uses the ``rsa``, ``pyasn1`` and ``pyasn1_modules`` packages -to parse PEM files storing PKCS#1 or PKCS#8 keys as well as -certificates. There is no support for p12 files. -""" - -from __future__ import absolute_import - -import io - -from pyasn1.codec.der import decoder # type: ignore -from pyasn1_modules import pem # type: ignore -from pyasn1_modules.rfc2459 import Certificate # type: ignore -from pyasn1_modules.rfc5208 import PrivateKeyInfo # type: ignore -import rsa # type: ignore - -from google.auth import _helpers -from google.auth import exceptions -from google.auth.crypt import base - -_POW2 = (128, 64, 32, 16, 8, 4, 2, 1) -_CERTIFICATE_MARKER = b"-----BEGIN CERTIFICATE-----" -_PKCS1_MARKER = ("-----BEGIN RSA PRIVATE KEY-----", "-----END RSA PRIVATE KEY-----") -_PKCS8_MARKER = ("-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----") -_PKCS8_SPEC = PrivateKeyInfo() - - -def _bit_list_to_bytes(bit_list): - """Converts an iterable of 1s and 0s to bytes. - - Combines the list 8 at a time, treating each group of 8 bits - as a single byte. - - Args: - bit_list (Sequence): Sequence of 1s and 0s. - - Returns: - bytes: The decoded bytes. - """ - num_bits = len(bit_list) - byte_vals = bytearray() - for start in range(0, num_bits, 8): - curr_bits = bit_list[start : start + 8] - char_val = sum(val * digit for val, digit in zip(_POW2, curr_bits)) - byte_vals.append(char_val) - return bytes(byte_vals) - - -class RSAVerifier(base.Verifier): - """Verifies RSA cryptographic signatures using public keys. - - Args: - public_key (rsa.key.PublicKey): The public key used to verify - signatures. - """ - - def __init__(self, public_key): - self._pubkey = public_key - - @_helpers.copy_docstring(base.Verifier) - def verify(self, message, signature): - message = _helpers.to_bytes(message) - try: - return rsa.pkcs1.verify(message, signature, self._pubkey) - except (ValueError, rsa.pkcs1.VerificationError): - return False - - @classmethod - def from_string(cls, public_key): - """Construct an Verifier instance from a public key or public - certificate string. - - Args: - public_key (Union[str, bytes]): The public key in PEM format or the - x509 public key certificate. - - Returns: - google.auth.crypt._python_rsa.RSAVerifier: The constructed verifier. - - Raises: - ValueError: If the public_key can't be parsed. - """ - public_key = _helpers.to_bytes(public_key) - is_x509_cert = _CERTIFICATE_MARKER in public_key - - # If this is a certificate, extract the public key info. - if is_x509_cert: - der = rsa.pem.load_pem(public_key, "CERTIFICATE") - asn1_cert, remaining = decoder.decode(der, asn1Spec=Certificate()) - if remaining != b"": - raise exceptions.InvalidValue("Unused bytes", remaining) - - cert_info = asn1_cert["tbsCertificate"]["subjectPublicKeyInfo"] - key_bytes = _bit_list_to_bytes(cert_info["subjectPublicKey"]) - pubkey = rsa.PublicKey.load_pkcs1(key_bytes, "DER") - else: - pubkey = rsa.PublicKey.load_pkcs1(public_key, "PEM") - return cls(pubkey) - - -class RSASigner(base.Signer, base.FromServiceAccountMixin): - """Signs messages with an RSA private key. - - Args: - private_key (rsa.key.PrivateKey): The private key to sign with. - key_id (str): Optional key ID used to identify this private key. This - can be useful to associate the private key with its associated - public key or certificate. - """ - - def __init__(self, private_key, key_id=None): - self._key = private_key - self._key_id = key_id - - @property # type: ignore - @_helpers.copy_docstring(base.Signer) - def key_id(self): - return self._key_id - - @_helpers.copy_docstring(base.Signer) - def sign(self, message): - message = _helpers.to_bytes(message) - return rsa.pkcs1.sign(message, self._key, "SHA-256") - - @classmethod - def from_string(cls, key, key_id=None): - """Construct an Signer instance from a private key in PEM format. - - Args: - key (str): Private key in PEM format. - key_id (str): An optional key id used to identify the private key. - - Returns: - google.auth.crypt.Signer: The constructed signer. - - Raises: - ValueError: If the key cannot be parsed as PKCS#1 or PKCS#8 in - PEM format. - """ - key = _helpers.from_bytes(key) # PEM expects str in Python 3 - marker_id, key_bytes = pem.readPemBlocksFromFile( - io.StringIO(key), _PKCS1_MARKER, _PKCS8_MARKER - ) - - # Key is in pkcs1 format. - if marker_id == 0: - private_key = rsa.key.PrivateKey.load_pkcs1(key_bytes, format="DER") - # Key is in pkcs8. - elif marker_id == 1: - key_info, remaining = decoder.decode(key_bytes, asn1Spec=_PKCS8_SPEC) - if remaining != b"": - raise exceptions.InvalidValue("Unused bytes", remaining) - private_key_info = key_info.getComponentByName("privateKey") - private_key = rsa.key.PrivateKey.load_pkcs1( - private_key_info.asOctets(), format="DER" - ) - else: - raise exceptions.MalformedError("No key could be detected.") - - return cls(private_key, key_id=key_id) diff --git a/google/auth/crypt/rsa.py b/google/auth/crypt/rsa.py index ed842d1eb..cde4f4065 100644 --- a/google/auth/crypt/rsa.py +++ b/google/auth/crypt/rsa.py @@ -14,17 +14,8 @@ """RSA cryptography signer and verifier.""" +from google.auth.crypt._cryptography_rsa import RSASigner +from google.auth.crypt._cryptography_rsa import RSAVerifier -try: - # Prefer cryptograph-based RSA implementation. - from google.auth.crypt import _cryptography_rsa - RSASigner = _cryptography_rsa.RSASigner - RSAVerifier = _cryptography_rsa.RSAVerifier -except ImportError: # pragma: NO COVER - # Fallback to pure-python RSA implementation if cryptography is - # unavailable. - from google.auth.crypt import _python_rsa - - RSASigner = _python_rsa.RSASigner # type: ignore - RSAVerifier = _python_rsa.RSAVerifier # type: ignore +__all__ = ["RSASigner", "RSAVerifier"] diff --git a/setup.py b/setup.py index 3874354fd..6974f8b7c 100644 --- a/setup.py +++ b/setup.py @@ -24,28 +24,22 @@ "pyasn1-modules>=0.2.1", # rsa==4.5 is the last version to support 2.7 # https://github.com/sybrenstuvel/python-rsa/issues/152#issuecomment-643470233 - "rsa>=3.1.4,<5", -) - -# TODO(https://github.com/googleapis/google-auth-library-python/issues/1737): Unit test fails with -# `No module named 'cryptography.hazmat.backends.openssl.x509' for Python 3.7``. -cryptography_base_require = [ "cryptography >= 38.0.3", "cryptography < 39.0.0; python_version < '3.8'", -] +) requests_extra_require = ["requests >= 2.20.0, < 3.0.0"] aiohttp_extra_require = ["aiohttp >= 3.6.2, < 4.0.0", *requests_extra_require] -pyjwt_extra_require = ["pyjwt>=2.0", *cryptography_base_require] +pyjwt_extra_require = ["pyjwt>=2.0"] reauth_extra_require = ["pyu2f>=0.1.5"] # TODO(https://github.com/googleapis/google-auth-library-python/issues/1738): Add bounds for cryptography and pyopenssl dependencies. -enterprise_cert_extra_require = ["cryptography", "pyopenssl"] +enterprise_cert_extra_require = ["pyopenssl"] -pyopenssl_extra_require = ["pyopenssl>=20.0.0", cryptography_base_require] +pyopenssl_extra_require = ["pyopenssl>=20.0.0"] # TODO(https://github.com/googleapis/google-auth-library-python/issues/1739): Add bounds for urllib3 and packaging dependencies. urllib3_extra_require = ["urllib3", "packaging"] diff --git a/tests/crypt/test__python_rsa.py b/tests/crypt/test__python_rsa.py deleted file mode 100644 index 4a4ebe44e..000000000 --- a/tests/crypt/test__python_rsa.py +++ /dev/null @@ -1,193 +0,0 @@ -# Copyright 2016 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import io -import json -import os - -import mock -from pyasn1_modules import pem # type: ignore -import pytest # type: ignore -import rsa # type: ignore - -from google.auth import _helpers -from google.auth.crypt import _python_rsa -from google.auth.crypt import base - - -DATA_DIR = os.path.join(os.path.dirname(__file__), "..", "data") - -# To generate privatekey.pem, privatekey.pub, and public_cert.pem: -# $ openssl req -new -newkey rsa:1024 -x509 -nodes -out public_cert.pem \ -# > -keyout privatekey.pem -# $ openssl rsa -in privatekey.pem -pubout -out privatekey.pub - -with open(os.path.join(DATA_DIR, "privatekey.pem"), "rb") as fh: - PRIVATE_KEY_BYTES = fh.read() - PKCS1_KEY_BYTES = PRIVATE_KEY_BYTES - -with open(os.path.join(DATA_DIR, "privatekey.pub"), "rb") as fh: - PUBLIC_KEY_BYTES = fh.read() - -with open(os.path.join(DATA_DIR, "public_cert.pem"), "rb") as fh: - PUBLIC_CERT_BYTES = fh.read() - -# To generate pem_from_pkcs12.pem and privatekey.p12: -# $ openssl pkcs12 -export -out privatekey.p12 -inkey privatekey.pem \ -# > -in public_cert.pem -# $ openssl pkcs12 -in privatekey.p12 -nocerts -nodes \ -# > -out pem_from_pkcs12.pem - -with open(os.path.join(DATA_DIR, "pem_from_pkcs12.pem"), "rb") as fh: - PKCS8_KEY_BYTES = fh.read() - -with open(os.path.join(DATA_DIR, "privatekey.p12"), "rb") as fh: - PKCS12_KEY_BYTES = fh.read() - -# The service account JSON file can be generated from the Google Cloud Console. -SERVICE_ACCOUNT_JSON_FILE = os.path.join(DATA_DIR, "service_account.json") - -with open(SERVICE_ACCOUNT_JSON_FILE, "rb") as fh: - SERVICE_ACCOUNT_INFO = json.load(fh) - - -class TestRSAVerifier(object): - def test_verify_success(self): - to_sign = b"foo" - signer = _python_rsa.RSASigner.from_string(PRIVATE_KEY_BYTES) - actual_signature = signer.sign(to_sign) - - verifier = _python_rsa.RSAVerifier.from_string(PUBLIC_KEY_BYTES) - assert verifier.verify(to_sign, actual_signature) - - def test_verify_unicode_success(self): - to_sign = u"foo" - signer = _python_rsa.RSASigner.from_string(PRIVATE_KEY_BYTES) - actual_signature = signer.sign(to_sign) - - verifier = _python_rsa.RSAVerifier.from_string(PUBLIC_KEY_BYTES) - assert verifier.verify(to_sign, actual_signature) - - def test_verify_failure(self): - verifier = _python_rsa.RSAVerifier.from_string(PUBLIC_KEY_BYTES) - bad_signature1 = b"" - assert not verifier.verify(b"foo", bad_signature1) - bad_signature2 = b"a" - assert not verifier.verify(b"foo", bad_signature2) - - def test_from_string_pub_key(self): - verifier = _python_rsa.RSAVerifier.from_string(PUBLIC_KEY_BYTES) - assert isinstance(verifier, _python_rsa.RSAVerifier) - assert isinstance(verifier._pubkey, rsa.key.PublicKey) - - def test_from_string_pub_key_unicode(self): - public_key = _helpers.from_bytes(PUBLIC_KEY_BYTES) - verifier = _python_rsa.RSAVerifier.from_string(public_key) - assert isinstance(verifier, _python_rsa.RSAVerifier) - assert isinstance(verifier._pubkey, rsa.key.PublicKey) - - def test_from_string_pub_cert(self): - verifier = _python_rsa.RSAVerifier.from_string(PUBLIC_CERT_BYTES) - assert isinstance(verifier, _python_rsa.RSAVerifier) - assert isinstance(verifier._pubkey, rsa.key.PublicKey) - - def test_from_string_pub_cert_unicode(self): - public_cert = _helpers.from_bytes(PUBLIC_CERT_BYTES) - verifier = _python_rsa.RSAVerifier.from_string(public_cert) - assert isinstance(verifier, _python_rsa.RSAVerifier) - assert isinstance(verifier._pubkey, rsa.key.PublicKey) - - def test_from_string_pub_cert_failure(self): - cert_bytes = PUBLIC_CERT_BYTES - true_der = rsa.pem.load_pem(cert_bytes, "CERTIFICATE") - load_pem_patch = mock.patch( - "rsa.pem.load_pem", return_value=true_der + b"extra", autospec=True - ) - - with load_pem_patch as load_pem: - with pytest.raises(ValueError): - _python_rsa.RSAVerifier.from_string(cert_bytes) - load_pem.assert_called_once_with(cert_bytes, "CERTIFICATE") - - -class TestRSASigner(object): - def test_from_string_pkcs1(self): - signer = _python_rsa.RSASigner.from_string(PKCS1_KEY_BYTES) - assert isinstance(signer, _python_rsa.RSASigner) - assert isinstance(signer._key, rsa.key.PrivateKey) - - def test_from_string_pkcs1_unicode(self): - key_bytes = _helpers.from_bytes(PKCS1_KEY_BYTES) - signer = _python_rsa.RSASigner.from_string(key_bytes) - assert isinstance(signer, _python_rsa.RSASigner) - assert isinstance(signer._key, rsa.key.PrivateKey) - - def test_from_string_pkcs8(self): - signer = _python_rsa.RSASigner.from_string(PKCS8_KEY_BYTES) - assert isinstance(signer, _python_rsa.RSASigner) - assert isinstance(signer._key, rsa.key.PrivateKey) - - def test_from_string_pkcs8_extra_bytes(self): - key_bytes = PKCS8_KEY_BYTES - _, pem_bytes = pem.readPemBlocksFromFile( - io.StringIO(_helpers.from_bytes(key_bytes)), _python_rsa._PKCS8_MARKER - ) - - key_info, remaining = None, "extra" - decode_patch = mock.patch( - "pyasn1.codec.der.decoder.decode", - return_value=(key_info, remaining), - autospec=True, - ) - - with decode_patch as decode: - with pytest.raises(ValueError): - _python_rsa.RSASigner.from_string(key_bytes) - # Verify mock was called. - decode.assert_called_once_with(pem_bytes, asn1Spec=_python_rsa._PKCS8_SPEC) - - def test_from_string_pkcs8_unicode(self): - key_bytes = _helpers.from_bytes(PKCS8_KEY_BYTES) - signer = _python_rsa.RSASigner.from_string(key_bytes) - assert isinstance(signer, _python_rsa.RSASigner) - assert isinstance(signer._key, rsa.key.PrivateKey) - - def test_from_string_pkcs12(self): - with pytest.raises(ValueError): - _python_rsa.RSASigner.from_string(PKCS12_KEY_BYTES) - - def test_from_string_bogus_key(self): - key_bytes = "bogus-key" - with pytest.raises(ValueError): - _python_rsa.RSASigner.from_string(key_bytes) - - def test_from_service_account_info(self): - signer = _python_rsa.RSASigner.from_service_account_info(SERVICE_ACCOUNT_INFO) - - assert signer.key_id == SERVICE_ACCOUNT_INFO[base._JSON_FILE_PRIVATE_KEY_ID] - assert isinstance(signer._key, rsa.key.PrivateKey) - - def test_from_service_account_info_missing_key(self): - with pytest.raises(ValueError) as excinfo: - _python_rsa.RSASigner.from_service_account_info({}) - - assert excinfo.match(base._JSON_FILE_PRIVATE_KEY) - - def test_from_service_account_file(self): - signer = _python_rsa.RSASigner.from_service_account_file( - SERVICE_ACCOUNT_JSON_FILE - ) - - assert signer.key_id == SERVICE_ACCOUNT_INFO[base._JSON_FILE_PRIVATE_KEY_ID] - assert isinstance(signer._key, rsa.key.PrivateKey) From 1d665b3a68dd821b1e497644c0328b922df4a572 Mon Sep 17 00:00:00 2001 From: Sai Sunder Srinivasan Date: Fri, 23 May 2025 22:07:14 +0000 Subject: [PATCH 02/16] update secret --- system_tests/secrets.tar.enc | Bin 10324 -> 10324 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/system_tests/secrets.tar.enc b/system_tests/secrets.tar.enc index c19e8785acd4dc496707e68ccea9c2f61430b0aa..9ecfb2d252214779460eb2deb013d6cf4d1b460c 100644 GIT binary patch literal 10324 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 literal 10324 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 From c6ad0e667c173986cc90e710ba840547fdf46942 Mon Sep 17 00:00:00 2001 From: Sai Sunder Srinivasan Date: Sat, 24 May 2025 05:40:44 +0000 Subject: [PATCH 03/16] fix doc issue --- docs/conf.py | 27 +++++++++++++++++++++++++++ google/auth/crypt/rsa.py | 7 +++---- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 8ab609390..00f6cc0b0 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -358,6 +358,33 @@ # texinfo_no_detailmenu = False +# -- Options for autodoc -------------------------------------------------- + + +def autodoc_skip_member_handler(app, what, name, obj, skip, options): + """ + Skips the RSASigner and RSAVerifier from the internal _cryptography_rsa module + if they are being documented under that internal module path, + as they are publicly exposed via google.auth.crypt. + """ + if name in ("RSASigner", "RSAVerifier") and hasattr(obj, "__module__"): + if obj.__module__ == "google.auth.crypt._cryptography_rsa": + # Check if it's also available via the public google.auth.crypt path + try: + import google.auth.crypt + + public_obj = getattr(google.auth.crypt, name, None) + if public_obj is obj: + return True # Skip this internal one + except ImportError: + pass # Should not happen if the library is installed + return None # Default behavior (don't skip) + + +def setup(app): + app.connect("autodoc-skip-member", autodoc_skip_member_handler) + + # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = { "python": ("https://docs.python.org/3.5", None), diff --git a/google/auth/crypt/rsa.py b/google/auth/crypt/rsa.py index cde4f4065..274bafc5f 100644 --- a/google/auth/crypt/rsa.py +++ b/google/auth/crypt/rsa.py @@ -14,8 +14,7 @@ """RSA cryptography signer and verifier.""" -from google.auth.crypt._cryptography_rsa import RSASigner -from google.auth.crypt._cryptography_rsa import RSAVerifier +from google.auth.crypt import _cryptography_rsa - -__all__ = ["RSASigner", "RSAVerifier"] +RSASigner = _cryptography_rsa.RSASigner +RSAVerifier = _cryptography_rsa.RSAVerifier From 2c461ce20168e2140a9ff8d5dabf5fc9461ed9a1 Mon Sep 17 00:00:00 2001 From: Sai Sunder Srinivasan Date: Tue, 27 May 2025 22:25:38 +0000 Subject: [PATCH 04/16] fix es256 sphix error --- docs/conf.py | 19 ++++++++++++++++--- system_tests/secrets.tar.enc | Bin 10324 -> 10324 bytes 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 00f6cc0b0..c73f540a5 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -363,10 +363,11 @@ def autodoc_skip_member_handler(app, what, name, obj, skip, options): """ - Skips the RSASigner and RSAVerifier from the internal _cryptography_rsa module - if they are being documented under that internal module path, - as they are publicly exposed via google.auth.crypt. + Skips members from internal modules (like _cryptography_rsa or base) + if they are publicly exposed via a higher-level package (like google.auth.crypt), + to avoid duplicate documentation entries and ambiguous cross-references. """ + # Handle RSASigner and RSAVerifier from _cryptography_rsa if name in ("RSASigner", "RSAVerifier") and hasattr(obj, "__module__"): if obj.__module__ == "google.auth.crypt._cryptography_rsa": # Check if it's also available via the public google.auth.crypt path @@ -378,6 +379,18 @@ def autodoc_skip_member_handler(app, what, name, obj, skip, options): return True # Skip this internal one except ImportError: pass # Should not happen if the library is installed + + # Handle Signer and Verifier from base + elif name in ("Signer", "Verifier") and hasattr(obj, "__module__"): + if obj.__module__ == "google.auth.crypt.base": + # Check if it's also available via the public google.auth.crypt path + try: + import google.auth.crypt + public_obj = getattr(google.auth.crypt, name, None) + if public_obj is obj: + return True # Skip this internal one + except ImportError: + pass # Should not happen if the library is installed return None # Default behavior (don't skip) diff --git a/system_tests/secrets.tar.enc b/system_tests/secrets.tar.enc index 9ecfb2d252214779460eb2deb013d6cf4d1b460c..9bc5bbcfd6687ca1f670bea60ec15fe8f9217fce 100644 GIT binary patch literal 10324 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 From 6170a48b0285c51c1f7e56a4b17af7b0ef45430e Mon Sep 17 00:00:00 2001 From: Sai Sunder Srinivasan Date: Tue, 27 May 2025 23:00:18 +0000 Subject: [PATCH 05/16] lint --- docs/conf.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index c73f540a5..3c95be670 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -386,11 +386,12 @@ def autodoc_skip_member_handler(app, what, name, obj, skip, options): # Check if it's also available via the public google.auth.crypt path try: import google.auth.crypt + public_obj = getattr(google.auth.crypt, name, None) if public_obj is obj: - return True # Skip this internal one + return True # Skip this internal one except ImportError: - pass # Should not happen if the library is installed + pass # Should not happen if the library is installed return None # Default behavior (don't skip) From 94819ad2b0525ddd13f2895c51df84a90bc7e034 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Wed, 19 Nov 2025 15:11:29 -0800 Subject: [PATCH 06/16] removed autodoc custimizations --- docs/conf.py | 41 ----------------------------------------- 1 file changed, 41 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 3c95be670..8ab609390 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -358,47 +358,6 @@ # texinfo_no_detailmenu = False -# -- Options for autodoc -------------------------------------------------- - - -def autodoc_skip_member_handler(app, what, name, obj, skip, options): - """ - Skips members from internal modules (like _cryptography_rsa or base) - if they are publicly exposed via a higher-level package (like google.auth.crypt), - to avoid duplicate documentation entries and ambiguous cross-references. - """ - # Handle RSASigner and RSAVerifier from _cryptography_rsa - if name in ("RSASigner", "RSAVerifier") and hasattr(obj, "__module__"): - if obj.__module__ == "google.auth.crypt._cryptography_rsa": - # Check if it's also available via the public google.auth.crypt path - try: - import google.auth.crypt - - public_obj = getattr(google.auth.crypt, name, None) - if public_obj is obj: - return True # Skip this internal one - except ImportError: - pass # Should not happen if the library is installed - - # Handle Signer and Verifier from base - elif name in ("Signer", "Verifier") and hasattr(obj, "__module__"): - if obj.__module__ == "google.auth.crypt.base": - # Check if it's also available via the public google.auth.crypt path - try: - import google.auth.crypt - - public_obj = getattr(google.auth.crypt, name, None) - if public_obj is obj: - return True # Skip this internal one - except ImportError: - pass # Should not happen if the library is installed - return None # Default behavior (don't skip) - - -def setup(app): - app.connect("autodoc-skip-member", autodoc_skip_member_handler) - - # Example configuration for intersphinx: refer to the Python standard library. intersphinx_mapping = { "python": ("https://docs.python.org/3.5", None), From 4de2ddecf0bb03320d0641a1eda2b91dcab1768c Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Wed, 19 Nov 2025 15:11:44 -0800 Subject: [PATCH 07/16] removed conditional imports --- google/auth/crypt/__init__.py | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/google/auth/crypt/__init__.py b/google/auth/crypt/__init__.py index 6d147e706..2bab07d9e 100644 --- a/google/auth/crypt/__init__.py +++ b/google/auth/crypt/__init__.py @@ -39,23 +39,7 @@ from google.auth.crypt import base from google.auth.crypt import rsa - -try: - from google.auth.crypt import es256 -except ImportError: # pragma: NO COVER - es256 = None # type: ignore - -if es256 is not None: # pragma: NO COVER - __all__ = [ - "ES256Signer", - "ES256Verifier", - "RSASigner", - "RSAVerifier", - "Signer", - "Verifier", - ] -else: # pragma: NO COVER - __all__ = ["RSASigner", "RSAVerifier", "Signer", "Verifier"] +from google.auth.crypt import es256 # Aliases to maintain the v1.0.0 interface, as the crypt module was split @@ -64,10 +48,17 @@ Verifier = base.Verifier RSASigner = rsa.RSASigner RSAVerifier = rsa.RSAVerifier - -if es256 is not None: # pragma: NO COVER - ES256Signer = es256.ES256Signer - ES256Verifier = es256.ES256Verifier +ES256Signer = es256.ES256Signer +ES256Verifier = es256.ES256Verifier + +__all__ = [ + "ES256Signer", + "ES256Verifier", + "RSASigner", + "RSAVerifier", + "Signer", + "Verifier", +] def verify_signature(message, signature, certs, verifier_cls=rsa.RSAVerifier): From 4c0de25f3184f2d0234de1cb443737318e00e82c Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Wed, 19 Nov 2025 15:21:14 -0800 Subject: [PATCH 08/16] fixed docs reference --- google/auth/crypt/_cryptography_rsa.py | 2 +- google/auth/crypt/es256.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/google/auth/crypt/_cryptography_rsa.py b/google/auth/crypt/_cryptography_rsa.py index 1a3e9ff52..1034ed6c1 100644 --- a/google/auth/crypt/_cryptography_rsa.py +++ b/google/auth/crypt/_cryptography_rsa.py @@ -66,7 +66,7 @@ def from_string(cls, public_key): x509 public key certificate. Returns: - Verifier: The constructed verifier. + google.auth.crypt.base.Verifier: The constructed verifier. Raises: ValueError: If the public key can't be parsed. diff --git a/google/auth/crypt/es256.py b/google/auth/crypt/es256.py index 820e4becc..66867a0d8 100644 --- a/google/auth/crypt/es256.py +++ b/google/auth/crypt/es256.py @@ -82,7 +82,7 @@ def from_string(cls, public_key): x509 public key certificate. Returns: - Verifier: The constructed verifier. + google.auth.crypt.base.Verifier: The constructed verifier. Raises: ValueError: If the public key can't be parsed. From e587b280dbdbae352d46c66c4ea7d7e75bb0875b Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Wed, 19 Nov 2025 15:22:55 -0800 Subject: [PATCH 09/16] remove conditional import --- google/auth/crypt/__init__.py | 33 ++++++++++++--------------------- 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/google/auth/crypt/__init__.py b/google/auth/crypt/__init__.py index 6d147e706..2bab07d9e 100644 --- a/google/auth/crypt/__init__.py +++ b/google/auth/crypt/__init__.py @@ -39,23 +39,7 @@ from google.auth.crypt import base from google.auth.crypt import rsa - -try: - from google.auth.crypt import es256 -except ImportError: # pragma: NO COVER - es256 = None # type: ignore - -if es256 is not None: # pragma: NO COVER - __all__ = [ - "ES256Signer", - "ES256Verifier", - "RSASigner", - "RSAVerifier", - "Signer", - "Verifier", - ] -else: # pragma: NO COVER - __all__ = ["RSASigner", "RSAVerifier", "Signer", "Verifier"] +from google.auth.crypt import es256 # Aliases to maintain the v1.0.0 interface, as the crypt module was split @@ -64,10 +48,17 @@ Verifier = base.Verifier RSASigner = rsa.RSASigner RSAVerifier = rsa.RSAVerifier - -if es256 is not None: # pragma: NO COVER - ES256Signer = es256.ES256Signer - ES256Verifier = es256.ES256Verifier +ES256Signer = es256.ES256Signer +ES256Verifier = es256.ES256Verifier + +__all__ = [ + "ES256Signer", + "ES256Verifier", + "RSASigner", + "RSAVerifier", + "Signer", + "Verifier", +] def verify_signature(message, signature, certs, verifier_cls=rsa.RSAVerifier): From 8659ec5228ee29e28c4e57771248d835419c9916 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Fri, 21 Nov 2025 10:20:18 -0800 Subject: [PATCH 10/16] fixed lint --- google/auth/crypt/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google/auth/crypt/__init__.py b/google/auth/crypt/__init__.py index 2bab07d9e..05e36148e 100644 --- a/google/auth/crypt/__init__.py +++ b/google/auth/crypt/__init__.py @@ -38,8 +38,8 @@ """ from google.auth.crypt import base -from google.auth.crypt import rsa from google.auth.crypt import es256 +from google.auth.crypt import rsa # Aliases to maintain the v1.0.0 interface, as the crypt module was split From fd53d0b601d07829fc9ae887efba389214fbed86 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Wed, 26 Nov 2025 10:28:24 -0800 Subject: [PATCH 11/16] update secret --- system_tests/secrets.tar.enc | Bin 10324 -> 10324 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/system_tests/secrets.tar.enc b/system_tests/secrets.tar.enc index 9bc5bbcfd6687ca1f670bea60ec15fe8f9217fce..cceff7d61595c68826dc5859a3d214b4e37d48ee 100644 GIT binary patch literal 10324 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 mdJYvBOkffKITnyPeippzomzngu1T^Mk@g7( Date: Wed, 26 Nov 2025 11:09:42 -0800 Subject: [PATCH 12/16] fixed docs issue --- google/auth/crypt/es.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google/auth/crypt/es.py b/google/auth/crypt/es.py index f9466af3c..c392d8f68 100644 --- a/google/auth/crypt/es.py +++ b/google/auth/crypt/es.py @@ -110,7 +110,7 @@ def from_string(cls, public_key: Union[str, bytes]) -> "EsVerifier": x509 public key certificate. Returns: - Verifier: The constructed verifier. + google.auth.crypt.base.Verifier: The constructed verifier. Raises: ValueError: If the public key can't be parsed. From 64f7be8557074abaade582b71093f0e7740a87a0 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Wed, 26 Nov 2025 11:11:02 -0800 Subject: [PATCH 13/16] Apply suggestion from @parthea Co-authored-by: Anthonios Partheniou --- setup.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/setup.py b/setup.py index 2461fda62..1fbdf65ab 100644 --- a/setup.py +++ b/setup.py @@ -22,8 +22,6 @@ DEPENDENCIES = ( "cachetools>=2.0.0,<7.0", "pyasn1-modules>=0.2.1", - # rsa==4.5 is the last version to support 2.7 - # https://github.com/sybrenstuvel/python-rsa/issues/152#issuecomment-643470233 "cryptography >= 38.0.3", "cryptography < 39.0.0; python_version < '3.8'", ) From fb8437327dc712ab711297cfcbb00d9cf77714bd Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Thu, 4 Dec 2025 14:25:43 -0800 Subject: [PATCH 14/16] avoid circular dependency --- google/auth/credentials.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/google/auth/credentials.py b/google/auth/credentials.py index 82c73c3bf..8a9a74a4d 100644 --- a/google/auth/credentials.py +++ b/google/auth/credentials.py @@ -17,6 +17,7 @@ import abc from enum import Enum +import logging import os from typing import List @@ -24,13 +25,14 @@ from google.auth import exceptions from google.auth import metrics from google.auth._credentials_base import _BaseCredentials -from google.auth._default import _LOGGER from google.auth._refresh_worker import RefreshThreadManager DEFAULT_UNIVERSE_DOMAIN = "googleapis.com" NO_OP_TRUST_BOUNDARY_LOCATIONS: List[str] = [] NO_OP_TRUST_BOUNDARY_ENCODED_LOCATIONS = "0x0" +_LOGGER = logging.getLogger("google.auth._default") + class Credentials(_BaseCredentials): """Base class for all credentials. From 165377e789105ad2c54b6b25815f1e90655a1241 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Thu, 18 Dec 2025 15:03:14 -0800 Subject: [PATCH 15/16] make cryptography extra optional --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index acda83138..aa33e254d 100644 --- a/setup.py +++ b/setup.py @@ -73,7 +73,7 @@ ] extras = { - "cryptography": cryptography_base_require, + "cryptography": [], # cryptography is required, but keep as extra for backwards compatibility "aiohttp": aiohttp_extra_require, "enterprise_cert": enterprise_cert_extra_require, "pyopenssl": pyopenssl_extra_require, From 1c2c49614076b3ed15a29e33b11ffe56a21ef165 Mon Sep 17 00:00:00 2001 From: Daniel Sanche Date: Thu, 18 Dec 2025 15:20:21 -0800 Subject: [PATCH 16/16] revert file --- system_tests/secrets.tar.enc | Bin 10324 -> 10324 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/system_tests/secrets.tar.enc b/system_tests/secrets.tar.enc index cceff7d61595c68826dc5859a3d214b4e37d48ee..d89763db03ebdf5a1bee80f1027afe8cd168a93b 100644 GIT binary patch literal 10324 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 literal 10324 zcmV-aD67{BB>?tKRTD7 ziXL9unN2hHZ7YE5PH?cK@CqASFlO*o*@#A(r58&-KgnmOz|o+KC`9LJ`F#gWMa7EVLKTZjixxR3wen2Zxrr*pWAn9x4}Afx&Xe5l2vdX; z#%s--6vV;Le7S0ougM5Hz#HRT*E z_aCyKmO_yYQKbx4Xg9)!Sj4HY={p^n{UX!aufoMY|7a-W7;RShGC`&-eUxnTX`Q3w zyQ1B>BbC@WK(YBy+!P}_T-WN5%f@8?Y{`I@DG$9+i{7q+#?5`(C$(KFj-ot787`c- zy!7|OI~(_r8qwuW%3fgYYkqqF&fDo+R6fglH8+6L_u7(OJ7_4SOlvwH2clyCR%pSd zv&4p(+DB$G=*3XeRS-CAy6Y%WY15ihe_y7d%7+=dz=6J@qt~X3FQ%;Ir8-z(6Oz_- zh{8Fr>Nuj%oMjZ?UT13HsMjAjs(}P0h6^415DKce?|&ts*4ec)_VH?a(6d@C>QMI89R^c6dx;&eRcCes7%PeR#A#{$ zO3cV)_uLS}{^TuT)XfCYU#A+I)FQ z24#fWcTE%YC87ezVHQsv*r(GzZ|6GqHbl#8HnLv3LtnOdU@!3IoDGvE&=E%z%E4*b zq#Kx~_oL6)WG2UjUoP}$Xl`7-{sP&gXOx+%*g=L6>-ZWSh~0F*4z0Z7o9iv{0Y*s7P_2U0n51ZozHB=E9n-m) zmm-K2{y#8J7n7Mi-O@L|fVO7CmSvsbgKAHz9yT*(&zV|^n7Y!9qHjWuu5r$|ptCd$ z*l{AS8&>Uzywuu4Pgi1->*l~inq108%E~hi-uIRAKcE802g?4og8a@)e5dc)f0ao{ zzRmk@B>}<-)GEC=Bd8Bp{B?5x;>hc5iHf179lnWK6Tq@dhbvb-=zIA+IMSR?OcMoj z*mkUFECq`a`aUOd)(orKr8;?-okNy3NQ^Cl#wq~IQgRe{gr2^Yj!{vNJc}^U%ZUOz zmP$zul;mU?q2&EpMak7JC zEKKOgBKQxGe>(wTzrT}0LlQ5rE_GmHjzD4XTS~ia zp&_co)(XX{PKRxlCn>vDt!356nA>3*F2z{76{CPWXVHa--y}m_y1&GmcW|2Es^#Y&H~+WH$eh>)@Y*Ssf>+1Dkmu9gWM3hzSa3s7{4=_ zsuH@?Fzgh{!eu@VF15ze25^dCRQeS{Qt4k8FlKRnnJUyFu!bF$L9#3?F&A<((oO>@ zKUh0#y%G=$3EoQMn}v_+2CfrbKHZgA8!_XQFw(F9%qfpu4Cr6w1IzJoO2d`f;oJBq zSuZAN!ZB7CJFY_&f&hSf);wd%|6vj%5$?}MJ+G#t^!~b)of7Kjbr%_2(xJRRfi)J? z>|CQOkqH?0fs`fCEehT}zjCDznH?m)hm2_SGW-ktIWhpr$Dua90*%TlByf0Yvz|_s z8xLx?y+?=vhNb)pdd>Xi8Fo-1CW~N^r;sbpUIpU;H_=c*SHEiQ4S?QhB7; zK!v0fQ$QM#IfBn~D6>Ri)4O4_Lfg0x0**n>M(R=*KS0|rV3dRKf%#)K`0CT(*4E=O zm)$2Wa5(l-CE4h8fQ~GSTNd_TZa3o{U^hu6z{XW-Shx`bv?TpIcyo)E^^Szt4_*fj zCCNGc(>~98IS5d7BFo73>#p0ub)bT>t*KA?FK>0nTo43w!12ud@bE;5z6-?Z?)=)G zdTHGX5kXge)<{= ze|ed4%7fzRCy5z#U_u3OJHgD}=FaoN(*$h}KEevTY*NXh+{U36$BrH7m1Chu2qhzJ z`lpbTtK5Zq6h1fcy(dTqN@rkvn?~84A$Tu$WUL|OigHB6Ky~kjczu09!_2kH8+$gp z7~6RVV(o;q$r&&j^BbLDe9X}e`8AJQ*SEZmi_Lauwz1KUE`z$uMT~{C-Akab55I1| zU3pNUNS%S-1Ad?b#$L{3r}UyG?5O*GcDyBVx$m8|y?kzpNT;D6oJzsz$$OIgNmCbj z8a!dqUQ$kdy}KzoD&(PIcXC+ebD5dahXhr#fXkU8q{|cWRw!dt6>?VOjBQ1+wQuJY z_s(HSEta(4EOF{ORj#HZcrpV<$O;lpBaP(5+@~np$Tw6i_)5HZ8t8tN^ueOX3@`F- z;wQ!mk;yh}g7WqK9u?$GZN}GCB+K2liG|}^p>K)3#}KBULGeI+pT(vUycGYs&9g4@}1t)~c;XY03m*}AskZF{sF3A825_wv+- z6KWde35aOlL2Xz6sC9Mhr4xWft^2civBvd+8&)`XA&$&RiNJBjb)OIgrpw0E%rf3X zKNWVQ-@cE(JZ^Q4eMC7xwy0KbYy#mjDRmN#Q|SK4q(YLJ7CyYEHQ zvVprq@UWyg0HOvkvSd~py!pV|umZ9RjENJOfltwMA1B*m&|(j!KUo?{PHp>8sEgTg zAD!jT=c~m5_POB@_#_s$Ogh&wTG?c^lRJT8$eS5QvyEP>){lJqz#^5Nr^=Y@(2Mn$ z0kD1Nt>fmxRToVljo9hjY}r5b3kgBMr;@HY|y~ z;|xvrFF;F|$o~!w7#<=+rv*zV<&pV-ArVMVj*(Z3&D(eI4islgw! zKpz*+TF-aKwW43_zK!G2>TQHgMR_BYjK22s=ZuZu4?8jQwi}W22i56hyZq7PgDmCT zgHq+SE(9qRi7ui#ovo~&(ulHC+=tu}<4DiIr1%VT^%qxX@<_~uPQzJnS{hsl!KUb@ zWVA7bau%#WtVrgQTPGeo?6Ys9B0W_1M*gI5<;H(adUiqLhfDOQ!yVe|a%UrRxtdzh zgM)^O?3w)4I2DU-Mpw|w5v)8}zp}60S{lBn@5JH4%KqWG^l(Y-B0C1i& zzD0H8s7^3!iZ$+p`<+^zs8@WaC&s4a!h|=httEKz#0OELk;O(#?OohKu=c$lVnM1e zj@H9F^(=sn!1jb4zcD?(4UWe1!NYW?lbLDUL7WN8pxzrm`KZv@Js~ra6KMPQ?J$|% z*siIW&XCT@Z^CsU#s?Yn3p54%nCW(ay6n?H(!RHA!@m$j1)#t`Yb8;8F0z#(__ovA z-T;r2sBV7`uq+9bj;YkQvR!{>a_S)jrnWyi)qo#Wc6W&=$2o@sQXR329=N&KKXk3B zEWvRlATNZARmcj+V?jowr4#L!VIwuhwFE{D=3?; zY<6*WvnwZo2<}-0D^dLmk9W818d9Lg9k(Z-s;Ao$_Ilw^3NG51X zOKX=pUyzzRW=2h@4w9IX6zveaz7L2hSa_X5ZE~jsGYhX z=s6~#HaxT5#5ry>t)8VNgU)S$ZS*m^Rxj0wsL$IT#pa_FW8{5P_h(;U6-IFhj2(RL zyiXS=cr-sL)*xrH9V%v4QtE@pW27ogHfraABshXTfa__LQ3sb8VuaY|+$NyVI!Rq6 zX4Mc8HGhYatl65us<4!K0TO3k4(rvrdLK9?BvleXyvUMP5?*deW6ee2H;B?Vvo>%M z97Nud7jc&3iFuRahjMg!dL51#wj>bbEUUKg-58i`)ty_uLk>})aPDS+1kMJ8>Sn&CQuecOE7Qg<3|7*g#Qi{}N! zlSqt<&TXKJW7c0Jo}9BTKR9uz4CR2RK_%Z<+?@^RX|P4t$;+NF>l0ub$Ui0Vas>xr z(Lmk@QJ?wX-@Yd};x}#u)JKE$Lt0SFpQVTFq(FuT`DS13mWAgoZldg2(G{l!61te) zl!I|a?hWkYVo--^jY0qlqbo&~(|LbMpMfC%;iY8_npfJ0!!9B)w0EB(1P^nsSGVOs zslL%{*|Vu=X2ZBVULMl3EP1}`8L&hHKlrP`@KHQ2QKXL<)pvKG;cJ#F7aUUt;JK1; z>~}3Jp~MF0!D#73lkU@{mDG^E_+E(CqGHEJ8M9Rw3Q#~7+#PU51f_8B6m2d_@ zh|g>{VA9Lna62O6W*E{3Sv(z$@-hR-0v50lk-$qci5kc)<;g-%UL*IXjhJtxZY~8L zd+!3tt*^WmtZc3VPsx@$PH}F?I$N}X=N1DMiy`=mv!LBG0}tt@iM&=rSN{Z_%XUMgP&t3MX;Z*jV@8PAF&|2j#Q?v-(d{ zy?%B>z>*)ItW8;4C2pDYziqvaNy*V`g@fcb7MEA?e;j2RNS=FrVSBllI44{_J=IT? z2|plaZwqrWgx*N!umf2<%owEj$ZPE(*{I8MO-ILKvjHw0dnF*Rkd?U;7uyU2;Af&83BJlQe{THe!kbWX0igGj_DE40ulx4c43q)m+oyzLo*-{h z6Ekn33B7C1e|rQc`0ov-zwyLUMhDw^5~mB3We%AoUfd%LaNzHz35u$_+8CTUszNutP8nsz2* zN^68BYW@KpNRT4E7KzA+@md}#YgU|Mwm9$^7noU@{^qpc)hcO|?9&Q70@3I084+mC<>@R;u+w(*(|73{n z@7`eXt-3Xn&Jp4Js%8+g^+u?H<~}0@l;GBSHXg*+KVjcXJ|&fG#DyGLe1z1~e}acd z;NMCjt$U4`Xu&7CHbp0Ba(o+99C-bYLune@a&%fnMw{|HL4yhforqMI7+c2 z(5avy%^-aap(e0R^JI2416&+h;45EInDTlcOLJ|evU3g9wB<2G)V>3Rcub0+R<(uTC#7_CDwQ*0jsTi`-rym3) z?`8?6ij>yA^H3ps2+|Yqd2YOk6zuG&1_88X&NhZkML^oLaO#pUFj5~xVc3E>UQR>> zvFqjRwOS~6zg{*w?jmCN&~is+=R;$PNA^$2DoFN$TdYeuezf^~HLwS%ES5^IuXq(U zqb^SXHhzQiNG$e87SSesRWf>qO%ZLmS|Tt~dUjYh=e>)SK7DefPBF@SrM3tptVoGk zn!TEl(kYqeg#`Vi;*AME8_6Rg#|*|>6cUkCdVi$~>6*&GYvuzemllXA`q~7QmC{px z;W^qT_EV1)tWcO9OT6Eno;3klHqR0MgLlY2hIBrTDkq&)V6$hKb%`{(-7~EtTlJ{` z*n7V_50<$nZ@}Y46!m5>veM9@Lg|>vWCqOR+>fm>IUcia%3MIn(@x1-sIsltVP8vj zbu#=lK6&~~^3##51*9B?k$Ul{ZkV!kCV@azGnO&g+uAY*@NbZ$2#RXH*(~0#u>#K4 zKFuNFAtCb<44Q$ymLf67QNx_T4b0V>+CVqIvHb%s}NcFq*D;H^O@& zM^ijO!q}ocj$RlR+D1N`<9lmKc#4K!_DXuL#G4*X)5zF&V>iGUpi&PapN2x*1;>WS z4Qk$%UU0kitQxPRZ32xLuAX8N(y}M2Cb&~-4sCk`aefh>eYOanwhw%9H!P+_zM`B> zO@=nM8~wikN$H=TUxR7Aa_6Xv-bs4EB=}%go z5+!8*p$vZZED+Y{$U@OUiN^!1fj{1nqAF<`Nq~_jiv$9lpN2f+ih`e9(+jEgTaWV6L|1~#WDs~};rPM%F-;XTS!J*O=0JI$9E&avJw(DDv`q{!vzogtpIPR8l-i zzh=>BnL*NA#0j~?2G5`*mrpsNqwW{DQA%aVIo|@#eVRChKQRUcV z_Jrc1D~g^Npu-NqPtUG@<8RDeio}N3E}I0G2UV*22^z)NT`-{%JxJeU_D#tV zqAnAiPmmkVIVCbn)uX9oJ;;b#LvnSI>A7cZ_+5x9Xq`mp*g6vpK_X`}0MMvi52sz| z?U8fj5e%I~h*VB=xXi4~yg~UWq>2Nm!qilHBfK;xF~f8K0f&?OY=P%1NuDx5+%!sl zPkAWYFxhum7rUdD*aqYMu{?*-VR@kUM=SIzZb+1O4p+AzL9MdB|AIRF(x4+ z@)H_bTLxsu+fg3RE)p6a5cE7@&e4dW@C{er>B^K*&njCAU?(cj0E>^Q)I%Qw{u0wP zYzRSV^fh?9fA^I}&3ov@ujL74DnI&~)bVkv6eN?v#GBsSefI$W+p&&clw>K@-zJwfbI22BzJuj#b5D6cRKb0QZ;lw5-A%Q~j3QxI>P!XT=NX zH+ewBJx-iFx2armzcC}>D;OYz3-+t2RUyR$Wg*mE0f>}jLvov?*F85WhH9!vKRF5`@1Sj#?W#N~g zF&KAUK{Oj{25itOU|?=R)?g}kj?6&P(j{5;)h{m5cv}$^3jeA3ZEaChPj;9S!KXwv zGeF{eUN->89X!BNl6u8!O^XZ}!b&fa1K8up7<0ZfpjM~6G4Yi*ZhyMcV?`G1>WER0 z2oHt3rd2$P`E@2cS=W_Y4(EQY7$ItSEUUXib@f?40#}I_|V@XlSkG`ZQLB~0Set4-zhp%Oo(w>p1+t0zsrFe zoed=AX7};UXo(-apVNBmn(bL+)wD}l$X8I}YK9%H#UcNnY;RDoldwG&hBvEv8Xev1 zX929`in1G%Q`CHPNvr>&S)a%Df)E+y-sp26F1m^)y)kw`#GyYq_EN{%9r}%sYP2@n z*v0!}MXTNcTwrtc5!phKG0UgP(~dE-KSX`K0nm7`!4*GBV?kOC4kQ)It!^H6$6vd5 z(Ajzy-++OD!MEUCtFt>5%wc-(KSZF&EeJ+qXmlHQr@WHE8XTm8vW~{t|2Z27ZzO^< zwEFaBAFtSsS>I^uP2zY^d3y%`z26>gP_FLBbGgU{T1IWN!P&@Sob@_N%n~(FCU5&S z%Ic#G)+L24xlWY^IM6&UxsBRvVr!z5hK~w*uMR_=&IPr3&s$3iuR@yT?W5=#wG5x< zgEKW4nczfxGc2XN52ah`w6^fg2pX|B39^9Ik(R)ef&Ny>iS0A15J%sTPsSCvz;d>Qg)OQ- zm&j^!@m}aH3$YUzvc=bB4eh+>{)E_ROIA&0%Cr9zEIc#{{ko{v8{MPzGmZDyE@6iC zgmcI8$~SDL${BffT!?&Vnw0M|h(RFM3!zAmFtt%>uBj>mwkd^}sd2-2SCq(&eE)?2 z$LsLvX%~nn`&Yspv7_w+E9@+Sd#g zvgqwp1o`f}x+rCLsrSdH^Z|u$qEKh-#zq4kmM7lTwo%=p_TqvV5zuJehC98xVC6D> zLq&OHe?!T9!P21o=_8GoxsMg?)MOU-^~Ot9Nj8IyP;n(wEZWmFT3j1qL|oH@A1ep( zfR|r!`-~Lve)#cqjl}~VCoGrVg`A!12%6c5v;}Z10Zy!+p?eZ3!WaOmf@0|4qXmrZ z!Rm42U|l~}xXlqEGqywbf~vd z6Wd!WuD#XQ3Z>8?P+6kXY+|%xtWKteysjyP38e-i1L2v(!4%-It54FWUH9#~DoQp0 z?UE%8Vs|Qa!-hipDHiFb(y)5cT>m%%f2e3jyR@P|6+WUJ zQU3lc6_coN3%(5h&_%()31!L6INAw}w1FZU=BFh+(9Og)2NkU)Z(r zX}}z9LwB$uDFSnJ%6Qz9?bP`!UWmggH~rY68HRBbUxLqzA%6hVl>G+oQKa%Eccij^ zkcNU7EU}7lvp_X#Q2VMRJ?=`@@nt8RbyoCQkqRE)Q2N92vU4Tny|6KV- zu&{JC6`>3LM!qhV*6d)+XeZmqr;QdyRbpW#g41j6<1_bJxay)R*x!C=LvveE;h}nA zp>=;gpnkiy4a}2tMpN`w^>u)FxwN9u4T^sSbUf*!n-% zh#6Gf`Gww6K?w^hAGLkMrUc#^7)nb1PmiP{GFW6k3~@(xCBQ5 z3y5C!63L6Aaw#S-NCvRxQL2@1BU35CJb%)cI9La1XIQv`^W#TOTsC0??(=c?`g5aM=JEDhC-PnUY!2?*t zYNv6{iSLud=7`Nm&@mdUl7?VbZ8=+k?zYI0fdbLG3=!4<*+52nhiA3Q(lG#9<@BDz zZiE{0gZuMbEh)~gL)OUv!goXYWud-lq-Al6H2i%7OqW3HgmxEG-ciL zqf>+C6%XI0@lYz7=8c(_ZQ^%WW1<700iAt_+sbU5#p9;G28QQbrn7zcl;`$yfW!oo zT<2$lsmRGH9QD@~_5*ZZyxEWo#90(HUF7;2iRhAmn{Rt+63npfCKF~ERXO4Z82?%I zo12)M_`L%oycuE=ulR!2O712`C&xa#K~*EbH@RNVeFa>%rc`A?YV+T#g5+aG7R0P- zOZaWvFQkzFBo4FnbdW}sPXwBYJUv{M<=k<2&1DGXV-fcj(136QR+^zh%cAc!`2<0@{Ow$~t8UI|-1XpY*UnZdnu z`ue3b>PuvRQ(^q%?{rNWUErEpiNB%HNDWS@4ShCg1%*P^&vGl*SWke6)iCAb#M=kR z@Jzoe(O@x;lTt|eitNRemc8;iRqoB2IUp74_oQg7Ix`^JMFAU1nvYH}#l2r)5)Y>AKM5+}>n78>s$ofkh2l$5a4!WK{Veec?if4X<$C6ux1(C{V^ zO|=y-0|^k_7~}-*Wvdpn$mb21f#NmKHww^;E^56JP_u+WBxtCoL6cjwmS&#^(swyb z&d_HC=2P;@9c%j@IM`VR=|W#!EP9?IFemK?K@}%5IIq}pEijMUeqv_)7oSt{9J{

vlD`{=WCTpJRc706D)?RdC3U~`x8C+m2En+z;9Q>G+}^BcwN7fCpHs|ho? zJ0GPD6+^PjmbVw?1F4lX3#~%HV5z3v^7Y{`_x9SE`ivP_Y22k?Ma6_OR$05?w@byR zOR~CRQkfa(`c5-E{O)eUR9LkeN! zc(P=PT`7tdfq7dtF*?=qJC{YXoB-tQYa4kEl#t@s)n+8;?6`5IG9b{5mA7c<6OqR+ zM=5n*L1+%hieh124*}Lt7+q?iaR=QV>v>YOaku=B?(&-Aq)(hi7Sfvuu&}KDV@Z(% zDcKW8cua_X9Y>L~VWgPkUl)Q}+a=iD@;h