From fbc16417131e947b5cefcd797e01d79c54c5084a Mon Sep 17 00:00:00 2001 From: Gupta Shrinath Date: Thu, 12 Nov 2020 22:19:15 +0530 Subject: [PATCH 1/6] Add flask faceboook google twitter login demo --- flask-facebok-google-twitter-login/app.py | 116 + .../env/bin/Activate.ps1 | 241 + .../env/bin/activate | 76 + .../env/bin/activate.csh | 37 + .../env/bin/activate.fish | 75 + .../env/bin/chardetect | 8 + .../env/bin/easy_install | 8 + .../env/bin/easy_install-3.8 | 8 + .../env/bin/flask | 8 + .../env/bin/pip | 8 + .../env/bin/pip3 | 8 + .../env/bin/pip3.8 | 8 + .../env/bin/python | 1 + .../env/bin/python3 | 1 + .../Authlib-0.15.2.dist-info/INSTALLER | 1 + .../Authlib-0.15.2.dist-info/LICENSE | 29 + .../Authlib-0.15.2.dist-info/METADATA | 109 + .../Authlib-0.15.2.dist-info/RECORD | 361 + .../Authlib-0.15.2.dist-info/REQUESTED | 0 .../Authlib-0.15.2.dist-info/WHEEL | 6 + .../Authlib-0.15.2.dist-info/top_level.txt | 1 + .../Flask-1.1.2.dist-info/INSTALLER | 1 + .../Flask-1.1.2.dist-info/LICENSE.rst | 28 + .../Flask-1.1.2.dist-info/METADATA | 137 + .../Flask-1.1.2.dist-info/RECORD | 49 + .../Flask-1.1.2.dist-info/REQUESTED | 0 .../site-packages/Flask-1.1.2.dist-info/WHEEL | 6 + .../Flask-1.1.2.dist-info/entry_points.txt | 3 + .../Flask-1.1.2.dist-info/top_level.txt | 1 + .../Jinja2-2.11.2.dist-info/INSTALLER | 1 + .../Jinja2-2.11.2.dist-info/LICENSE.rst | 28 + .../Jinja2-2.11.2.dist-info/METADATA | 106 + .../Jinja2-2.11.2.dist-info/RECORD | 61 + .../Jinja2-2.11.2.dist-info/WHEEL | 6 + .../Jinja2-2.11.2.dist-info/entry_points.txt | 3 + .../Jinja2-2.11.2.dist-info/top_level.txt | 1 + .../MarkupSafe-1.1.1.dist-info/INSTALLER | 1 + .../MarkupSafe-1.1.1.dist-info/LICENSE.txt | 28 + .../MarkupSafe-1.1.1.dist-info/METADATA | 105 + .../MarkupSafe-1.1.1.dist-info/RECORD | 16 + .../MarkupSafe-1.1.1.dist-info/WHEEL | 5 + .../MarkupSafe-1.1.1.dist-info/top_level.txt | 1 + .../Werkzeug-1.0.1.dist-info/INSTALLER | 1 + .../Werkzeug-1.0.1.dist-info/LICENSE.rst | 28 + .../Werkzeug-1.0.1.dist-info/METADATA | 128 + .../Werkzeug-1.0.1.dist-info/RECORD | 101 + .../Werkzeug-1.0.1.dist-info/WHEEL | 6 + .../Werkzeug-1.0.1.dist-info/top_level.txt | 1 + ...ffi_backend.cpython-38-x86_64-linux-gnu.so | Bin 0 -> 886648 bytes .../site-packages/authlib/__init__.py | 17 + .../site-packages/authlib/common/__init__.py | 0 .../site-packages/authlib/common/encoding.py | 88 + .../site-packages/authlib/common/errors.py | 76 + .../site-packages/authlib/common/security.py | 19 + .../site-packages/authlib/common/urls.py | 162 + .../python3.8/site-packages/authlib/consts.py | 11 + .../site-packages/authlib/deprecate.py | 16 + .../authlib/integrations/__init__.py | 0 .../integrations/base_client/__init__.py | 16 + .../integrations/base_client/async_app.py | 205 + .../integrations/base_client/base_app.py | 244 + .../integrations/base_client/base_oauth.py | 120 + .../integrations/base_client/errors.py | 30 + .../base_client/framework_integration.py | 25 + .../integrations/base_client/remote_app.py | 204 + .../integrations/django_client/__init__.py | 15 + .../integrations/django_client/integration.py | 76 + .../authlib/integrations/django_helpers.py | 72 + .../integrations/django_oauth1/__init__.py | 9 + .../django_oauth1/authorization_server.py | 121 + .../integrations/django_oauth1/nonce.py | 15 + .../django_oauth1/resource_protector.py | 66 + .../integrations/django_oauth2/__init__.py | 10 + .../django_oauth2/authorization_server.py | 152 + .../integrations/django_oauth2/endpoints.py | 59 + .../django_oauth2/resource_protector.py | 79 + .../integrations/django_oauth2/signals.py | 11 + .../integrations/flask_client/__init__.py | 11 + .../integrations/flask_client/integration.py | 61 + .../flask_client/oauth_registry.py | 118 + .../integrations/flask_client/remote_app.py | 81 + .../authlib/integrations/flask_helpers.py | 25 + .../integrations/flask_oauth1/__init__.py | 9 + .../flask_oauth1/authorization_server.py | 180 + .../integrations/flask_oauth1/cache.py | 80 + .../flask_oauth1/resource_protector.py | 114 + .../integrations/flask_oauth2/__init__.py | 12 + .../flask_oauth2/authorization_server.py | 212 + .../integrations/flask_oauth2/errors.py | 20 + .../flask_oauth2/resource_protector.py | 123 + .../integrations/flask_oauth2/signals.py | 12 + .../integrations/httpx_client/__init__.py | 25 + .../httpx_client/assertion_client.py | 89 + .../httpx_client/oauth1_client.py | 101 + .../httpx_client/oauth2_client.py | 214 + .../integrations/httpx_client/utils.py | 14 + .../integrations/requests_client/__init__.py | 22 + .../requests_client/assertion_session.py | 48 + .../requests_client/oauth1_session.py | 58 + .../requests_client/oauth2_session.py | 117 + .../integrations/sqla_oauth1/__init__.py | 17 + .../integrations/sqla_oauth1/functions.py | 154 + .../integrations/sqla_oauth1/mixins.py | 97 + .../integrations/sqla_oauth2/__init__.py | 17 + .../integrations/sqla_oauth2/client_mixin.py | 134 + .../integrations/sqla_oauth2/functions.py | 101 + .../integrations/sqla_oauth2/tokens_mixins.py | 62 + .../integrations/starlette_client/__init__.py | 20 + .../starlette_client/integration.py | 72 + .../site-packages/authlib/jose/__init__.py | 74 + .../authlib/jose/drafts/__init__.py | 3 + .../jose/drafts/_jwe_enc_cryptography.py | 54 + .../site-packages/authlib/jose/errors.py | 88 + .../site-packages/authlib/jose/jwk.py | 19 + .../authlib/jose/rfc7515/__init__.py | 18 + .../site-packages/authlib/jose/rfc7515/jws.py | 318 + .../authlib/jose/rfc7515/models.py | 81 + .../authlib/jose/rfc7516/__init__.py | 18 + .../site-packages/authlib/jose/rfc7516/jwe.py | 207 + .../authlib/jose/rfc7516/models.py | 78 + .../authlib/jose/rfc7517/__init__.py | 15 + .../authlib/jose/rfc7517/_cryptography_key.py | 34 + .../site-packages/authlib/jose/rfc7517/jwk.py | 63 + .../authlib/jose/rfc7517/models.py | 156 + .../authlib/jose/rfc7518/__init__.py | 19 + .../_cryptography_backends/__init__.py | 7 + .../_cryptography_backends/_jwe_alg.py | 268 + .../_cryptography_backends/_jwe_enc.py | 144 + .../rfc7518/_cryptography_backends/_jws.py | 159 + .../rfc7518/_cryptography_backends/_keys.py | 306 + .../authlib/jose/rfc7518/jwe_algorithms.py | 50 + .../authlib/jose/rfc7518/jws_algorithms.py | 68 + .../authlib/jose/rfc7518/oct_key.py | 48 + .../authlib/jose/rfc7518/util.py | 12 + .../authlib/jose/rfc7519/__init__.py | 16 + .../authlib/jose/rfc7519/claims.py | 214 + .../site-packages/authlib/jose/rfc7519/jwt.py | 138 + .../authlib/jose/rfc8037/__init__.py | 5 + .../authlib/jose/rfc8037/_jws_cryptography.py | 32 + .../authlib/jose/rfc8037/okp_key.py | 130 + .../site-packages/authlib/jose/util.py | 23 + .../site-packages/authlib/oauth1/__init__.py | 36 + .../site-packages/authlib/oauth1/client.py | 189 + .../site-packages/authlib/oauth1/errors.py | 3 + .../authlib/oauth1/rfc5849/__init__.py | 45 + .../oauth1/rfc5849/authorization_server.py | 357 + .../authlib/oauth1/rfc5849/base_server.py | 119 + .../authlib/oauth1/rfc5849/client_auth.py | 184 + .../authlib/oauth1/rfc5849/errors.py | 100 + .../authlib/oauth1/rfc5849/models.py | 109 + .../authlib/oauth1/rfc5849/parameters.py | 103 + .../oauth1/rfc5849/resource_protector.py | 41 + .../authlib/oauth1/rfc5849/rsa.py | 29 + .../authlib/oauth1/rfc5849/signature.py | 387 + .../authlib/oauth1/rfc5849/util.py | 9 + .../authlib/oauth1/rfc5849/wrapper.py | 129 + .../site-packages/authlib/oauth2/__init__.py | 16 + .../site-packages/authlib/oauth2/auth.py | 105 + .../site-packages/authlib/oauth2/base.py | 27 + .../site-packages/authlib/oauth2/client.py | 415 + .../authlib/oauth2/rfc6749/__init__.py | 77 + .../oauth2/rfc6749/authenticate_client.py | 124 + .../oauth2/rfc6749/authorization_server.py | 240 + .../authlib/oauth2/rfc6749/errors.py | 200 + .../authlib/oauth2/rfc6749/grants/__init__.py | 37 + .../rfc6749/grants/authorization_code.py | 384 + .../authlib/oauth2/rfc6749/grants/base.py | 151 + .../rfc6749/grants/client_credentials.py | 103 + .../authlib/oauth2/rfc6749/grants/implicit.py | 229 + .../oauth2/rfc6749/grants/refresh_token.py | 183 + .../resource_owner_password_credentials.py | 154 + .../authlib/oauth2/rfc6749/models.py | 212 + .../authlib/oauth2/rfc6749/parameters.py | 213 + .../oauth2/rfc6749/resource_protector.py | 37 + .../authlib/oauth2/rfc6749/token_endpoint.py | 34 + .../authlib/oauth2/rfc6749/util.py | 40 + .../authlib/oauth2/rfc6749/wrappers.py | 96 + .../authlib/oauth2/rfc6750/__init__.py | 23 + .../authlib/oauth2/rfc6750/errors.py | 85 + .../authlib/oauth2/rfc6750/parameters.py | 41 + .../authlib/oauth2/rfc6750/validator.py | 99 + .../authlib/oauth2/rfc6750/wrappers.py | 97 + .../authlib/oauth2/rfc7009/__init__.py | 15 + .../authlib/oauth2/rfc7009/parameters.py | 25 + .../authlib/oauth2/rfc7009/revocation.py | 98 + .../authlib/oauth2/rfc7521/__init__.py | 3 + .../authlib/oauth2/rfc7521/client.py | 84 + .../authlib/oauth2/rfc7523/__init__.py | 34 + .../authlib/oauth2/rfc7523/assertion.py | 66 + .../authlib/oauth2/rfc7523/auth.py | 100 + .../authlib/oauth2/rfc7523/client.py | 113 + .../authlib/oauth2/rfc7523/jwt_bearer.py | 155 + .../authlib/oauth2/rfc7591/__init__.py | 25 + .../authlib/oauth2/rfc7591/claims.py | 218 + .../authlib/oauth2/rfc7591/endpoint.py | 199 + .../authlib/oauth2/rfc7591/errors.py | 33 + .../authlib/oauth2/rfc7592/__init__.py | 13 + .../authlib/oauth2/rfc7592/endpoint.py | 172 + .../authlib/oauth2/rfc7636/__init__.py | 14 + .../authlib/oauth2/rfc7636/challenge.py | 134 + .../authlib/oauth2/rfc7662/__init__.py | 15 + .../authlib/oauth2/rfc7662/introspection.py | 119 + .../authlib/oauth2/rfc7662/models.py | 30 + .../authlib/oauth2/rfc8414/__init__.py | 16 + .../authlib/oauth2/rfc8414/models.py | 368 + .../authlib/oauth2/rfc8414/well_known.py | 22 + .../authlib/oauth2/rfc8628/__init__.py | 23 + .../authlib/oauth2/rfc8628/device_code.py | 198 + .../authlib/oauth2/rfc8628/endpoint.py | 148 + .../authlib/oauth2/rfc8628/errors.py | 27 + .../authlib/oauth2/rfc8628/models.py | 27 + .../authlib/oauth2/rfc8693/__init__.py | 10 + .../site-packages/authlib/oidc/__init__.py | 0 .../authlib/oidc/core/__init__.py | 23 + .../site-packages/authlib/oidc/core/claims.py | 242 + .../site-packages/authlib/oidc/core/errors.py | 78 + .../authlib/oidc/core/grants/__init__.py | 9 + .../authlib/oidc/core/grants/code.py | 119 + .../authlib/oidc/core/grants/hybrid.py | 97 + .../authlib/oidc/core/grants/implicit.py | 151 + .../authlib/oidc/core/grants/util.py | 155 + .../site-packages/authlib/oidc/core/models.py | 13 + .../site-packages/authlib/oidc/core/util.py | 12 + .../authlib/oidc/discovery/__init__.py | 13 + .../authlib/oidc/discovery/models.py | 283 + .../authlib/oidc/discovery/well_known.py | 17 + .../certifi-2020.11.8.dist-info/INSTALLER | 1 + .../certifi-2020.11.8.dist-info/LICENSE | 21 + .../certifi-2020.11.8.dist-info/METADATA | 83 + .../certifi-2020.11.8.dist-info/RECORD | 13 + .../certifi-2020.11.8.dist-info/WHEEL | 6 + .../certifi-2020.11.8.dist-info/top_level.txt | 1 + .../site-packages/certifi/__init__.py | 3 + .../site-packages/certifi/__main__.py | 12 + .../site-packages/certifi/cacert.pem | 4606 +++++++++ .../python3.8/site-packages/certifi/core.py | 60 + .../cffi-1.14.3.dist-info/INSTALLER | 1 + .../cffi-1.14.3.dist-info/LICENSE | 26 + .../cffi-1.14.3.dist-info/METADATA | 37 + .../cffi-1.14.3.dist-info/RECORD | 45 + .../site-packages/cffi-1.14.3.dist-info/WHEEL | 5 + .../cffi-1.14.3.dist-info/entry_points.txt | 3 + .../cffi-1.14.3.dist-info/top_level.txt | 2 + .../cffi.libs/libffi-806b1a9d.so.6.0.4 | Bin 0 -> 46632 bytes .../python3.8/site-packages/cffi/__init__.py | 14 + .../site-packages/cffi/_cffi_errors.h | 147 + .../site-packages/cffi/_cffi_include.h | 385 + .../python3.8/site-packages/cffi/_embedding.h | 527 ++ .../lib/python3.8/site-packages/cffi/api.py | 965 ++ .../site-packages/cffi/backend_ctypes.py | 1121 +++ .../site-packages/cffi/cffi_opcode.py | 187 + .../site-packages/cffi/commontypes.py | 80 + .../python3.8/site-packages/cffi/cparser.py | 1006 ++ .../lib/python3.8/site-packages/cffi/error.py | 31 + .../site-packages/cffi/ffiplatform.py | 127 + .../lib/python3.8/site-packages/cffi/lock.py | 30 + .../lib/python3.8/site-packages/cffi/model.py | 617 ++ .../site-packages/cffi/parse_c_type.h | 181 + .../python3.8/site-packages/cffi/pkgconfig.py | 121 + .../site-packages/cffi/recompiler.py | 1571 ++++ .../site-packages/cffi/setuptools_ext.py | 219 + .../site-packages/cffi/vengine_cpy.py | 1076 +++ .../site-packages/cffi/vengine_gen.py | 675 ++ .../python3.8/site-packages/cffi/verifier.py | 306 + .../chardet-3.0.4.dist-info/DESCRIPTION.rst | 70 + .../chardet-3.0.4.dist-info/INSTALLER | 1 + .../chardet-3.0.4.dist-info/METADATA | 96 + .../chardet-3.0.4.dist-info/RECORD | 91 + .../chardet-3.0.4.dist-info/WHEEL | 6 + .../chardet-3.0.4.dist-info/entry_points.txt | 3 + .../chardet-3.0.4.dist-info/metadata.json | 1 + .../chardet-3.0.4.dist-info/top_level.txt | 1 + .../site-packages/chardet/__init__.py | 39 + .../site-packages/chardet/big5freq.py | 386 + .../site-packages/chardet/big5prober.py | 47 + .../site-packages/chardet/chardistribution.py | 233 + .../chardet/charsetgroupprober.py | 106 + .../site-packages/chardet/charsetprober.py | 145 + .../site-packages/chardet/cli/__init__.py | 1 + .../site-packages/chardet/cli/chardetect.py | 85 + .../chardet/codingstatemachine.py | 88 + .../python3.8/site-packages/chardet/compat.py | 34 + .../site-packages/chardet/cp949prober.py | 49 + .../python3.8/site-packages/chardet/enums.py | 76 + .../site-packages/chardet/escprober.py | 101 + .../python3.8/site-packages/chardet/escsm.py | 246 + .../site-packages/chardet/eucjpprober.py | 92 + .../site-packages/chardet/euckrfreq.py | 195 + .../site-packages/chardet/euckrprober.py | 47 + .../site-packages/chardet/euctwfreq.py | 387 + .../site-packages/chardet/euctwprober.py | 46 + .../site-packages/chardet/gb2312freq.py | 283 + .../site-packages/chardet/gb2312prober.py | 46 + .../site-packages/chardet/hebrewprober.py | 292 + .../site-packages/chardet/jisfreq.py | 325 + .../python3.8/site-packages/chardet/jpcntx.py | 233 + .../chardet/langbulgarianmodel.py | 228 + .../chardet/langcyrillicmodel.py | 333 + .../site-packages/chardet/langgreekmodel.py | 225 + .../site-packages/chardet/langhebrewmodel.py | 200 + .../chardet/langhungarianmodel.py | 225 + .../site-packages/chardet/langthaimodel.py | 199 + .../site-packages/chardet/langturkishmodel.py | 193 + .../site-packages/chardet/latin1prober.py | 145 + .../site-packages/chardet/mbcharsetprober.py | 91 + .../site-packages/chardet/mbcsgroupprober.py | 54 + .../python3.8/site-packages/chardet/mbcssm.py | 572 ++ .../site-packages/chardet/sbcharsetprober.py | 132 + .../site-packages/chardet/sbcsgroupprober.py | 73 + .../site-packages/chardet/sjisprober.py | 92 + .../chardet/universaldetector.py | 286 + .../site-packages/chardet/utf8prober.py | 82 + .../site-packages/chardet/version.py | 9 + .../click-7.1.2.dist-info/INSTALLER | 1 + .../click-7.1.2.dist-info/LICENSE.rst | 28 + .../click-7.1.2.dist-info/METADATA | 102 + .../click-7.1.2.dist-info/RECORD | 40 + .../site-packages/click-7.1.2.dist-info/WHEEL | 6 + .../click-7.1.2.dist-info/top_level.txt | 1 + .../python3.8/site-packages/click/__init__.py | 79 + .../site-packages/click/_bashcomplete.py | 375 + .../python3.8/site-packages/click/_compat.py | 786 ++ .../site-packages/click/_termui_impl.py | 657 ++ .../site-packages/click/_textwrap.py | 37 + .../site-packages/click/_unicodefun.py | 131 + .../site-packages/click/_winconsole.py | 370 + .../lib/python3.8/site-packages/click/core.py | 2030 ++++ .../site-packages/click/decorators.py | 333 + .../site-packages/click/exceptions.py | 253 + .../site-packages/click/formatting.py | 283 + .../python3.8/site-packages/click/globals.py | 47 + .../python3.8/site-packages/click/parser.py | 428 + .../python3.8/site-packages/click/termui.py | 681 ++ .../python3.8/site-packages/click/testing.py | 382 + .../python3.8/site-packages/click/types.py | 762 ++ .../python3.8/site-packages/click/utils.py | 455 + .../cryptography-3.2.1.dist-info/AUTHORS.rst | 44 + .../cryptography-3.2.1.dist-info/INSTALLER | 1 + .../cryptography-3.2.1.dist-info/LICENSE | 6 + .../LICENSE.APACHE | 202 + .../cryptography-3.2.1.dist-info/LICENSE.BSD | 27 + .../cryptography-3.2.1.dist-info/LICENSE.PSF | 41 + .../cryptography-3.2.1.dist-info/METADATA | 134 + .../cryptography-3.2.1.dist-info/RECORD | 178 + .../cryptography-3.2.1.dist-info/WHEEL | 5 + .../top_level.txt | 3 + .../site-packages/cryptography/__about__.py | 31 + .../site-packages/cryptography/__init__.py | 48 + .../site-packages/cryptography/exceptions.py | 58 + .../site-packages/cryptography/fernet.py | 190 + .../cryptography/hazmat/__init__.py | 11 + .../site-packages/cryptography/hazmat/_der.py | 156 + .../site-packages/cryptography/hazmat/_oid.py | 77 + .../cryptography/hazmat/backends/__init__.py | 26 + .../hazmat/backends/interfaces.py | 396 + .../hazmat/backends/openssl/__init__.py | 10 + .../hazmat/backends/openssl/aead.py | 166 + .../hazmat/backends/openssl/backend.py | 2785 ++++++ .../hazmat/backends/openssl/ciphers.py | 231 + .../hazmat/backends/openssl/cmac.py | 82 + .../hazmat/backends/openssl/decode_asn1.py | 878 ++ .../hazmat/backends/openssl/dh.py | 271 + .../hazmat/backends/openssl/dsa.py | 263 + .../hazmat/backends/openssl/ec.py | 337 + .../hazmat/backends/openssl/ed25519.py | 145 + .../hazmat/backends/openssl/ed448.py | 146 + .../hazmat/backends/openssl/encode_asn1.py | 657 ++ .../hazmat/backends/openssl/hashes.py | 82 + .../hazmat/backends/openssl/hmac.py | 78 + .../hazmat/backends/openssl/ocsp.py | 401 + .../hazmat/backends/openssl/poly1305.py | 65 + .../hazmat/backends/openssl/rsa.py | 465 + .../hazmat/backends/openssl/utils.py | 65 + .../hazmat/backends/openssl/x25519.py | 123 + .../hazmat/backends/openssl/x448.py | 107 + .../hazmat/backends/openssl/x509.py | 587 ++ .../cryptography/hazmat/bindings/__init__.py | 5 + .../hazmat/bindings/_openssl.abi3.so | Bin 0 -> 7050912 bytes .../hazmat/bindings/_padding.abi3.so | Bin 0 -> 37232 bytes .../hazmat/bindings/openssl/__init__.py | 5 + .../hazmat/bindings/openssl/_conditional.py | 345 + .../hazmat/bindings/openssl/binding.py | 222 + .../hazmat/primitives/__init__.py | 5 + .../hazmat/primitives/asymmetric/__init__.py | 40 + .../hazmat/primitives/asymmetric/dh.py | 216 + .../hazmat/primitives/asymmetric/dsa.py | 261 + .../hazmat/primitives/asymmetric/ec.py | 502 + .../hazmat/primitives/asymmetric/ed25519.py | 87 + .../hazmat/primitives/asymmetric/ed448.py | 82 + .../hazmat/primitives/asymmetric/padding.py | 80 + .../hazmat/primitives/asymmetric/rsa.py | 374 + .../hazmat/primitives/asymmetric/utils.py | 41 + .../hazmat/primitives/asymmetric/x25519.py | 76 + .../hazmat/primitives/asymmetric/x448.py | 76 + .../hazmat/primitives/ciphers/__init__.py | 26 + .../hazmat/primitives/ciphers/aead.py | 174 + .../hazmat/primitives/ciphers/algorithms.py | 170 + .../hazmat/primitives/ciphers/base.py | 241 + .../hazmat/primitives/ciphers/modes.py | 223 + .../cryptography/hazmat/primitives/cmac.py | 64 + .../hazmat/primitives/constant_time.py | 14 + .../cryptography/hazmat/primitives/hashes.py | 259 + .../cryptography/hazmat/primitives/hmac.py | 70 + .../hazmat/primitives/kdf/__init__.py | 26 + .../hazmat/primitives/kdf/concatkdf.py | 131 + .../hazmat/primitives/kdf/hkdf.py | 115 + .../hazmat/primitives/kdf/kbkdf.py | 162 + .../hazmat/primitives/kdf/pbkdf2.py | 62 + .../hazmat/primitives/kdf/scrypt.py | 68 + .../hazmat/primitives/kdf/x963kdf.py | 74 + .../cryptography/hazmat/primitives/keywrap.py | 161 + .../cryptography/hazmat/primitives/padding.py | 208 + .../hazmat/primitives/poly1305.py | 58 + .../primitives/serialization/__init__.py | 44 + .../hazmat/primitives/serialization/base.py | 91 + .../hazmat/primitives/serialization/pkcs12.py | 50 + .../hazmat/primitives/serialization/pkcs7.py | 132 + .../hazmat/primitives/serialization/ssh.py | 683 ++ .../hazmat/primitives/twofactor/__init__.py | 9 + .../hazmat/primitives/twofactor/hotp.py | 69 + .../hazmat/primitives/twofactor/totp.py | 51 + .../hazmat/primitives/twofactor/utils.py | 33 + .../site-packages/cryptography/utils.py | 171 + .../cryptography/x509/__init__.py | 248 + .../site-packages/cryptography/x509/base.py | 892 ++ .../x509/certificate_transparency.py | 46 + .../cryptography/x509/extensions.py | 1702 ++++ .../cryptography/x509/general_name.py | 294 + .../site-packages/cryptography/x509/name.py | 261 + .../site-packages/cryptography/x509/ocsp.py | 467 + .../site-packages/cryptography/x509/oid.py | 265 + .../python3.8/site-packages/easy_install.py | 5 + .../python3.8/site-packages/flask/__init__.py | 60 + .../python3.8/site-packages/flask/__main__.py | 15 + .../python3.8/site-packages/flask/_compat.py | 145 + .../lib/python3.8/site-packages/flask/app.py | 2467 +++++ .../site-packages/flask/blueprints.py | 569 ++ .../lib/python3.8/site-packages/flask/cli.py | 971 ++ .../python3.8/site-packages/flask/config.py | 269 + .../lib/python3.8/site-packages/flask/ctx.py | 475 + .../site-packages/flask/debughelpers.py | 183 + .../python3.8/site-packages/flask/globals.py | 62 + .../python3.8/site-packages/flask/helpers.py | 1155 +++ .../site-packages/flask/json/__init__.py | 376 + .../python3.8/site-packages/flask/json/tag.py | 309 + .../python3.8/site-packages/flask/logging.py | 109 + .../python3.8/site-packages/flask/sessions.py | 388 + .../python3.8/site-packages/flask/signals.py | 65 + .../site-packages/flask/templating.py | 155 + .../python3.8/site-packages/flask/testing.py | 283 + .../python3.8/site-packages/flask/views.py | 163 + .../python3.8/site-packages/flask/wrappers.py | 137 + .../idna-2.10.dist-info/INSTALLER | 1 + .../idna-2.10.dist-info/LICENSE.rst | 34 + .../idna-2.10.dist-info/METADATA | 243 + .../site-packages/idna-2.10.dist-info/RECORD | 22 + .../site-packages/idna-2.10.dist-info/WHEEL | 6 + .../idna-2.10.dist-info/top_level.txt | 1 + .../python3.8/site-packages/idna/__init__.py | 2 + .../lib/python3.8/site-packages/idna/codec.py | 118 + .../python3.8/site-packages/idna/compat.py | 12 + .../lib/python3.8/site-packages/idna/core.py | 400 + .../python3.8/site-packages/idna/idnadata.py | 2050 ++++ .../python3.8/site-packages/idna/intranges.py | 53 + .../site-packages/idna/package_data.py | 2 + .../python3.8/site-packages/idna/uts46data.py | 8357 +++++++++++++++++ .../itsdangerous-1.1.0.dist-info/INSTALLER | 1 + .../itsdangerous-1.1.0.dist-info/LICENSE.rst | 47 + .../itsdangerous-1.1.0.dist-info/METADATA | 98 + .../itsdangerous-1.1.0.dist-info/RECORD | 26 + .../itsdangerous-1.1.0.dist-info/WHEEL | 6 + .../top_level.txt | 1 + .../site-packages/itsdangerous/__init__.py | 22 + .../site-packages/itsdangerous/_compat.py | 46 + .../site-packages/itsdangerous/_json.py | 18 + .../site-packages/itsdangerous/encoding.py | 49 + .../site-packages/itsdangerous/exc.py | 98 + .../site-packages/itsdangerous/jws.py | 218 + .../site-packages/itsdangerous/serializer.py | 233 + .../site-packages/itsdangerous/signer.py | 179 + .../site-packages/itsdangerous/timed.py | 147 + .../site-packages/itsdangerous/url_safe.py | 65 + .../site-packages/jinja2/__init__.py | 44 + .../python3.8/site-packages/jinja2/_compat.py | 132 + .../site-packages/jinja2/_identifier.py | 6 + .../site-packages/jinja2/asyncfilters.py | 158 + .../site-packages/jinja2/asyncsupport.py | 264 + .../python3.8/site-packages/jinja2/bccache.py | 350 + .../site-packages/jinja2/compiler.py | 1843 ++++ .../site-packages/jinja2/constants.py | 21 + .../python3.8/site-packages/jinja2/debug.py | 268 + .../site-packages/jinja2/defaults.py | 44 + .../site-packages/jinja2/environment.py | 1362 +++ .../site-packages/jinja2/exceptions.py | 177 + .../lib/python3.8/site-packages/jinja2/ext.py | 704 ++ .../python3.8/site-packages/jinja2/filters.py | 1382 +++ .../site-packages/jinja2/idtracking.py | 290 + .../python3.8/site-packages/jinja2/lexer.py | 848 ++ .../python3.8/site-packages/jinja2/loaders.py | 504 + .../python3.8/site-packages/jinja2/meta.py | 101 + .../site-packages/jinja2/nativetypes.py | 94 + .../python3.8/site-packages/jinja2/nodes.py | 1088 +++ .../site-packages/jinja2/optimizer.py | 41 + .../python3.8/site-packages/jinja2/parser.py | 939 ++ .../python3.8/site-packages/jinja2/runtime.py | 1011 ++ .../python3.8/site-packages/jinja2/sandbox.py | 510 + .../python3.8/site-packages/jinja2/tests.py | 215 + .../python3.8/site-packages/jinja2/utils.py | 732 ++ .../python3.8/site-packages/jinja2/visitor.py | 81 + .../site-packages/markupsafe/__init__.py | 327 + .../site-packages/markupsafe/_compat.py | 33 + .../site-packages/markupsafe/_constants.py | 264 + .../site-packages/markupsafe/_native.py | 69 + .../site-packages/markupsafe/_speedups.c | 423 + .../_speedups.cpython-38-x86_64-linux-gnu.so | Bin 0 -> 48016 bytes .../pip-20.2.1.dist-info/INSTALLER | 1 + .../pip-20.2.1.dist-info/LICENSE.txt | 20 + .../pip-20.2.1.dist-info/METADATA | 88 + .../site-packages/pip-20.2.1.dist-info/RECORD | 752 ++ .../pip-20.2.1.dist-info/REQUESTED | 0 .../site-packages/pip-20.2.1.dist-info/WHEEL | 6 + .../pip-20.2.1.dist-info/entry_points.txt | 5 + .../pip-20.2.1.dist-info/top_level.txt | 1 + .../python3.8/site-packages/pip/__init__.py | 18 + .../python3.8/site-packages/pip/__main__.py | 26 + .../site-packages/pip/_internal/__init__.py | 17 + .../site-packages/pip/_internal/build_env.py | 241 + .../site-packages/pip/_internal/cache.py | 346 + .../pip/_internal/cli/__init__.py | 4 + .../pip/_internal/cli/autocompletion.py | 164 + .../pip/_internal/cli/base_command.py | 253 + .../pip/_internal/cli/cmdoptions.py | 975 ++ .../pip/_internal/cli/command_context.py | 36 + .../site-packages/pip/_internal/cli/main.py | 75 + .../pip/_internal/cli/main_parser.py | 99 + .../site-packages/pip/_internal/cli/parser.py | 266 + .../pip/_internal/cli/progress_bars.py | 280 + .../pip/_internal/cli/req_command.py | 402 + .../pip/_internal/cli/spinners.py | 173 + .../pip/_internal/cli/status_codes.py | 8 + .../pip/_internal/commands/__init__.py | 122 + .../pip/_internal/commands/cache.py | 182 + .../pip/_internal/commands/check.py | 51 + .../pip/_internal/commands/completion.py | 98 + .../pip/_internal/commands/configuration.py | 284 + .../pip/_internal/commands/debug.py | 229 + .../pip/_internal/commands/download.py | 143 + .../pip/_internal/commands/freeze.py | 103 + .../pip/_internal/commands/hash.py | 63 + .../pip/_internal/commands/help.py | 44 + .../pip/_internal/commands/install.py | 764 ++ .../pip/_internal/commands/list.py | 320 + .../pip/_internal/commands/search.py | 159 + .../pip/_internal/commands/show.py | 186 + .../pip/_internal/commands/uninstall.py | 95 + .../pip/_internal/commands/wheel.py | 188 + .../pip/_internal/configuration.py | 418 + .../pip/_internal/distributions/__init__.py | 24 + .../pip/_internal/distributions/base.py | 45 + .../pip/_internal/distributions/installed.py | 24 + .../pip/_internal/distributions/sdist.py | 104 + .../pip/_internal/distributions/wheel.py | 36 + .../site-packages/pip/_internal/exceptions.py | 381 + .../pip/_internal/index/__init__.py | 2 + .../pip/_internal/index/collector.py | 692 ++ .../pip/_internal/index/package_finder.py | 1014 ++ .../site-packages/pip/_internal/locations.py | 194 + .../site-packages/pip/_internal/main.py | 16 + .../pip/_internal/models/__init__.py | 2 + .../pip/_internal/models/candidate.py | 38 + .../pip/_internal/models/direct_url.py | 245 + .../pip/_internal/models/format_control.py | 92 + .../pip/_internal/models/index.py | 34 + .../pip/_internal/models/link.py | 245 + .../pip/_internal/models/scheme.py | 31 + .../pip/_internal/models/search_scope.py | 135 + .../pip/_internal/models/selection_prefs.py | 49 + .../pip/_internal/models/target_python.py | 120 + .../pip/_internal/models/wheel.py | 78 + .../pip/_internal/network/__init__.py | 2 + .../pip/_internal/network/auth.py | 308 + .../pip/_internal/network/cache.py | 79 + .../pip/_internal/network/download.py | 182 + .../pip/_internal/network/lazy_wheel.py | 233 + .../pip/_internal/network/session.py | 421 + .../pip/_internal/network/utils.py | 97 + .../pip/_internal/network/xmlrpc.py | 52 + .../pip/_internal/operations/__init__.py | 0 .../_internal/operations/build/__init__.py | 0 .../_internal/operations/build/metadata.py | 37 + .../operations/build/metadata_legacy.py | 77 + .../pip/_internal/operations/build/wheel.py | 46 + .../operations/build/wheel_legacy.py | 115 + .../pip/_internal/operations/check.py | 158 + .../pip/_internal/operations/freeze.py | 272 + .../_internal/operations/install/__init__.py | 2 + .../operations/install/editable_legacy.py | 52 + .../_internal/operations/install/legacy.py | 130 + .../pip/_internal/operations/install/wheel.py | 861 ++ .../pip/_internal/operations/prepare.py | 562 ++ .../site-packages/pip/_internal/pyproject.py | 196 + .../pip/_internal/req/__init__.py | 103 + .../pip/_internal/req/constructors.py | 486 + .../pip/_internal/req/req_file.py | 592 ++ .../pip/_internal/req/req_install.py | 892 ++ .../pip/_internal/req/req_set.py | 203 + .../pip/_internal/req/req_tracker.py | 150 + .../pip/_internal/req/req_uninstall.py | 648 ++ .../pip/_internal/resolution/__init__.py | 0 .../pip/_internal/resolution/base.py | 20 + .../_internal/resolution/legacy/__init__.py | 0 .../_internal/resolution/legacy/resolver.py | 485 + .../resolution/resolvelib/__init__.py | 0 .../_internal/resolution/resolvelib/base.py | 82 + .../resolution/resolvelib/candidates.py | 600 ++ .../resolution/resolvelib/factory.py | 459 + .../resolution/resolvelib/provider.py | 153 + .../resolution/resolvelib/requirements.py | 137 + .../resolution/resolvelib/resolver.py | 258 + .../pip/_internal/self_outdated_check.py | 205 + .../pip/_internal/utils/__init__.py | 0 .../pip/_internal/utils/appdirs.py | 44 + .../pip/_internal/utils/compat.py | 271 + .../pip/_internal/utils/compatibility_tags.py | 166 + .../pip/_internal/utils/datetime.py | 14 + .../pip/_internal/utils/deprecation.py | 104 + .../pip/_internal/utils/direct_url_helpers.py | 130 + .../pip/_internal/utils/distutils_args.py | 48 + .../pip/_internal/utils/encoding.py | 41 + .../pip/_internal/utils/entrypoints.py | 31 + .../pip/_internal/utils/filesystem.py | 224 + .../pip/_internal/utils/filetypes.py | 16 + .../pip/_internal/utils/glibc.py | 98 + .../pip/_internal/utils/hashes.py | 145 + .../_internal/utils/inject_securetransport.py | 36 + .../pip/_internal/utils/logging.py | 399 + .../site-packages/pip/_internal/utils/misc.py | 942 ++ .../pip/_internal/utils/models.py | 44 + .../pip/_internal/utils/packaging.py | 94 + .../pip/_internal/utils/parallel.py | 107 + .../pip/_internal/utils/pkg_resources.py | 44 + .../pip/_internal/utils/setuptools_build.py | 181 + .../pip/_internal/utils/subprocess.py | 280 + .../pip/_internal/utils/temp_dir.py | 274 + .../pip/_internal/utils/typing.py | 38 + .../pip/_internal/utils/unpacking.py | 281 + .../site-packages/pip/_internal/utils/urls.py | 55 + .../pip/_internal/utils/virtualenv.py | 116 + .../pip/_internal/utils/wheel.py | 225 + .../pip/_internal/vcs/__init__.py | 15 + .../site-packages/pip/_internal/vcs/bazaar.py | 119 + .../site-packages/pip/_internal/vcs/git.py | 397 + .../pip/_internal/vcs/mercurial.py | 158 + .../pip/_internal/vcs/subversion.py | 336 + .../pip/_internal/vcs/versioncontrol.py | 811 ++ .../pip/_internal/wheel_builder.py | 308 + .../site-packages/pip/_vendor/__init__.py | 110 + .../site-packages/pip/_vendor/appdirs.py | 633 ++ .../pip/_vendor/cachecontrol/__init__.py | 11 + .../pip/_vendor/cachecontrol/_cmd.py | 57 + .../pip/_vendor/cachecontrol/adapter.py | 133 + .../pip/_vendor/cachecontrol/cache.py | 39 + .../_vendor/cachecontrol/caches/__init__.py | 2 + .../_vendor/cachecontrol/caches/file_cache.py | 146 + .../cachecontrol/caches/redis_cache.py | 33 + .../pip/_vendor/cachecontrol/compat.py | 29 + .../pip/_vendor/cachecontrol/controller.py | 376 + .../pip/_vendor/cachecontrol/filewrapper.py | 80 + .../pip/_vendor/cachecontrol/heuristics.py | 135 + .../pip/_vendor/cachecontrol/serialize.py | 188 + .../pip/_vendor/cachecontrol/wrapper.py | 29 + .../pip/_vendor/certifi/__init__.py | 3 + .../pip/_vendor/certifi/__main__.py | 12 + .../pip/_vendor/certifi/cacert.pem | 4620 +++++++++ .../site-packages/pip/_vendor/certifi/core.py | 60 + .../pip/_vendor/chardet/__init__.py | 39 + .../pip/_vendor/chardet/big5freq.py | 386 + .../pip/_vendor/chardet/big5prober.py | 47 + .../pip/_vendor/chardet/chardistribution.py | 233 + .../pip/_vendor/chardet/charsetgroupprober.py | 106 + .../pip/_vendor/chardet/charsetprober.py | 145 + .../pip/_vendor/chardet/cli/__init__.py | 1 + .../pip/_vendor/chardet/cli/chardetect.py | 85 + .../pip/_vendor/chardet/codingstatemachine.py | 88 + .../pip/_vendor/chardet/compat.py | 34 + .../pip/_vendor/chardet/cp949prober.py | 49 + .../pip/_vendor/chardet/enums.py | 76 + .../pip/_vendor/chardet/escprober.py | 101 + .../pip/_vendor/chardet/escsm.py | 246 + .../pip/_vendor/chardet/eucjpprober.py | 92 + .../pip/_vendor/chardet/euckrfreq.py | 195 + .../pip/_vendor/chardet/euckrprober.py | 47 + .../pip/_vendor/chardet/euctwfreq.py | 387 + .../pip/_vendor/chardet/euctwprober.py | 46 + .../pip/_vendor/chardet/gb2312freq.py | 283 + .../pip/_vendor/chardet/gb2312prober.py | 46 + .../pip/_vendor/chardet/hebrewprober.py | 292 + .../pip/_vendor/chardet/jisfreq.py | 325 + .../pip/_vendor/chardet/jpcntx.py | 233 + .../pip/_vendor/chardet/langbulgarianmodel.py | 228 + .../pip/_vendor/chardet/langcyrillicmodel.py | 333 + .../pip/_vendor/chardet/langgreekmodel.py | 225 + .../pip/_vendor/chardet/langhebrewmodel.py | 200 + .../pip/_vendor/chardet/langhungarianmodel.py | 225 + .../pip/_vendor/chardet/langthaimodel.py | 199 + .../pip/_vendor/chardet/langturkishmodel.py | 193 + .../pip/_vendor/chardet/latin1prober.py | 145 + .../pip/_vendor/chardet/mbcharsetprober.py | 91 + .../pip/_vendor/chardet/mbcsgroupprober.py | 54 + .../pip/_vendor/chardet/mbcssm.py | 572 ++ .../pip/_vendor/chardet/sbcharsetprober.py | 132 + .../pip/_vendor/chardet/sbcsgroupprober.py | 73 + .../pip/_vendor/chardet/sjisprober.py | 92 + .../pip/_vendor/chardet/universaldetector.py | 286 + .../pip/_vendor/chardet/utf8prober.py | 82 + .../pip/_vendor/chardet/version.py | 9 + .../pip/_vendor/colorama/__init__.py | 6 + .../pip/_vendor/colorama/ansi.py | 102 + .../pip/_vendor/colorama/ansitowin32.py | 257 + .../pip/_vendor/colorama/initialise.py | 80 + .../pip/_vendor/colorama/win32.py | 152 + .../pip/_vendor/colorama/winterm.py | 169 + .../site-packages/pip/_vendor/contextlib2.py | 518 + .../pip/_vendor/distlib/__init__.py | 23 + .../pip/_vendor/distlib/_backport/__init__.py | 6 + .../pip/_vendor/distlib/_backport/misc.py | 41 + .../pip/_vendor/distlib/_backport/shutil.py | 764 ++ .../_vendor/distlib/_backport/sysconfig.cfg | 84 + .../_vendor/distlib/_backport/sysconfig.py | 786 ++ .../pip/_vendor/distlib/_backport/tarfile.py | 2607 +++++ .../pip/_vendor/distlib/compat.py | 1120 +++ .../pip/_vendor/distlib/database.py | 1339 +++ .../pip/_vendor/distlib/index.py | 516 + .../pip/_vendor/distlib/locators.py | 1302 +++ .../pip/_vendor/distlib/manifest.py | 393 + .../pip/_vendor/distlib/markers.py | 131 + .../pip/_vendor/distlib/metadata.py | 1056 +++ .../pip/_vendor/distlib/resources.py | 355 + .../pip/_vendor/distlib/scripts.py | 419 + .../site-packages/pip/_vendor/distlib/t32.exe | Bin 0 -> 96768 bytes .../site-packages/pip/_vendor/distlib/t64.exe | Bin 0 -> 105984 bytes .../site-packages/pip/_vendor/distlib/util.py | 1761 ++++ .../pip/_vendor/distlib/version.py | 736 ++ .../site-packages/pip/_vendor/distlib/w32.exe | Bin 0 -> 90112 bytes .../site-packages/pip/_vendor/distlib/w64.exe | Bin 0 -> 99840 bytes .../pip/_vendor/distlib/wheel.py | 1018 ++ .../site-packages/pip/_vendor/distro.py | 1230 +++ .../pip/_vendor/html5lib/__init__.py | 35 + .../pip/_vendor/html5lib/_ihatexml.py | 289 + .../pip/_vendor/html5lib/_inputstream.py | 918 ++ .../pip/_vendor/html5lib/_tokenizer.py | 1735 ++++ .../pip/_vendor/html5lib/_trie/__init__.py | 5 + .../pip/_vendor/html5lib/_trie/_base.py | 40 + .../pip/_vendor/html5lib/_trie/py.py | 67 + .../pip/_vendor/html5lib/_utils.py | 159 + .../pip/_vendor/html5lib/constants.py | 2946 ++++++ .../pip/_vendor/html5lib/filters/__init__.py | 0 .../filters/alphabeticalattributes.py | 29 + .../pip/_vendor/html5lib/filters/base.py | 12 + .../html5lib/filters/inject_meta_charset.py | 73 + .../pip/_vendor/html5lib/filters/lint.py | 93 + .../_vendor/html5lib/filters/optionaltags.py | 207 + .../pip/_vendor/html5lib/filters/sanitizer.py | 916 ++ .../_vendor/html5lib/filters/whitespace.py | 38 + .../pip/_vendor/html5lib/html5parser.py | 2795 ++++++ .../pip/_vendor/html5lib/serializer.py | 409 + .../_vendor/html5lib/treeadapters/__init__.py | 30 + .../_vendor/html5lib/treeadapters/genshi.py | 54 + .../pip/_vendor/html5lib/treeadapters/sax.py | 50 + .../_vendor/html5lib/treebuilders/__init__.py | 88 + .../pip/_vendor/html5lib/treebuilders/base.py | 417 + .../pip/_vendor/html5lib/treebuilders/dom.py | 239 + .../_vendor/html5lib/treebuilders/etree.py | 343 + .../html5lib/treebuilders/etree_lxml.py | 392 + .../_vendor/html5lib/treewalkers/__init__.py | 154 + .../pip/_vendor/html5lib/treewalkers/base.py | 252 + .../pip/_vendor/html5lib/treewalkers/dom.py | 43 + .../pip/_vendor/html5lib/treewalkers/etree.py | 131 + .../html5lib/treewalkers/etree_lxml.py | 215 + .../_vendor/html5lib/treewalkers/genshi.py | 69 + .../pip/_vendor/idna/__init__.py | 2 + .../site-packages/pip/_vendor/idna/codec.py | 118 + .../site-packages/pip/_vendor/idna/compat.py | 12 + .../site-packages/pip/_vendor/idna/core.py | 400 + .../pip/_vendor/idna/idnadata.py | 2050 ++++ .../pip/_vendor/idna/intranges.py | 53 + .../pip/_vendor/idna/package_data.py | 2 + .../pip/_vendor/idna/uts46data.py | 8357 +++++++++++++++++ .../site-packages/pip/_vendor/ipaddress.py | 2420 +++++ .../pip/_vendor/msgpack/__init__.py | 54 + .../pip/_vendor/msgpack/_version.py | 1 + .../pip/_vendor/msgpack/exceptions.py | 48 + .../site-packages/pip/_vendor/msgpack/ext.py | 191 + .../pip/_vendor/msgpack/fallback.py | 1063 +++ .../pip/_vendor/packaging/__about__.py | 27 + .../pip/_vendor/packaging/__init__.py | 26 + .../pip/_vendor/packaging/_compat.py | 38 + .../pip/_vendor/packaging/_structures.py | 86 + .../pip/_vendor/packaging/_typing.py | 48 + .../pip/_vendor/packaging/markers.py | 328 + .../pip/_vendor/packaging/requirements.py | 145 + .../pip/_vendor/packaging/specifiers.py | 863 ++ .../pip/_vendor/packaging/tags.py | 751 ++ .../pip/_vendor/packaging/utils.py | 65 + .../pip/_vendor/packaging/version.py | 535 ++ .../pip/_vendor/pep517/__init__.py | 4 + .../pip/_vendor/pep517/_in_process.py | 280 + .../site-packages/pip/_vendor/pep517/build.py | 124 + .../site-packages/pip/_vendor/pep517/check.py | 203 + .../pip/_vendor/pep517/colorlog.py | 115 + .../pip/_vendor/pep517/compat.py | 34 + .../pip/_vendor/pep517/dirtools.py | 44 + .../pip/_vendor/pep517/envbuild.py | 167 + .../site-packages/pip/_vendor/pep517/meta.py | 92 + .../pip/_vendor/pep517/wrappers.py | 308 + .../pip/_vendor/pkg_resources/__init__.py | 3296 +++++++ .../pip/_vendor/pkg_resources/py31compat.py | 23 + .../pip/_vendor/progress/__init__.py | 177 + .../site-packages/pip/_vendor/progress/bar.py | 91 + .../pip/_vendor/progress/counter.py | 41 + .../pip/_vendor/progress/spinner.py | 43 + .../site-packages/pip/_vendor/pyparsing.py | 7107 ++++++++++++++ .../pip/_vendor/requests/__init__.py | 144 + .../pip/_vendor/requests/__version__.py | 14 + .../pip/_vendor/requests/_internal_utils.py | 42 + .../pip/_vendor/requests/adapters.py | 533 ++ .../site-packages/pip/_vendor/requests/api.py | 161 + .../pip/_vendor/requests/auth.py | 305 + .../pip/_vendor/requests/certs.py | 18 + .../pip/_vendor/requests/compat.py | 76 + .../pip/_vendor/requests/cookies.py | 549 ++ .../pip/_vendor/requests/exceptions.py | 123 + .../pip/_vendor/requests/help.py | 119 + .../pip/_vendor/requests/hooks.py | 34 + .../pip/_vendor/requests/models.py | 954 ++ .../pip/_vendor/requests/packages.py | 16 + .../pip/_vendor/requests/sessions.py | 769 ++ .../pip/_vendor/requests/status_codes.py | 123 + .../pip/_vendor/requests/structures.py | 105 + .../pip/_vendor/requests/utils.py | 982 ++ .../pip/_vendor/resolvelib/__init__.py | 26 + .../pip/_vendor/resolvelib/compat/__init__.py | 0 .../resolvelib/compat/collections_abc.py | 6 + .../pip/_vendor/resolvelib/providers.py | 109 + .../pip/_vendor/resolvelib/reporters.py | 42 + .../pip/_vendor/resolvelib/resolvers.py | 428 + .../pip/_vendor/resolvelib/structs.py | 68 + .../site-packages/pip/_vendor/retrying.py | 267 + .../site-packages/pip/_vendor/six.py | 982 ++ .../pip/_vendor/toml/__init__.py | 25 + .../site-packages/pip/_vendor/toml/common.py | 6 + .../site-packages/pip/_vendor/toml/decoder.py | 1052 +++ .../site-packages/pip/_vendor/toml/encoder.py | 304 + .../site-packages/pip/_vendor/toml/ordered.py | 15 + .../site-packages/pip/_vendor/toml/tz.py | 21 + .../pip/_vendor/urllib3/__init__.py | 86 + .../pip/_vendor/urllib3/_collections.py | 336 + .../pip/_vendor/urllib3/connection.py | 423 + .../pip/_vendor/urllib3/connectionpool.py | 1033 ++ .../pip/_vendor/urllib3/contrib/__init__.py | 0 .../urllib3/contrib/_appengine_environ.py | 36 + .../contrib/_securetransport/__init__.py | 0 .../contrib/_securetransport/bindings.py | 493 + .../contrib/_securetransport/low_level.py | 328 + .../pip/_vendor/urllib3/contrib/appengine.py | 314 + .../pip/_vendor/urllib3/contrib/ntlmpool.py | 121 + .../pip/_vendor/urllib3/contrib/pyopenssl.py | 501 + .../urllib3/contrib/securetransport.py | 864 ++ .../pip/_vendor/urllib3/contrib/socks.py | 210 + .../pip/_vendor/urllib3/exceptions.py | 272 + .../pip/_vendor/urllib3/fields.py | 273 + .../pip/_vendor/urllib3/filepost.py | 98 + .../pip/_vendor/urllib3/packages/__init__.py | 5 + .../urllib3/packages/backports/__init__.py | 0 .../urllib3/packages/backports/makefile.py | 52 + .../pip/_vendor/urllib3/packages/six.py | 1021 ++ .../packages/ssl_match_hostname/__init__.py | 19 + .../ssl_match_hostname/_implementation.py | 160 + .../pip/_vendor/urllib3/poolmanager.py | 492 + .../pip/_vendor/urllib3/request.py | 171 + .../pip/_vendor/urllib3/response.py | 821 ++ .../pip/_vendor/urllib3/util/__init__.py | 46 + .../pip/_vendor/urllib3/util/connection.py | 138 + .../pip/_vendor/urllib3/util/queue.py | 21 + .../pip/_vendor/urllib3/util/request.py | 135 + .../pip/_vendor/urllib3/util/response.py | 86 + .../pip/_vendor/urllib3/util/retry.py | 453 + .../pip/_vendor/urllib3/util/ssl_.py | 414 + .../pip/_vendor/urllib3/util/timeout.py | 261 + .../pip/_vendor/urllib3/util/url.py | 430 + .../pip/_vendor/urllib3/util/wait.py | 153 + .../site-packages/pip/_vendor/vendor.txt | 24 + .../pip/_vendor/webencodings/__init__.py | 342 + .../pip/_vendor/webencodings/labels.py | 231 + .../pip/_vendor/webencodings/mklabels.py | 59 + .../pip/_vendor/webencodings/tests.py | 153 + .../_vendor/webencodings/x_user_defined.py | 325 + .../site-packages/pkg_resources/__init__.py | 3302 +++++++ .../pkg_resources/_vendor/__init__.py | 0 .../pkg_resources/_vendor/appdirs.py | 608 ++ .../_vendor/packaging/__about__.py | 27 + .../_vendor/packaging/__init__.py | 26 + .../_vendor/packaging/_compat.py | 31 + .../_vendor/packaging/_structures.py | 68 + .../_vendor/packaging/markers.py | 296 + .../_vendor/packaging/requirements.py | 138 + .../_vendor/packaging/specifiers.py | 749 ++ .../pkg_resources/_vendor/packaging/tags.py | 404 + .../pkg_resources/_vendor/packaging/utils.py | 57 + .../_vendor/packaging/version.py | 420 + .../pkg_resources/_vendor/pyparsing.py | 5742 +++++++++++ .../pkg_resources/_vendor/six.py | 868 ++ .../pkg_resources/extern/__init__.py | 66 + .../pycparser-2.20.dist-info/INSTALLER | 1 + .../pycparser-2.20.dist-info/LICENSE | 27 + .../pycparser-2.20.dist-info/METADATA | 27 + .../pycparser-2.20.dist-info/RECORD | 41 + .../pycparser-2.20.dist-info/WHEEL | 6 + .../pycparser-2.20.dist-info/top_level.txt | 1 + .../site-packages/pycparser/__init__.py | 90 + .../site-packages/pycparser/_ast_gen.py | 338 + .../site-packages/pycparser/_build_tables.py | 37 + .../site-packages/pycparser/_c_ast.cfg | 191 + .../site-packages/pycparser/ast_transforms.py | 106 + .../site-packages/pycparser/c_ast.py | 1084 +++ .../site-packages/pycparser/c_generator.py | 444 + .../site-packages/pycparser/c_lexer.py | 514 + .../site-packages/pycparser/c_parser.py | 1863 ++++ .../site-packages/pycparser/lextab.py | 10 + .../site-packages/pycparser/ply/__init__.py | 5 + .../site-packages/pycparser/ply/cpp.py | 905 ++ .../site-packages/pycparser/ply/ctokens.py | 133 + .../site-packages/pycparser/ply/lex.py | 1099 +++ .../site-packages/pycparser/ply/yacc.py | 3494 +++++++ .../site-packages/pycparser/ply/ygen.py | 74 + .../site-packages/pycparser/plyparser.py | 133 + .../site-packages/pycparser/yacctab.py | 338 + .../requests-2.25.0.dist-info/INSTALLER | 1 + .../requests-2.25.0.dist-info/LICENSE | 175 + .../requests-2.25.0.dist-info/METADATA | 103 + .../requests-2.25.0.dist-info/RECORD | 43 + .../requests-2.25.0.dist-info/REQUESTED | 0 .../requests-2.25.0.dist-info/WHEEL | 6 + .../requests-2.25.0.dist-info/top_level.txt | 1 + .../site-packages/requests/__init__.py | 139 + .../site-packages/requests/__version__.py | 14 + .../site-packages/requests/_internal_utils.py | 42 + .../site-packages/requests/adapters.py | 533 ++ .../python3.8/site-packages/requests/api.py | 161 + .../python3.8/site-packages/requests/auth.py | 305 + .../python3.8/site-packages/requests/certs.py | 18 + .../site-packages/requests/compat.py | 72 + .../site-packages/requests/cookies.py | 549 ++ .../site-packages/requests/exceptions.py | 123 + .../python3.8/site-packages/requests/help.py | 119 + .../python3.8/site-packages/requests/hooks.py | 34 + .../site-packages/requests/models.py | 956 ++ .../site-packages/requests/packages.py | 14 + .../site-packages/requests/sessions.py | 781 ++ .../site-packages/requests/status_codes.py | 123 + .../site-packages/requests/structures.py | 105 + .../python3.8/site-packages/requests/utils.py | 988 ++ .../setuptools-49.2.1.dist-info/INSTALLER | 1 + .../setuptools-49.2.1.dist-info/LICENSE | 19 + .../setuptools-49.2.1.dist-info/METADATA | 109 + .../setuptools-49.2.1.dist-info/RECORD | 297 + .../setuptools-49.2.1.dist-info/REQUESTED | 0 .../setuptools-49.2.1.dist-info/WHEEL | 5 + .../dependency_links.txt | 2 + .../entry_points.txt | 68 + .../setuptools-49.2.1.dist-info/top_level.txt | 3 + .../setuptools-49.2.1.dist-info/zip-safe | 1 + .../site-packages/setuptools/__init__.py | 253 + .../setuptools/_deprecation_warning.py | 7 + .../setuptools/_distutils/__init__.py | 15 + .../setuptools/_distutils/_msvccompiler.py | 537 ++ .../setuptools/_distutils/archive_util.py | 256 + .../setuptools/_distutils/bcppcompiler.py | 393 + .../setuptools/_distutils/ccompiler.py | 1116 +++ .../setuptools/_distutils/cmd.py | 403 + .../setuptools/_distutils/command/__init__.py | 31 + .../setuptools/_distutils/command/bdist.py | 143 + .../_distutils/command/bdist_dumb.py | 123 + .../_distutils/command/bdist_msi.py | 749 ++ .../_distutils/command/bdist_rpm.py | 579 ++ .../_distutils/command/bdist_wininst.py | 377 + .../setuptools/_distutils/command/build.py | 157 + .../_distutils/command/build_clib.py | 209 + .../_distutils/command/build_ext.py | 754 ++ .../setuptools/_distutils/command/build_py.py | 416 + .../_distutils/command/build_scripts.py | 160 + .../setuptools/_distutils/command/check.py | 148 + .../setuptools/_distutils/command/clean.py | 76 + .../setuptools/_distutils/command/config.py | 344 + .../setuptools/_distutils/command/install.py | 677 ++ .../_distutils/command/install_data.py | 79 + .../_distutils/command/install_egg_info.py | 77 + .../_distutils/command/install_headers.py | 47 + .../_distutils/command/install_lib.py | 217 + .../_distutils/command/install_scripts.py | 60 + .../setuptools/_distutils/command/register.py | 304 + .../setuptools/_distutils/command/sdist.py | 494 + .../setuptools/_distutils/command/upload.py | 214 + .../setuptools/_distutils/config.py | 130 + .../setuptools/_distutils/core.py | 234 + .../setuptools/_distutils/cygwinccompiler.py | 403 + .../setuptools/_distutils/debug.py | 5 + .../setuptools/_distutils/dep_util.py | 92 + .../setuptools/_distutils/dir_util.py | 210 + .../setuptools/_distutils/dist.py | 1257 +++ .../setuptools/_distutils/errors.py | 97 + .../setuptools/_distutils/extension.py | 240 + .../setuptools/_distutils/fancy_getopt.py | 457 + .../setuptools/_distutils/file_util.py | 238 + .../setuptools/_distutils/filelist.py | 327 + .../setuptools/_distutils/log.py | 77 + .../setuptools/_distutils/msvc9compiler.py | 788 ++ .../setuptools/_distutils/msvccompiler.py | 643 ++ .../setuptools/_distutils/spawn.py | 125 + .../setuptools/_distutils/sysconfig.py | 573 ++ .../setuptools/_distutils/text_file.py | 286 + .../setuptools/_distutils/unixccompiler.py | 328 + .../setuptools/_distutils/util.py | 559 ++ .../setuptools/_distutils/version.py | 347 + .../setuptools/_distutils/versionpredicate.py | 166 + .../site-packages/setuptools/_imp.py | 82 + .../setuptools/_vendor/__init__.py | 0 .../setuptools/_vendor/ordered_set.py | 488 + .../setuptools/_vendor/packaging/__about__.py | 27 + .../setuptools/_vendor/packaging/__init__.py | 26 + .../setuptools/_vendor/packaging/_compat.py | 31 + .../_vendor/packaging/_structures.py | 68 + .../setuptools/_vendor/packaging/markers.py | 296 + .../_vendor/packaging/requirements.py | 138 + .../_vendor/packaging/specifiers.py | 749 ++ .../setuptools/_vendor/packaging/tags.py | 404 + .../setuptools/_vendor/packaging/utils.py | 57 + .../setuptools/_vendor/packaging/version.py | 420 + .../setuptools/_vendor/pyparsing.py | 5742 +++++++++++ .../site-packages/setuptools/_vendor/six.py | 868 ++ .../site-packages/setuptools/archive_util.py | 175 + .../site-packages/setuptools/build_meta.py | 271 + .../site-packages/setuptools/cli-32.exe | Bin 0 -> 65536 bytes .../site-packages/setuptools/cli-64.exe | Bin 0 -> 74752 bytes .../site-packages/setuptools/cli.exe | Bin 0 -> 65536 bytes .../setuptools/command/__init__.py | 17 + .../site-packages/setuptools/command/alias.py | 80 + .../setuptools/command/bdist_egg.py | 510 + .../setuptools/command/bdist_rpm.py | 43 + .../setuptools/command/bdist_wininst.py | 30 + .../setuptools/command/build_clib.py | 101 + .../setuptools/command/build_ext.py | 332 + .../setuptools/command/build_py.py | 276 + .../setuptools/command/develop.py | 220 + .../setuptools/command/dist_info.py | 36 + .../setuptools/command/easy_install.py | 2339 +++++ .../setuptools/command/egg_info.py | 721 ++ .../setuptools/command/install.py | 125 + .../setuptools/command/install_egg_info.py | 62 + .../setuptools/command/install_lib.py | 122 + .../setuptools/command/install_scripts.py | 68 + .../setuptools/command/launcher manifest.xml | 15 + .../setuptools/command/py36compat.py | 136 + .../setuptools/command/register.py | 18 + .../setuptools/command/rotate.py | 66 + .../setuptools/command/saveopts.py | 22 + .../site-packages/setuptools/command/sdist.py | 252 + .../setuptools/command/setopt.py | 149 + .../site-packages/setuptools/command/test.py | 280 + .../setuptools/command/upload.py | 17 + .../setuptools/command/upload_docs.py | 206 + .../site-packages/setuptools/config.py | 701 ++ .../site-packages/setuptools/dep_util.py | 25 + .../site-packages/setuptools/depends.py | 176 + .../site-packages/setuptools/dist.py | 1035 ++ .../setuptools/distutils_patch.py | 61 + .../site-packages/setuptools/errors.py | 16 + .../site-packages/setuptools/extension.py | 57 + .../setuptools/extern/__init__.py | 66 + .../site-packages/setuptools/glob.py | 174 + .../site-packages/setuptools/gui-32.exe | Bin 0 -> 65536 bytes .../site-packages/setuptools/gui-64.exe | Bin 0 -> 75264 bytes .../site-packages/setuptools/gui.exe | Bin 0 -> 65536 bytes .../site-packages/setuptools/installer.py | 150 + .../site-packages/setuptools/launch.py | 36 + .../site-packages/setuptools/lib2to3_ex.py | 71 + .../site-packages/setuptools/monkey.py | 179 + .../site-packages/setuptools/msvc.py | 1831 ++++ .../site-packages/setuptools/namespaces.py | 111 + .../site-packages/setuptools/package_index.py | 1140 +++ .../site-packages/setuptools/py27compat.py | 60 + .../site-packages/setuptools/py31compat.py | 32 + .../site-packages/setuptools/py33compat.py | 59 + .../site-packages/setuptools/py34compat.py | 13 + .../site-packages/setuptools/sandbox.py | 492 + .../setuptools/script (dev).tmpl | 6 + .../site-packages/setuptools/script.tmpl | 3 + .../site-packages/setuptools/ssl_support.py | 265 + .../site-packages/setuptools/unicode_utils.py | 44 + .../site-packages/setuptools/version.py | 6 + .../site-packages/setuptools/wheel.py | 217 + .../setuptools/windows_support.py | 29 + .../six-1.15.0.dist-info/INSTALLER | 1 + .../six-1.15.0.dist-info/LICENSE | 18 + .../six-1.15.0.dist-info/METADATA | 49 + .../site-packages/six-1.15.0.dist-info/RECORD | 8 + .../site-packages/six-1.15.0.dist-info/WHEEL | 6 + .../six-1.15.0.dist-info/top_level.txt | 1 + .../env/lib/python3.8/site-packages/six.py | 982 ++ .../urllib3-1.26.1.dist-info/INSTALLER | 1 + .../urllib3-1.26.1.dist-info/LICENSE.txt | 21 + .../urllib3-1.26.1.dist-info/METADATA | 1342 +++ .../urllib3-1.26.1.dist-info/RECORD | 84 + .../urllib3-1.26.1.dist-info/WHEEL | 6 + .../urllib3-1.26.1.dist-info/top_level.txt | 1 + .../site-packages/urllib3/__init__.py | 85 + .../site-packages/urllib3/_collections.py | 337 + .../site-packages/urllib3/_version.py | 2 + .../site-packages/urllib3/connection.py | 535 ++ .../site-packages/urllib3/connectionpool.py | 1067 +++ .../site-packages/urllib3/contrib/__init__.py | 0 .../urllib3/contrib/_appengine_environ.py | 36 + .../contrib/_securetransport/__init__.py | 0 .../contrib/_securetransport/bindings.py | 519 + .../contrib/_securetransport/low_level.py | 396 + .../urllib3/contrib/appengine.py | 314 + .../site-packages/urllib3/contrib/ntlmpool.py | 121 + .../urllib3/contrib/pyopenssl.py | 509 + .../urllib3/contrib/securetransport.py | 920 ++ .../site-packages/urllib3/contrib/socks.py | 216 + .../site-packages/urllib3/exceptions.py | 313 + .../python3.8/site-packages/urllib3/fields.py | 274 + .../site-packages/urllib3/filepost.py | 98 + .../urllib3/packages/__init__.py | 5 + .../urllib3/packages/backports/__init__.py | 0 .../urllib3/packages/backports/makefile.py | 51 + .../site-packages/urllib3/packages/six.py | 1021 ++ .../packages/ssl_match_hostname/__init__.py | 22 + .../ssl_match_hostname/_implementation.py | 160 + .../site-packages/urllib3/poolmanager.py | 536 ++ .../site-packages/urllib3/request.py | 170 + .../site-packages/urllib3/response.py | 821 ++ .../site-packages/urllib3/util/__init__.py | 49 + .../site-packages/urllib3/util/connection.py | 150 + .../site-packages/urllib3/util/proxy.py | 56 + .../site-packages/urllib3/util/queue.py | 22 + .../site-packages/urllib3/util/request.py | 143 + .../site-packages/urllib3/util/response.py | 107 + .../site-packages/urllib3/util/retry.py | 601 ++ .../site-packages/urllib3/util/ssl_.py | 466 + .../urllib3/util/ssltransport.py | 221 + .../site-packages/urllib3/util/timeout.py | 268 + .../site-packages/urllib3/util/url.py | 430 + .../site-packages/urllib3/util/wait.py | 153 + .../site-packages/werkzeug/__init__.py | 20 + .../site-packages/werkzeug/_compat.py | 228 + .../site-packages/werkzeug/_internal.py | 473 + .../site-packages/werkzeug/_reloader.py | 341 + .../site-packages/werkzeug/datastructures.py | 3120 ++++++ .../site-packages/werkzeug/debug/__init__.py | 498 + .../site-packages/werkzeug/debug/console.py | 218 + .../site-packages/werkzeug/debug/repr.py | 297 + .../werkzeug/debug/shared/FONT_LICENSE | 96 + .../werkzeug/debug/shared/console.png | Bin 0 -> 507 bytes .../werkzeug/debug/shared/debugger.js | 210 + .../werkzeug/debug/shared/jquery.js | 2 + .../werkzeug/debug/shared/less.png | Bin 0 -> 191 bytes .../werkzeug/debug/shared/more.png | Bin 0 -> 200 bytes .../werkzeug/debug/shared/source.png | Bin 0 -> 818 bytes .../werkzeug/debug/shared/style.css | 154 + .../werkzeug/debug/shared/ubuntu.ttf | Bin 0 -> 70220 bytes .../site-packages/werkzeug/debug/tbtools.py | 628 ++ .../site-packages/werkzeug/exceptions.py | 829 ++ .../site-packages/werkzeug/filesystem.py | 64 + .../site-packages/werkzeug/formparser.py | 584 ++ .../python3.8/site-packages/werkzeug/http.py | 1307 +++ .../python3.8/site-packages/werkzeug/local.py | 420 + .../werkzeug/middleware/__init__.py | 25 + .../werkzeug/middleware/dispatcher.py | 66 + .../werkzeug/middleware/http_proxy.py | 219 + .../site-packages/werkzeug/middleware/lint.py | 408 + .../werkzeug/middleware/profiler.py | 132 + .../werkzeug/middleware/proxy_fix.py | 169 + .../werkzeug/middleware/shared_data.py | 293 + .../site-packages/werkzeug/posixemulation.py | 117 + .../site-packages/werkzeug/routing.py | 2210 +++++ .../site-packages/werkzeug/security.py | 249 + .../site-packages/werkzeug/serving.py | 1117 +++ .../python3.8/site-packages/werkzeug/test.py | 1123 +++ .../site-packages/werkzeug/testapp.py | 241 + .../python3.8/site-packages/werkzeug/urls.py | 1138 +++ .../site-packages/werkzeug/useragents.py | 202 + .../python3.8/site-packages/werkzeug/utils.py | 778 ++ .../werkzeug/wrappers/__init__.py | 36 + .../site-packages/werkzeug/wrappers/accept.py | 50 + .../site-packages/werkzeug/wrappers/auth.py | 33 + .../werkzeug/wrappers/base_request.py | 673 ++ .../werkzeug/wrappers/base_response.py | 700 ++ .../werkzeug/wrappers/common_descriptors.py | 341 + .../site-packages/werkzeug/wrappers/cors.py | 100 + .../site-packages/werkzeug/wrappers/etag.py | 304 + .../site-packages/werkzeug/wrappers/json.py | 145 + .../werkzeug/wrappers/request.py | 49 + .../werkzeug/wrappers/response.py | 84 + .../werkzeug/wrappers/user_agent.py | 14 + .../python3.8/site-packages/werkzeug/wsgi.py | 1000 ++ flask-facebok-google-twitter-login/env/lib64 | 1 + .../env/pyvenv.cfg | 3 + .../templates/index.html | 30 + 1209 files changed, 328358 insertions(+) create mode 100644 flask-facebok-google-twitter-login/app.py create mode 100644 flask-facebok-google-twitter-login/env/bin/Activate.ps1 create mode 100644 flask-facebok-google-twitter-login/env/bin/activate create mode 100644 flask-facebok-google-twitter-login/env/bin/activate.csh create mode 100644 flask-facebok-google-twitter-login/env/bin/activate.fish create mode 100755 flask-facebok-google-twitter-login/env/bin/chardetect create mode 100755 flask-facebok-google-twitter-login/env/bin/easy_install create mode 100755 flask-facebok-google-twitter-login/env/bin/easy_install-3.8 create mode 100755 flask-facebok-google-twitter-login/env/bin/flask create mode 100755 flask-facebok-google-twitter-login/env/bin/pip create mode 100755 flask-facebok-google-twitter-login/env/bin/pip3 create mode 100755 flask-facebok-google-twitter-login/env/bin/pip3.8 create mode 120000 flask-facebok-google-twitter-login/env/bin/python create mode 120000 flask-facebok-google-twitter-login/env/bin/python3 create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Authlib-0.15.2.dist-info/INSTALLER create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Authlib-0.15.2.dist-info/LICENSE create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Authlib-0.15.2.dist-info/METADATA create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Authlib-0.15.2.dist-info/RECORD create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Authlib-0.15.2.dist-info/REQUESTED create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Authlib-0.15.2.dist-info/WHEEL create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Authlib-0.15.2.dist-info/top_level.txt create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/INSTALLER create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/LICENSE.rst create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/METADATA create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/RECORD create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/REQUESTED create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/WHEEL create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/entry_points.txt create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/top_level.txt create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/INSTALLER create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/LICENSE.rst create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/METADATA create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/RECORD create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/WHEEL create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/entry_points.txt create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/top_level.txt create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/INSTALLER create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/LICENSE.txt create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/METADATA create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/RECORD create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/WHEEL create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/top_level.txt create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Werkzeug-1.0.1.dist-info/INSTALLER create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Werkzeug-1.0.1.dist-info/LICENSE.rst create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Werkzeug-1.0.1.dist-info/METADATA create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Werkzeug-1.0.1.dist-info/RECORD create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Werkzeug-1.0.1.dist-info/WHEEL create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Werkzeug-1.0.1.dist-info/top_level.txt create mode 100755 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/_cffi_backend.cpython-38-x86_64-linux-gnu.so create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/common/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/common/encoding.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/common/errors.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/common/security.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/common/urls.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/consts.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/deprecate.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/async_app.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/base_app.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/base_oauth.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/errors.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/framework_integration.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/remote_app.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_client/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_client/integration.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_helpers.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth1/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth1/authorization_server.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth1/nonce.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth1/resource_protector.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth2/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth2/authorization_server.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth2/endpoints.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth2/resource_protector.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth2/signals.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_client/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_client/integration.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_client/oauth_registry.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_client/remote_app.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_helpers.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth1/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth1/authorization_server.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth1/cache.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth1/resource_protector.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth2/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth2/authorization_server.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth2/errors.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth2/resource_protector.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth2/signals.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/httpx_client/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/httpx_client/assertion_client.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/httpx_client/oauth1_client.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/httpx_client/oauth2_client.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/httpx_client/utils.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/requests_client/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/requests_client/assertion_session.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/requests_client/oauth1_session.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/requests_client/oauth2_session.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth1/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth1/functions.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth1/mixins.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth2/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth2/client_mixin.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth2/functions.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth2/tokens_mixins.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/starlette_client/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/starlette_client/integration.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/drafts/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/drafts/_jwe_enc_cryptography.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/errors.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/jwk.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7515/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7515/jws.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7515/models.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7516/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7516/jwe.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7516/models.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7517/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7517/_cryptography_key.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7517/jwk.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7517/models.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/_cryptography_backends/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/_cryptography_backends/_jwe_alg.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/_cryptography_backends/_jwe_enc.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/_cryptography_backends/_jws.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/_cryptography_backends/_keys.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/jwe_algorithms.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/jws_algorithms.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/oct_key.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/util.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7519/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7519/claims.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7519/jwt.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc8037/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc8037/_jws_cryptography.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc8037/okp_key.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/util.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/client.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/errors.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/authorization_server.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/base_server.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/client_auth.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/errors.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/models.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/parameters.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/resource_protector.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/rsa.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/signature.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/util.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/wrapper.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/auth.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/base.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/client.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/authenticate_client.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/authorization_server.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/errors.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/authorization_code.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/base.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/client_credentials.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/implicit.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/refresh_token.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/resource_owner_password_credentials.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/models.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/parameters.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/resource_protector.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/token_endpoint.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/util.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/wrappers.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6750/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6750/errors.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6750/parameters.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6750/validator.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6750/wrappers.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7009/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7009/parameters.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7009/revocation.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7521/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7521/client.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7523/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7523/assertion.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7523/auth.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7523/client.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7523/jwt_bearer.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7591/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7591/claims.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7591/endpoint.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7591/errors.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7592/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7592/endpoint.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7636/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7636/challenge.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7662/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7662/introspection.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7662/models.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8414/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8414/models.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8414/well_known.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8628/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8628/device_code.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8628/endpoint.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8628/errors.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8628/models.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8693/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/claims.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/errors.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/grants/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/grants/code.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/grants/hybrid.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/grants/implicit.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/grants/util.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/models.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/util.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/discovery/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/discovery/models.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/discovery/well_known.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi-2020.11.8.dist-info/INSTALLER create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi-2020.11.8.dist-info/LICENSE create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi-2020.11.8.dist-info/METADATA create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi-2020.11.8.dist-info/RECORD create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi-2020.11.8.dist-info/WHEEL create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi-2020.11.8.dist-info/top_level.txt create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi/__main__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi/cacert.pem create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi/core.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/INSTALLER create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/LICENSE create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/METADATA create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/RECORD create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/WHEEL create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/entry_points.txt create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/top_level.txt create mode 100755 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi.libs/libffi-806b1a9d.so.6.0.4 create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/_cffi_errors.h create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/_cffi_include.h create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/_embedding.h create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/api.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/backend_ctypes.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/cffi_opcode.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/commontypes.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/cparser.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/error.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/ffiplatform.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/lock.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/model.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/parse_c_type.h create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/pkgconfig.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/recompiler.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/setuptools_ext.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/vengine_cpy.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/vengine_gen.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/verifier.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/DESCRIPTION.rst create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/INSTALLER create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/METADATA create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/RECORD create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/WHEEL create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/entry_points.txt create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/metadata.json create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/top_level.txt create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/big5freq.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/big5prober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/chardistribution.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/charsetgroupprober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/charsetprober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/cli/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/cli/chardetect.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/codingstatemachine.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/compat.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/cp949prober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/enums.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/escprober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/escsm.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/eucjpprober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/euckrfreq.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/euckrprober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/euctwfreq.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/euctwprober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/gb2312freq.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/gb2312prober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/hebrewprober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/jisfreq.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/jpcntx.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langbulgarianmodel.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langcyrillicmodel.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langgreekmodel.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langhebrewmodel.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langhungarianmodel.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langthaimodel.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langturkishmodel.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/latin1prober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/mbcharsetprober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/mbcsgroupprober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/mbcssm.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/sbcharsetprober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/sbcsgroupprober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/sjisprober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/universaldetector.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/utf8prober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/version.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click-7.1.2.dist-info/INSTALLER create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click-7.1.2.dist-info/LICENSE.rst create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click-7.1.2.dist-info/METADATA create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click-7.1.2.dist-info/RECORD create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click-7.1.2.dist-info/WHEEL create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click-7.1.2.dist-info/top_level.txt create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/_bashcomplete.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/_compat.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/_termui_impl.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/_textwrap.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/_unicodefun.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/_winconsole.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/core.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/decorators.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/exceptions.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/formatting.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/globals.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/parser.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/termui.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/testing.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/types.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/utils.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/AUTHORS.rst create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/INSTALLER create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/LICENSE create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/LICENSE.APACHE create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/LICENSE.BSD create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/LICENSE.PSF create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/METADATA create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/RECORD create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/WHEEL create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/top_level.txt create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/__about__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/exceptions.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/fernet.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/_der.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/_oid.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/interfaces.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/aead.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/backend.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/ciphers.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/cmac.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/decode_asn1.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/dh.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/dsa.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/ec.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/ed25519.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/ed448.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/encode_asn1.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/hashes.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/hmac.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/ocsp.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/poly1305.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/rsa.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/utils.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/x25519.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/x448.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/x509.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/bindings/__init__.py create mode 100755 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/bindings/_openssl.abi3.so create mode 100755 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/bindings/_padding.abi3.so create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/bindings/openssl/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/bindings/openssl/_conditional.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/bindings/openssl/binding.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/dh.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/dsa.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/ec.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/ed25519.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/ed448.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/padding.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/rsa.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/utils.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/x25519.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/x448.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/ciphers/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/ciphers/aead.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/ciphers/algorithms.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/ciphers/base.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/ciphers/modes.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/cmac.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/constant_time.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/hashes.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/hmac.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/kdf/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/kdf/concatkdf.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/kdf/hkdf.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/kdf/kbkdf.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/kdf/pbkdf2.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/kdf/scrypt.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/kdf/x963kdf.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/keywrap.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/padding.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/poly1305.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/serialization/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/serialization/base.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/serialization/pkcs12.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/serialization/pkcs7.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/serialization/ssh.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/twofactor/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/twofactor/hotp.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/twofactor/totp.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/primitives/twofactor/utils.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/utils.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/x509/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/x509/base.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/x509/certificate_transparency.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/x509/extensions.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/x509/general_name.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/x509/name.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/x509/ocsp.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/x509/oid.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/easy_install.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/flask/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/flask/__main__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/flask/_compat.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/flask/app.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/flask/blueprints.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/flask/cli.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/flask/config.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/flask/ctx.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/flask/debughelpers.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/flask/globals.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/flask/helpers.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/flask/json/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/flask/json/tag.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/flask/logging.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/flask/sessions.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/flask/signals.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/flask/templating.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/flask/testing.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/flask/views.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/flask/wrappers.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/idna-2.10.dist-info/INSTALLER create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/idna-2.10.dist-info/LICENSE.rst create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/idna-2.10.dist-info/METADATA create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/idna-2.10.dist-info/RECORD create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/idna-2.10.dist-info/WHEEL create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/idna-2.10.dist-info/top_level.txt create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/idna/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/idna/codec.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/idna/compat.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/idna/core.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/idna/idnadata.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/idna/intranges.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/idna/package_data.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/idna/uts46data.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/itsdangerous-1.1.0.dist-info/INSTALLER create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/itsdangerous-1.1.0.dist-info/LICENSE.rst create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/itsdangerous-1.1.0.dist-info/METADATA create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/itsdangerous-1.1.0.dist-info/RECORD create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/itsdangerous-1.1.0.dist-info/WHEEL create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/itsdangerous-1.1.0.dist-info/top_level.txt create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/itsdangerous/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/itsdangerous/_compat.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/itsdangerous/_json.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/itsdangerous/encoding.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/itsdangerous/exc.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/itsdangerous/jws.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/itsdangerous/serializer.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/itsdangerous/signer.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/itsdangerous/timed.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/itsdangerous/url_safe.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/jinja2/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/jinja2/_compat.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/jinja2/_identifier.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/jinja2/asyncfilters.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/jinja2/asyncsupport.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/jinja2/bccache.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/jinja2/compiler.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/jinja2/constants.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/jinja2/debug.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/jinja2/defaults.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/jinja2/environment.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/jinja2/exceptions.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/jinja2/ext.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/jinja2/filters.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/jinja2/idtracking.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/jinja2/lexer.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/jinja2/loaders.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/jinja2/meta.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/jinja2/nativetypes.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/jinja2/nodes.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/jinja2/optimizer.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/jinja2/parser.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/jinja2/runtime.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/jinja2/sandbox.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/jinja2/tests.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/jinja2/utils.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/jinja2/visitor.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/markupsafe/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/markupsafe/_compat.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/markupsafe/_constants.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/markupsafe/_native.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/markupsafe/_speedups.c create mode 100755 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/markupsafe/_speedups.cpython-38-x86_64-linux-gnu.so create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip-20.2.1.dist-info/INSTALLER create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip-20.2.1.dist-info/LICENSE.txt create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip-20.2.1.dist-info/METADATA create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip-20.2.1.dist-info/RECORD create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip-20.2.1.dist-info/REQUESTED create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip-20.2.1.dist-info/WHEEL create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip-20.2.1.dist-info/entry_points.txt create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip-20.2.1.dist-info/top_level.txt create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/__main__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/build_env.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/cache.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/cli/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/cli/autocompletion.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/cli/base_command.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/cli/cmdoptions.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/cli/command_context.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/cli/main.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/cli/main_parser.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/cli/parser.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/cli/progress_bars.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/cli/req_command.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/cli/spinners.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/cli/status_codes.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/commands/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/commands/cache.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/commands/check.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/commands/completion.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/commands/configuration.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/commands/debug.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/commands/download.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/commands/freeze.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/commands/hash.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/commands/help.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/commands/install.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/commands/list.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/commands/search.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/commands/show.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/commands/uninstall.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/commands/wheel.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/configuration.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/distributions/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/distributions/base.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/distributions/installed.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/distributions/sdist.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/distributions/wheel.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/exceptions.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/index/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/index/collector.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/index/package_finder.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/locations.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/main.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/models/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/models/candidate.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/models/direct_url.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/models/format_control.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/models/index.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/models/link.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/models/scheme.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/models/search_scope.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/models/selection_prefs.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/models/target_python.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/models/wheel.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/network/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/network/auth.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/network/cache.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/network/download.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/network/lazy_wheel.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/network/session.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/network/utils.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/network/xmlrpc.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/operations/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/operations/build/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/operations/build/metadata.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/operations/build/metadata_legacy.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/operations/build/wheel.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/operations/build/wheel_legacy.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/operations/check.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/operations/freeze.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/operations/install/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/operations/install/editable_legacy.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/operations/install/legacy.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/operations/install/wheel.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/operations/prepare.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/pyproject.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/req/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/req/constructors.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/req/req_file.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/req/req_install.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/req/req_set.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/req/req_tracker.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/req/req_uninstall.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/resolution/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/resolution/base.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/resolution/legacy/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/resolution/legacy/resolver.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/base.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/candidates.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/factory.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/provider.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/requirements.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/resolver.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/self_outdated_check.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/appdirs.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/compat.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/compatibility_tags.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/datetime.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/deprecation.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/direct_url_helpers.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/distutils_args.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/encoding.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/entrypoints.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/filesystem.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/filetypes.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/glibc.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/hashes.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/inject_securetransport.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/logging.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/misc.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/models.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/packaging.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/parallel.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/pkg_resources.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/setuptools_build.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/subprocess.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/temp_dir.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/typing.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/unpacking.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/urls.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/virtualenv.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/utils/wheel.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/vcs/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/vcs/bazaar.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/vcs/git.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/vcs/mercurial.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/vcs/subversion.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/vcs/versioncontrol.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_internal/wheel_builder.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/appdirs.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/cachecontrol/_cmd.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/cachecontrol/adapter.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/cachecontrol/cache.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/cachecontrol/caches/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/cachecontrol/caches/file_cache.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/cachecontrol/caches/redis_cache.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/cachecontrol/compat.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/cachecontrol/controller.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/cachecontrol/filewrapper.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/cachecontrol/heuristics.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/cachecontrol/serialize.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/cachecontrol/wrapper.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/certifi/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/certifi/__main__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/certifi/cacert.pem create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/certifi/core.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/big5freq.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/big5prober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/chardistribution.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/charsetgroupprober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/charsetprober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/cli/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/cli/chardetect.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/codingstatemachine.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/compat.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/cp949prober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/enums.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/escprober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/escsm.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/eucjpprober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/euckrfreq.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/euckrprober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/euctwfreq.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/euctwprober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/gb2312freq.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/gb2312prober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/hebrewprober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/jisfreq.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/jpcntx.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/langbulgarianmodel.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/langcyrillicmodel.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/langgreekmodel.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/langhebrewmodel.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/langhungarianmodel.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/langthaimodel.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/langturkishmodel.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/latin1prober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/mbcharsetprober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/mbcsgroupprober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/mbcssm.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/sbcharsetprober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/sbcsgroupprober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/sjisprober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/universaldetector.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/utf8prober.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/chardet/version.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/colorama/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/colorama/ansi.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/colorama/ansitowin32.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/colorama/initialise.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/colorama/win32.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/colorama/winterm.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/contextlib2.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/distlib/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/misc.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/shutil.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/sysconfig.cfg create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/sysconfig.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/tarfile.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/distlib/compat.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/distlib/database.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/distlib/index.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/distlib/locators.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/distlib/manifest.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/distlib/markers.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/distlib/metadata.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/distlib/resources.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/distlib/scripts.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/distlib/t32.exe create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/distlib/t64.exe create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/distlib/util.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/distlib/version.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/distlib/w32.exe create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/distlib/w64.exe create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/distlib/wheel.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/distro.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/_ihatexml.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/_inputstream.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/_tokenizer.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/_base.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/py.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/_utils.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/constants.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/alphabeticalattributes.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/base.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/inject_meta_charset.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/lint.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/optionaltags.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/sanitizer.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/whitespace.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/html5parser.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/serializer.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/treeadapters/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/treeadapters/genshi.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/treeadapters/sax.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/base.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/dom.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/etree.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/etree_lxml.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/base.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/dom.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/etree.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/etree_lxml.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/genshi.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/idna/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/idna/codec.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/idna/compat.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/idna/core.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/idna/idnadata.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/idna/intranges.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/idna/package_data.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/idna/uts46data.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/ipaddress.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/msgpack/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/msgpack/_version.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/msgpack/exceptions.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/msgpack/ext.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/msgpack/fallback.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/packaging/__about__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/packaging/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/packaging/_compat.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/packaging/_structures.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/packaging/_typing.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/packaging/markers.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/packaging/requirements.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/packaging/specifiers.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/packaging/tags.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/packaging/utils.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/packaging/version.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/pep517/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/pep517/_in_process.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/pep517/build.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/pep517/check.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/pep517/colorlog.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/pep517/compat.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/pep517/dirtools.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/pep517/envbuild.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/pep517/meta.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/pep517/wrappers.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/pkg_resources/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/pkg_resources/py31compat.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/progress/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/progress/bar.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/progress/counter.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/progress/spinner.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/pyparsing.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/requests/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/requests/__version__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/requests/_internal_utils.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/requests/adapters.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/requests/api.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/requests/auth.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/requests/certs.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/requests/compat.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/requests/cookies.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/requests/exceptions.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/requests/help.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/requests/hooks.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/requests/models.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/requests/packages.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/requests/sessions.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/requests/status_codes.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/requests/structures.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/requests/utils.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/resolvelib/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/resolvelib/compat/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/resolvelib/compat/collections_abc.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/resolvelib/providers.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/resolvelib/reporters.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/resolvelib/resolvers.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/resolvelib/structs.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/retrying.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/six.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/toml/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/toml/common.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/toml/decoder.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/toml/encoder.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/toml/ordered.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/toml/tz.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/_collections.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/connection.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/connectionpool.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_appengine_environ.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_securetransport/bindings.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/appengine.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/ntlmpool.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/pyopenssl.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/securetransport.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/socks.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/exceptions.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/fields.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/filepost.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/backports/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/backports/makefile.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/six.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/_implementation.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/poolmanager.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/request.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/response.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/util/connection.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/util/queue.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/util/request.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/util/response.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/util/retry.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/util/ssl_.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/util/timeout.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/util/url.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/urllib3/util/wait.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/vendor.txt create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/webencodings/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/webencodings/labels.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/webencodings/mklabels.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/webencodings/tests.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pip/_vendor/webencodings/x_user_defined.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pkg_resources/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pkg_resources/_vendor/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pkg_resources/_vendor/appdirs.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__about__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_compat.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_structures.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/markers.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/requirements.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/specifiers.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/tags.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/utils.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/version.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pkg_resources/_vendor/pyparsing.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pkg_resources/_vendor/six.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pkg_resources/extern/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pycparser-2.20.dist-info/INSTALLER create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pycparser-2.20.dist-info/LICENSE create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pycparser-2.20.dist-info/METADATA create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pycparser-2.20.dist-info/RECORD create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pycparser-2.20.dist-info/WHEEL create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pycparser-2.20.dist-info/top_level.txt create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pycparser/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pycparser/_ast_gen.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pycparser/_build_tables.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pycparser/_c_ast.cfg create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pycparser/ast_transforms.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pycparser/c_ast.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pycparser/c_generator.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pycparser/c_lexer.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pycparser/c_parser.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pycparser/lextab.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pycparser/ply/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pycparser/ply/cpp.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pycparser/ply/ctokens.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pycparser/ply/lex.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pycparser/ply/yacc.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pycparser/ply/ygen.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pycparser/plyparser.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/pycparser/yacctab.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/requests-2.25.0.dist-info/INSTALLER create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/requests-2.25.0.dist-info/LICENSE create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/requests-2.25.0.dist-info/METADATA create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/requests-2.25.0.dist-info/RECORD create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/requests-2.25.0.dist-info/REQUESTED create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/requests-2.25.0.dist-info/WHEEL create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/requests-2.25.0.dist-info/top_level.txt create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/requests/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/requests/__version__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/requests/_internal_utils.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/requests/adapters.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/requests/api.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/requests/auth.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/requests/certs.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/requests/compat.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/requests/cookies.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/requests/exceptions.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/requests/help.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/requests/hooks.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/requests/models.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/requests/packages.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/requests/sessions.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/requests/status_codes.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/requests/structures.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/requests/utils.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools-49.2.1.dist-info/INSTALLER create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools-49.2.1.dist-info/LICENSE create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools-49.2.1.dist-info/METADATA create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools-49.2.1.dist-info/RECORD create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools-49.2.1.dist-info/REQUESTED create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools-49.2.1.dist-info/WHEEL create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools-49.2.1.dist-info/dependency_links.txt create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools-49.2.1.dist-info/entry_points.txt create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools-49.2.1.dist-info/top_level.txt create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools-49.2.1.dist-info/zip-safe create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_deprecation_warning.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/_msvccompiler.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/archive_util.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/bcppcompiler.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/ccompiler.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/cmd.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/command/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/command/bdist.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/command/bdist_dumb.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/command/bdist_msi.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/command/bdist_rpm.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/command/bdist_wininst.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/command/build.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/command/build_clib.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/command/build_ext.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/command/build_py.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/command/build_scripts.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/command/check.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/command/clean.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/command/config.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/command/install.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/command/install_data.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/command/install_egg_info.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/command/install_headers.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/command/install_lib.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/command/install_scripts.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/command/register.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/command/sdist.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/command/upload.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/config.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/core.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/cygwinccompiler.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/debug.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/dep_util.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/dir_util.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/dist.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/errors.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/extension.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/fancy_getopt.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/file_util.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/filelist.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/log.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/msvc9compiler.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/msvccompiler.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/spawn.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/sysconfig.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/text_file.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/unixccompiler.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/util.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/version.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_distutils/versionpredicate.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_imp.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_vendor/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_vendor/ordered_set.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_vendor/packaging/__about__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_vendor/packaging/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_vendor/packaging/_compat.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_vendor/packaging/_structures.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_vendor/packaging/markers.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_vendor/packaging/requirements.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_vendor/packaging/specifiers.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_vendor/packaging/tags.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_vendor/packaging/utils.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_vendor/packaging/version.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_vendor/pyparsing.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/_vendor/six.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/archive_util.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/build_meta.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/cli-32.exe create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/cli-64.exe create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/cli.exe create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/command/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/command/alias.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/command/bdist_egg.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/command/bdist_rpm.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/command/bdist_wininst.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/command/build_clib.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/command/build_ext.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/command/build_py.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/command/develop.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/command/dist_info.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/command/easy_install.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/command/egg_info.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/command/install.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/command/install_egg_info.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/command/install_lib.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/command/install_scripts.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/command/launcher manifest.xml create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/command/py36compat.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/command/register.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/command/rotate.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/command/saveopts.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/command/sdist.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/command/setopt.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/command/test.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/command/upload.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/command/upload_docs.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/config.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/dep_util.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/depends.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/dist.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/distutils_patch.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/errors.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/extension.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/extern/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/glob.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/gui-32.exe create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/gui-64.exe create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/gui.exe create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/installer.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/launch.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/lib2to3_ex.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/monkey.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/msvc.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/namespaces.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/package_index.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/py27compat.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/py31compat.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/py33compat.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/py34compat.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/sandbox.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/script (dev).tmpl create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/script.tmpl create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/ssl_support.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/unicode_utils.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/version.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/wheel.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/setuptools/windows_support.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/six-1.15.0.dist-info/INSTALLER create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/six-1.15.0.dist-info/LICENSE create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/six-1.15.0.dist-info/METADATA create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/six-1.15.0.dist-info/RECORD create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/six-1.15.0.dist-info/WHEEL create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/six-1.15.0.dist-info/top_level.txt create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/six.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3-1.26.1.dist-info/INSTALLER create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3-1.26.1.dist-info/LICENSE.txt create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3-1.26.1.dist-info/METADATA create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3-1.26.1.dist-info/RECORD create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3-1.26.1.dist-info/WHEEL create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3-1.26.1.dist-info/top_level.txt create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/_collections.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/_version.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/connection.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/connectionpool.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/contrib/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/contrib/_appengine_environ.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/contrib/_securetransport/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/contrib/_securetransport/bindings.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/contrib/_securetransport/low_level.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/contrib/appengine.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/contrib/ntlmpool.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/contrib/pyopenssl.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/contrib/securetransport.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/contrib/socks.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/exceptions.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/fields.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/filepost.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/packages/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/packages/backports/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/packages/backports/makefile.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/packages/six.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/packages/ssl_match_hostname/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/packages/ssl_match_hostname/_implementation.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/poolmanager.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/request.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/response.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/util/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/util/connection.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/util/proxy.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/util/queue.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/util/request.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/util/response.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/util/retry.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/util/ssl_.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/util/ssltransport.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/util/timeout.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/util/url.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/urllib3/util/wait.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/_compat.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/_internal.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/_reloader.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/datastructures.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/debug/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/debug/console.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/debug/repr.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/debug/shared/FONT_LICENSE create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/debug/shared/console.png create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/debug/shared/debugger.js create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/debug/shared/jquery.js create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/debug/shared/less.png create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/debug/shared/more.png create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/debug/shared/source.png create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/debug/shared/style.css create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/debug/shared/ubuntu.ttf create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/debug/tbtools.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/exceptions.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/filesystem.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/formparser.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/http.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/local.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/middleware/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/middleware/dispatcher.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/middleware/http_proxy.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/middleware/lint.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/middleware/profiler.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/middleware/proxy_fix.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/middleware/shared_data.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/posixemulation.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/routing.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/security.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/serving.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/test.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/testapp.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/urls.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/useragents.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/utils.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/wrappers/__init__.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/wrappers/accept.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/wrappers/auth.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/wrappers/base_request.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/wrappers/base_response.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/wrappers/common_descriptors.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/wrappers/cors.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/wrappers/etag.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/wrappers/json.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/wrappers/request.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/wrappers/response.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/wrappers/user_agent.py create mode 100644 flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/werkzeug/wsgi.py create mode 120000 flask-facebok-google-twitter-login/env/lib64 create mode 100644 flask-facebok-google-twitter-login/env/pyvenv.cfg create mode 100644 flask-facebok-google-twitter-login/templates/index.html diff --git a/flask-facebok-google-twitter-login/app.py b/flask-facebok-google-twitter-login/app.py new file mode 100644 index 0000000..08d2fb9 --- /dev/null +++ b/flask-facebok-google-twitter-login/app.py @@ -0,0 +1,116 @@ +''' + The user details get print in the console. + so you can do whatever you want to you do instead + of printing it +''' + +from flask import Flask,render_template,url_for,redirect +from authlib.integrations.flask_client import OAuth +import os + +app = Flask(__name__) + +app.secret_key = os.environ.get('APP_SECRET') +''' + Set SERVER_NAME to localhost as twitter callback + url does not accept 127.0.0.1 + Tip : set callback origin(site) for facebook and twitter + as http://domain.com (or use your domain name) as this provider + don't accept 127.0.0.1 / localhost +''' +app.config['SERVER_NAME'] = 'localhost:5000' + +oauth = OAuth(app) + +@app.route('/') +def index(): + return render_template('index.html') + +@app.route('/google/') +def google(): + # Google Oauth Config + # Get client_id and client_secret from enviroment variables + # For developement purpose you can directly put it here + GOOGLE_CLIENT_ID = os.environ.get('GOOGLE_CLIENT_ID') + GOOGLE_CLIENT_SECRET = os.environ.get('GOOGLE_CLIENT_SECRET') + CONF_URL = 'https://accounts.google.com/.well-known/openid-configuration' + oauth.register( + name = 'google', + client_id = GOOGLE_CLIENT_ID, + client_secret = GOOGLE_CLIENT_SECRET, + server_metadata_url = CONF_URL, + client_kwargs={ + 'scope': 'openid email profile' + } + ) + # Redirect to google_auth funcion + redirect_uri = url_for('google_auth', _external=True) + return oauth.google.authorize_redirect(redirect_uri) + +@app.route('/google/auth/') +def google_auth(): + token = oauth.google.authorize_access_token() + user = oauth.google.parse_id_token(token) + print(" Google User ",user) + return redirect('/') + +@app.route('/twitter/') +def twitter(): + # Twitter Oauth Config + TWITTER_CLIENT_ID = os.environ.get('TWITTER_CLIENT_ID') + TWITTER_CLIENT_SECRET = os.environ.get('TWITTER_CLIENT_SECRET') + oauth.register( + name='twitter', + client_id = TWITTER_CLIENT_ID, + client_secret = TWITTER_CLIENT_SECRET, + request_token_url = 'https://api.twitter.com/oauth/request_token', + request_token_params = None, + access_token_url = 'https://api.twitter.com/oauth/access_token', + access_token_params = None, + authorize_url = 'https://api.twitter.com/oauth/authenticate', + authorize_params = None, + api_base_url = 'https://api.twitter.com/1.1/', + client_kwargs = None, + ) + redirect_uri = url_for('twitter_auth', _external=True) + return oauth.twitter.authorize_redirect(redirect_uri) + +@app.route('/twitter/auth/') +def twitter_auth(): + token = oauth.twitter.authorize_access_token() + resp = oauth.twitter.get('account/verify_credentials.json') + profile = resp.json() + print(" Twitter User",profile) + return redirect('/') + +# Thanks @nelsonher019 for reference +@app.route('/facebook/') +def facebook(): + # Facebook Oauth Config + FACEBOOK_CLIENT_ID = os.environ.get('FACEBOOK_CLIENT_ID') + FACEBOOK_CLIENT_SECRET = os.environ.get('FACEBOOK_CLIENT_SECRET') + oauth.register( + name='facebook', + client_id = FACEBOOK_CLIENT_ID, + client_secret = FACEBOOK_CLIENT_SECRET, + access_token_url = 'https://graph.facebook.com/oauth/access_token', + access_token_params = None, + authorize_url = 'https://www.facebook.com/dialog/oauth', + authorize_params = None, + api_base_url = 'https://graph.facebook.com/', + client_kwargs={'scope': 'email'}, + ) + redirect_uri = url_for('facebook_auth', _external=True) + return oauth.facebook.authorize_redirect(redirect_uri) + +@app.route('/facebook/auth/') +def facebook_auth(): + token = oauth.facebook.authorize_access_token() + resp = oauth.facebook.get( + 'https://graph.facebook.com/me?fields=id,name,email,picture{url}') + profile = resp.json() + print("Facebook User ",profile) + return redirect('/') + +if __name__ == "__main__": + app.run(debug=True) \ No newline at end of file diff --git a/flask-facebok-google-twitter-login/env/bin/Activate.ps1 b/flask-facebok-google-twitter-login/env/bin/Activate.ps1 new file mode 100644 index 0000000..2fb3852 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/bin/Activate.ps1 @@ -0,0 +1,241 @@ +<# +.Synopsis +Activate a Python virtual environment for the current PowerShell session. + +.Description +Pushes the python executable for a virtual environment to the front of the +$Env:PATH environment variable and sets the prompt to signify that you are +in a Python virtual environment. Makes use of the command line switches as +well as the `pyvenv.cfg` file values present in the virtual environment. + +.Parameter VenvDir +Path to the directory that contains the virtual environment to activate. The +default value for this is the parent of the directory that the Activate.ps1 +script is located within. + +.Parameter Prompt +The prompt prefix to display when this virtual environment is activated. By +default, this prompt is the name of the virtual environment folder (VenvDir) +surrounded by parentheses and followed by a single space (ie. '(.venv) '). + +.Example +Activate.ps1 +Activates the Python virtual environment that contains the Activate.ps1 script. + +.Example +Activate.ps1 -Verbose +Activates the Python virtual environment that contains the Activate.ps1 script, +and shows extra information about the activation as it executes. + +.Example +Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv +Activates the Python virtual environment located in the specified location. + +.Example +Activate.ps1 -Prompt "MyPython" +Activates the Python virtual environment that contains the Activate.ps1 script, +and prefixes the current prompt with the specified string (surrounded in +parentheses) while the virtual environment is active. + +.Notes +On Windows, it may be required to enable this Activate.ps1 script by setting the +execution policy for the user. You can do this by issuing the following PowerShell +command: + +PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser + +For more information on Execution Policies: +https://go.microsoft.com/fwlink/?LinkID=135170 + +#> +Param( + [Parameter(Mandatory = $false)] + [String] + $VenvDir, + [Parameter(Mandatory = $false)] + [String] + $Prompt +) + +<# Function declarations --------------------------------------------------- #> + +<# +.Synopsis +Remove all shell session elements added by the Activate script, including the +addition of the virtual environment's Python executable from the beginning of +the PATH variable. + +.Parameter NonDestructive +If present, do not remove this function from the global namespace for the +session. + +#> +function global:deactivate ([switch]$NonDestructive) { + # Revert to original values + + # The prior prompt: + if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) { + Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt + Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT + } + + # The prior PYTHONHOME: + if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) { + Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME + Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME + } + + # The prior PATH: + if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) { + Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH + Remove-Item -Path Env:_OLD_VIRTUAL_PATH + } + + # Just remove the VIRTUAL_ENV altogether: + if (Test-Path -Path Env:VIRTUAL_ENV) { + Remove-Item -Path env:VIRTUAL_ENV + } + + # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether: + if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) { + Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force + } + + # Leave deactivate function in the global namespace if requested: + if (-not $NonDestructive) { + Remove-Item -Path function:deactivate + } +} + +<# +.Description +Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the +given folder, and returns them in a map. + +For each line in the pyvenv.cfg file, if that line can be parsed into exactly +two strings separated by `=` (with any amount of whitespace surrounding the =) +then it is considered a `key = value` line. The left hand string is the key, +the right hand is the value. + +If the value starts with a `'` or a `"` then the first and last character is +stripped from the value before being captured. + +.Parameter ConfigDir +Path to the directory that contains the `pyvenv.cfg` file. +#> +function Get-PyVenvConfig( + [String] + $ConfigDir +) { + Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg" + + # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue). + $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue + + # An empty map will be returned if no config file is found. + $pyvenvConfig = @{ } + + if ($pyvenvConfigPath) { + + Write-Verbose "File exists, parse `key = value` lines" + $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath + + $pyvenvConfigContent | ForEach-Object { + $keyval = $PSItem -split "\s*=\s*", 2 + if ($keyval[0] -and $keyval[1]) { + $val = $keyval[1] + + # Remove extraneous quotations around a string value. + if ("'""".Contains($val.Substring(0, 1))) { + $val = $val.Substring(1, $val.Length - 2) + } + + $pyvenvConfig[$keyval[0]] = $val + Write-Verbose "Adding Key: '$($keyval[0])'='$val'" + } + } + } + return $pyvenvConfig +} + + +<# Begin Activate script --------------------------------------------------- #> + +# Determine the containing directory of this script +$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition +$VenvExecDir = Get-Item -Path $VenvExecPath + +Write-Verbose "Activation script is located in path: '$VenvExecPath'" +Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)" +Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)" + +# Set values required in priority: CmdLine, ConfigFile, Default +# First, get the location of the virtual environment, it might not be +# VenvExecDir if specified on the command line. +if ($VenvDir) { + Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values" +} +else { + Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir." + $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/") + Write-Verbose "VenvDir=$VenvDir" +} + +# Next, read the `pyvenv.cfg` file to determine any required value such +# as `prompt`. +$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir + +# Next, set the prompt from the command line, or the config file, or +# just use the name of the virtual environment folder. +if ($Prompt) { + Write-Verbose "Prompt specified as argument, using '$Prompt'" +} +else { + Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value" + if ($pyvenvCfg -and $pyvenvCfg['prompt']) { + Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'" + $Prompt = $pyvenvCfg['prompt']; + } + else { + Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virutal environment)" + Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'" + $Prompt = Split-Path -Path $venvDir -Leaf + } +} + +Write-Verbose "Prompt = '$Prompt'" +Write-Verbose "VenvDir='$VenvDir'" + +# Deactivate any currently active virtual environment, but leave the +# deactivate function in place. +deactivate -nondestructive + +# Now set the environment variable VIRTUAL_ENV, used by many tools to determine +# that there is an activated venv. +$env:VIRTUAL_ENV = $VenvDir + +if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) { + + Write-Verbose "Setting prompt to '$Prompt'" + + # Set the prompt to include the env name + # Make sure _OLD_VIRTUAL_PROMPT is global + function global:_OLD_VIRTUAL_PROMPT { "" } + Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT + New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt + + function global:prompt { + Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) " + _OLD_VIRTUAL_PROMPT + } +} + +# Clear PYTHONHOME +if (Test-Path -Path Env:PYTHONHOME) { + Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME + Remove-Item -Path Env:PYTHONHOME +} + +# Add the venv to the PATH +Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH +$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH" diff --git a/flask-facebok-google-twitter-login/env/bin/activate b/flask-facebok-google-twitter-login/env/bin/activate new file mode 100644 index 0000000..5250980 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/bin/activate @@ -0,0 +1,76 @@ +# This file must be used with "source bin/activate" *from bash* +# you cannot run it directly + +deactivate () { + # reset old environment variables + if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then + PATH="${_OLD_VIRTUAL_PATH:-}" + export PATH + unset _OLD_VIRTUAL_PATH + fi + if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then + PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}" + export PYTHONHOME + unset _OLD_VIRTUAL_PYTHONHOME + fi + + # This should detect bash and zsh, which have a hash command that must + # be called to get it to forget past commands. Without forgetting + # past commands the $PATH changes we made may not be respected + if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then + hash -r + fi + + if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then + PS1="${_OLD_VIRTUAL_PS1:-}" + export PS1 + unset _OLD_VIRTUAL_PS1 + fi + + unset VIRTUAL_ENV + if [ ! "${1:-}" = "nondestructive" ] ; then + # Self destruct! + unset -f deactivate + fi +} + +# unset irrelevant variables +deactivate nondestructive + +VIRTUAL_ENV="/home/droid/Projects/Web-Projects/demo-oauth-client/flask-facebok-google-twitter-login/env" +export VIRTUAL_ENV + +_OLD_VIRTUAL_PATH="$PATH" +PATH="$VIRTUAL_ENV/bin:$PATH" +export PATH + +# unset PYTHONHOME if set +# this will fail if PYTHONHOME is set to the empty string (which is bad anyway) +# could use `if (set -u; : $PYTHONHOME) ;` in bash +if [ -n "${PYTHONHOME:-}" ] ; then + _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}" + unset PYTHONHOME +fi + +if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then + _OLD_VIRTUAL_PS1="${PS1:-}" + if [ "x(env) " != x ] ; then + PS1="(env) ${PS1:-}" + else + if [ "`basename \"$VIRTUAL_ENV\"`" = "__" ] ; then + # special case for Aspen magic directories + # see https://aspen.io/ + PS1="[`basename \`dirname \"$VIRTUAL_ENV\"\``] $PS1" + else + PS1="(`basename \"$VIRTUAL_ENV\"`)$PS1" + fi + fi + export PS1 +fi + +# This should detect bash and zsh, which have a hash command that must +# be called to get it to forget past commands. Without forgetting +# past commands the $PATH changes we made may not be respected +if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then + hash -r +fi diff --git a/flask-facebok-google-twitter-login/env/bin/activate.csh b/flask-facebok-google-twitter-login/env/bin/activate.csh new file mode 100644 index 0000000..1aa71ce --- /dev/null +++ b/flask-facebok-google-twitter-login/env/bin/activate.csh @@ -0,0 +1,37 @@ +# This file must be used with "source bin/activate.csh" *from csh*. +# You cannot run it directly. +# Created by Davide Di Blasi . +# Ported to Python 3.3 venv by Andrew Svetlov + +alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate' + +# Unset irrelevant variables. +deactivate nondestructive + +setenv VIRTUAL_ENV "/home/droid/Projects/Web-Projects/demo-oauth-client/flask-facebok-google-twitter-login/env" + +set _OLD_VIRTUAL_PATH="$PATH" +setenv PATH "$VIRTUAL_ENV/bin:$PATH" + + +set _OLD_VIRTUAL_PROMPT="$prompt" + +if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then + if ("env" != "") then + set env_name = "env" + else + if (`basename "VIRTUAL_ENV"` == "__") then + # special case for Aspen magic directories + # see https://aspen.io/ + set env_name = `basename \`dirname "$VIRTUAL_ENV"\`` + else + set env_name = `basename "$VIRTUAL_ENV"` + endif + endif + set prompt = "[$env_name] $prompt" + unset env_name +endif + +alias pydoc python -m pydoc + +rehash diff --git a/flask-facebok-google-twitter-login/env/bin/activate.fish b/flask-facebok-google-twitter-login/env/bin/activate.fish new file mode 100644 index 0000000..96a0706 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/bin/activate.fish @@ -0,0 +1,75 @@ +# This file must be used with ". bin/activate.fish" *from fish* (http://fishshell.org) +# you cannot run it directly + +function deactivate -d "Exit virtualenv and return to normal shell environment" + # reset old environment variables + if test -n "$_OLD_VIRTUAL_PATH" + set -gx PATH $_OLD_VIRTUAL_PATH + set -e _OLD_VIRTUAL_PATH + end + if test -n "$_OLD_VIRTUAL_PYTHONHOME" + set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME + set -e _OLD_VIRTUAL_PYTHONHOME + end + + if test -n "$_OLD_FISH_PROMPT_OVERRIDE" + functions -e fish_prompt + set -e _OLD_FISH_PROMPT_OVERRIDE + functions -c _old_fish_prompt fish_prompt + functions -e _old_fish_prompt + end + + set -e VIRTUAL_ENV + if test "$argv[1]" != "nondestructive" + # Self destruct! + functions -e deactivate + end +end + +# unset irrelevant variables +deactivate nondestructive + +set -gx VIRTUAL_ENV "/home/droid/Projects/Web-Projects/demo-oauth-client/flask-facebok-google-twitter-login/env" + +set -gx _OLD_VIRTUAL_PATH $PATH +set -gx PATH "$VIRTUAL_ENV/bin" $PATH + +# unset PYTHONHOME if set +if set -q PYTHONHOME + set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME + set -e PYTHONHOME +end + +if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" + # fish uses a function instead of an env var to generate the prompt. + + # save the current fish_prompt function as the function _old_fish_prompt + functions -c fish_prompt _old_fish_prompt + + # with the original prompt function renamed, we can override with our own. + function fish_prompt + # Save the return status of the last command + set -l old_status $status + + # Prompt override? + if test -n "(env) " + printf "%s%s" "(env) " (set_color normal) + else + # ...Otherwise, prepend env + set -l _checkbase (basename "$VIRTUAL_ENV") + if test $_checkbase = "__" + # special case for Aspen magic directories + # see https://aspen.io/ + printf "%s[%s]%s " (set_color -b blue white) (basename (dirname "$VIRTUAL_ENV")) (set_color normal) + else + printf "%s(%s)%s" (set_color -b blue white) (basename "$VIRTUAL_ENV") (set_color normal) + end + end + + # Restore the return status of the previous command. + echo "exit $old_status" | . + _old_fish_prompt + end + + set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" +end diff --git a/flask-facebok-google-twitter-login/env/bin/chardetect b/flask-facebok-google-twitter-login/env/bin/chardetect new file mode 100755 index 0000000..8ee90d5 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/bin/chardetect @@ -0,0 +1,8 @@ +#!/home/droid/Projects/Web-Projects/demo-oauth-client/flask-facebok-google-twitter-login/env/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from chardet.cli.chardetect import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/flask-facebok-google-twitter-login/env/bin/easy_install b/flask-facebok-google-twitter-login/env/bin/easy_install new file mode 100755 index 0000000..bde5f32 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/bin/easy_install @@ -0,0 +1,8 @@ +#!/home/droid/Projects/Web-Projects/demo-oauth-client/flask-facebok-google-twitter-login/env/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from setuptools.command.easy_install import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/flask-facebok-google-twitter-login/env/bin/easy_install-3.8 b/flask-facebok-google-twitter-login/env/bin/easy_install-3.8 new file mode 100755 index 0000000..bde5f32 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/bin/easy_install-3.8 @@ -0,0 +1,8 @@ +#!/home/droid/Projects/Web-Projects/demo-oauth-client/flask-facebok-google-twitter-login/env/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from setuptools.command.easy_install import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/flask-facebok-google-twitter-login/env/bin/flask b/flask-facebok-google-twitter-login/env/bin/flask new file mode 100755 index 0000000..062829c --- /dev/null +++ b/flask-facebok-google-twitter-login/env/bin/flask @@ -0,0 +1,8 @@ +#!/home/droid/Projects/Web-Projects/demo-oauth-client/flask-facebok-google-twitter-login/env/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from flask.cli import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/flask-facebok-google-twitter-login/env/bin/pip b/flask-facebok-google-twitter-login/env/bin/pip new file mode 100755 index 0000000..bcd96f7 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/bin/pip @@ -0,0 +1,8 @@ +#!/home/droid/Projects/Web-Projects/demo-oauth-client/flask-facebok-google-twitter-login/env/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/flask-facebok-google-twitter-login/env/bin/pip3 b/flask-facebok-google-twitter-login/env/bin/pip3 new file mode 100755 index 0000000..bcd96f7 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/bin/pip3 @@ -0,0 +1,8 @@ +#!/home/droid/Projects/Web-Projects/demo-oauth-client/flask-facebok-google-twitter-login/env/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/flask-facebok-google-twitter-login/env/bin/pip3.8 b/flask-facebok-google-twitter-login/env/bin/pip3.8 new file mode 100755 index 0000000..bcd96f7 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/bin/pip3.8 @@ -0,0 +1,8 @@ +#!/home/droid/Projects/Web-Projects/demo-oauth-client/flask-facebok-google-twitter-login/env/bin/python +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/flask-facebok-google-twitter-login/env/bin/python b/flask-facebok-google-twitter-login/env/bin/python new file mode 120000 index 0000000..acd4152 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/bin/python @@ -0,0 +1 @@ +/usr/bin/python \ No newline at end of file diff --git a/flask-facebok-google-twitter-login/env/bin/python3 b/flask-facebok-google-twitter-login/env/bin/python3 new file mode 120000 index 0000000..d8654aa --- /dev/null +++ b/flask-facebok-google-twitter-login/env/bin/python3 @@ -0,0 +1 @@ +python \ No newline at end of file diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Authlib-0.15.2.dist-info/INSTALLER b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Authlib-0.15.2.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Authlib-0.15.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Authlib-0.15.2.dist-info/LICENSE b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Authlib-0.15.2.dist-info/LICENSE new file mode 100644 index 0000000..4244199 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Authlib-0.15.2.dist-info/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2017, Hsiaoming Yang +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Authlib-0.15.2.dist-info/METADATA b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Authlib-0.15.2.dist-info/METADATA new file mode 100644 index 0000000..5e8f570 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Authlib-0.15.2.dist-info/METADATA @@ -0,0 +1,109 @@ +Metadata-Version: 2.1 +Name: Authlib +Version: 0.15.2 +Summary: The ultimate Python library in building OAuth and OpenID Connect servers. +Home-page: https://authlib.org/ +Author: Hsiaoming Yang +Author-email: me@lepture.com +License: BSD-3-Clause +Project-URL: Documentation, https://docs.authlib.org/ +Project-URL: Commercial License, https://authlib.org/plans +Project-URL: Bug Tracker, https://github.com/lepture/authlib/issues +Project-URL: Source Code, https://github.com/lepture/authlib +Project-URL: Blog, https://blog.authlib.org/ +Project-URL: Donate, https://lepture.com/donate +Platform: any +Classifier: Development Status :: 4 - Beta +Classifier: Environment :: Console +Classifier: Environment :: Web Environment +Classifier: Framework :: Flask +Classifier: Framework :: Django +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Requires-Dist: cryptography +Provides-Extra: client +Requires-Dist: requests ; extra == 'client' + +Authlib +======= + +The ultimate Python library in building OAuth and OpenID Connect servers. +JWS, JWK, JWA, JWT are included. + +Useful Links +------------ + +1. Homepage: https://authlib.org/ +2. Documentation: https://docs.authlib.org/ +3. Purchase Commercial License: https://authlib.org/plans +4. Blog: https://blog.authlib.org/ +5. More Repositories: https://github.com/authlib +6. Twitter: https://twitter.com/authlib +7. Donate: https://www.patreon.com/lepture + +Specifications +-------------- + +- RFC5849: The OAuth 1.0 Protocol +- RFC6749: The OAuth 2.0 Authorization Framework +- RFC6750: The OAuth 2.0 Authorization Framework: Bearer Token Usage +- RFC7009: OAuth 2.0 Token Revocation +- RFC7515: JSON Web Signature +- RFC7516: JSON Web Encryption +- RFC7517: JSON Web Key +- RFC7518: JSON Web Algorithms +- RFC7519: JSON Web Token +- RFC7521: Assertion Framework for OAuth 2.0 Client Authentication and Authorization Grants +- RFC7523: JSON Web Token (JWT) Profile for OAuth 2.0 Client Authentication and Authorization Grants +- RFC7591: OAuth 2.0 Dynamic Client Registration Protocol +- RFC7636: Proof Key for Code Exchange by OAuth Public Clients +- RFC7638: JSON Web Key (JWK) Thumbprint +- RFC7662: OAuth 2.0 Token Introspection +- RFC8037: CFRG Elliptic Curve Diffie-Hellman (ECDH) and Signatures in JSON Object Signing and Encryption (JOSE) +- RFC8414: OAuth 2.0 Authorization Server Metadata +- RFC8628: OAuth 2.0 Device Authorization Grant +- OpenID Connect 1.0 +- OpenID Connect Discovery 1.0 + +Implementations +--------------- + +- Requests OAuth 1 Session +- Requests OAuth 2 Session +- Requests Assertion Session +- HTTPX OAuth 1 Session +- HTTPX OAuth 2 Session +- HTTPX Assertion Session +- Flask OAuth 1/2 Client +- Django OAuth 1/2 Client +- Starlette OAuth 1/2 Client +- Flask OAuth 1.0 Server +- Flask OAuth 2.0 Server +- Flask OpenID Connect 1.0 +- Django OAuth 1.0 Server +- Django OAuth 2.0 Server +- Django OpenID Connect 1.0 + +License +------- + +Authlib is licensed under BSD. Please see LICENSE for licensing details. + +If this license does not fit your company, consider to purchase a commercial +license. Find more information on `Authlib Plans`_. + +.. _`Authlib Plans`: https://authlib.org/plans + + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Authlib-0.15.2.dist-info/RECORD b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Authlib-0.15.2.dist-info/RECORD new file mode 100644 index 0000000..c13b6ad --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Authlib-0.15.2.dist-info/RECORD @@ -0,0 +1,361 @@ +Authlib-0.15.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +Authlib-0.15.2.dist-info/LICENSE,sha256=jhtIUY3pxs0Ay0jH_luAI_2Q1VUsoS6-c2Kg3zDdvkU,1514 +Authlib-0.15.2.dist-info/METADATA,sha256=3ALVlese2kaUWHrKWUDX4jAU4ofGwJ8PMg4Qn1Y8Xkg,3778 +Authlib-0.15.2.dist-info/RECORD,, +Authlib-0.15.2.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +Authlib-0.15.2.dist-info/WHEEL,sha256=8zNYZbwQSXoB9IfXOjPfeNwvAsALAjffgk27FqvCWbo,110 +Authlib-0.15.2.dist-info/top_level.txt,sha256=Rj3mJn0jhRuCs6x7ysI6hYE2PePbuxey6y6jswadAEY,8 +authlib/__init__.py,sha256=CoObQJQX-YGSJy-HWbJPtK6XbpfKDBc21DJwjhLnIcM,476 +authlib/__pycache__/__init__.cpython-38.pyc,, +authlib/__pycache__/consts.cpython-38.pyc,, +authlib/__pycache__/deprecate.cpython-38.pyc,, +authlib/common/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +authlib/common/__pycache__/__init__.cpython-38.pyc,, +authlib/common/__pycache__/encoding.cpython-38.pyc,, +authlib/common/__pycache__/errors.cpython-38.pyc,, +authlib/common/__pycache__/security.cpython-38.pyc,, +authlib/common/__pycache__/urls.cpython-38.pyc,, +authlib/common/encoding.py,sha256=YrDqWLo_60BLEzl8VEurkkwf2EBXqh_9NLWnlt0VsLs,2108 +authlib/common/errors.py,sha256=31LVEXiqySK8ydbtBip64qxtnJk5V24eN8GPlO_9dP8,2210 +authlib/common/security.py,sha256=2xcxtJWVE26kosNJTWtnN3skeSzm3Jjtpm4wxoTCBYs,493 +authlib/common/urls.py,sha256=dfUNEI8Y6kR8mT8zZ2UWryc942-Z-vhDIDupX8u3TPQ,4973 +authlib/consts.py,sha256=frl4_wBKERE-IUvFfttPh5cC2SMprlQwzYxLscuwoFY,313 +authlib/deprecate.py,sha256=GkYSPN_Tsx6FvPf1I8lWg8MtFjq2la66UlyuRAJHZX0,499 +authlib/integrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +authlib/integrations/__pycache__/__init__.cpython-38.pyc,, +authlib/integrations/__pycache__/django_helpers.cpython-38.pyc,, +authlib/integrations/__pycache__/flask_helpers.cpython-38.pyc,, +authlib/integrations/base_client/__init__.py,sha256=xHA18_6VJt2TxV3F70orbo6jQSTOEEgSNbDTPd7RdzY,586 +authlib/integrations/base_client/__pycache__/__init__.cpython-38.pyc,, +authlib/integrations/base_client/__pycache__/async_app.cpython-38.pyc,, +authlib/integrations/base_client/__pycache__/base_app.cpython-38.pyc,, +authlib/integrations/base_client/__pycache__/base_oauth.cpython-38.pyc,, +authlib/integrations/base_client/__pycache__/errors.cpython-38.pyc,, +authlib/integrations/base_client/__pycache__/framework_integration.cpython-38.pyc,, +authlib/integrations/base_client/__pycache__/remote_app.cpython-38.pyc,, +authlib/integrations/base_client/async_app.py,sha256=7ZSp2a_nCfRPAvXWLHwhOpSsfgxfHajRMcDGXqw_2EQ,7846 +authlib/integrations/base_client/base_app.py,sha256=q7_v5-y_M2vvyKg-2bOvDb4Tw6W-f0gtrrvMBsSR-sY,9594 +authlib/integrations/base_client/base_oauth.py,sha256=cZxSJ24Hqg7pYTxKgeS9ZqjFCusdtKGfkKFlKvEo1U0,3948 +authlib/integrations/base_client/errors.py,sha256=fwXW7ldF-TeCIHeANGWYqv5hhaFpXzLLsGRUBwgcy4c,632 +authlib/integrations/base_client/framework_integration.py,sha256=TibSZ2cC0vFRZhwTWTqh57Ecyzgzak3JZ6I2gx25ZWs,782 +authlib/integrations/base_client/remote_app.py,sha256=sDExyMctCIuirDpvUeanwyyxauqFBT_Td9s0mZ6Xy5I,7843 +authlib/integrations/django_client/__init__.py,sha256=opYrgbuD8-hl5tzFp9Ehrb1UN7BzIpuc8ARxrwRdycU,360 +authlib/integrations/django_client/__pycache__/__init__.cpython-38.pyc,, +authlib/integrations/django_client/__pycache__/integration.cpython-38.pyc,, +authlib/integrations/django_client/integration.py,sha256=nNXuELMzkVFarM5eJMnqotEozL2xgJNrkBuqXXS4g0o,2659 +authlib/integrations/django_helpers.py,sha256=WjqcQtA7fF1dU8Yf1fxTAMIBv9cR6HV_TQ4uuaEIRQk,1869 +authlib/integrations/django_oauth1/__init__.py,sha256=yp66WLC43YdsICGgVDbu6AfIRyPR17M43umIUcxjH10,221 +authlib/integrations/django_oauth1/__pycache__/__init__.cpython-38.pyc,, +authlib/integrations/django_oauth1/__pycache__/authorization_server.cpython-38.pyc,, +authlib/integrations/django_oauth1/__pycache__/nonce.cpython-38.pyc,, +authlib/integrations/django_oauth1/__pycache__/resource_protector.cpython-38.pyc,, +authlib/integrations/django_oauth1/authorization_server.py,sha256=UAfP61s-OW0MkVVdq2ld-jjksdPVL5ui_j10sLq3N14,4446 +authlib/integrations/django_oauth1/nonce.py,sha256=auueaxe_Hn9gftyqcjs7jzMxOJVw-xfe3hdG9NyEB6Y,420 +authlib/integrations/django_oauth1/resource_protector.py,sha256=secfPld3RXGhl8szQnGketEq9ClbJ5VRxsS-MaN68tQ,2428 +authlib/integrations/django_oauth2/__init__.py,sha256=HGqxRud5D9EGZIthXmySYhB7d-90qzZlXZDrd4mPHnQ,278 +authlib/integrations/django_oauth2/__pycache__/__init__.cpython-38.pyc,, +authlib/integrations/django_oauth2/__pycache__/authorization_server.cpython-38.pyc,, +authlib/integrations/django_oauth2/__pycache__/endpoints.cpython-38.pyc,, +authlib/integrations/django_oauth2/__pycache__/resource_protector.cpython-38.pyc,, +authlib/integrations/django_oauth2/__pycache__/signals.cpython-38.pyc,, +authlib/integrations/django_oauth2/authorization_server.py,sha256=TAA4D-xX6GeI39-Q_wkVonBphhYKAaVxi0Ju8jbkOs8,5457 +authlib/integrations/django_oauth2/endpoints.py,sha256=ljbhHpMlf5PnbxSXUWYE5gNyqXYypd_WO7jyZAaS200,1964 +authlib/integrations/django_oauth2/resource_protector.py,sha256=XsrQSmZcOAi5xifmM6NxYHU3sWEF46Z8UdYsrOzgZ0I,2715 +authlib/integrations/django_oauth2/signals.py,sha256=8SlnOsi1IuBPmrCi7dOLXK70N_m9y6B3msjMCtBMnSk,236 +authlib/integrations/flask_client/__init__.py,sha256=QVjHRttNnYBJpDALAnJ-pZmF2THks2hvAvh61_Awz3w,282 +authlib/integrations/flask_client/__pycache__/__init__.cpython-38.pyc,, +authlib/integrations/flask_client/__pycache__/integration.cpython-38.pyc,, +authlib/integrations/flask_client/__pycache__/oauth_registry.cpython-38.pyc,, +authlib/integrations/flask_client/__pycache__/remote_app.cpython-38.pyc,, +authlib/integrations/flask_client/integration.py,sha256=HBoSF7ugPoulPyla4JagLqqJcDCSA1kC72-mDsYJmDQ,1975 +authlib/integrations/flask_client/oauth_registry.py,sha256=-H2jqDgQsEW56U5YEN8CsALVpkdFNV5HPWs5ZZMhPXA,3743 +authlib/integrations/flask_client/remote_app.py,sha256=4zoL16AbBnTVRG_mq6NtSIHylqOkuMrsk0u4ho53jfU,2949 +authlib/integrations/flask_helpers.py,sha256=3SV9MbI2B0dw-0TkNYwzH7rOrGjqYc2-goGlC9DVVCM,749 +authlib/integrations/flask_oauth1/__init__.py,sha256=PGDVdNJ9oGs5bYJr7oGdpQX0tE2nQJNcHJ8t-SxEAEY,260 +authlib/integrations/flask_oauth1/__pycache__/__init__.cpython-38.pyc,, +authlib/integrations/flask_oauth1/__pycache__/authorization_server.cpython-38.pyc,, +authlib/integrations/flask_oauth1/__pycache__/cache.cpython-38.pyc,, +authlib/integrations/flask_oauth1/__pycache__/resource_protector.cpython-38.pyc,, +authlib/integrations/flask_oauth1/authorization_server.py,sha256=2FB54nMUXBGIlOLHcB_zEc5tLPvUc8p0QoQi0iBHwYY,6320 +authlib/integrations/flask_oauth1/cache.py,sha256=MtmYy-Zr_OgJoEngS2vOiuYTketegsFZDzlE6rOw1b4,3020 +authlib/integrations/flask_oauth1/resource_protector.py,sha256=95Z7Dx-fwTkdslIgOs9Sok51AjVYh8T3yhCKv2QftHU,4031 +authlib/integrations/flask_oauth2/__init__.py,sha256=8xa6R7Otk9DSHzKFcyGeDv-H7OLUbFwtF73ybpe9jNY,243 +authlib/integrations/flask_oauth2/__pycache__/__init__.cpython-38.pyc,, +authlib/integrations/flask_oauth2/__pycache__/authorization_server.cpython-38.pyc,, +authlib/integrations/flask_oauth2/__pycache__/errors.cpython-38.pyc,, +authlib/integrations/flask_oauth2/__pycache__/resource_protector.cpython-38.pyc,, +authlib/integrations/flask_oauth2/__pycache__/signals.cpython-38.pyc,, +authlib/integrations/flask_oauth2/authorization_server.py,sha256=1ehIZmVtJJdwdbA8vW55PB32C7v_JiuryDnyDklWeV4,8011 +authlib/integrations/flask_oauth2/errors.py,sha256=dLgIH7AYMyGCxZkZLKT6H97w5WZkwE7IkesI3SsYy5k,521 +authlib/integrations/flask_oauth2/resource_protector.py,sha256=fmyL4gml_dvnX6NVDRAiATGatx_RI08VkzRPXmUM5_4,4079 +authlib/integrations/flask_oauth2/signals.py,sha256=CKao8F778CkUzl7mKjF96smr7WKJ0nfxBT0onVFq10Y,341 +authlib/integrations/httpx_client/__init__.py,sha256=zuO_FIAdLEJ9Ch25kTa-Nsyi2gqkPuAsXdHAeYc0nBI,804 +authlib/integrations/httpx_client/__pycache__/__init__.cpython-38.pyc,, +authlib/integrations/httpx_client/__pycache__/assertion_client.cpython-38.pyc,, +authlib/integrations/httpx_client/__pycache__/oauth1_client.cpython-38.pyc,, +authlib/integrations/httpx_client/__pycache__/oauth2_client.cpython-38.pyc,, +authlib/integrations/httpx_client/__pycache__/utils.cpython-38.pyc,, +authlib/integrations/httpx_client/assertion_client.py,sha256=GSoFSshLhUJNxd2J7NRXXWhUAfBdC8wjSqB764AhTfU,3329 +authlib/integrations/httpx_client/oauth1_client.py,sha256=4HEX5Pr3dYmCl8KyRn-X5sHLPOyG92FzATyysK7Es54,4045 +authlib/integrations/httpx_client/oauth2_client.py,sha256=AGm3W1N2Gq5ij-yBv4W2aMU4uuFT77U7SRT-GpGzam8,8256 +authlib/integrations/httpx_client/utils.py,sha256=R1ZUGKhTeMSdB08Sz7p7D6CxmxDTmUJqMaWv44lW-1g,404 +authlib/integrations/requests_client/__init__.py,sha256=Nco-Q1_wOswQ9qCgBgh0rVWPYO9ddEKnlnnJ9rGZE_U,652 +authlib/integrations/requests_client/__pycache__/__init__.cpython-38.pyc,, +authlib/integrations/requests_client/__pycache__/assertion_session.cpython-38.pyc,, +authlib/integrations/requests_client/__pycache__/oauth1_session.cpython-38.pyc,, +authlib/integrations/requests_client/__pycache__/oauth2_session.cpython-38.pyc,, +authlib/integrations/requests_client/assertion_session.py,sha256=TuyzkN59OvTCJFB8TW2giSPlJ0VdNjJoefX4xVbUGxg,1827 +authlib/integrations/requests_client/oauth1_session.py,sha256=LXMIaWciRUjQd2ma4CJbF3dr60orItQOZ6n4e4IiZo4,2142 +authlib/integrations/requests_client/oauth2_session.py,sha256=7bZbK3Eg40GH7uVLCAaIlr8eTcd15NzRPuS7vinNluQ,4782 +authlib/integrations/sqla_oauth1/__init__.py,sha256=6TIiiz_YtxpULt_Gf8qNgmYCreAbMxXHCK4VHUqIArM,416 +authlib/integrations/sqla_oauth1/__pycache__/__init__.cpython-38.pyc,, +authlib/integrations/sqla_oauth1/__pycache__/functions.cpython-38.pyc,, +authlib/integrations/sqla_oauth1/__pycache__/mixins.cpython-38.pyc,, +authlib/integrations/sqla_oauth1/functions.py,sha256=DLi0HbRx2IGUFO2kUH1QZ1WlHgkhAkSdTp1MUTTqDWQ,5254 +authlib/integrations/sqla_oauth1/mixins.py,sha256=SxSM12UTEXW3pV01gCWhjwAMyOas7cmsj7NbFCvgM34,2795 +authlib/integrations/sqla_oauth2/__init__.py,sha256=d8g3ipiiPtyk1JnmTDzeAKCdm-ozjNoERDWLEkpBgL8,548 +authlib/integrations/sqla_oauth2/__pycache__/__init__.cpython-38.pyc,, +authlib/integrations/sqla_oauth2/__pycache__/client_mixin.cpython-38.pyc,, +authlib/integrations/sqla_oauth2/__pycache__/functions.cpython-38.pyc,, +authlib/integrations/sqla_oauth2/__pycache__/tokens_mixins.cpython-38.pyc,, +authlib/integrations/sqla_oauth2/client_mixin.py,sha256=uem_suLalYLeCu-szePyT8WsZAjewHXeQKrtzh1f_U0,3986 +authlib/integrations/sqla_oauth2/functions.py,sha256=7RejfsKhlmioD4qHb4v-8a-iOlYxV9vcwEatKHGlvGg,3210 +authlib/integrations/sqla_oauth2/tokens_mixins.py,sha256=VXdtQ69jhxGtVMWxSkWiISU7avd--yvGv9JjDkLEc6E,1678 +authlib/integrations/starlette_client/__init__.py,sha256=vFPq0GQEzIWPjeLrNyzNnfUXVrCLOZvyVJpR2TO6A3c,557 +authlib/integrations/starlette_client/__pycache__/__init__.cpython-38.pyc,, +authlib/integrations/starlette_client/__pycache__/integration.cpython-38.pyc,, +authlib/integrations/starlette_client/integration.py,sha256=MY1nhdozsGZKD-j7-v5_2igpbeGCy0wQ1vqkU0BS92w,2608 +authlib/jose/__init__.py,sha256=-FGxiCk9Q_ZcLIn2BBN_VLrncRqOy9FCoLyyfWCabWQ,1853 +authlib/jose/__pycache__/__init__.cpython-38.pyc,, +authlib/jose/__pycache__/errors.cpython-38.pyc,, +authlib/jose/__pycache__/jwk.cpython-38.pyc,, +authlib/jose/__pycache__/util.cpython-38.pyc,, +authlib/jose/drafts/__init__.py,sha256=kRzfvWoD5kRl2d8CEIYgH5fdW6xj32sNORuxWgd7X98,88 +authlib/jose/drafts/__pycache__/__init__.cpython-38.pyc,, +authlib/jose/drafts/__pycache__/_jwe_enc_cryptography.cpython-38.pyc,, +authlib/jose/drafts/_jwe_enc_cryptography.py,sha256=631oL-4cTVygvocbgZkKVYqzq3rEd_xMH60k01ycv5Q,1806 +authlib/jose/errors.py,sha256=mVxr-NznmqEicn2xxnjeBDKD1RnnzoFWC9qa9NiEVAg,2262 +authlib/jose/jwk.py,sha256=Ge-UMTx7sk6ccl1BcA8CHxSfYtJiaUYx5hd_icb3ZHc,408 +authlib/jose/rfc7515/__init__.py,sha256=0NhWGkry69LiJH6cAkwIUNmQUpuGh463TNwIpoQjtE4,360 +authlib/jose/rfc7515/__pycache__/__init__.cpython-38.pyc,, +authlib/jose/rfc7515/__pycache__/jws.cpython-38.pyc,, +authlib/jose/rfc7515/__pycache__/models.cpython-38.pyc,, +authlib/jose/rfc7515/jws.py,sha256=mA-qIdJPVuPWnpKSG-slT3DHgWfaNnvhfm5AfXClJwI,11524 +authlib/jose/rfc7515/models.py,sha256=JPUPg7pHW-_aztpfX517y6SWBZI5_AfrNxUxwUhrilM,2483 +authlib/jose/rfc7516/__init__.py,sha256=d3i3YFUn5AuIjOfBJfRuogFocP2C0i4w5vt8aOK1VD0,387 +authlib/jose/rfc7516/__pycache__/__init__.cpython-38.pyc,, +authlib/jose/rfc7516/__pycache__/jwe.cpython-38.pyc,, +authlib/jose/rfc7516/__pycache__/models.cpython-38.pyc,, +authlib/jose/rfc7516/jwe.py,sha256=Ik4FSMSxPAGt1jkyTauv5eGW0Df0mMkhPQ8bWHxVNY0,7345 +authlib/jose/rfc7516/models.py,sha256=KaGK3YaQQ0ZxBfneR0tG2skIfZh0NcsQvLXSLWNnI24,2023 +authlib/jose/rfc7517/__init__.py,sha256=CzzNku-UcE9IUabtQIlvApTXlLPrslbPL3z02IW-8-U,343 +authlib/jose/rfc7517/__pycache__/__init__.cpython-38.pyc,, +authlib/jose/rfc7517/__pycache__/_cryptography_key.cpython-38.pyc,, +authlib/jose/rfc7517/__pycache__/jwk.cpython-38.pyc,, +authlib/jose/rfc7517/__pycache__/models.cpython-38.pyc,, +authlib/jose/rfc7517/_cryptography_key.py,sha256=1-EQ1YD7ZR7Gp7FBntrWEN-76Su_vlunuzC77VPJ_sg,1257 +authlib/jose/rfc7517/jwk.py,sha256=O7LNBPeQVZEQPMOnGJuU0knIoixuFy7rvyMjkbMPKKM,2024 +authlib/jose/rfc7517/models.py,sha256=z8eh-znjpsRKwVZLiyNU5eyFKm1_fXdR2aZ2QUqsT7E,4576 +authlib/jose/rfc7518/__init__.py,sha256=mO7V2nXWRIL_w-HEIXHl3E0yS5jfMksDGjt1jjKao8s,431 +authlib/jose/rfc7518/__pycache__/__init__.cpython-38.pyc,, +authlib/jose/rfc7518/__pycache__/jwe_algorithms.cpython-38.pyc,, +authlib/jose/rfc7518/__pycache__/jws_algorithms.cpython-38.pyc,, +authlib/jose/rfc7518/__pycache__/oct_key.cpython-38.pyc,, +authlib/jose/rfc7518/__pycache__/util.cpython-38.pyc,, +authlib/jose/rfc7518/_cryptography_backends/__init__.py,sha256=fONfDQ5SmC7DNgX4kY4oUXa2HcmWuaT9U2QecmkmVFQ,214 +authlib/jose/rfc7518/_cryptography_backends/__pycache__/__init__.cpython-38.pyc,, +authlib/jose/rfc7518/_cryptography_backends/__pycache__/_jwe_alg.cpython-38.pyc,, +authlib/jose/rfc7518/_cryptography_backends/__pycache__/_jwe_enc.cpython-38.pyc,, +authlib/jose/rfc7518/_cryptography_backends/__pycache__/_jws.cpython-38.pyc,, +authlib/jose/rfc7518/_cryptography_backends/__pycache__/_keys.cpython-38.pyc,, +authlib/jose/rfc7518/_cryptography_backends/_jwe_alg.py,sha256=gabtQSsWXgK9yAY2yRpFdWAut7Bo6H6X0l_I32akEXE,8917 +authlib/jose/rfc7518/_cryptography_backends/_jwe_enc.py,sha256=QRtPVbspgqniWOziDRCUNrdTLe1sewxS1AQTX21wCfo,5093 +authlib/jose/rfc7518/_cryptography_backends/_jws.py,sha256=MJwKMOkAfey7Lua2XTu4rtnjEhC1XQOVeXVQp-AT63Q,4908 +authlib/jose/rfc7518/_cryptography_backends/_keys.py,sha256=p9K-1O_3LDn-bKgVnRapjSM1EuWUsKF40w1vMLBjwNk,10237 +authlib/jose/rfc7518/jwe_algorithms.py,sha256=FCQWLbHjLmU5hGhVkbsTOPmiypgwKvIu7PTDc-h0Xno,1556 +authlib/jose/rfc7518/jws_algorithms.py,sha256=8myW2tgFqI9UtD00zDWkCNcTcXUVHXQn6aPuK9W1mbU,2003 +authlib/jose/rfc7518/oct_key.py,sha256=NX-B4x7NJTfpzCzggskKG9ah_yBrINVs8TtgOo79FQY,1426 +authlib/jose/rfc7518/util.py,sha256=LpOgX10QHuqss6x015QPgApTlnYJ_cQyd0hzeYALnaE,265 +authlib/jose/rfc7519/__init__.py,sha256=CORkKBZ135xSAR-wQJob9P5EfdmyRkJ58MM6EOGvCAE,333 +authlib/jose/rfc7519/__pycache__/__init__.cpython-38.pyc,, +authlib/jose/rfc7519/__pycache__/claims.cpython-38.pyc,, +authlib/jose/rfc7519/__pycache__/jwt.cpython-38.pyc,, +authlib/jose/rfc7519/claims.py,sha256=ICLyAq41f7PehIpW_QMaeVbVKw9Is84Y6iRlgS7SlD8,8159 +authlib/jose/rfc7519/jwt.py,sha256=dCjgVXAa67o2KL5cqkR72dTgZOTh9-uqIiSSe2SDEvY,4846 +authlib/jose/rfc8037/__init__.py,sha256=FfxjfiZ2H0UviK6V9cu-be_-lYzfZ5RuV_1srzOosf4,127 +authlib/jose/rfc8037/__pycache__/__init__.cpython-38.pyc,, +authlib/jose/rfc8037/__pycache__/_jws_cryptography.cpython-38.pyc,, +authlib/jose/rfc8037/__pycache__/okp_key.cpython-38.pyc,, +authlib/jose/rfc8037/_jws_cryptography.py,sha256=3wj6AjgE_YZcRSATyds6DVc4bqA3uy8X277ExJjvkfA,939 +authlib/jose/rfc8037/okp_key.py,sha256=s51o1WI8hBFUPF3OYOO0wi-e-TEgXNmVEv6T9Pj70vE,4187 +authlib/jose/util.py,sha256=SDqaGQD64M6uQ0PcLHPIhxo5cpiUHKqB_TfxBB0paqI,699 +authlib/oauth1/__init__.py,sha256=YrqE1RUU0Dyqf5whN5vWiGLgpdhUSU_LKEswHbWEHJs,752 +authlib/oauth1/__pycache__/__init__.cpython-38.pyc,, +authlib/oauth1/__pycache__/client.cpython-38.pyc,, +authlib/oauth1/__pycache__/errors.cpython-38.pyc,, +authlib/oauth1/client.py,sha256=GQ7w2t9iHjWrHO6pO0hm-m0fti9mui9ToI0AdOmbmMI,7116 +authlib/oauth1/errors.py,sha256=pg0NaUgENjfTN_ba50_yQB9aSNe5Mte5MDlikFuypBY,46 +authlib/oauth1/rfc5849/__init__.py,sha256=S4rdtQiDd83QsR1hBqdsvuI-VgmgoG7rFuJH2fLP_K4,1036 +authlib/oauth1/rfc5849/__pycache__/__init__.cpython-38.pyc,, +authlib/oauth1/rfc5849/__pycache__/authorization_server.cpython-38.pyc,, +authlib/oauth1/rfc5849/__pycache__/base_server.cpython-38.pyc,, +authlib/oauth1/rfc5849/__pycache__/client_auth.cpython-38.pyc,, +authlib/oauth1/rfc5849/__pycache__/errors.cpython-38.pyc,, +authlib/oauth1/rfc5849/__pycache__/models.cpython-38.pyc,, +authlib/oauth1/rfc5849/__pycache__/parameters.cpython-38.pyc,, +authlib/oauth1/rfc5849/__pycache__/resource_protector.cpython-38.pyc,, +authlib/oauth1/rfc5849/__pycache__/rsa.cpython-38.pyc,, +authlib/oauth1/rfc5849/__pycache__/signature.cpython-38.pyc,, +authlib/oauth1/rfc5849/__pycache__/util.cpython-38.pyc,, +authlib/oauth1/rfc5849/__pycache__/wrapper.cpython-38.pyc,, +authlib/oauth1/rfc5849/authorization_server.py,sha256=slLBnoxt-OECk67DrGTG_Las-ady5pKsmtgfRtyDDFg,13880 +authlib/oauth1/rfc5849/base_server.py,sha256=0rewbcJmcQ9G-MIjOgv2nezDBlZefuK0Yf6mjs4Mppk,3857 +authlib/oauth1/rfc5849/client_auth.py,sha256=7aVbcU5j3MU5XAOKluI8fLDCIDcJHTxViv-z6CbulJE,6892 +authlib/oauth1/rfc5849/errors.py,sha256=cT5PASueBNDWmD3TTZYMwXS9Nr4y4khJ5kF58pmoKso,2597 +authlib/oauth1/rfc5849/models.py,sha256=9MQ1hHVOsoyKr0RAR5uMnhZPjEfzWHUo3lq5tb_x-tA,3435 +authlib/oauth1/rfc5849/parameters.py,sha256=XQMgNFrl9NkUSddnVEIO0mXproIySqFMyb7PY8chY5Q,3508 +authlib/oauth1/rfc5849/resource_protector.py,sha256=v4EsTBnqYAQMarwukpYmgiyT3J9khnp8Apj6n_RRabI,1258 +authlib/oauth1/rfc5849/rsa.py,sha256=z2cx8e-p2pdvzx_WQm9mcMzkGfsBJniWoy6SLn6XZa4,896 +authlib/oauth1/rfc5849/signature.py,sha256=G5-iy8Oa8paMnTRyxQ1u7a9xCKHDufkDMS1zuDz1hjs,14159 +authlib/oauth1/rfc5849/util.py,sha256=89kP-xwQHop8SaBjCEkppxzYO7GQFbmi3ekVyI-zFvE,136 +authlib/oauth1/rfc5849/wrapper.py,sha256=qXqW9_UHLkHQ7R6Mb2PgiUNtjh_fpdBQcFiN6gPbJrY,3931 +authlib/oauth2/__init__.py,sha256=QbT0eXEAwNUr9RbRGRHIw6kw-pUnFXbfcbZJZ5_ynmc,423 +authlib/oauth2/__pycache__/__init__.cpython-38.pyc,, +authlib/oauth2/__pycache__/auth.cpython-38.pyc,, +authlib/oauth2/__pycache__/base.cpython-38.pyc,, +authlib/oauth2/__pycache__/client.cpython-38.pyc,, +authlib/oauth2/auth.py,sha256=zM9AX-4jOSoJrsr_OQsU5n8V1JJVcAQsfahfez2piZg,3481 +authlib/oauth2/base.py,sha256=0Iw_UabgRNpsmyzI4jpxEakAuyg7duRlGBJPFv0xg1E,1069 +authlib/oauth2/client.py,sha256=yt7dHA8xu55pA-NoxrdC7igfUHSWFiUa4AAhLfd22CU,16656 +authlib/oauth2/rfc6749/__init__.py,sha256=LFNVOywMSdTtssoQ1ZLpfzsvaBBHgk0I1dY4NlZtCHI,2129 +authlib/oauth2/rfc6749/__pycache__/__init__.cpython-38.pyc,, +authlib/oauth2/rfc6749/__pycache__/authenticate_client.cpython-38.pyc,, +authlib/oauth2/rfc6749/__pycache__/authorization_server.cpython-38.pyc,, +authlib/oauth2/rfc6749/__pycache__/errors.cpython-38.pyc,, +authlib/oauth2/rfc6749/__pycache__/models.cpython-38.pyc,, +authlib/oauth2/rfc6749/__pycache__/parameters.cpython-38.pyc,, +authlib/oauth2/rfc6749/__pycache__/resource_protector.cpython-38.pyc,, +authlib/oauth2/rfc6749/__pycache__/token_endpoint.cpython-38.pyc,, +authlib/oauth2/rfc6749/__pycache__/util.cpython-38.pyc,, +authlib/oauth2/rfc6749/__pycache__/wrappers.cpython-38.pyc,, +authlib/oauth2/rfc6749/authenticate_client.py,sha256=nGgHKc3qEZIhTzqX4R1IEu3oyO0cKa74o8twzXQpTwQ,4132 +authlib/oauth2/rfc6749/authorization_server.py,sha256=fL1cWhVq1Qm_4dJ88byb6a-cxwn8qzFeVK3-GcbRwxM,9284 +authlib/oauth2/rfc6749/errors.py,sha256=cMhJI0YP9_DK9sjv5wKMmDwG4mCqyoioaypIyjVi6QQ,6314 +authlib/oauth2/rfc6749/grants/__init__.py,sha256=jJZOtFgyBztuIGQxcuK1qtvnR3hWRDU-G59RuyWmqKI,1314 +authlib/oauth2/rfc6749/grants/__pycache__/__init__.cpython-38.pyc,, +authlib/oauth2/rfc6749/grants/__pycache__/authorization_code.cpython-38.pyc,, +authlib/oauth2/rfc6749/grants/__pycache__/base.cpython-38.pyc,, +authlib/oauth2/rfc6749/grants/__pycache__/client_credentials.cpython-38.pyc,, +authlib/oauth2/rfc6749/grants/__pycache__/implicit.cpython-38.pyc,, +authlib/oauth2/rfc6749/grants/__pycache__/refresh_token.cpython-38.pyc,, +authlib/oauth2/rfc6749/grants/__pycache__/resource_owner_password_credentials.cpython-38.pyc,, +authlib/oauth2/rfc6749/grants/authorization_code.py,sha256=NbDz5Y7AiWi2V6gcbo-gGD0upZ0fhEkSe1hYfhOLo-U,15797 +authlib/oauth2/rfc6749/grants/base.py,sha256=85k98YZsYGJ0eQ3Tsbnp4nZYFIFduoA8jb-MtjgVVTA,5007 +authlib/oauth2/rfc6749/grants/client_credentials.py,sha256=pf3tfaiSVeuCudaqZGKpFU1OVBWkSOTB8SErEjJQWvY,3924 +authlib/oauth2/rfc6749/grants/implicit.py,sha256=qNBYKp8GG3sNLZSfC1VL6xRiloTXDl3c1qPXsGf3XF8,9297 +authlib/oauth2/rfc6749/grants/refresh_token.py,sha256=uAphAHXiNAbuwbv4v-aJWocgWQY0OG-Kl4o-UZ3HMDE,6503 +authlib/oauth2/rfc6749/grants/resource_owner_password_credentials.py,sha256=_wkF0JsdnqMLnPJ7wY_Y70P0nYmvsYCX3maM7LzAa8Q,5763 +authlib/oauth2/rfc6749/models.py,sha256=0EStfaA7dYa2xPWDDmjJn9p-EUz6EhUrHZHQWhTg-Y4,6813 +authlib/oauth2/rfc6749/parameters.py,sha256=YCDcu9BammKPLEM5cOoZ0fwF2pTl9lpYYMC97ZUwxQM,8270 +authlib/oauth2/rfc6749/resource_protector.py,sha256=6oH0DjNbFojoP9tPVE1vd8eENO-VCxRuVgTBvOeJ9hY,1223 +authlib/oauth2/rfc6749/token_endpoint.py,sha256=iVeh_uYIXLAsvfWLdyqm1cF5ZFCh37CaTJGz4U7asDs,1143 +authlib/oauth2/rfc6749/util.py,sha256=xzebTUJciyJ9qy1jrYqiXfNBq6GfqCkb9Ok0XMoPWFc,1122 +authlib/oauth2/rfc6749/wrappers.py,sha256=7vDgNMHAB6bopYhOBxspkCjJY4QyYEoSGwSxZGN0QhA,2663 +authlib/oauth2/rfc6750/__init__.py,sha256=0DgFrRaX5hJWPIzt6ZUSNTyPOU3ROT4hG5IwuG5rCaU,609 +authlib/oauth2/rfc6750/__pycache__/__init__.cpython-38.pyc,, +authlib/oauth2/rfc6750/__pycache__/errors.cpython-38.pyc,, +authlib/oauth2/rfc6750/__pycache__/parameters.cpython-38.pyc,, +authlib/oauth2/rfc6750/__pycache__/validator.cpython-38.pyc,, +authlib/oauth2/rfc6750/__pycache__/wrappers.cpython-38.pyc,, +authlib/oauth2/rfc6750/errors.py,sha256=lS7sg0y4yCIZD4IQnr6_O_DtV-q7bhZpz4iJIhnMZlA,2915 +authlib/oauth2/rfc6750/parameters.py,sha256=WfNCvwARR8dIzIyhNnatnP_6hlogYoWVEbmwe60tZCM,1212 +authlib/oauth2/rfc6750/validator.py,sha256=ACGGSiNKKgJNlDOKLyvXcqCl_crPAEjgOGXfOEEPhW0,3247 +authlib/oauth2/rfc6750/wrappers.py,sha256=vQ7Z5RN_repa8pCX399-rInrL9lkpysar-7kj7yATyc,3733 +authlib/oauth2/rfc7009/__init__.py,sha256=P0aYdtZ-B5Nj8mUkEqS-snMvJ8hLTDR5unZKAZ7KGLo,377 +authlib/oauth2/rfc7009/__pycache__/__init__.cpython-38.pyc,, +authlib/oauth2/rfc7009/__pycache__/parameters.cpython-38.pyc,, +authlib/oauth2/rfc7009/__pycache__/revocation.cpython-38.pyc,, +authlib/oauth2/rfc7009/parameters.py,sha256=klTaHudte5Oncfw6M5Mr6LL9Y-cVnN29Th1ix-uVYAU,854 +authlib/oauth2/rfc7009/revocation.py,sha256=sU4_hrtADGvlMig4kBVRASxjspa4UkGxiWJHROUHqeQ,3715 +authlib/oauth2/rfc7521/__init__.py,sha256=sI-EfGOAZTLM-LxfBfYEXU_74cd3ib63g8fkGu39PJA,67 +authlib/oauth2/rfc7521/__pycache__/__init__.cpython-38.pyc,, +authlib/oauth2/rfc7521/__pycache__/client.cpython-38.pyc,, +authlib/oauth2/rfc7521/client.py,sha256=1PrWuGraLfzCVL0cpZLnvVFdfcHUT2hkE6-dbrraiCs,2481 +authlib/oauth2/rfc7523/__init__.py,sha256=AY1iuAHaOFfwYI3WwkUZCov2SMe_7jNAwWAvBh4gqZQ,769 +authlib/oauth2/rfc7523/__pycache__/__init__.cpython-38.pyc,, +authlib/oauth2/rfc7523/__pycache__/assertion.cpython-38.pyc,, +authlib/oauth2/rfc7523/__pycache__/auth.cpython-38.pyc,, +authlib/oauth2/rfc7523/__pycache__/client.cpython-38.pyc,, +authlib/oauth2/rfc7523/__pycache__/jwt_bearer.cpython-38.pyc,, +authlib/oauth2/rfc7523/assertion.py,sha256=ZFklvOm9ulLdUCoWn245igaK4LjXsFIJn5GcWJRl7iU,2024 +authlib/oauth2/rfc7523/auth.py,sha256=T51UbZbq8eLMK0cQPe5uJiIRv7VlcpCdMXrmRAi9810,3675 +authlib/oauth2/rfc7523/client.py,sha256=UmVfZdBxqimCvx7oQwTErQzPdjKaqqs7FjTvPSMHkBY,4393 +authlib/oauth2/rfc7523/jwt_bearer.py,sha256=-6QbwuKsAhsQZLlHp8F7xzopPMIXZZsfytvjDAnH7bw,5417 +authlib/oauth2/rfc7591/__init__.py,sha256=Wb4PkmuGy8makvgceRVV1472cGL1udCS2bD9SGbqJyg,667 +authlib/oauth2/rfc7591/__pycache__/__init__.cpython-38.pyc,, +authlib/oauth2/rfc7591/__pycache__/claims.cpython-38.pyc,, +authlib/oauth2/rfc7591/__pycache__/endpoint.cpython-38.pyc,, +authlib/oauth2/rfc7591/__pycache__/errors.cpython-38.pyc,, +authlib/oauth2/rfc7591/claims.py,sha256=4eMNWjY0Osh4IvdxAZE-bHXf0gqfk0VoERxtkSL07AQ,9809 +authlib/oauth2/rfc7591/endpoint.py,sha256=bJMaKIY-ZsIzGcPohMOKxGOaCkFRN5PjtJjF_xBBqGs,7509 +authlib/oauth2/rfc7591/errors.py,sha256=nx_1-wyT1kznHXh1R91uwa1gbRJ5YKUxWY1SiFVRTWg,1098 +authlib/oauth2/rfc7592/__init__.py,sha256=4du9AjzDNRXbmtkTWBPbpXz5ivugseKIuXtp3oAsk4w,315 +authlib/oauth2/rfc7592/__pycache__/__init__.cpython-38.pyc,, +authlib/oauth2/rfc7592/__pycache__/endpoint.cpython-38.pyc,, +authlib/oauth2/rfc7592/endpoint.py,sha256=FldOO50vPPpXjic7mGXuQROR5C7QHj0ehCvty4_Czxc,6662 +authlib/oauth2/rfc7636/__init__.py,sha256=TIKOEYQWQqOw6bFU9Kf2-sZFSWR-e_iJGnRiowhybD0,364 +authlib/oauth2/rfc7636/__pycache__/__init__.cpython-38.pyc,, +authlib/oauth2/rfc7636/__pycache__/challenge.cpython-38.pyc,, +authlib/oauth2/rfc7636/challenge.py,sha256=Og_V80QCDT1v6tq186FPoEwKRieLXvHEM8lnJhJFSMM,5126 +authlib/oauth2/rfc7662/__init__.py,sha256=qOguHj3TeVYLrdf9qvxe5HMyDDv_t7A5FZ6hKA1hCw0,365 +authlib/oauth2/rfc7662/__pycache__/__init__.cpython-38.pyc,, +authlib/oauth2/rfc7662/__pycache__/introspection.cpython-38.pyc,, +authlib/oauth2/rfc7662/__pycache__/models.cpython-38.pyc,, +authlib/oauth2/rfc7662/introspection.py,sha256=GMjfNQFGxpoqOM2Bv7gK2CusTMS_r1dMlxaFgPCpVDU,4788 +authlib/oauth2/rfc7662/models.py,sha256=vlmy-_UJmzy4rFjOjLsKpybpodoMsxt4FRi-URDoCKQ,868 +authlib/oauth2/rfc8414/__init__.py,sha256=G_tQ8TI6qGx1Udk5ogjd7pP-Q15k0X7tPVN4IyUUoTA,385 +authlib/oauth2/rfc8414/__pycache__/__init__.cpython-38.pyc,, +authlib/oauth2/rfc8414/__pycache__/models.cpython-38.pyc,, +authlib/oauth2/rfc8414/__pycache__/well_known.cpython-38.pyc,, +authlib/oauth2/rfc8414/models.py,sha256=k_Bl8dJu7HxLob7c9R288Z3FtQAV9zTZlrzEBYii_xI,17490 +authlib/oauth2/rfc8414/well_known.py,sha256=PW0DH8-CrRehqy9kmm_iaeViOl7lFgMqWG_TZWq6NJs,745 +authlib/oauth2/rfc8628/__init__.py,sha256=oQSZsFfTr-BhdrdFhXW31FfgW3Qn5PjClNq3k1GF3z0,702 +authlib/oauth2/rfc8628/__pycache__/__init__.cpython-38.pyc,, +authlib/oauth2/rfc8628/__pycache__/device_code.cpython-38.pyc,, +authlib/oauth2/rfc8628/__pycache__/endpoint.cpython-38.pyc,, +authlib/oauth2/rfc8628/__pycache__/errors.cpython-38.pyc,, +authlib/oauth2/rfc8628/__pycache__/models.cpython-38.pyc,, +authlib/oauth2/rfc8628/device_code.py,sha256=GnsNFrs-3OaSEdo7g1SlUCWmaq-35LIxH-gPiIH7fyg,8165 +authlib/oauth2/rfc8628/endpoint.py,sha256=PYcYyCzf8l9Rn53eJh5qfs09ms7DEio84gKNWCi7Bfw,6254 +authlib/oauth2/rfc8628/errors.py,sha256=c761U-GWU58bmfyEPw1VveaOkmOgXElBVlWaE-tXMTg,919 +authlib/oauth2/rfc8628/models.py,sha256=J2AWUdxaTScJuevuqzHE_xs5ufIGmANsIxrxsboj03A,610 +authlib/oauth2/rfc8693/__init__.py,sha256=MiJMzPYCjHeCqCZmIUrEoUfif7UVIbKGS_tjBXTPN-w,206 +authlib/oauth2/rfc8693/__pycache__/__init__.cpython-38.pyc,, +authlib/oidc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +authlib/oidc/__pycache__/__init__.cpython-38.pyc,, +authlib/oidc/core/__init__.py,sha256=ncECH1dHLHLM1k7f2a8_nM32RextszP0SvYRGk4Q4ww,622 +authlib/oidc/core/__pycache__/__init__.cpython-38.pyc,, +authlib/oidc/core/__pycache__/claims.cpython-38.pyc,, +authlib/oidc/core/__pycache__/errors.cpython-38.pyc,, +authlib/oidc/core/__pycache__/models.cpython-38.pyc,, +authlib/oidc/core/__pycache__/util.cpython-38.pyc,, +authlib/oidc/core/claims.py,sha256=R4B-hPqaVxjQisSDf3PWbLOz9-Ak63f6ny8oX1XyvIU,10218 +authlib/oidc/core/errors.py,sha256=2nZdVIlTweNwXapWa7QodgCR0_5neGlCbGB2U4xUT6o,2883 +authlib/oidc/core/grants/__init__.py,sha256=uREj2j3vw3szffWCVLCGn6aCXt91ZnwNKSzGL_bYKH8,194 +authlib/oidc/core/grants/__pycache__/__init__.cpython-38.pyc,, +authlib/oidc/core/grants/__pycache__/code.cpython-38.pyc,, +authlib/oidc/core/grants/__pycache__/hybrid.cpython-38.pyc,, +authlib/oidc/core/grants/__pycache__/implicit.cpython-38.pyc,, +authlib/oidc/core/grants/__pycache__/util.cpython-38.pyc,, +authlib/oidc/core/grants/code.py,sha256=Dpf5w55SR44mp2A5t-Vdfk7epmwBAFic_AAhRJAiILw,4071 +authlib/oidc/core/grants/hybrid.py,sha256=mDF66-sX40Qz1trtBg0xDLZMeh17dpiUy71jtjS67Ik,3649 +authlib/oidc/core/grants/implicit.py,sha256=ADCMVuGrOrUVSR57S4z9Pe2D6rUwKC3Qn5qb5-kqepg,5326 +authlib/oidc/core/grants/util.py,sha256=r40yHBeE63fC1_kbrCXKT5ftTojF19TOOenE_-uDehs,4785 +authlib/oidc/core/models.py,sha256=eYGC-NcIuu1m50h5o1bJFwUjwGF9l-AytTic8B07zmU,413 +authlib/oidc/core/util.py,sha256=J0x7rU_X35h2fLN3D49G3-F9wN3WAamFpsRPIclarK0,390 +authlib/oidc/discovery/__init__.py,sha256=sI40mT-HXoRPqxAE5UfPg-r3xa_wrQZ8jIuN5n5nm70,321 +authlib/oidc/discovery/__pycache__/__init__.cpython-38.pyc,, +authlib/oidc/discovery/__pycache__/models.cpython-38.pyc,, +authlib/oidc/discovery/__pycache__/well_known.cpython-38.pyc,, +authlib/oidc/discovery/models.py,sha256=dcb7fprftGNQtlDKOBUxTf3fVtDj8CpmocBM1PjtRBc,12611 +authlib/oidc/discovery/well_known.py,sha256=3VmfTsVReChVVxBuN1eoL7fIRHL0-tN0aXH2XVKeiDM,574 diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Authlib-0.15.2.dist-info/REQUESTED b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Authlib-0.15.2.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Authlib-0.15.2.dist-info/WHEEL b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Authlib-0.15.2.dist-info/WHEEL new file mode 100644 index 0000000..8b701e9 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Authlib-0.15.2.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.33.6) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Authlib-0.15.2.dist-info/top_level.txt b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Authlib-0.15.2.dist-info/top_level.txt new file mode 100644 index 0000000..b91e7e4 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Authlib-0.15.2.dist-info/top_level.txt @@ -0,0 +1 @@ +authlib diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/INSTALLER b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/LICENSE.rst b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/LICENSE.rst new file mode 100644 index 0000000..9d227a0 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2010 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/METADATA b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/METADATA new file mode 100644 index 0000000..db7fcd1 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/METADATA @@ -0,0 +1,137 @@ +Metadata-Version: 2.1 +Name: Flask +Version: 1.1.2 +Summary: A simple framework for building complex web applications. +Home-page: https://palletsprojects.com/p/flask/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Documentation, https://flask.palletsprojects.com/ +Project-URL: Code, https://github.com/pallets/flask +Project-URL: Issue tracker, https://github.com/pallets/flask/issues +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Framework :: Flask +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application +Classifier: Topic :: Software Development :: Libraries :: Application Frameworks +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* +Requires-Dist: Werkzeug (>=0.15) +Requires-Dist: Jinja2 (>=2.10.1) +Requires-Dist: itsdangerous (>=0.24) +Requires-Dist: click (>=5.1) +Provides-Extra: dev +Requires-Dist: pytest ; extra == 'dev' +Requires-Dist: coverage ; extra == 'dev' +Requires-Dist: tox ; extra == 'dev' +Requires-Dist: sphinx ; extra == 'dev' +Requires-Dist: pallets-sphinx-themes ; extra == 'dev' +Requires-Dist: sphinxcontrib-log-cabinet ; extra == 'dev' +Requires-Dist: sphinx-issues ; extra == 'dev' +Provides-Extra: docs +Requires-Dist: sphinx ; extra == 'docs' +Requires-Dist: pallets-sphinx-themes ; extra == 'docs' +Requires-Dist: sphinxcontrib-log-cabinet ; extra == 'docs' +Requires-Dist: sphinx-issues ; extra == 'docs' +Provides-Extra: dotenv +Requires-Dist: python-dotenv ; extra == 'dotenv' + +Flask +===== + +Flask is a lightweight `WSGI`_ web application framework. It is designed +to make getting started quick and easy, with the ability to scale up to +complex applications. It began as a simple wrapper around `Werkzeug`_ +and `Jinja`_ and has become one of the most popular Python web +application frameworks. + +Flask offers suggestions, but doesn't enforce any dependencies or +project layout. It is up to the developer to choose the tools and +libraries they want to use. There are many extensions provided by the +community that make adding new functionality easy. + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + pip install -U Flask + + +A Simple Example +---------------- + +.. code-block:: python + + from flask import Flask + + app = Flask(__name__) + + @app.route("/") + def hello(): + return "Hello, World!" + +.. code-block:: text + + $ env FLASK_APP=hello.py flask run + * Serving Flask app "hello" + * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) + + +Contributing +------------ + +For guidance on setting up a development environment and how to make a +contribution to Flask, see the `contributing guidelines`_. + +.. _contributing guidelines: https://github.com/pallets/flask/blob/master/CONTRIBUTING.rst + + +Donate +------ + +The Pallets organization develops and supports Flask and the libraries +it uses. In order to grow the community of contributors and users, and +allow the maintainers to devote more time to the projects, `please +donate today`_. + +.. _please donate today: https://psfmember.org/civicrm/contribute/transact?reset=1&id=20 + + +Links +----- + +* Website: https://palletsprojects.com/p/flask/ +* Documentation: https://flask.palletsprojects.com/ +* Releases: https://pypi.org/project/Flask/ +* Code: https://github.com/pallets/flask +* Issue tracker: https://github.com/pallets/flask/issues +* Test status: https://dev.azure.com/pallets/flask/_build +* Official chat: https://discord.gg/t6rrQZH + +.. _WSGI: https://wsgi.readthedocs.io +.. _Werkzeug: https://www.palletsprojects.com/p/werkzeug/ +.. _Jinja: https://www.palletsprojects.com/p/jinja/ +.. _pip: https://pip.pypa.io/en/stable/quickstart/ + + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/RECORD b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/RECORD new file mode 100644 index 0000000..b7f0bf1 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/RECORD @@ -0,0 +1,49 @@ +../../../bin/flask,sha256=YlY6gkOdtl0cZBsv6C59y7KUAcrZWL9w8yxSL_EhxL0,293 +Flask-1.1.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +Flask-1.1.2.dist-info/LICENSE.rst,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475 +Flask-1.1.2.dist-info/METADATA,sha256=3INpPWH6nKfZ33R2N-bQZy4TOe1wQCMweZc9mwcNrtc,4591 +Flask-1.1.2.dist-info/RECORD,, +Flask-1.1.2.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +Flask-1.1.2.dist-info/WHEEL,sha256=8zNYZbwQSXoB9IfXOjPfeNwvAsALAjffgk27FqvCWbo,110 +Flask-1.1.2.dist-info/entry_points.txt,sha256=gBLA1aKg0OYR8AhbAfg8lnburHtKcgJLDU52BBctN0k,42 +Flask-1.1.2.dist-info/top_level.txt,sha256=dvi65F6AeGWVU0TBpYiC04yM60-FX1gJFkK31IKQr5c,6 +flask/__init__.py,sha256=YnA9wkwbJcnb_jTT-nMsMFeFE_UWt33khKzdHmMSuyI,1894 +flask/__main__.py,sha256=fjVtt3QTANXlpJCOv3Ha7d5H-76MwzSIOab7SFD9TEk,254 +flask/__pycache__/__init__.cpython-38.pyc,, +flask/__pycache__/__main__.cpython-38.pyc,, +flask/__pycache__/_compat.cpython-38.pyc,, +flask/__pycache__/app.cpython-38.pyc,, +flask/__pycache__/blueprints.cpython-38.pyc,, +flask/__pycache__/cli.cpython-38.pyc,, +flask/__pycache__/config.cpython-38.pyc,, +flask/__pycache__/ctx.cpython-38.pyc,, +flask/__pycache__/debughelpers.cpython-38.pyc,, +flask/__pycache__/globals.cpython-38.pyc,, +flask/__pycache__/helpers.cpython-38.pyc,, +flask/__pycache__/logging.cpython-38.pyc,, +flask/__pycache__/sessions.cpython-38.pyc,, +flask/__pycache__/signals.cpython-38.pyc,, +flask/__pycache__/templating.cpython-38.pyc,, +flask/__pycache__/testing.cpython-38.pyc,, +flask/__pycache__/views.cpython-38.pyc,, +flask/__pycache__/wrappers.cpython-38.pyc,, +flask/_compat.py,sha256=8KPT54Iig96TuLipdogLRHNYToIcg-xPhnSV5VRERnw,4099 +flask/app.py,sha256=tmEhx_XrIRP24vZg39dHMWFzJ2jj-YxIcd51LaIT5cE,98059 +flask/blueprints.py,sha256=vkdm8NusGsfZUeIfPdCluj733QFmiQcT4Sk1tuZLUjw,21400 +flask/cli.py,sha256=SIb22uq9wYBeB2tKMl0pYdhtZ1MAQyZtPL-3m6es4G0,31035 +flask/config.py,sha256=3dejvQRYfNHw_V7dCLMxU8UNFpL34xIKemN7gHZIZ8Y,10052 +flask/ctx.py,sha256=cks-omGedkxawHFo6bKIrdOHsJCAgg1i_NWw_htxb5U,16724 +flask/debughelpers.py,sha256=-whvPKuAoU8AZ9c1z_INuOeBgfYDqE1J2xNBsoriugU,6475 +flask/globals.py,sha256=OgcHb6_NCyX6-TldciOdKcyj4PNfyQwClxdMhvov6aA,1637 +flask/helpers.py,sha256=IHa578HU_3XAAo1wpXQv24MYRYO5TzaiDQQwvUIcE6Q,43074 +flask/json/__init__.py,sha256=6nITbZYiYOPB8Qfi1-dvsblwn01KRz8VOsMBIZyaYek,11988 +flask/json/__pycache__/__init__.cpython-38.pyc,, +flask/json/__pycache__/tag.cpython-38.pyc,, +flask/json/tag.py,sha256=vq9GOllg_0kTWKuVFrwmkeOQzR-jdBD23x-89JyCCQI,8306 +flask/logging.py,sha256=WcY5UkqTysGfmosyygSlXyZYGwOp3y-VsE6ehoJ48dk,3250 +flask/sessions.py,sha256=G0KsEkr_i1LG_wOINwFSOW3ts7Xbv4bNgEZKc7TRloc,14360 +flask/signals.py,sha256=yYLOed2x8WnQ7pirGalQYfpYpCILJ0LJhmNSrnWvjqw,2212 +flask/templating.py,sha256=F8E_IZXn9BGsjMzUJ5N_ACMyZdiFBp_SSEaUunvfZ7g,4939 +flask/testing.py,sha256=WXsciCQbHBP7xjHqNvOA4bT0k86GvSNpgzncfXLDEEg,10146 +flask/views.py,sha256=eeWnadLAj0QdQPLtjKipDetRZyG62CT2y7fNOFDJz0g,5802 +flask/wrappers.py,sha256=kgsvtZuMM6RQaDqhRbc5Pcj9vqTnaERl2pmXcdGL7LU,4736 diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/REQUESTED b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/WHEEL b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/WHEEL new file mode 100644 index 0000000..8b701e9 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.33.6) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/entry_points.txt b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/entry_points.txt new file mode 100644 index 0000000..1eb0252 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[console_scripts] +flask = flask.cli:main + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/top_level.txt b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/top_level.txt new file mode 100644 index 0000000..7e10602 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Flask-1.1.2.dist-info/top_level.txt @@ -0,0 +1 @@ +flask diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/INSTALLER b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/LICENSE.rst b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/LICENSE.rst new file mode 100644 index 0000000..c37cae4 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2007 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/METADATA b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/METADATA new file mode 100644 index 0000000..55c0f82 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/METADATA @@ -0,0 +1,106 @@ +Metadata-Version: 2.1 +Name: Jinja2 +Version: 2.11.2 +Summary: A very fast and expressive template engine. +Home-page: https://palletsprojects.com/p/jinja/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Documentation, https://jinja.palletsprojects.com/ +Project-URL: Code, https://github.com/pallets/jinja +Project-URL: Issue tracker, https://github.com/pallets/jinja/issues +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Text Processing :: Markup :: HTML +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* +Description-Content-Type: text/x-rst +Requires-Dist: MarkupSafe (>=0.23) +Provides-Extra: i18n +Requires-Dist: Babel (>=0.8) ; extra == 'i18n' + +Jinja +===== + +Jinja is a fast, expressive, extensible templating engine. Special +placeholders in the template allow writing code similar to Python +syntax. Then the template is passed data to render the final document. + +It includes: + +- Template inheritance and inclusion. +- Define and import macros within templates. +- HTML templates can use autoescaping to prevent XSS from untrusted + user input. +- A sandboxed environment can safely render untrusted templates. +- AsyncIO support for generating templates and calling async + functions. +- I18N support with Babel. +- Templates are compiled to optimized Python code just-in-time and + cached, or can be compiled ahead-of-time. +- Exceptions point to the correct line in templates to make debugging + easier. +- Extensible filters, tests, functions, and even syntax. + +Jinja's philosophy is that while application logic belongs in Python if +possible, it shouldn't make the template designer's job difficult by +restricting functionality too much. + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + $ pip install -U Jinja2 + +.. _pip: https://pip.pypa.io/en/stable/quickstart/ + + +In A Nutshell +------------- + +.. code-block:: jinja + + {% extends "base.html" %} + {% block title %}Members{% endblock %} + {% block content %} + + {% endblock %} + + +Links +----- + +- Website: https://palletsprojects.com/p/jinja/ +- Documentation: https://jinja.palletsprojects.com/ +- Releases: https://pypi.org/project/Jinja2/ +- Code: https://github.com/pallets/jinja +- Issue tracker: https://github.com/pallets/jinja/issues +- Test status: https://dev.azure.com/pallets/jinja/_build +- Official chat: https://discord.gg/t6rrQZH + + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/RECORD b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/RECORD new file mode 100644 index 0000000..413fef4 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/RECORD @@ -0,0 +1,61 @@ +Jinja2-2.11.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +Jinja2-2.11.2.dist-info/LICENSE.rst,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475 +Jinja2-2.11.2.dist-info/METADATA,sha256=5ZHRZoIRAMHsJPnqhlJ622_dRPsYePYJ-9EH4-Ry7yI,3535 +Jinja2-2.11.2.dist-info/RECORD,, +Jinja2-2.11.2.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110 +Jinja2-2.11.2.dist-info/entry_points.txt,sha256=Qy_DkVo6Xj_zzOtmErrATe8lHZhOqdjpt3e4JJAGyi8,61 +Jinja2-2.11.2.dist-info/top_level.txt,sha256=PkeVWtLb3-CqjWi1fO29OCbj55EhX_chhKrCdrVe_zs,7 +jinja2/__init__.py,sha256=0QCM_jKKDM10yzSdHRVV4mQbCbDqf0GN0GirAqibn9Y,1549 +jinja2/__pycache__/__init__.cpython-38.pyc,, +jinja2/__pycache__/_compat.cpython-38.pyc,, +jinja2/__pycache__/_identifier.cpython-38.pyc,, +jinja2/__pycache__/asyncfilters.cpython-38.pyc,, +jinja2/__pycache__/asyncsupport.cpython-38.pyc,, +jinja2/__pycache__/bccache.cpython-38.pyc,, +jinja2/__pycache__/compiler.cpython-38.pyc,, +jinja2/__pycache__/constants.cpython-38.pyc,, +jinja2/__pycache__/debug.cpython-38.pyc,, +jinja2/__pycache__/defaults.cpython-38.pyc,, +jinja2/__pycache__/environment.cpython-38.pyc,, +jinja2/__pycache__/exceptions.cpython-38.pyc,, +jinja2/__pycache__/ext.cpython-38.pyc,, +jinja2/__pycache__/filters.cpython-38.pyc,, +jinja2/__pycache__/idtracking.cpython-38.pyc,, +jinja2/__pycache__/lexer.cpython-38.pyc,, +jinja2/__pycache__/loaders.cpython-38.pyc,, +jinja2/__pycache__/meta.cpython-38.pyc,, +jinja2/__pycache__/nativetypes.cpython-38.pyc,, +jinja2/__pycache__/nodes.cpython-38.pyc,, +jinja2/__pycache__/optimizer.cpython-38.pyc,, +jinja2/__pycache__/parser.cpython-38.pyc,, +jinja2/__pycache__/runtime.cpython-38.pyc,, +jinja2/__pycache__/sandbox.cpython-38.pyc,, +jinja2/__pycache__/tests.cpython-38.pyc,, +jinja2/__pycache__/utils.cpython-38.pyc,, +jinja2/__pycache__/visitor.cpython-38.pyc,, +jinja2/_compat.py,sha256=B6Se8HjnXVpzz9-vfHejn-DV2NjaVK-Iewupc5kKlu8,3191 +jinja2/_identifier.py,sha256=EdgGJKi7O1yvr4yFlvqPNEqV6M1qHyQr8Gt8GmVTKVM,1775 +jinja2/asyncfilters.py,sha256=XJtYXTxFvcJ5xwk6SaDL4S0oNnT0wPYvXBCSzc482fI,4250 +jinja2/asyncsupport.py,sha256=ZBFsDLuq3Gtji3Ia87lcyuDbqaHZJRdtShZcqwpFnSQ,7209 +jinja2/bccache.py,sha256=3Pmp4jo65M9FQuIxdxoDBbEDFwe4acDMQf77nEJfrHA,12139 +jinja2/compiler.py,sha256=Ta9W1Lit542wItAHXlDcg0sEOsFDMirCdlFPHAurg4o,66284 +jinja2/constants.py,sha256=RR1sTzNzUmKco6aZicw4JpQpJGCuPuqm1h1YmCNUEFY,1458 +jinja2/debug.py,sha256=neR7GIGGjZH3_ILJGVUYy3eLQCCaWJMXOb7o0kGInWc,8529 +jinja2/defaults.py,sha256=85B6YUUCyWPSdrSeVhcqFVuu_bHUAQXeey--FIwSeVQ,1126 +jinja2/environment.py,sha256=XDSLKc4SqNLMOwTSq3TbWEyA5WyXfuLuVD0wAVjEFwM,50629 +jinja2/exceptions.py,sha256=VjNLawcmf2ODffqVMCQK1cRmvFaUfQWF4u8ouP3QPcE,5425 +jinja2/ext.py,sha256=AtwL5O5enT_L3HR9-oBvhGyUTdGoyaqG_ICtnR_EVd4,26441 +jinja2/filters.py,sha256=_RpPgAlgIj7ExvyDzcHAC3B36cocfWK-1TEketbNeM0,41415 +jinja2/idtracking.py,sha256=J3O4VHsrbf3wzwiBc7Cro26kHb6_5kbULeIOzocchIU,9211 +jinja2/lexer.py,sha256=nUFLRKhhKmmEWkLI65nQePgcQs7qsRdjVYZETMt_v0g,30331 +jinja2/loaders.py,sha256=C-fST_dmFjgWkp0ZuCkrgICAoOsoSIF28wfAFink0oU,17666 +jinja2/meta.py,sha256=QjyYhfNRD3QCXjBJpiPl9KgkEkGXJbAkCUq4-Ur10EQ,4131 +jinja2/nativetypes.py,sha256=Ul__gtVw4xH-0qvUvnCNHedQeNDwmEuyLJztzzSPeRg,2753 +jinja2/nodes.py,sha256=Mk1oJPVgIjnQw9WOqILvcu3rLepcFZ0ahxQm2mbwDwc,31095 +jinja2/optimizer.py,sha256=gQLlMYzvQhluhzmAIFA1tXS0cwgWYOjprN-gTRcHVsc,1457 +jinja2/parser.py,sha256=fcfdqePNTNyvosIvczbytVA332qpsURvYnCGcjDHSkA,35660 +jinja2/runtime.py,sha256=0y-BRyIEZ9ltByL2Id6GpHe1oDRQAwNeQvI0SKobNMw,30618 +jinja2/sandbox.py,sha256=knayyUvXsZ-F0mk15mO2-ehK9gsw04UhB8td-iUOtLc,17127 +jinja2/tests.py,sha256=iO_Y-9Vo60zrVe1lMpSl5sKHqAxe2leZHC08OoZ8K24,4799 +jinja2/utils.py,sha256=OoVMlQe9S2-lWT6jJbTu9tDuDvGNyWUhHDcE51i5_Do,22522 +jinja2/visitor.py,sha256=DUHupl0a4PGp7nxRtZFttUzAi1ccxzqc2hzetPYUz8U,3240 diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/WHEEL b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/WHEEL new file mode 100644 index 0000000..ef99c6c --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.34.2) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/entry_points.txt b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/entry_points.txt new file mode 100644 index 0000000..3619483 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[babel.extractors] +jinja2 = jinja2.ext:babel_extract [i18n] + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/top_level.txt b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/top_level.txt new file mode 100644 index 0000000..7f7afbf --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/top_level.txt @@ -0,0 +1 @@ +jinja2 diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/INSTALLER b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/LICENSE.txt b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/LICENSE.txt new file mode 100644 index 0000000..9d227a0 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/LICENSE.txt @@ -0,0 +1,28 @@ +Copyright 2010 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/METADATA b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/METADATA new file mode 100644 index 0000000..c50370d --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/METADATA @@ -0,0 +1,105 @@ +Metadata-Version: 2.1 +Name: MarkupSafe +Version: 1.1.1 +Summary: Safely add untrusted strings to HTML/XML markup. +Home-page: https://palletsprojects.com/p/markupsafe/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +Maintainer: The Pallets Team +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Documentation, https://markupsafe.palletsprojects.com/ +Project-URL: Code, https://github.com/pallets/markupsafe +Project-URL: Issue tracker, https://github.com/pallets/markupsafe/issues +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Text Processing :: Markup :: HTML +Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.* +Description-Content-Type: text/x-rst + +MarkupSafe +========== + +MarkupSafe implements a text object that escapes characters so it is +safe to use in HTML and XML. Characters that have special meanings are +replaced so that they display as the actual characters. This mitigates +injection attacks, meaning untrusted user input can safely be displayed +on a page. + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + pip install -U MarkupSafe + +.. _pip: https://pip.pypa.io/en/stable/quickstart/ + + +Examples +-------- + +.. code-block:: pycon + + >>> from markupsafe import Markup, escape + >>> # escape replaces special characters and wraps in Markup + >>> escape('') + Markup(u'<script>alert(document.cookie);</script>') + >>> # wrap in Markup to mark text "safe" and prevent escaping + >>> Markup('Hello') + Markup('hello') + >>> escape(Markup('Hello')) + Markup('hello') + >>> # Markup is a text subclass (str on Python 3, unicode on Python 2) + >>> # methods and operators escape their arguments + >>> template = Markup("Hello %s") + >>> template % '"World"' + Markup('Hello "World"') + + +Donate +------ + +The Pallets organization develops and supports MarkupSafe and other +libraries that use it. In order to grow the community of contributors +and users, and allow the maintainers to devote more time to the +projects, `please donate today`_. + +.. _please donate today: https://palletsprojects.com/donate + + +Links +----- + +* Website: https://palletsprojects.com/p/markupsafe/ +* Documentation: https://markupsafe.palletsprojects.com/ +* License: `BSD-3-Clause `_ +* Releases: https://pypi.org/project/MarkupSafe/ +* Code: https://github.com/pallets/markupsafe +* Issue tracker: https://github.com/pallets/markupsafe/issues +* Test status: + + * Linux, Mac: https://travis-ci.org/pallets/markupsafe + * Windows: https://ci.appveyor.com/project/pallets/markupsafe + +* Test coverage: https://codecov.io/gh/pallets/markupsafe +* Official chat: https://discord.gg/t6rrQZH + + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/RECORD b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/RECORD new file mode 100644 index 0000000..95c3339 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/RECORD @@ -0,0 +1,16 @@ +MarkupSafe-1.1.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +MarkupSafe-1.1.1.dist-info/LICENSE.txt,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475 +MarkupSafe-1.1.1.dist-info/METADATA,sha256=IFCP4hCNGjXJgMoSvdjPiKDLAMUTTWoxKXQsQvmyMNU,3653 +MarkupSafe-1.1.1.dist-info/RECORD,, +MarkupSafe-1.1.1.dist-info/WHEEL,sha256=VEyGcIFAmk_1KbI6gaZGw_mMiT-pdGweASQLX-DzYaY,108 +MarkupSafe-1.1.1.dist-info/top_level.txt,sha256=qy0Plje5IJuvsCBjejJyhDCjEAdcDLK_2agVcex8Z6U,11 +markupsafe/__init__.py,sha256=oTblO5f9KFM-pvnq9bB0HgElnqkJyqHnFN1Nx2NIvnY,10126 +markupsafe/__pycache__/__init__.cpython-38.pyc,, +markupsafe/__pycache__/_compat.cpython-38.pyc,, +markupsafe/__pycache__/_constants.cpython-38.pyc,, +markupsafe/__pycache__/_native.cpython-38.pyc,, +markupsafe/_compat.py,sha256=uEW1ybxEjfxIiuTbRRaJpHsPFf4yQUMMKaPgYEC5XbU,558 +markupsafe/_constants.py,sha256=zo2ajfScG-l1Sb_52EP3MlDCqO7Y1BVHUXXKRsVDRNk,4690 +markupsafe/_native.py,sha256=d-8S_zzYt2y512xYcuSxq0NeG2DUUvG80wVdTn-4KI8,1873 +markupsafe/_speedups.c,sha256=k0fzEIK3CP6MmMqeY0ob43TP90mVN0DTyn7BAl3RqSg,9884 +markupsafe/_speedups.cpython-38-x86_64-linux-gnu.so,sha256=SbJwN321Xn7OPYGv5a6Ghzga75uT8RHQUGkoQUASF-o,48016 diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/WHEEL b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/WHEEL new file mode 100644 index 0000000..ae40efd --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.31.1) +Root-Is-Purelib: false +Tag: cp38-cp38-manylinux1_x86_64 + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/top_level.txt b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/top_level.txt new file mode 100644 index 0000000..75bf729 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/MarkupSafe-1.1.1.dist-info/top_level.txt @@ -0,0 +1 @@ +markupsafe diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Werkzeug-1.0.1.dist-info/INSTALLER b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Werkzeug-1.0.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Werkzeug-1.0.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Werkzeug-1.0.1.dist-info/LICENSE.rst b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Werkzeug-1.0.1.dist-info/LICENSE.rst new file mode 100644 index 0000000..c37cae4 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Werkzeug-1.0.1.dist-info/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2007 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Werkzeug-1.0.1.dist-info/METADATA b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Werkzeug-1.0.1.dist-info/METADATA new file mode 100644 index 0000000..eb5f709 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Werkzeug-1.0.1.dist-info/METADATA @@ -0,0 +1,128 @@ +Metadata-Version: 2.1 +Name: Werkzeug +Version: 1.0.1 +Summary: The comprehensive WSGI web application library. +Home-page: https://palletsprojects.com/p/werkzeug/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Documentation, https://werkzeug.palletsprojects.com/ +Project-URL: Code, https://github.com/pallets/werkzeug +Project-URL: Issue tracker, https://github.com/pallets/werkzeug/issues +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware +Classifier: Topic :: Software Development :: Libraries :: Application Frameworks +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* +Description-Content-Type: text/x-rst +Provides-Extra: dev +Requires-Dist: pytest ; extra == 'dev' +Requires-Dist: pytest-timeout ; extra == 'dev' +Requires-Dist: coverage ; extra == 'dev' +Requires-Dist: tox ; extra == 'dev' +Requires-Dist: sphinx ; extra == 'dev' +Requires-Dist: pallets-sphinx-themes ; extra == 'dev' +Requires-Dist: sphinx-issues ; extra == 'dev' +Provides-Extra: watchdog +Requires-Dist: watchdog ; extra == 'watchdog' + +Werkzeug +======== + +*werkzeug* German noun: "tool". Etymology: *werk* ("work"), *zeug* ("stuff") + +Werkzeug is a comprehensive `WSGI`_ web application library. It began as +a simple collection of various utilities for WSGI applications and has +become one of the most advanced WSGI utility libraries. + +It includes: + +- An interactive debugger that allows inspecting stack traces and + source code in the browser with an interactive interpreter for any + frame in the stack. +- A full-featured request object with objects to interact with + headers, query args, form data, files, and cookies. +- A response object that can wrap other WSGI applications and handle + streaming data. +- A routing system for matching URLs to endpoints and generating URLs + for endpoints, with an extensible system for capturing variables + from URLs. +- HTTP utilities to handle entity tags, cache control, dates, user + agents, cookies, files, and more. +- A threaded WSGI server for use while developing applications + locally. +- A test client for simulating HTTP requests during testing without + requiring running a server. + +Werkzeug is Unicode aware and doesn't enforce any dependencies. It is up +to the developer to choose a template engine, database adapter, and even +how to handle requests. It can be used to build all sorts of end user +applications such as blogs, wikis, or bulletin boards. + +`Flask`_ wraps Werkzeug, using it to handle the details of WSGI while +providing more structure and patterns for defining powerful +applications. + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + pip install -U Werkzeug + + +A Simple Example +---------------- + +.. code-block:: python + + from werkzeug.wrappers import Request, Response + + @Request.application + def application(request): + return Response('Hello, World!') + + if __name__ == '__main__': + from werkzeug.serving import run_simple + run_simple('localhost', 4000, application) + + +Links +----- + +- Website: https://palletsprojects.com/p/werkzeug/ +- Documentation: https://werkzeug.palletsprojects.com/ +- Releases: https://pypi.org/project/Werkzeug/ +- Code: https://github.com/pallets/werkzeug +- Issue tracker: https://github.com/pallets/werkzeug/issues +- Test status: https://dev.azure.com/pallets/werkzeug/_build +- Official chat: https://discord.gg/t6rrQZH + +.. _WSGI: https://wsgi.readthedocs.io/en/latest/ +.. _Flask: https://www.palletsprojects.com/p/flask/ +.. _pip: https://pip.pypa.io/en/stable/quickstart/ + + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Werkzeug-1.0.1.dist-info/RECORD b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Werkzeug-1.0.1.dist-info/RECORD new file mode 100644 index 0000000..1b8ceae --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Werkzeug-1.0.1.dist-info/RECORD @@ -0,0 +1,101 @@ +Werkzeug-1.0.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +Werkzeug-1.0.1.dist-info/LICENSE.rst,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475 +Werkzeug-1.0.1.dist-info/METADATA,sha256=d0zmVNa4UC2-nAo2A8_81oiy123D6JTGRSuY_Ymgyt4,4730 +Werkzeug-1.0.1.dist-info/RECORD,, +Werkzeug-1.0.1.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110 +Werkzeug-1.0.1.dist-info/top_level.txt,sha256=QRyj2VjwJoQkrwjwFIOlB8Xg3r9un0NtqVHQF-15xaw,9 +werkzeug/__init__.py,sha256=rb-yPiXOjTLbtDOl5fQp5hN7oBdaoXAoQ-slAAvfZAo,502 +werkzeug/__pycache__/__init__.cpython-38.pyc,, +werkzeug/__pycache__/_compat.cpython-38.pyc,, +werkzeug/__pycache__/_internal.cpython-38.pyc,, +werkzeug/__pycache__/_reloader.cpython-38.pyc,, +werkzeug/__pycache__/datastructures.cpython-38.pyc,, +werkzeug/__pycache__/exceptions.cpython-38.pyc,, +werkzeug/__pycache__/filesystem.cpython-38.pyc,, +werkzeug/__pycache__/formparser.cpython-38.pyc,, +werkzeug/__pycache__/http.cpython-38.pyc,, +werkzeug/__pycache__/local.cpython-38.pyc,, +werkzeug/__pycache__/posixemulation.cpython-38.pyc,, +werkzeug/__pycache__/routing.cpython-38.pyc,, +werkzeug/__pycache__/security.cpython-38.pyc,, +werkzeug/__pycache__/serving.cpython-38.pyc,, +werkzeug/__pycache__/test.cpython-38.pyc,, +werkzeug/__pycache__/testapp.cpython-38.pyc,, +werkzeug/__pycache__/urls.cpython-38.pyc,, +werkzeug/__pycache__/useragents.cpython-38.pyc,, +werkzeug/__pycache__/utils.cpython-38.pyc,, +werkzeug/__pycache__/wsgi.cpython-38.pyc,, +werkzeug/_compat.py,sha256=zjufTNrhQ8BgYSGSh-sVu6iW3r3O9WzjE9j-qJobx-g,6671 +werkzeug/_internal.py,sha256=d_4AqheyS6dHMViwdc0drFrjs67ZzT6Ej2gWf-Z-Iys,14351 +werkzeug/_reloader.py,sha256=I3mg3oRQ0lLzl06oEoVopN3bN7CtINuuUQdqDcmTnEs,11531 +werkzeug/datastructures.py,sha256=AonxOcwU0TPMEzfKF1368ySULxHgxE-JE-DEAGdo2ts,100480 +werkzeug/debug/__init__.py,sha256=3RtUMc5Y9hYyK11ugHltgkQ9Dt-ViR945Vy_X5NV7zU,17289 +werkzeug/debug/__pycache__/__init__.cpython-38.pyc,, +werkzeug/debug/__pycache__/console.cpython-38.pyc,, +werkzeug/debug/__pycache__/repr.cpython-38.pyc,, +werkzeug/debug/__pycache__/tbtools.cpython-38.pyc,, +werkzeug/debug/console.py,sha256=OATaO7KHYMqpbzIFe1HeW9Mnl3wZgA3jMQoGDPn5URc,5488 +werkzeug/debug/repr.py,sha256=lIwuhbyrMwVe3P_cFqNyqzHL7P93TLKod7lw9clydEw,9621 +werkzeug/debug/shared/FONT_LICENSE,sha256=LwAVEI1oYnvXiNMT9SnCH_TaLCxCpeHziDrMg0gPkAI,4673 +werkzeug/debug/shared/console.png,sha256=bxax6RXXlvOij_KeqvSNX0ojJf83YbnZ7my-3Gx9w2A,507 +werkzeug/debug/shared/debugger.js,sha256=rOhqZMRfpZnnu6_XCGn6wMWPhtfwRAcyZKksdIxPJas,6400 +werkzeug/debug/shared/jquery.js,sha256=CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo,88145 +werkzeug/debug/shared/less.png,sha256=-4-kNRaXJSONVLahrQKUxMwXGm9R4OnZ9SxDGpHlIR4,191 +werkzeug/debug/shared/more.png,sha256=GngN7CioHQoV58rH6ojnkYi8c_qED2Aka5FO5UXrReY,200 +werkzeug/debug/shared/source.png,sha256=RoGcBTE4CyCB85GBuDGTFlAnUqxwTBiIfDqW15EpnUQ,818 +werkzeug/debug/shared/style.css,sha256=gZ9uhmb5zj3XLuT9RvnMp6jMINgQ-VVBCp-2AZbG3YQ,6604 +werkzeug/debug/shared/ubuntu.ttf,sha256=1eaHFyepmy4FyDvjLVzpITrGEBu_CZYY94jE0nED1c0,70220 +werkzeug/debug/tbtools.py,sha256=2iJ8RURUZUSbopOIehy53LnVJWx47lsHN2V2l6hc7Wc,20363 +werkzeug/exceptions.py,sha256=UTYSDkmAsH-vt8VSidlEffwqBVNXuT7bRg-_NqgUe8A,25188 +werkzeug/filesystem.py,sha256=HzKl-j0Hd8Jl66j778UbPTAYNnY6vUZgYLlBZ0e7uw0,2101 +werkzeug/formparser.py,sha256=Sto0jZid9im9ZVIf56vilCdyX-arK33wSftkYsLCnzo,21788 +werkzeug/http.py,sha256=KVRV3yFK14PJeI56qClEq4qxFdvKUQVy4C_dwuWz9_Q,43107 +werkzeug/local.py,sha256=_Tk7gB238pPWUU7habxFkZF02fiCMRVW6d62YWL1Rh0,14371 +werkzeug/middleware/__init__.py,sha256=f1SFZo67IlW4k1uqKzNHxYQlsakUS-D6KK_j0e3jjwQ,549 +werkzeug/middleware/__pycache__/__init__.cpython-38.pyc,, +werkzeug/middleware/__pycache__/dispatcher.cpython-38.pyc,, +werkzeug/middleware/__pycache__/http_proxy.cpython-38.pyc,, +werkzeug/middleware/__pycache__/lint.cpython-38.pyc,, +werkzeug/middleware/__pycache__/profiler.cpython-38.pyc,, +werkzeug/middleware/__pycache__/proxy_fix.cpython-38.pyc,, +werkzeug/middleware/__pycache__/shared_data.cpython-38.pyc,, +werkzeug/middleware/dispatcher.py,sha256=_-KoMzHtcISHS7ouWKAOraqlCLprdh83YOAn_8DjLp8,2240 +werkzeug/middleware/http_proxy.py,sha256=lRjTdMmghHiZuZrS7_UJ3gZc-vlFizhBbFZ-XZPLwIA,7117 +werkzeug/middleware/lint.py,sha256=ItTwuWJnflF8xMT1uqU_Ty1ryhux-CjeUfskqaUpxsw,12967 +werkzeug/middleware/profiler.py,sha256=8B_s23d6BGrU_q54gJsm6kcCbOJbTSqrXCsioHON0Xs,4471 +werkzeug/middleware/proxy_fix.py,sha256=K5oZ3DPXOzdZi0Xba5zW7ClPOxgUuqXHQHvY2-AWCGw,6431 +werkzeug/middleware/shared_data.py,sha256=sPSRTKqtKSVBUyN8fr6jOJbdq9cdOLu6pg3gz4Y_1Xo,9599 +werkzeug/posixemulation.py,sha256=gSSiv1SCmOyzOM_nq1ZaZCtxP__C5MeDJl_4yXJmi4Q,3541 +werkzeug/routing.py,sha256=6-iZ7CKeUILYAehoKXLbmi5E6LgLbwuzUh8TNplnf5Q,79019 +werkzeug/security.py,sha256=81149MplFq7-hD4RK4sKp9kzXXejjV9D4lWBzaRyeQ8,8106 +werkzeug/serving.py,sha256=YvTqvurA-Mnj8mkqRe2kBdVr2ap4ibCq1ByQjOA6g1w,38694 +werkzeug/test.py,sha256=GJ9kxTMSJ-nB7kfGtxuROr9JGmXxDRev-2U1SkeUJGE,39564 +werkzeug/testapp.py,sha256=bHekqMsqRfVxwgFbvOMem-DYa_sdB7R47yUXpt1RUTo,9329 +werkzeug/urls.py,sha256=T8-hV_1vwhu6xhX93FwsHteK-W-kIE2orj5WoMf-WFw,39322 +werkzeug/useragents.py,sha256=TSoGv5IOvP375eK5gLLpsLQCeUgTR6sO1WftmAP_YvM,5563 +werkzeug/utils.py,sha256=hrVK4u_wi8z9viBO9bgOLlm1aaIvCpn-p2d1FeZQDEo,25251 +werkzeug/wrappers/__init__.py,sha256=S4VioKAmF_av9Ec9zQvG71X1EOkYfPx1TYck9jyDiyY,1384 +werkzeug/wrappers/__pycache__/__init__.cpython-38.pyc,, +werkzeug/wrappers/__pycache__/accept.cpython-38.pyc,, +werkzeug/wrappers/__pycache__/auth.cpython-38.pyc,, +werkzeug/wrappers/__pycache__/base_request.cpython-38.pyc,, +werkzeug/wrappers/__pycache__/base_response.cpython-38.pyc,, +werkzeug/wrappers/__pycache__/common_descriptors.cpython-38.pyc,, +werkzeug/wrappers/__pycache__/cors.cpython-38.pyc,, +werkzeug/wrappers/__pycache__/etag.cpython-38.pyc,, +werkzeug/wrappers/__pycache__/json.cpython-38.pyc,, +werkzeug/wrappers/__pycache__/request.cpython-38.pyc,, +werkzeug/wrappers/__pycache__/response.cpython-38.pyc,, +werkzeug/wrappers/__pycache__/user_agent.cpython-38.pyc,, +werkzeug/wrappers/accept.py,sha256=TIvjUc0g73fhTWX54wg_D9NNzKvpnG1X8u1w26tK1o8,1760 +werkzeug/wrappers/auth.py,sha256=Pmn6iaGHBrUyHbJpW0lZhO_q9RVoAa5QalaTqcavdAI,1158 +werkzeug/wrappers/base_request.py,sha256=4TuGlKWeKQdlq4eU94hJYcXSfWo8Rk7CS1Ef5lJ3ZM0,26012 +werkzeug/wrappers/base_response.py,sha256=JTxJZ8o-IBetpoWJqt2HFwPaNWNDAlM3_GXJe1Whw80,27784 +werkzeug/wrappers/common_descriptors.py,sha256=X2Ktd5zUWsmcd4ciaF62Dd8Lru9pLGP_XDUNukc8cXs,12829 +werkzeug/wrappers/cors.py,sha256=XMbaCol4dWTGvb-dCJBoN0p3JX91v93AIAHd7tnB3L4,3466 +werkzeug/wrappers/etag.py,sha256=XMXtyfByBsOjxwaX8U7ZtUY7JXkbQLP45oXZ0qkyTNs,12217 +werkzeug/wrappers/json.py,sha256=HvK_A4NpO0sLqgb10sTJcoZydYOwyNiPCJPV7SVgcgE,4343 +werkzeug/wrappers/request.py,sha256=QbHGqDpGPN684pnOPEokwkPESfm-NnfYM7ydOMxW_NI,1514 +werkzeug/wrappers/response.py,sha256=Oqv8TMG_dnOKTq_V30ddgkO5B7IJhkVPODvm7cbhZ3c,2524 +werkzeug/wrappers/user_agent.py,sha256=YJb-vr12cujG7sQMG9V89VsJa-03SWSenhg1W4cT0EY,435 +werkzeug/wsgi.py,sha256=ZGk85NzRyQTzkYis-xl8V9ydJgfClBdStvhzDzER2mw,34367 diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Werkzeug-1.0.1.dist-info/WHEEL b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Werkzeug-1.0.1.dist-info/WHEEL new file mode 100644 index 0000000..ef99c6c --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Werkzeug-1.0.1.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.34.2) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Werkzeug-1.0.1.dist-info/top_level.txt b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Werkzeug-1.0.1.dist-info/top_level.txt new file mode 100644 index 0000000..6fe8da8 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/Werkzeug-1.0.1.dist-info/top_level.txt @@ -0,0 +1 @@ +werkzeug diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/_cffi_backend.cpython-38-x86_64-linux-gnu.so b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/_cffi_backend.cpython-38-x86_64-linux-gnu.so new file mode 100755 index 0000000000000000000000000000000000000000..14bc892f2495a2d170532c5724a595adaa0ab1ed GIT binary patch literal 886648 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

ol1G)jlS>TK5sl}otOP__se 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

    (t*3A(RGi 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 literal 0 HcmV?d00001 diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/__init__.py new file mode 100644 index 0000000..2a2e5ad --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/__init__.py @@ -0,0 +1,17 @@ +""" + authlib + ~~~~~~~ + + The ultimate Python library in building OAuth 1.0, OAuth 2.0 and OpenID + Connect clients and providers. It covers from low level specification + implementation to high level framework integrations. + + :copyright: (c) 2017 by Hsiaoming Yang. + :license: BSD, see LICENSE for more details. +""" +from .consts import version, homepage, author + +__version__ = version +__homepage__ = homepage +__author__ = author +__license__ = 'BSD-3-Clause' diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/common/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/common/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/common/encoding.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/common/encoding.py new file mode 100644 index 0000000..31df0b0 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/common/encoding.py @@ -0,0 +1,88 @@ +import sys +import json +import base64 +import struct + +is_py2 = sys.version_info[0] == 2 + +if is_py2: + unicode_type = unicode # noqa: F821 + byte_type = str + text_types = (unicode, str) # noqa: F821 +else: + unicode_type = str + byte_type = bytes + text_types = (str, ) + + +def to_bytes(x, charset='utf-8', errors='strict'): + if x is None: + return None + if isinstance(x, byte_type): + return x + if isinstance(x, unicode_type): + return x.encode(charset, errors) + if isinstance(x, (int, float)): + return str(x).encode(charset, errors) + return byte_type(x) + + +def to_unicode(x, charset='utf-8', errors='strict'): + if x is None or isinstance(x, unicode_type): + return x + if isinstance(x, byte_type): + return x.decode(charset, errors) + return unicode_type(x) + + +def to_native(x, encoding='ascii'): + if isinstance(x, str): + return x + if is_py2: + return x.encode(encoding) + return x.decode(encoding) + + +def json_loads(s): + return json.loads(s) + + +def json_dumps(data, ensure_ascii=False): + return json.dumps(data, ensure_ascii=ensure_ascii, separators=(',', ':')) + + +def urlsafe_b64decode(s): + s += b'=' * (-len(s) % 4) + return base64.urlsafe_b64decode(s) + + +def urlsafe_b64encode(s): + return base64.urlsafe_b64encode(s).rstrip(b'=') + + +def base64_to_int(s): + data = urlsafe_b64decode(to_bytes(s, charset='ascii')) + buf = struct.unpack('%sB' % len(data), data) + return int(''.join(["%02x" % byte for byte in buf]), 16) + + +def int_to_base64(num): + if num < 0: + raise ValueError('Must be a positive integer') + + if hasattr(int, 'to_bytes'): + s = num.to_bytes((num.bit_length() + 7) // 8, 'big', signed=False) + else: + buf = [] + while num: + num, remainder = divmod(num, 256) + buf.append(remainder) + buf.reverse() + s = struct.pack('%sB' % len(buf), *buf) + return to_unicode(urlsafe_b64encode(s)) + + +def json_b64encode(text): + if isinstance(text, dict): + text = json_dumps(text) + return urlsafe_b64encode(to_bytes(text)) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/common/errors.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/common/errors.py new file mode 100644 index 0000000..015ab4b --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/common/errors.py @@ -0,0 +1,76 @@ +#: coding: utf-8 +from authlib.consts import default_json_headers + + +class AuthlibBaseError(Exception): + """Base Exception for all errors in Authlib.""" + + #: short-string error code + error = None + #: long-string to describe this error + description = '' + #: web page that describes this error + uri = None + + def __init__(self, error=None, description=None, uri=None): + if error is not None: + self.error = error + if description is not None: + self.description = description + if uri is not None: + self.uri = uri + + message = '{}: {}'.format(self.error, self.description) + super(AuthlibBaseError, self).__init__(message) + + def __repr__(self): + return '<{} "{}">'.format(self.__class__.__name__, self.error) + + +class AuthlibHTTPError(AuthlibBaseError): + #: HTTP status code + status_code = 400 + + def __init__(self, error=None, description=None, uri=None, + status_code=None): + super(AuthlibHTTPError, self).__init__(error, description, uri) + if status_code is not None: + self.status_code = status_code + self._translations = None + self._error_uris = None + + def gettext(self, s): + if self._translations: + return self._translations.gettext(s) + return s + + def get_error_description(self): + return self.description + + def get_error_uri(self): + if self.uri: + return self.uri + if self._error_uris: + return self._error_uris.get(self.error) + + def get_body(self): + error = [('error', self.error)] + + description = self.get_error_description() + if description: + error.append(('error_description', description)) + + uri = self.get_error_uri() + if uri: + error.append(('error_uri', uri)) + return error + + def get_headers(self): + return default_json_headers[:] + + def __call__(self, translations=None, error_uris=None): + self._translations = translations + self._error_uris = error_uris + body = dict(self.get_body()) + headers = self.get_headers() + return self.status_code, body, headers diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/common/security.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/common/security.py new file mode 100644 index 0000000..b05ea14 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/common/security.py @@ -0,0 +1,19 @@ +import os +import string +import random + +UNICODE_ASCII_CHARACTER_SET = string.ascii_letters + string.digits + + +def generate_token(length=30, chars=UNICODE_ASCII_CHARACTER_SET): + rand = random.SystemRandom() + return ''.join(rand.choice(chars) for _ in range(length)) + + +def is_secure_transport(uri): + """Check if the uri is over ssl.""" + if os.getenv('AUTHLIB_INSECURE_TRANSPORT'): + return True + + uri = uri.lower() + return uri.startswith(('https://', 'http://localhost:')) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/common/urls.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/common/urls.py new file mode 100644 index 0000000..d03b173 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/common/urls.py @@ -0,0 +1,162 @@ +""" + authlib.util.urls + ~~~~~~~~~~~~~~~~~ + + Wrapper functions for URL encoding and decoding. +""" + +import re +try: + from urllib import quote as _quote + from urllib import unquote as _unquote + from urllib import urlencode as _urlencode +except ImportError: + from urllib.parse import quote as _quote + from urllib.parse import unquote as _unquote + from urllib.parse import urlencode as _urlencode + +try: + from urllib2 import parse_keqv_list # noqa: F401 + from urllib2 import parse_http_list # noqa: F401 +except ImportError: + from urllib.request import parse_keqv_list # noqa: F401 + from urllib.request import parse_http_list # noqa: F401 + +try: + import urlparse +except ImportError: + import urllib.parse as urlparse + +from .encoding import to_unicode, to_bytes + +always_safe = ( + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' + 'abcdefghijklmnopqrstuvwxyz' + '0123456789_.-' +) +urlencoded = set(always_safe) | set('=&;:%+~,*@!()/?') +INVALID_HEX_PATTERN = re.compile(r'%[^0-9A-Fa-f]|%[0-9A-Fa-f][^0-9A-Fa-f]') + + +def url_encode(params): + encoded = [] + for k, v in params: + encoded.append((to_bytes(k), to_bytes(v))) + return to_unicode(_urlencode(encoded)) + + +def url_decode(query): + """Decode a query string in x-www-form-urlencoded format into a sequence + of two-element tuples. + + Unlike urlparse.parse_qsl(..., strict_parsing=True) urldecode will enforce + correct formatting of the query string by validation. If validation fails + a ValueError will be raised. urllib.parse_qsl will only raise errors if + any of name-value pairs omits the equals sign. + """ + # Check if query contains invalid characters + if query and not set(query) <= urlencoded: + error = ("Error trying to decode a non urlencoded string. " + "Found invalid characters: %s " + "in the string: '%s'. " + "Please ensure the request/response body is " + "x-www-form-urlencoded.") + raise ValueError(error % (set(query) - urlencoded, query)) + + # Check for correctly hex encoded values using a regular expression + # All encoded values begin with % followed by two hex characters + # correct = %00, %A0, %0A, %FF + # invalid = %G0, %5H, %PO + if INVALID_HEX_PATTERN.search(query): + raise ValueError('Invalid hex encoding in query string.') + + # We encode to utf-8 prior to parsing because parse_qsl behaves + # differently on unicode input in python 2 and 3. + # Python 2.7 + # >>> urlparse.parse_qsl(u'%E5%95%A6%E5%95%A6') + # u'\xe5\x95\xa6\xe5\x95\xa6' + # Python 2.7, non unicode input gives the same + # >>> urlparse.parse_qsl('%E5%95%A6%E5%95%A6') + # '\xe5\x95\xa6\xe5\x95\xa6' + # but now we can decode it to unicode + # >>> urlparse.parse_qsl('%E5%95%A6%E5%95%A6').decode('utf-8') + # u'\u5566\u5566' + # Python 3.3 however + # >>> urllib.parse.parse_qsl(u'%E5%95%A6%E5%95%A6') + # u'\u5566\u5566' + + # We want to allow queries such as "c2" whereas urlparse.parse_qsl + # with the strict_parsing flag will not. + params = urlparse.parse_qsl(query, keep_blank_values=True) + + # unicode all the things + decoded = [] + for k, v in params: + decoded.append((to_unicode(k), to_unicode(v))) + return decoded + + +def add_params_to_qs(query, params): + """Extend a query with a list of two-tuples.""" + if isinstance(params, dict): + params = params.items() + + qs = urlparse.parse_qsl(query, keep_blank_values=True) + qs.extend(params) + return url_encode(qs) + + +def add_params_to_uri(uri, params, fragment=False): + """Add a list of two-tuples to the uri query components.""" + sch, net, path, par, query, fra = urlparse.urlparse(uri) + if fragment: + fra = add_params_to_qs(fra, params) + else: + query = add_params_to_qs(query, params) + return urlparse.urlunparse((sch, net, path, par, query, fra)) + + +def quote(s, safe=b'/'): + return to_unicode(_quote(to_bytes(s), safe)) + + +def unquote(s): + return to_unicode(_unquote(s)) + + +def quote_url(s): + return quote(s, b'~@#$&()*!+=:;,.?/\'') + + +def extract_params(raw): + """Extract parameters and return them as a list of 2-tuples. + + Will successfully extract parameters from urlencoded query strings, + dicts, or lists of 2-tuples. Empty strings/dicts/lists will return an + empty list of parameters. Any other input will result in a return + value of None. + """ + if isinstance(raw, (list, tuple)): + try: + raw = dict(raw) + except (TypeError, ValueError): + return None + + if isinstance(raw, dict): + params = [] + for k, v in raw.items(): + params.append((to_unicode(k), to_unicode(v))) + return params + + if not raw: + return None + + try: + return url_decode(raw) + except ValueError: + return None + + +def is_valid_url(url): + parsed = urlparse.urlparse(url) + return parsed.scheme and parsed.hostname diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/consts.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/consts.py new file mode 100644 index 0000000..ac8051d --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/consts.py @@ -0,0 +1,11 @@ +name = 'Authlib' +version = '0.15.2' +author = 'Hsiaoming Yang ' +homepage = 'https://authlib.org/' +default_user_agent = '{}/{} (+{})'.format(name, version, homepage) + +default_json_headers = [ + ('Content-Type', 'application/json'), + ('Cache-Control', 'no-store'), + ('Pragma', 'no-cache'), +] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/deprecate.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/deprecate.py new file mode 100644 index 0000000..ba87f3c --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/deprecate.py @@ -0,0 +1,16 @@ +import warnings + + +class AuthlibDeprecationWarning(DeprecationWarning): + pass + + +warnings.simplefilter('always', AuthlibDeprecationWarning) + + +def deprecate(message, version=None, link_uid=None, link_file=None): + if version: + message += '\nIt will be compatible before version {}.'.format(version) + if link_uid and link_file: + message += '\nRead more '.format(link_uid, link_file) + warnings.warn(AuthlibDeprecationWarning(message), stacklevel=2) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/__init__.py new file mode 100644 index 0000000..4fa35b8 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/__init__.py @@ -0,0 +1,16 @@ +from .base_oauth import BaseOAuth +from .base_app import BaseApp +from .remote_app import RemoteApp +from .framework_integration import FrameworkIntegration +from .errors import ( + OAuthError, MissingRequestTokenError, MissingTokenError, + TokenExpiredError, InvalidTokenError, UnsupportedTokenTypeError, + MismatchingStateError, +) + +__all__ = [ + 'BaseOAuth', 'BaseApp', 'RemoteApp', 'FrameworkIntegration', + 'OAuthError', 'MissingRequestTokenError', 'MissingTokenError', + 'TokenExpiredError', 'InvalidTokenError', 'UnsupportedTokenTypeError', + 'MismatchingStateError', +] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/async_app.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/async_app.py new file mode 100644 index 0000000..60d3d73 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/async_app.py @@ -0,0 +1,205 @@ +import time +import logging +from authlib.common.urls import urlparse +from authlib.jose import JsonWebToken, JsonWebKey +from authlib.oidc.core import UserInfo, CodeIDToken, ImplicitIDToken +from .base_app import BaseApp +from .errors import ( + MissingRequestTokenError, + MissingTokenError, +) + +__all__ = ['AsyncRemoteApp'] + +log = logging.getLogger(__name__) + + +class AsyncRemoteApp(BaseApp): + async def load_server_metadata(self): + if self._server_metadata_url and '_loaded_at' not in self.server_metadata: + metadata = await self._fetch_server_metadata(self._server_metadata_url) + metadata['_loaded_at'] = time.time() + self.server_metadata.update(metadata) + return self.server_metadata + + async def _on_update_token(self, token, refresh_token=None, access_token=None): + if self._update_token: + await self._update_token( + token, + refresh_token=refresh_token, + access_token=access_token, + ) + + async def _create_oauth1_authorization_url(self, client, authorization_endpoint, **kwargs): + params = {} + if self.request_token_params: + params.update(self.request_token_params) + token = await client.fetch_request_token( + self.request_token_url, **params + ) + log.debug('Fetch request token: {!r}'.format(token)) + url = client.create_authorization_url(authorization_endpoint, **kwargs) + return {'url': url, 'request_token': token} + + async def create_authorization_url(self, redirect_uri=None, **kwargs): + """Generate the authorization url and state for HTTP redirect. + + :param redirect_uri: Callback or redirect URI for authorization. + :param kwargs: Extra parameters to include. + :return: dict + """ + metadata = await self.load_server_metadata() + authorization_endpoint = self.authorize_url + if not authorization_endpoint and not self.request_token_url: + authorization_endpoint = metadata.get('authorization_endpoint') + + if not authorization_endpoint: + raise RuntimeError('Missing "authorize_url" value') + + if self.authorize_params: + kwargs.update(self.authorize_params) + + async with self._get_oauth_client(**metadata) as client: + client.redirect_uri = redirect_uri + + if self.request_token_url: + return await self._create_oauth1_authorization_url( + client, authorization_endpoint, **kwargs) + else: + return self._create_oauth2_authorization_url( + client, authorization_endpoint, **kwargs) + + async def fetch_access_token(self, redirect_uri=None, request_token=None, **params): + """Fetch access token in one step. + + :param redirect_uri: Callback or Redirect URI that is used in + previous :meth:`authorize_redirect`. + :param request_token: A previous request token for OAuth 1. + :param params: Extra parameters to fetch access token. + :return: A token dict. + """ + metadata = await self.load_server_metadata() + token_endpoint = self.access_token_url + if not token_endpoint and not self.request_token_url: + token_endpoint = metadata.get('token_endpoint') + + async with self._get_oauth_client(**metadata) as client: + if self.request_token_url: + client.redirect_uri = redirect_uri + if request_token is None: + raise MissingRequestTokenError() + # merge request token with verifier + token = {} + token.update(request_token) + token.update(params) + client.token = token + kwargs = self.access_token_params or {} + token = await client.fetch_access_token(token_endpoint, **kwargs) + client.redirect_uri = None + else: + client.redirect_uri = redirect_uri + kwargs = {} + if self.access_token_params: + kwargs.update(self.access_token_params) + kwargs.update(params) + token = await client.fetch_token(token_endpoint, **kwargs) + return token + + async def request(self, method, url, token=None, **kwargs): + if self.api_base_url and not url.startswith(('https://', 'http://')): + url = urlparse.urljoin(self.api_base_url, url) + + withhold_token = kwargs.get('withhold_token') + if not withhold_token: + metadata = await self.load_server_metadata() + else: + metadata = {} + + async with self._get_oauth_client(**metadata) as client: + request = kwargs.pop('request', None) + + if withhold_token: + return await client.request(method, url, **kwargs) + + if token is None and request: + token = await self._fetch_token(request) + + if token is None: + raise MissingTokenError() + + client.token = token + return await client.request(method, url, **kwargs) + + async def userinfo(self, **kwargs): + """Fetch user info from ``userinfo_endpoint``.""" + metadata = await self.load_server_metadata() + resp = await self.get(metadata['userinfo_endpoint'], **kwargs) + data = resp.json() + + compliance_fix = metadata.get('userinfo_compliance_fix') + if compliance_fix: + data = await compliance_fix(self, data) + return UserInfo(data) + + async def _parse_id_token(self, token, nonce, claims_options=None): + """Return an instance of UserInfo from token's ``id_token``.""" + claims_params = dict( + nonce=nonce, + client_id=self.client_id, + ) + if 'access_token' in token: + claims_params['access_token'] = token['access_token'] + claims_cls = CodeIDToken + else: + claims_cls = ImplicitIDToken + + metadata = await self.load_server_metadata() + if claims_options is None and 'issuer' in metadata: + claims_options = {'iss': {'values': [metadata['issuer']]}} + + alg_values = metadata.get('id_token_signing_alg_values_supported') + if not alg_values: + alg_values = ['RS256'] + + jwt = JsonWebToken(alg_values) + + jwk_set = await self._fetch_jwk_set() + try: + claims = jwt.decode( + token['id_token'], + key=JsonWebKey.import_key_set(jwk_set), + claims_cls=claims_cls, + claims_options=claims_options, + claims_params=claims_params, + ) + except ValueError: + jwk_set = await self._fetch_jwk_set(force=True) + claims = jwt.decode( + token['id_token'], + key=JsonWebKey.import_key_set(jwk_set), + claims_cls=claims_cls, + claims_options=claims_options, + claims_params=claims_params, + ) + + claims.validate(leeway=120) + return UserInfo(claims) + + async def _fetch_jwk_set(self, force=False): + metadata = await self.load_server_metadata() + jwk_set = metadata.get('jwks') + if jwk_set and not force: + return jwk_set + + uri = metadata.get('jwks_uri') + if not uri: + raise RuntimeError('Missing "jwks_uri" in metadata') + + jwk_set = await self._fetch_server_metadata(uri) + self.server_metadata['jwks'] = jwk_set + return jwk_set + + async def _fetch_server_metadata(self, url): + async with self._get_oauth_client() as client: + resp = await client.request('GET', url, withhold_token=True) + return resp.json() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/base_app.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/base_app.py new file mode 100644 index 0000000..3df09a1 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/base_app.py @@ -0,0 +1,244 @@ +import logging + +from authlib.common.security import generate_token +from authlib.consts import default_user_agent +from .errors import ( + MismatchingStateError, +) + +__all__ = ['BaseApp'] + +log = logging.getLogger(__name__) + + +class BaseApp(object): + """The remote application for OAuth 1 and OAuth 2. It is used together + with OAuth registry. + + :param name: The name of the OAuth client, like: github, twitter + :param fetch_token: A function to fetch access token from database + :param update_token: A function to update access token to database + :param client_id: Client key of OAuth 1, or Client ID of OAuth 2 + :param client_secret: Client secret of OAuth 2, or Client Secret of OAuth 2 + :param request_token_url: Request Token endpoint for OAuth 1 + :param request_token_params: Extra parameters for Request Token endpoint + :param access_token_url: Access Token endpoint for OAuth 1 and OAuth 2 + :param access_token_params: Extra parameters for Access Token endpoint + :param authorize_url: Endpoint for user authorization of OAuth 1 or OAuth 2 + :param authorize_params: Extra parameters for Authorization Endpoint + :param api_base_url: The base API endpoint to make requests simple + :param client_kwargs: Extra keyword arguments for session + :param server_metadata_url: Discover server metadata from this URL + :param user_agent: Define a custom user agent to be used in HTTP request + :param kwargs: Extra server metadata + + Create an instance of ``RemoteApp``. If ``request_token_url`` is configured, + it would be an OAuth 1 instance, otherwise it is OAuth 2 instance:: + + oauth1_client = RemoteApp( + client_id='Twitter Consumer Key', + client_secret='Twitter Consumer Secret', + request_token_url='https://api.twitter.com/oauth/request_token', + access_token_url='https://api.twitter.com/oauth/access_token', + authorize_url='https://api.twitter.com/oauth/authenticate', + api_base_url='https://api.twitter.com/1.1/', + ) + + oauth2_client = RemoteApp( + client_id='GitHub Client ID', + client_secret='GitHub Client Secret', + api_base_url='https://api.github.com/', + access_token_url='https://github.com/login/oauth/access_token', + authorize_url='https://github.com/login/oauth/authorize', + client_kwargs={'scope': 'user:email'}, + ) + """ + OAUTH_APP_CONFIG = None + + def __init__( + self, framework, name=None, fetch_token=None, update_token=None, + client_id=None, client_secret=None, + request_token_url=None, request_token_params=None, + access_token_url=None, access_token_params=None, + authorize_url=None, authorize_params=None, + api_base_url=None, client_kwargs=None, server_metadata_url=None, + compliance_fix=None, client_auth_methods=None, user_agent=None, **kwargs): + + self.framework = framework + self.name = name + self.client_id = client_id + self.client_secret = client_secret + self.request_token_url = request_token_url + self.request_token_params = request_token_params + self.access_token_url = access_token_url + self.access_token_params = access_token_params + self.authorize_url = authorize_url + self.authorize_params = authorize_params + self.api_base_url = api_base_url + self.client_kwargs = client_kwargs or {} + + self.compliance_fix = compliance_fix + self.client_auth_methods = client_auth_methods + self._fetch_token = fetch_token + self._update_token = update_token + self._user_agent = user_agent or default_user_agent + + self._server_metadata_url = server_metadata_url + self.server_metadata = kwargs + + def _on_update_token(self, token, refresh_token=None, access_token=None): + raise NotImplementedError() + + def _get_oauth_client(self, **kwargs): + client_kwargs = {} + client_kwargs.update(self.client_kwargs) + client_kwargs.update(kwargs) + if self.request_token_url: + session = self.framework.oauth1_client_cls( + self.client_id, self.client_secret, + **client_kwargs + ) + else: + if self.authorize_url: + client_kwargs['authorization_endpoint'] = self.authorize_url + if self.access_token_url: + client_kwargs['token_endpoint'] = self.access_token_url + session = self.framework.oauth2_client_cls( + client_id=self.client_id, + client_secret=self.client_secret, + update_token=self._on_update_token, + **client_kwargs + ) + if self.client_auth_methods: + for f in self.client_auth_methods: + session.register_client_auth_method(f) + # only OAuth2 has compliance_fix currently + if self.compliance_fix: + self.compliance_fix(session) + + session.headers['User-Agent'] = self._user_agent + return session + + def _retrieve_oauth2_access_token_params(self, request, params): + request_state = params.pop('state', None) + state = self.framework.get_session_data(request, 'state') + if state != request_state: + raise MismatchingStateError() + if state: + params['state'] = state + + code_verifier = self.framework.get_session_data(request, 'code_verifier') + if code_verifier: + params['code_verifier'] = code_verifier + return params + + def retrieve_access_token_params(self, request, request_token=None): + """Retrieve parameters for fetching access token, those parameters come + from request and previously saved temporary data in session. + """ + params = self.framework.generate_access_token_params(self.request_token_url, request) + if self.request_token_url: + if request_token is None: + request_token = self.framework.get_session_data(request, 'request_token') + params['request_token'] = request_token + else: + params = self._retrieve_oauth2_access_token_params(request, params) + + redirect_uri = self.framework.get_session_data(request, 'redirect_uri') + if redirect_uri: + params['redirect_uri'] = redirect_uri + + log.debug('Retrieve temporary data: {!r}'.format(params)) + return params + + def save_authorize_data(self, request, **kwargs): + """Save temporary data into session for the authorization step. These + data can be retrieved later when fetching access token. + """ + log.debug('Saving authorize data: {!r}'.format(kwargs)) + keys = [ + 'redirect_uri', 'request_token', + 'state', 'code_verifier', 'nonce' + ] + for k in keys: + if k in kwargs: + self.framework.set_session_data(request, k, kwargs[k]) + + @staticmethod + def _create_oauth2_authorization_url(client, authorization_endpoint, **kwargs): + rv = {} + if client.code_challenge_method: + code_verifier = kwargs.get('code_verifier') + if not code_verifier: + code_verifier = generate_token(48) + kwargs['code_verifier'] = code_verifier + rv['code_verifier'] = code_verifier + log.debug('Using code_verifier: {!r}'.format(code_verifier)) + + scope = kwargs.get('scope', client.scope) + if scope and scope.startswith('openid'): + # this is an OpenID Connect service + nonce = kwargs.get('nonce') + if not nonce: + nonce = generate_token(20) + kwargs['nonce'] = nonce + rv['nonce'] = nonce + + url, state = client.create_authorization_url( + authorization_endpoint, **kwargs) + rv['url'] = url + rv['state'] = state + return rv + + def request(self, method, url, token=None, **kwargs): + raise NotImplementedError() + + def get(self, url, **kwargs): + """Invoke GET http request. + + If ``api_base_url`` configured, shortcut is available:: + + client.get('users/lepture') + """ + return self.request('GET', url, **kwargs) + + def post(self, url, **kwargs): + """Invoke POST http request. + + If ``api_base_url`` configured, shortcut is available:: + + client.post('timeline', json={'text': 'Hi'}) + """ + return self.request('POST', url, **kwargs) + + def patch(self, url, **kwargs): + """Invoke PATCH http request. + + If ``api_base_url`` configured, shortcut is available:: + + client.patch('profile', json={'name': 'Hsiaoming Yang'}) + """ + return self.request('PATCH', url, **kwargs) + + def put(self, url, **kwargs): + """Invoke PUT http request. + + If ``api_base_url`` configured, shortcut is available:: + + client.put('profile', json={'name': 'Hsiaoming Yang'}) + """ + return self.request('PUT', url, **kwargs) + + def delete(self, url, **kwargs): + """Invoke DELETE http request. + + If ``api_base_url`` configured, shortcut is available:: + + client.delete('posts/123') + """ + return self.request('DELETE', url, **kwargs) + + def _fetch_server_metadata(self, url): + with self._get_oauth_client() as session: + resp = session.request('GET', url, withhold_token=True) + return resp.json() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/base_oauth.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/base_oauth.py new file mode 100644 index 0000000..36c027b --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/base_oauth.py @@ -0,0 +1,120 @@ +import functools +from .framework_integration import FrameworkIntegration + +__all__ = ['BaseOAuth'] + + +OAUTH_CLIENT_PARAMS = ( + 'client_id', 'client_secret', + 'request_token_url', 'request_token_params', + 'access_token_url', 'access_token_params', + 'refresh_token_url', 'refresh_token_params', + 'authorize_url', 'authorize_params', + 'api_base_url', 'client_kwargs', + 'server_metadata_url', +) + + +class BaseOAuth(object): + """Registry for oauth clients. + + Create an instance for registry:: + + oauth = OAuth() + """ + framework_client_cls = None + framework_integration_cls = FrameworkIntegration + + def __init__(self, fetch_token=None, update_token=None): + self._registry = {} + self._clients = {} + self.fetch_token = fetch_token + self.update_token = update_token + + def create_client(self, name): + """Create or get the given named OAuth client. For instance, the + OAuth registry has ``.register`` a twitter client, developers may + access the client with:: + + client = oauth.create_client('twitter') + + :param: name: Name of the remote application + :return: OAuth remote app + """ + if name in self._clients: + return self._clients[name] + + if name not in self._registry: + return None + + overwrite, config = self._registry[name] + client_cls = config.pop('client_cls', self.framework_client_cls) + if client_cls.OAUTH_APP_CONFIG: + kwargs = client_cls.OAUTH_APP_CONFIG + kwargs.update(config) + else: + kwargs = config + kwargs = self.generate_client_kwargs(name, overwrite, **kwargs) + client = client_cls(self.framework_integration_cls(name), name, **kwargs) + self._clients[name] = client + return client + + def register(self, name, overwrite=False, **kwargs): + """Registers a new remote application. + + :param name: Name of the remote application. + :param overwrite: Overwrite existing config with framework settings. + :param kwargs: Parameters for :class:`RemoteApp`. + + Find parameters for the given remote app class. When a remote app is + registered, it can be accessed with *named* attribute:: + + oauth.register('twitter', client_id='', ...) + oauth.twitter.get('timeline') + """ + self._registry[name] = (overwrite, kwargs) + return self.create_client(name) + + def generate_client_kwargs(self, name, overwrite, **kwargs): + fetch_token = kwargs.pop('fetch_token', None) + update_token = kwargs.pop('update_token', None) + + config = self.load_config(name, OAUTH_CLIENT_PARAMS) + if config: + kwargs = _config_client(config, kwargs, overwrite) + + if not fetch_token and self.fetch_token: + fetch_token = functools.partial(self.fetch_token, name) + + kwargs['fetch_token'] = fetch_token + + if not kwargs.get('request_token_url'): + if not update_token and self.update_token: + update_token = functools.partial(self.update_token, name) + + kwargs['update_token'] = update_token + return kwargs + + def load_config(self, name, params): + return self.framework_integration_cls.load_config(self, name, params) + + def __getattr__(self, key): + try: + return object.__getattribute__(self, key) + except AttributeError: + if key in self._registry: + return self.create_client(key) + raise AttributeError('No such client: %s' % key) + + +def _config_client(config, kwargs, overwrite): + for k in OAUTH_CLIENT_PARAMS: + v = config.get(k, None) + if k not in kwargs: + kwargs[k] = v + elif overwrite and v: + if isinstance(kwargs[k], dict): + kwargs[k].update(v) + else: + kwargs[k] = v + return kwargs diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/errors.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/errors.py new file mode 100644 index 0000000..bb4dd2b --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/errors.py @@ -0,0 +1,30 @@ +from authlib.common.errors import AuthlibBaseError + + +class OAuthError(AuthlibBaseError): + error = 'oauth_error' + + +class MissingRequestTokenError(OAuthError): + error = 'missing_request_token' + + +class MissingTokenError(OAuthError): + error = 'missing_token' + + +class TokenExpiredError(OAuthError): + error = 'token_expired' + + +class InvalidTokenError(OAuthError): + error = 'token_invalid' + + +class UnsupportedTokenTypeError(OAuthError): + error = 'unsupported_token_type' + + +class MismatchingStateError(OAuthError): + error = 'mismatching_state' + description = 'CSRF Warning! State not equal in request and response.' diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/framework_integration.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/framework_integration.py new file mode 100644 index 0000000..2f27689 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/framework_integration.py @@ -0,0 +1,25 @@ + +class FrameworkIntegration(object): + oauth1_client_cls = None + oauth2_client_cls = None + + def __init__(self, name): + self.name = name + + def set_session_data(self, request, key, value): + sess_key = '_{}_authlib_{}_'.format(self.name, key) + request.session[sess_key] = value + + def get_session_data(self, request, key): + sess_key = '_{}_authlib_{}_'.format(self.name, key) + return request.session.pop(sess_key, None) + + def update_token(self, token, refresh_token=None, access_token=None): + raise NotImplementedError() + + def generate_access_token_params(self, request_token_url, request): + raise NotImplementedError() + + @staticmethod + def load_config(oauth, name, params): + raise NotImplementedError() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/remote_app.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/remote_app.py new file mode 100644 index 0000000..430d56f --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/base_client/remote_app.py @@ -0,0 +1,204 @@ +import time +import logging +from authlib.common.urls import urlparse +from authlib.jose import JsonWebToken, JsonWebKey +from authlib.oidc.core import UserInfo, CodeIDToken, ImplicitIDToken +from .base_app import BaseApp +from .errors import ( + MissingRequestTokenError, + MissingTokenError, +) + +__all__ = ['RemoteApp'] + +log = logging.getLogger(__name__) + + +class RemoteApp(BaseApp): + def load_server_metadata(self): + if self._server_metadata_url and '_loaded_at' not in self.server_metadata: + metadata = self._fetch_server_metadata(self._server_metadata_url) + metadata['_loaded_at'] = time.time() + self.server_metadata.update(metadata) + return self.server_metadata + + def _on_update_token(self, token, refresh_token=None, access_token=None): + if callable(self._update_token): + self._update_token( + token, + refresh_token=refresh_token, + access_token=access_token, + ) + self.framework.update_token( + token, + refresh_token=refresh_token, + access_token=access_token, + ) + + def _create_oauth1_authorization_url(self, client, authorization_endpoint, **kwargs): + params = {} + if self.request_token_params: + params.update(self.request_token_params) + token = client.fetch_request_token( + self.request_token_url, **params + ) + log.debug('Fetch request token: {!r}'.format(token)) + url = client.create_authorization_url(authorization_endpoint, **kwargs) + return {'url': url, 'request_token': token} + + def create_authorization_url(self, redirect_uri=None, **kwargs): + """Generate the authorization url and state for HTTP redirect. + + :param redirect_uri: Callback or redirect URI for authorization. + :param kwargs: Extra parameters to include. + :return: dict + """ + metadata = self.load_server_metadata() + authorization_endpoint = self.authorize_url + if not authorization_endpoint and not self.request_token_url: + authorization_endpoint = metadata.get('authorization_endpoint') + + if not authorization_endpoint: + raise RuntimeError('Missing "authorize_url" value') + + if self.authorize_params: + kwargs.update(self.authorize_params) + + with self._get_oauth_client(**metadata) as client: + client.redirect_uri = redirect_uri + + if self.request_token_url: + return self._create_oauth1_authorization_url( + client, authorization_endpoint, **kwargs) + else: + return self._create_oauth2_authorization_url( + client, authorization_endpoint, **kwargs) + + def fetch_access_token(self, redirect_uri=None, request_token=None, **params): + """Fetch access token in one step. + + :param redirect_uri: Callback or Redirect URI that is used in + previous :meth:`authorize_redirect`. + :param request_token: A previous request token for OAuth 1. + :param params: Extra parameters to fetch access token. + :return: A token dict. + """ + metadata = self.load_server_metadata() + token_endpoint = self.access_token_url + if not token_endpoint and not self.request_token_url: + token_endpoint = metadata.get('token_endpoint') + + with self._get_oauth_client(**metadata) as client: + if self.request_token_url: + client.redirect_uri = redirect_uri + if request_token is None: + raise MissingRequestTokenError() + # merge request token with verifier + token = {} + token.update(request_token) + token.update(params) + client.token = token + kwargs = self.access_token_params or {} + token = client.fetch_access_token(token_endpoint, **kwargs) + client.redirect_uri = None + else: + client.redirect_uri = redirect_uri + kwargs = {} + if self.access_token_params: + kwargs.update(self.access_token_params) + kwargs.update(params) + token = client.fetch_token(token_endpoint, **kwargs) + return token + + def request(self, method, url, token=None, **kwargs): + if self.api_base_url and not url.startswith(('https://', 'http://')): + url = urlparse.urljoin(self.api_base_url, url) + + withhold_token = kwargs.get('withhold_token') + if not withhold_token: + metadata = self.load_server_metadata() + else: + metadata = {} + + with self._get_oauth_client(**metadata) as session: + request = kwargs.pop('request', None) + if withhold_token: + return session.request(method, url, **kwargs) + + if token is None and self._fetch_token and request: + token = self._fetch_token(request) + if token is None: + raise MissingTokenError() + + session.token = token + return session.request(method, url, **kwargs) + + def fetch_jwk_set(self, force=False): + metadata = self.load_server_metadata() + jwk_set = metadata.get('jwks') + if jwk_set and not force: + return jwk_set + uri = metadata.get('jwks_uri') + if not uri: + raise RuntimeError('Missing "jwks_uri" in metadata') + + jwk_set = self._fetch_server_metadata(uri) + self.server_metadata['jwks'] = jwk_set + return jwk_set + + def userinfo(self, **kwargs): + """Fetch user info from ``userinfo_endpoint``.""" + metadata = self.load_server_metadata() + resp = self.get(metadata['userinfo_endpoint'], **kwargs) + data = resp.json() + + compliance_fix = metadata.get('userinfo_compliance_fix') + if compliance_fix: + data = compliance_fix(self, data) + return UserInfo(data) + + def _parse_id_token(self, request, token, claims_options=None, leeway=120): + """Return an instance of UserInfo from token's ``id_token``.""" + if 'id_token' not in token: + return None + + def load_key(header, payload): + jwk_set = JsonWebKey.import_key_set(self.fetch_jwk_set()) + try: + return jwk_set.find_by_kid(header.get('kid')) + except ValueError: + # re-try with new jwk set + jwk_set = JsonWebKey.import_key_set(self.fetch_jwk_set(force=True)) + return jwk_set.find_by_kid(header.get('kid')) + + nonce = self.framework.get_session_data(request, 'nonce') + claims_params = dict( + nonce=nonce, + client_id=self.client_id, + ) + if 'access_token' in token: + claims_params['access_token'] = token['access_token'] + claims_cls = CodeIDToken + else: + claims_cls = ImplicitIDToken + + metadata = self.load_server_metadata() + if claims_options is None and 'issuer' in metadata: + claims_options = {'iss': {'values': [metadata['issuer']]}} + + alg_values = metadata.get('id_token_signing_alg_values_supported') + if not alg_values: + alg_values = ['RS256'] + + jwt = JsonWebToken(alg_values) + claims = jwt.decode( + token['id_token'], key=load_key, + claims_cls=claims_cls, + claims_options=claims_options, + claims_params=claims_params, + ) + # https://github.com/lepture/authlib/issues/259 + if claims.get('nonce_supported') is False: + claims.params['nonce'] = None + claims.validate(leeway=leeway) + return UserInfo(claims) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_client/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_client/__init__.py new file mode 100644 index 0000000..18a30ca --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_client/__init__.py @@ -0,0 +1,15 @@ +# flake8: noqa + +from .integration import DjangoIntegration, DjangoRemoteApp, token_update +from ..base_client import BaseOAuth, OAuthError + + +class OAuth(BaseOAuth): + framework_integration_cls = DjangoIntegration + framework_client_cls = DjangoRemoteApp + + +__all__ = [ + 'OAuth', 'DjangoRemoteApp', 'DjangoIntegration', + 'token_update', 'OAuthError', +] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_client/integration.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_client/integration.py new file mode 100644 index 0000000..0665172 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_client/integration.py @@ -0,0 +1,76 @@ +from django.conf import settings +from django.dispatch import Signal +from django.http import HttpResponseRedirect +from ..base_client import FrameworkIntegration, RemoteApp, OAuthError +from ..requests_client import OAuth1Session, OAuth2Session + + +token_update = Signal() + + +class DjangoIntegration(FrameworkIntegration): + oauth1_client_cls = OAuth1Session + oauth2_client_cls = OAuth2Session + + def update_token(self, token, refresh_token=None, access_token=None): + token_update.send( + sender=self.__class__, + name=self.name, + token=token, + refresh_token=refresh_token, + access_token=access_token, + ) + + def generate_access_token_params(self, request_token_url, request): + if request_token_url: + return request.GET.dict() + + if request.method == 'GET': + error = request.GET.get('error') + if error: + description = request.GET.get('error_description') + raise OAuthError(error=error, description=description) + + params = { + 'code': request.GET.get('code'), + 'state': request.GET.get('state'), + } + else: + params = { + 'code': request.POST.get('code'), + 'state': request.POST.get('state'), + } + return params + + @staticmethod + def load_config(oauth, name, params): + config = getattr(settings, 'AUTHLIB_OAUTH_CLIENTS', None) + if config: + return config.get(name) + + +class DjangoRemoteApp(RemoteApp): + def authorize_redirect(self, request, redirect_uri=None, **kwargs): + """Create a HTTP Redirect for Authorization Endpoint. + + :param request: HTTP request instance from Django view. + :param redirect_uri: Callback or redirect URI for authorization. + :param kwargs: Extra parameters to include. + :return: A HTTP redirect response. + """ + rv = self.create_authorization_url(redirect_uri, **kwargs) + self.save_authorize_data(request, redirect_uri=redirect_uri, **rv) + return HttpResponseRedirect(rv['url']) + + def authorize_access_token(self, request, **kwargs): + """Fetch access token in one step. + + :param request: HTTP request instance from Django view. + :return: A token dict. + """ + params = self.retrieve_access_token_params(request) + params.update(kwargs) + return self.fetch_access_token(**params) + + def parse_id_token(self, request, token, claims_options=None, leeway=120): + return self._parse_id_token(request, token, claims_options, leeway) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_helpers.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_helpers.py new file mode 100644 index 0000000..117958d --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_helpers.py @@ -0,0 +1,72 @@ +try: + from collections.abc import MutableMapping as DictMixin +except ImportError: + from collections import MutableMapping as DictMixin +from authlib.common.encoding import to_unicode, json_loads + + +def create_oauth_request(request, request_cls, use_json=False): + if isinstance(request, request_cls): + return request + + if request.method == 'POST': + if use_json: + body = json_loads(request.body) + else: + body = request.POST.dict() + else: + body = None + + headers = parse_request_headers(request) + url = request.get_raw_uri() + return request_cls(request.method, url, body, headers) + + +def parse_request_headers(request): + return WSGIHeaderDict(request.META) + + +class WSGIHeaderDict(DictMixin): + CGI_KEYS = ('CONTENT_TYPE', 'CONTENT_LENGTH') + + def __init__(self, environ): + self.environ = environ + + def keys(self): + return [x for x in self] + + def _ekey(self, key): + key = key.replace('-', '_').upper() + if key in self.CGI_KEYS: + return key + return 'HTTP_' + key + + def __getitem__(self, key): + return _unicode_value(self.environ[self._ekey(key)]) + + def __delitem__(self, key): # pragma: no cover + raise ValueError('Can not delete item') + + def __setitem__(self, key, value): # pragma: no cover + raise ValueError('Can not set item') + + def __iter__(self): + for key in self.environ: + if key[:5] == 'HTTP_': + yield _unify_key(key[5:]) + elif key in self.CGI_KEYS: + yield _unify_key(key) + + def __len__(self): + return len(self.keys()) + + def __contains__(self, key): + return self._ekey(key) in self.environ + + +def _unicode_value(value): + return to_unicode(value, 'latin-1') + + +def _unify_key(key): + return key.replace('_', '-').title() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth1/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth1/__init__.py new file mode 100644 index 0000000..39f0e13 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth1/__init__.py @@ -0,0 +1,9 @@ +# flake8: noqa + +from .authorization_server import ( + BaseServer, CacheAuthorizationServer +) +from .resource_protector import ResourceProtector + + +__all__ = ['BaseServer', 'CacheAuthorizationServer', 'ResourceProtector'] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth1/authorization_server.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth1/authorization_server.py new file mode 100644 index 0000000..0ac8b5c --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth1/authorization_server.py @@ -0,0 +1,121 @@ +import logging +from authlib.oauth1 import ( + OAuth1Request, + AuthorizationServer as _AuthorizationServer, +) +from authlib.oauth1 import TemporaryCredential +from authlib.common.security import generate_token +from authlib.common.urls import url_encode +from django.core.cache import cache +from django.conf import settings +from django.http import HttpResponse +from .nonce import exists_nonce_in_cache +from ..django_helpers import create_oauth_request + +log = logging.getLogger(__name__) + + +class BaseServer(_AuthorizationServer): + def __init__(self, client_model, token_model, token_generator=None): + self.client_model = client_model + self.token_model = token_model + + if token_generator is None: + def token_generator(): + return { + 'oauth_token': generate_token(42), + 'oauth_token_secret': generate_token(48) + } + + self.token_generator = token_generator + self._config = getattr(settings, 'AUTHLIB_OAUTH1_PROVIDER', {}) + self._nonce_expires_in = self._config.get('nonce_expires_in', 86400) + methods = self._config.get('signature_methods') + if methods: + self.SUPPORTED_SIGNATURE_METHODS = methods + + def get_client_by_id(self, client_id): + try: + return self.client_model.objects.get(client_id=client_id) + except self.client_model.DoesNotExist: + return None + + def exists_nonce(self, nonce, request): + return exists_nonce_in_cache(nonce, request, self._nonce_expires_in) + + def create_token_credential(self, request): + temporary_credential = request.credential + token = self.token_generator() + item = self.token_model( + oauth_token=token['oauth_token'], + oauth_token_secret=token['oauth_token_secret'], + user_id=temporary_credential.get_user_id(), + client_id=temporary_credential.get_client_id() + ) + item.save() + return item + + def check_authorization_request(self, request): + req = self.create_oauth1_request(request) + self.validate_authorization_request(req) + return req + + def create_oauth1_request(self, request): + return create_oauth_request(request, OAuth1Request) + + def handle_response(self, status_code, payload, headers): + resp = HttpResponse(url_encode(payload), status=status_code) + for k, v in headers: + resp[k] = v + return resp + + +class CacheAuthorizationServer(BaseServer): + def __init__(self, client_model, token_model, token_generator=None): + super(CacheAuthorizationServer, self).__init__( + client_model, token_model, token_generator) + self._temporary_expires_in = self._config.get( + 'temporary_credential_expires_in', 86400) + self._temporary_credential_key_prefix = self._config.get( + 'temporary_credential_key_prefix', 'temporary_credential:') + + def create_temporary_credential(self, request): + key_prefix = self._temporary_credential_key_prefix + token = self.token_generator() + + client_id = request.client_id + redirect_uri = request.redirect_uri + key = key_prefix + token['oauth_token'] + token['client_id'] = client_id + if redirect_uri: + token['oauth_callback'] = redirect_uri + + cache.set(key, token, timeout=self._temporary_expires_in) + return TemporaryCredential(token) + + def get_temporary_credential(self, request): + if not request.token: + return None + + key_prefix = self._temporary_credential_key_prefix + key = key_prefix + request.token + value = cache.get(key) + if value: + return TemporaryCredential(value) + + def delete_temporary_credential(self, request): + if request.token: + key_prefix = self._temporary_credential_key_prefix + key = key_prefix + request.token + cache.delete(key) + + def create_authorization_verifier(self, request): + key_prefix = self._temporary_credential_key_prefix + verifier = generate_token(36) + credential = request.credential + user = request.user + key = key_prefix + credential.get_oauth_token() + credential['oauth_verifier'] = verifier + credential['user_id'] = user.pk + cache.set(key, credential, timeout=self._temporary_expires_in) + return verifier diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth1/nonce.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth1/nonce.py new file mode 100644 index 0000000..535bf7e --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth1/nonce.py @@ -0,0 +1,15 @@ +from django.core.cache import cache + + +def exists_nonce_in_cache(nonce, request, timeout): + key_prefix = 'nonce:' + timestamp = request.timestamp + client_id = request.client_id + token = request.token + key = '{}{}-{}-{}'.format(key_prefix, nonce, timestamp, client_id) + if token: + key = '{}-{}'.format(key, token) + + rv = bool(cache.get(key)) + cache.set(key, 1, timeout=timeout) + return rv diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth1/resource_protector.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth1/resource_protector.py new file mode 100644 index 0000000..cc2854b --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth1/resource_protector.py @@ -0,0 +1,66 @@ +import functools +from authlib.oauth1.errors import OAuth1Error +from authlib.oauth1 import ResourceProtector as _ResourceProtector +from django.http import JsonResponse +from django.conf import settings +from .nonce import exists_nonce_in_cache +from ..django_helpers import parse_request_headers + + +class ResourceProtector(_ResourceProtector): + def __init__(self, client_model, token_model): + self.client_model = client_model + self.token_model = token_model + + config = getattr(settings, 'AUTHLIB_OAUTH1_PROVIDER', {}) + methods = config.get('signature_methods', []) + if methods and isinstance(methods, (list, tuple)): + self.SUPPORTED_SIGNATURE_METHODS = methods + + self._nonce_expires_in = config.get('nonce_expires_in', 86400) + + def get_client_by_id(self, client_id): + try: + return self.client_model.objects.get(client_id=client_id) + except self.client_model.DoesNotExist: + return None + + def get_token_credential(self, request): + try: + return self.token_model.objects.get( + client_id=request.client_id, + oauth_token=request.token + ) + except self.token_model.DoesNotExist: + return None + + def exists_nonce(self, nonce, request): + return exists_nonce_in_cache(nonce, request, self._nonce_expires_in) + + def acquire_credential(self, request): + if request.method in ['POST', 'PUT']: + body = request.POST.dict() + else: + body = None + + headers = parse_request_headers(request) + url = request.get_raw_uri() + req = self.validate_request(request.method, url, body, headers) + return req.credential + + def __call__(self, realm=None): + def wrapper(f): + @functools.wraps(f) + def decorated(request, *args, **kwargs): + try: + credential = self.acquire_credential(request) + request.oauth1_credential = credential + except OAuth1Error as error: + body = dict(error.get_body()) + resp = JsonResponse(body, status=error.status_code) + resp['Cache-Control'] = 'no-store' + resp['Pragma'] = 'no-cache' + return resp + return f(request, *args, **kwargs) + return decorated + return wrapper diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth2/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth2/__init__.py new file mode 100644 index 0000000..05c1fdf --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth2/__init__.py @@ -0,0 +1,10 @@ +# flake8: noqa + +from .authorization_server import AuthorizationServer +from .resource_protector import ResourceProtector, BearerTokenValidator +from .endpoints import RevocationEndpoint +from .signals import ( + client_authenticated, + token_authenticated, + token_revoked +) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth2/authorization_server.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth2/authorization_server.py new file mode 100644 index 0000000..fae60aa --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth2/authorization_server.py @@ -0,0 +1,152 @@ +import json +from django.http import HttpResponse +from django.utils.module_loading import import_string +from django.conf import settings +from authlib.oauth2 import ( + OAuth2Request, + HttpRequest, + AuthorizationServer as _AuthorizationServer, +) +from authlib.oauth2.rfc6750 import BearerToken +from authlib.oauth2.rfc8414 import AuthorizationServerMetadata +from authlib.common.security import generate_token as _generate_token +from authlib.common.encoding import json_dumps +from .signals import client_authenticated, token_revoked +from ..django_helpers import create_oauth_request + + +class AuthorizationServer(_AuthorizationServer): + """Django implementation of :class:`authlib.oauth2.rfc6749.AuthorizationServer`. + Initialize it with client model and token model:: + + from authlib.integrations.django_oauth2 import AuthorizationServer + from your_project.models import OAuth2Client, OAuth2Token + + server = AuthorizationServer(OAuth2Client, OAuth2Token) + """ + metadata_class = AuthorizationServerMetadata + + def __init__(self, client_model, token_model, generate_token=None, metadata=None): + self.config = getattr(settings, 'AUTHLIB_OAUTH2_PROVIDER', {}) + self.client_model = client_model + self.token_model = token_model + if generate_token is None: + generate_token = self.create_bearer_token_generator() + + if metadata is None: + metadata_file = self.config.get('metadata_file') + if metadata_file: + with open(metadata_file) as f: + metadata = json.load(f) + + if metadata: + metadata = self.metadata_class(metadata) + metadata.validate() + + super(AuthorizationServer, self).__init__( + query_client=self.get_client_by_id, + save_token=self.save_oauth2_token, + generate_token=generate_token, + metadata=metadata, + ) + + def get_client_by_id(self, client_id): + """Default method for ``AuthorizationServer.query_client``. Developers MAY + rewrite this function to meet their own needs. + """ + try: + return self.client_model.objects.get(client_id=client_id) + except self.client_model.DoesNotExist: + return None + + def save_oauth2_token(self, token, request): + """Default method for ``AuthorizationServer.save_token``. Developers MAY + rewrite this function to meet their own needs. + """ + client = request.client + if request.user: + user_id = request.user.pk + else: + user_id = client.user_id + item = self.token_model( + client_id=client.client_id, + user_id=user_id, + **token + ) + item.save() + return item + + def create_oauth2_request(self, request): + return create_oauth_request(request, OAuth2Request) + + def create_json_request(self, request): + req = create_oauth_request(request, HttpRequest, True) + req.user = request.user + return req + + def handle_response(self, status_code, payload, headers): + if isinstance(payload, dict): + payload = json_dumps(payload) + resp = HttpResponse(payload, status=status_code) + for k, v in headers: + resp[k] = v + return resp + + def send_signal(self, name, *args, **kwargs): + if name == 'after_authenticate_client': + client_authenticated.send(sender=self.__class__, *args, **kwargs) + elif name == 'after_revoke_token': + token_revoked.send(sender=self.__class__, *args, **kwargs) + + def create_bearer_token_generator(self): + """Default method to create BearerToken generator.""" + conf = self.config.get('access_token_generator', True) + access_token_generator = create_token_generator(conf, 42) + + conf = self.config.get('refresh_token_generator', False) + refresh_token_generator = create_token_generator(conf, 48) + + conf = self.config.get('token_expires_in') + expires_generator = create_token_expires_in_generator(conf) + + return BearerToken( + access_token_generator=access_token_generator, + refresh_token_generator=refresh_token_generator, + expires_generator=expires_generator, + ) + + def get_consent_grant(self, request): + grant = self.get_authorization_grant(request) + grant.validate_consent_request() + if not hasattr(grant, 'prompt'): + grant.prompt = None + return grant + + def validate_consent_request(self, request, end_user=None): + req = self.create_oauth2_request(request) + req.user = end_user + return self.get_consent_grant(req) + + +def create_token_generator(token_generator_conf, length=42): + if callable(token_generator_conf): + return token_generator_conf + + if isinstance(token_generator_conf, str): + return import_string(token_generator_conf) + elif token_generator_conf is True: + def token_generator(*args, **kwargs): + return _generate_token(length) + return token_generator + + +def create_token_expires_in_generator(expires_in_conf=None): + data = {} + data.update(BearerToken.GRANT_TYPES_EXPIRES_IN) + if expires_in_conf: + data.update(expires_in_conf) + + def expires_in(client, grant_type): + return data.get(grant_type, BearerToken.DEFAULT_EXPIRES_IN) + + return expires_in diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth2/endpoints.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth2/endpoints.py new file mode 100644 index 0000000..b3a8ccd --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth2/endpoints.py @@ -0,0 +1,59 @@ +from authlib.oauth2.rfc7009 import RevocationEndpoint as _RevocationEndpoint + + +class RevocationEndpoint(_RevocationEndpoint): + """The revocation endpoint for OAuth authorization servers allows clients + to notify the authorization server that a previously obtained refresh or + access token is no longer needed. + + Register it into authorization server, and create token endpoint response + for token revocation:: + + from django.views.decorators.http import require_http_methods + + # see register into authorization server instance + server.register_endpoint(RevocationEndpoint) + + @require_http_methods(["POST"]) + def revoke_token(request): + return server.create_endpoint_response( + RevocationEndpoint.ENDPOINT_NAME, + request + ) + """ + + def query_token(self, token, token_type_hint, client): + """Query requested token from database.""" + token_model = self.server.token_model + if token_type_hint == 'access_token': + rv = _query_access_token(token_model, token) + elif token_type_hint == 'refresh_token': + rv = _query_refresh_token(token_model, token) + else: + rv = _query_access_token(token_model, token) + if not rv: + rv = _query_refresh_token(token_model, token) + + client_id = client.get_client_id() + if rv and rv.client_id == client_id: + return rv + return None + + def revoke_token(self, token): + """Mark the give token as revoked.""" + token.revoked = True + token.save() + + +def _query_access_token(token_model, token): + try: + return token_model.objects.get(access_token=token) + except token_model.DoesNotExist: + return None + + +def _query_refresh_token(token_model, token): + try: + return token_model.objects.get(refresh_token=token) + except token_model.DoesNotExist: + return None diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth2/resource_protector.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth2/resource_protector.py new file mode 100644 index 0000000..3e7f78d --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth2/resource_protector.py @@ -0,0 +1,79 @@ +import functools +from django.http import JsonResponse +from authlib.oauth2 import ( + OAuth2Error, + ResourceProtector as _ResourceProtector, +) +from authlib.oauth2.rfc6749 import ( + MissingAuthorizationError, + HttpRequest, +) +from authlib.oauth2.rfc6750 import ( + BearerTokenValidator as _BearerTokenValidator +) +from .signals import token_authenticated +from ..django_helpers import parse_request_headers + + +class ResourceProtector(_ResourceProtector): + def acquire_token(self, request, scope=None, operator='AND'): + """A method to acquire current valid token with the given scope. + + :param request: Django HTTP request instance + :param scope: string or list of scope values + :param operator: value of "AND" or "OR" + :return: token object + """ + headers = parse_request_headers(request) + url = request.get_raw_uri() + req = HttpRequest(request.method, url, request.body, headers) + if not callable(operator): + operator = operator.upper() + token = self.validate_request(scope, req, operator) + token_authenticated.send(sender=self.__class__, token=token) + return token + + def __call__(self, scope=None, operator='AND', optional=False): + def wrapper(f): + @functools.wraps(f) + def decorated(request, *args, **kwargs): + try: + token = self.acquire_token(request, scope, operator) + request.oauth_token = token + except MissingAuthorizationError as error: + if optional: + request.oauth_token = None + return f(request, *args, **kwargs) + return return_error_response(error) + except OAuth2Error as error: + return return_error_response(error) + return f(request, *args, **kwargs) + return decorated + return wrapper + + +class BearerTokenValidator(_BearerTokenValidator): + def __init__(self, token_model, realm=None): + self.token_model = token_model + super(BearerTokenValidator, self).__init__(realm) + + def authenticate_token(self, token_string): + try: + return self.token_model.objects.get(access_token=token_string) + except self.token_model.DoesNotExist: + return None + + def request_invalid(self, request): + return False + + def token_revoked(self, token): + return token.revoked + + +def return_error_response(error): + body = dict(error.get_body()) + resp = JsonResponse(body, status=error.status_code) + headers = error.get_headers() + for k, v in headers: + resp[k] = v + return resp diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth2/signals.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth2/signals.py new file mode 100644 index 0000000..0e9c265 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/django_oauth2/signals.py @@ -0,0 +1,11 @@ +from django.dispatch import Signal + + +#: signal when client is authenticated +client_authenticated = Signal() + +#: signal when token is revoked +token_revoked = Signal() + +#: signal when token is authenticated +token_authenticated = Signal() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_client/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_client/__init__.py new file mode 100644 index 0000000..9aa6f71 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_client/__init__.py @@ -0,0 +1,11 @@ +# flake8: noqa + +from .oauth_registry import OAuth +from .remote_app import FlaskRemoteApp +from .integration import token_update, FlaskIntegration +from ..base_client import OAuthError + +__all__ = [ + 'OAuth', 'FlaskRemoteApp', 'FlaskIntegration', + 'token_update', 'OAuthError', +] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_client/integration.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_client/integration.py new file mode 100644 index 0000000..875e2dd --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_client/integration.py @@ -0,0 +1,61 @@ +from flask import current_app, session +from flask.signals import Namespace +from ..base_client import FrameworkIntegration, OAuthError +from ..requests_client import OAuth1Session, OAuth2Session + +_signal = Namespace() +#: signal when token is updated +token_update = _signal.signal('token_update') + + +class FlaskIntegration(FrameworkIntegration): + oauth1_client_cls = OAuth1Session + oauth2_client_cls = OAuth2Session + + def set_session_data(self, request, key, value): + sess_key = '_{}_authlib_{}_'.format(self.name, key) + session[sess_key] = value + + def get_session_data(self, request, key): + sess_key = '_{}_authlib_{}_'.format(self.name, key) + return session.pop(sess_key, None) + + def update_token(self, token, refresh_token=None, access_token=None): + token_update.send( + current_app, + name=self.name, + token=token, + refresh_token=refresh_token, + access_token=access_token, + ) + + def generate_access_token_params(self, request_token_url, request): + if request_token_url: + return request.args.to_dict(flat=True) + + if request.method == 'GET': + error = request.args.get('error') + if error: + description = request.args.get('error_description') + raise OAuthError(error=error, description=description) + + params = { + 'code': request.args['code'], + 'state': request.args.get('state'), + } + else: + params = { + 'code': request.form['code'], + 'state': request.form.get('state'), + } + return params + + @staticmethod + def load_config(oauth, name, params): + rv = {} + for k in params: + conf_key = '{}_{}'.format(name, k).upper() + v = oauth.app.config.get(conf_key, None) + if v is not None: + rv[k] = v + return rv diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_client/oauth_registry.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_client/oauth_registry.py new file mode 100644 index 0000000..8f5d1fe --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_client/oauth_registry.py @@ -0,0 +1,118 @@ +import uuid +from flask import session +from werkzeug.local import LocalProxy +from .integration import FlaskIntegration +from .remote_app import FlaskRemoteApp +from ..base_client import BaseOAuth + +__all__ = ['OAuth'] +_req_token_tpl = '_{}_authlib_req_token_' + + +class OAuth(BaseOAuth): + """A Flask OAuth registry for oauth clients. + + Create an instance with Flask:: + + oauth = OAuth(app, cache=cache) + + You can also pass the instance of Flask later:: + + oauth = OAuth() + oauth.init_app(app, cache=cache) + + :param app: Flask application instance + :param cache: A cache instance that has .get .set and .delete methods + :param fetch_token: a shared function to get current user's token + :param update_token: a share function to update current user's token + """ + framework_client_cls = FlaskRemoteApp + framework_integration_cls = FlaskIntegration + + def __init__(self, app=None, cache=None, fetch_token=None, update_token=None): + super(OAuth, self).__init__(fetch_token, update_token) + + self.app = app + self.cache = cache + if app: + self.init_app(app) + + def init_app(self, app, cache=None, fetch_token=None, update_token=None): + """Initialize lazy for Flask app. This is usually used for Flask application + factory pattern. + """ + self.app = app + if cache is not None: + self.cache = cache + + if fetch_token: + self.fetch_token = fetch_token + if update_token: + self.update_token = update_token + + app.extensions = getattr(app, 'extensions', {}) + app.extensions['authlib.integrations.flask_client'] = self + + def create_client(self, name): + if not self.app: + raise RuntimeError('OAuth is not init with Flask app.') + return super(OAuth, self).create_client(name) + + def register(self, name, overwrite=False, **kwargs): + self._registry[name] = (overwrite, kwargs) + if self.app: + return self.create_client(name) + return LocalProxy(lambda: self.create_client(name)) + + def generate_client_kwargs(self, name, overwrite, **kwargs): + kwargs = super(OAuth, self).generate_client_kwargs(name, overwrite, **kwargs) + + if kwargs.get('request_token_url'): + if self.cache: + _add_cache_request_token(self.cache, name, kwargs) + else: + _add_session_request_token(name, kwargs) + return kwargs + + +def _add_cache_request_token(cache, name, kwargs): + if not kwargs.get('fetch_request_token'): + def fetch_request_token(): + key = _req_token_tpl.format(name) + sid = session.pop(key, None) + if not sid: + return None + + token = cache.get(sid) + cache.delete(sid) + return token + + kwargs['fetch_request_token'] = fetch_request_token + + if not kwargs.get('save_request_token'): + def save_request_token(token): + key = _req_token_tpl.format(name) + sid = uuid.uuid4().hex + session[key] = sid + cache.set(sid, token, 600) + + kwargs['save_request_token'] = save_request_token + return kwargs + + +def _add_session_request_token(name, kwargs): + if not kwargs.get('fetch_request_token'): + def fetch_request_token(): + key = _req_token_tpl.format(name) + return session.pop(key, None) + + kwargs['fetch_request_token'] = fetch_request_token + + if not kwargs.get('save_request_token'): + def save_request_token(token): + key = _req_token_tpl.format(name) + session[key] = token + + kwargs['save_request_token'] = save_request_token + + return kwargs diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_client/remote_app.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_client/remote_app.py new file mode 100644 index 0000000..0d8eecb --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_client/remote_app.py @@ -0,0 +1,81 @@ +from flask import redirect +from flask import request as flask_req +from flask import _app_ctx_stack +from ..base_client import RemoteApp + + +class FlaskRemoteApp(RemoteApp): + """Flask integrated RemoteApp of :class:`~authlib.client.OAuthClient`. + It has built-in hooks for OAuthClient. The only required configuration + is token model. + """ + + def __init__(self, framework, name=None, fetch_token=None, **kwargs): + fetch_request_token = kwargs.pop('fetch_request_token', None) + save_request_token = kwargs.pop('save_request_token', None) + super(FlaskRemoteApp, self).__init__(framework, name, fetch_token, **kwargs) + + self._fetch_request_token = fetch_request_token + self._save_request_token = save_request_token + + def _on_update_token(self, token, refresh_token=None, access_token=None): + self.token = token + super(FlaskRemoteApp, self)._on_update_token( + token, refresh_token, access_token + ) + + @property + def token(self): + ctx = _app_ctx_stack.top + attr = 'authlib_oauth_token_{}'.format(self.name) + token = getattr(ctx, attr, None) + if token: + return token + if self._fetch_token: + token = self._fetch_token() + self.token = token + return token + + @token.setter + def token(self, token): + ctx = _app_ctx_stack.top + attr = 'authlib_oauth_token_{}'.format(self.name) + setattr(ctx, attr, token) + + def request(self, method, url, token=None, **kwargs): + if token is None and not kwargs.get('withhold_token'): + token = self.token + return super(FlaskRemoteApp, self).request( + method, url, token=token, **kwargs) + + def authorize_redirect(self, redirect_uri=None, **kwargs): + """Create a HTTP Redirect for Authorization Endpoint. + + :param redirect_uri: Callback or redirect URI for authorization. + :param kwargs: Extra parameters to include. + :return: A HTTP redirect response. + """ + rv = self.create_authorization_url(redirect_uri, **kwargs) + + if self.request_token_url: + request_token = rv.pop('request_token', None) + self._save_request_token(request_token) + + self.save_authorize_data(flask_req, redirect_uri=redirect_uri, **rv) + return redirect(rv['url']) + + def authorize_access_token(self, **kwargs): + """Authorize access token.""" + if self.request_token_url: + request_token = self._fetch_request_token() + else: + request_token = None + + params = self.retrieve_access_token_params(flask_req, request_token) + params.update(kwargs) + token = self.fetch_access_token(**params) + self.token = token + return token + + def parse_id_token(self, token, claims_options=None, leeway=120): + return self._parse_id_token(flask_req, token, claims_options, leeway) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_helpers.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_helpers.py new file mode 100644 index 0000000..6883e4b --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_helpers.py @@ -0,0 +1,25 @@ +from flask import request as flask_req +from authlib.common.encoding import to_unicode + + +def create_oauth_request(request, request_cls, use_json=False): + if isinstance(request, request_cls): + return request + + if not request: + request = flask_req + + if request.method == 'POST': + if use_json: + body = request.get_json() + else: + body = request.form.to_dict(flat=True) + else: + body = None + + # query string in werkzeug Request.url is very weird + # scope=profile%20email will be scope=profile email + url = request.base_url + if request.query_string: + url = url + '?' + to_unicode(request.query_string) + return request_cls(request.method, url, body, request.headers) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth1/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth1/__init__.py new file mode 100644 index 0000000..780b059 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth1/__init__.py @@ -0,0 +1,9 @@ +# flake8: noqa + +from .authorization_server import AuthorizationServer +from .resource_protector import ResourceProtector, current_credential +from .cache import ( + register_nonce_hooks, + register_temporary_credential_hooks, + create_exists_nonce_func, +) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth1/authorization_server.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth1/authorization_server.py new file mode 100644 index 0000000..1062a7b --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth1/authorization_server.py @@ -0,0 +1,180 @@ +import logging +from werkzeug.utils import import_string +from flask import Response +from authlib.oauth1 import ( + OAuth1Request, + AuthorizationServer as _AuthorizationServer, +) +from authlib.common.security import generate_token +from authlib.common.urls import url_encode +from ..flask_helpers import create_oauth_request + +log = logging.getLogger(__name__) + + +class AuthorizationServer(_AuthorizationServer): + """Flask implementation of :class:`authlib.rfc5849.AuthorizationServer`. + Initialize it with Flask app instance, client model class and cache:: + + server = AuthorizationServer(app=app, query_client=query_client) + # or initialize lazily + server = AuthorizationServer() + server.init_app(app, query_client=query_client) + + :param app: A Flask app instance + :param query_client: A function to get client by client_id. The client + model class MUST implement the methods described by + :class:`~authlib.oauth1.rfc5849.ClientMixin`. + :param token_generator: A function to generate token + """ + + def __init__(self, app=None, query_client=None, token_generator=None): + self.app = app + self.query_client = query_client + self.token_generator = token_generator + + self._hooks = { + 'exists_nonce': None, + 'create_temporary_credential': None, + 'get_temporary_credential': None, + 'delete_temporary_credential': None, + 'create_authorization_verifier': None, + 'create_token_credential': None, + } + if app is not None: + self.init_app(app) + + def init_app(self, app, query_client=None, token_generator=None): + if query_client is not None: + self.query_client = query_client + if token_generator is not None: + self.token_generator = token_generator + + if self.token_generator is None: + self.token_generator = self.create_token_generator(app) + + methods = app.config.get('OAUTH1_SUPPORTED_SIGNATURE_METHODS') + if methods and isinstance(methods, (list, tuple)): + self.SUPPORTED_SIGNATURE_METHODS = methods + + self.app = app + + def register_hook(self, name, func): + if name not in self._hooks: + raise ValueError('Invalid "name" of hook') + self._hooks[name] = func + + def create_token_generator(self, app): + token_generator = app.config.get('OAUTH1_TOKEN_GENERATOR') + + if isinstance(token_generator, str): + token_generator = import_string(token_generator) + else: + length = app.config.get('OAUTH1_TOKEN_LENGTH', 42) + + def token_generator(): + return generate_token(length) + + secret_generator = app.config.get('OAUTH1_TOKEN_SECRET_GENERATOR') + if isinstance(secret_generator, str): + secret_generator = import_string(secret_generator) + else: + length = app.config.get('OAUTH1_TOKEN_SECRET_LENGTH', 48) + + def secret_generator(): + return generate_token(length) + + def create_token(): + return { + 'oauth_token': token_generator(), + 'oauth_token_secret': secret_generator() + } + return create_token + + def get_client_by_id(self, client_id): + return self.query_client(client_id) + + def exists_nonce(self, nonce, request): + func = self._hooks['exists_nonce'] + if callable(func): + timestamp = request.timestamp + client_id = request.client_id + token = request.token + return func(nonce, timestamp, client_id, token) + + raise RuntimeError('"exists_nonce" hook is required.') + + def create_temporary_credential(self, request): + func = self._hooks['create_temporary_credential'] + if callable(func): + token = self.token_generator() + return func(token, request.client_id, request.redirect_uri) + raise RuntimeError( + '"create_temporary_credential" hook is required.' + ) + + def get_temporary_credential(self, request): + func = self._hooks['get_temporary_credential'] + if callable(func): + return func(request.token) + + raise RuntimeError( + '"get_temporary_credential" hook is required.' + ) + + def delete_temporary_credential(self, request): + func = self._hooks['delete_temporary_credential'] + if callable(func): + return func(request.token) + + raise RuntimeError( + '"delete_temporary_credential" hook is required.' + ) + + def create_authorization_verifier(self, request): + func = self._hooks['create_authorization_verifier'] + if callable(func): + verifier = generate_token(36) + func(request.credential, request.user, verifier) + return verifier + + raise RuntimeError( + '"create_authorization_verifier" hook is required.' + ) + + def create_token_credential(self, request): + func = self._hooks['create_token_credential'] + if callable(func): + temporary_credential = request.credential + token = self.token_generator() + return func(token, temporary_credential) + + raise RuntimeError( + '"create_token_credential" hook is required.' + ) + + def create_temporary_credentials_response(self, request=None): + return super(AuthorizationServer, self)\ + .create_temporary_credentials_response(request) + + def check_authorization_request(self): + req = self.create_oauth1_request(None) + self.validate_authorization_request(req) + return req + + def create_authorization_response(self, request=None, grant_user=None): + return super(AuthorizationServer, self)\ + .create_authorization_response(request, grant_user) + + def create_token_response(self, request=None): + return super(AuthorizationServer, self).create_token_response(request) + + def create_oauth1_request(self, request): + return create_oauth_request(request, OAuth1Request) + + def handle_response(self, status_code, payload, headers): + return Response( + url_encode(payload), + status=status_code, + headers=headers + ) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth1/cache.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth1/cache.py new file mode 100644 index 0000000..c22211b --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth1/cache.py @@ -0,0 +1,80 @@ +from authlib.oauth1 import TemporaryCredential + + +def register_temporary_credential_hooks( + authorization_server, cache, key_prefix='temporary_credential:'): + """Register temporary credential related hooks to authorization server. + + :param authorization_server: AuthorizationServer instance + :param cache: Cache instance + :param key_prefix: key prefix for temporary credential + """ + + def create_temporary_credential(token, client_id, redirect_uri): + key = key_prefix + token['oauth_token'] + token['client_id'] = client_id + if redirect_uri: + token['oauth_callback'] = redirect_uri + + cache.set(key, token, timeout=86400) # cache for one day + return TemporaryCredential(token) + + def get_temporary_credential(oauth_token): + if not oauth_token: + return None + key = key_prefix + oauth_token + value = cache.get(key) + if value: + return TemporaryCredential(value) + + def delete_temporary_credential(oauth_token): + if oauth_token: + key = key_prefix + oauth_token + cache.delete(key) + + def create_authorization_verifier(credential, grant_user, verifier): + key = key_prefix + credential.get_oauth_token() + credential['oauth_verifier'] = verifier + credential['user_id'] = grant_user.get_user_id() + cache.set(key, credential, timeout=86400) + return credential + + authorization_server.register_hook( + 'create_temporary_credential', create_temporary_credential) + authorization_server.register_hook( + 'get_temporary_credential', get_temporary_credential) + authorization_server.register_hook( + 'delete_temporary_credential', delete_temporary_credential) + authorization_server.register_hook( + 'create_authorization_verifier', create_authorization_verifier) + + +def create_exists_nonce_func(cache, key_prefix='nonce:', expires=86400): + """Create an ``exists_nonce`` function that can be used in hooks and + resource protector. + + :param cache: Cache instance + :param key_prefix: key prefix for temporary credential + :param expires: Expire time for nonce + """ + def exists_nonce(nonce, timestamp, client_id, oauth_token): + key = '{}{}-{}-{}'.format(key_prefix, nonce, timestamp, client_id) + if oauth_token: + key = '{}-{}'.format(key, oauth_token) + rv = cache.has(key) + cache.set(key, 1, timeout=expires) + return rv + return exists_nonce + + +def register_nonce_hooks( + authorization_server, cache, key_prefix='nonce:', expires=86400): + """Register nonce related hooks to authorization server. + + :param authorization_server: AuthorizationServer instance + :param cache: Cache instance + :param key_prefix: key prefix for temporary credential + :param expires: Expire time for nonce + """ + exists_nonce = create_exists_nonce_func(cache, key_prefix, expires) + authorization_server.register_hook('exists_nonce', exists_nonce) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth1/resource_protector.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth1/resource_protector.py new file mode 100644 index 0000000..9f3361e --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth1/resource_protector.py @@ -0,0 +1,114 @@ +import functools +from flask import json, Response +from flask import request as _req +from flask import _app_ctx_stack +from werkzeug.local import LocalProxy +from authlib.consts import default_json_headers +from authlib.oauth1 import ResourceProtector as _ResourceProtector +from authlib.oauth1.errors import OAuth1Error + + +class ResourceProtector(_ResourceProtector): + """A protecting method for resource servers. Initialize a resource + protector with the query_token method:: + + from authlib.integrations.flask_oauth1 import ResourceProtector, current_credential + from authlib.integrations.flask_oauth1 import create_exists_nonce_func + from authlib.integrations.sqla_oauth1 import ( + create_query_client_func, + create_query_token_func, + ) + from your_project.models import Token, User, cache + + # you need to define a ``cache`` instance yourself + + require_oauth= ResourceProtector( + app, + query_client=create_query_client_func(db.session, OAuth1Client), + query_token=create_query_token_func(db.session, OAuth1Token), + exists_nonce=create_exists_nonce_func(cache) + ) + # or initialize it lazily + require_oauth = ResourceProtector() + require_oauth.init_app( + app, + query_client=create_query_client_func(db.session, OAuth1Client), + query_token=create_query_token_func(db.session, OAuth1Token), + exists_nonce=create_exists_nonce_func(cache) + ) + """ + def __init__(self, app=None, query_client=None, + query_token=None, exists_nonce=None): + self.query_client = query_client + self.query_token = query_token + self._exists_nonce = exists_nonce + + self.app = app + if app: + self.init_app(app) + + def init_app(self, app, query_client=None, query_token=None, + exists_nonce=None): + if query_client is not None: + self.query_client = query_client + if query_token is not None: + self.query_token = query_token + if exists_nonce is not None: + self._exists_nonce = exists_nonce + + methods = app.config.get('OAUTH1_SUPPORTED_SIGNATURE_METHODS') + if methods and isinstance(methods, (list, tuple)): + self.SUPPORTED_SIGNATURE_METHODS = methods + + self.app = app + + def get_client_by_id(self, client_id): + return self.query_client(client_id) + + def get_token_credential(self, request): + return self.query_token(request.client_id, request.token) + + def exists_nonce(self, nonce, request): + if not self._exists_nonce: + raise RuntimeError('"exists_nonce" function is required.') + + timestamp = request.timestamp + client_id = request.client_id + token = request.token + return self._exists_nonce(nonce, timestamp, client_id, token) + + def acquire_credential(self): + req = self.validate_request( + _req.method, + _req.url, + _req.form.to_dict(flat=True), + _req.headers + ) + ctx = _app_ctx_stack.top + ctx.authlib_server_oauth1_credential = req.credential + return req.credential + + def __call__(self, scope=None): + def wrapper(f): + @functools.wraps(f) + def decorated(*args, **kwargs): + try: + self.acquire_credential() + except OAuth1Error as error: + body = dict(error.get_body()) + return Response( + json.dumps(body), + status=error.status_code, + headers=default_json_headers, + ) + return f(*args, **kwargs) + return decorated + return wrapper + + +def _get_current_credential(): + ctx = _app_ctx_stack.top + return getattr(ctx, 'authlib_server_oauth1_credential', None) + + +current_credential = LocalProxy(_get_current_credential) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth2/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth2/__init__.py new file mode 100644 index 0000000..170a719 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth2/__init__.py @@ -0,0 +1,12 @@ +# flake8: noqa + +from .authorization_server import AuthorizationServer +from .resource_protector import ( + ResourceProtector, + current_token, +) +from .signals import ( + client_authenticated, + token_authenticated, + token_revoked, +) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth2/authorization_server.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth2/authorization_server.py new file mode 100644 index 0000000..7eb411c --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth2/authorization_server.py @@ -0,0 +1,212 @@ +from werkzeug.utils import import_string +from flask import Response, json +from authlib.deprecate import deprecate +from authlib.oauth2 import ( + OAuth2Request, + HttpRequest, + AuthorizationServer as _AuthorizationServer, +) +from authlib.oauth2.rfc6750 import BearerToken +from authlib.oauth2.rfc8414 import AuthorizationServerMetadata +from authlib.common.security import generate_token +from authlib.common.encoding import to_unicode +from .signals import client_authenticated, token_revoked +from ..flask_helpers import create_oauth_request + + +class AuthorizationServer(_AuthorizationServer): + """Flask implementation of :class:`authlib.oauth2.rfc6749.AuthorizationServer`. + Initialize it with ``query_client``, ``save_token`` methods and Flask + app instance:: + + def query_client(client_id): + return Client.query.filter_by(client_id=client_id).first() + + def save_token(token, request): + if request.user: + user_id = request.user.get_user_id() + else: + user_id = None + client = request.client + tok = Token( + client_id=client.client_id, + user_id=user.get_user_id(), + **token + ) + db.session.add(tok) + db.session.commit() + + server = AuthorizationServer(app, query_client, save_token) + # or initialize lazily + server = AuthorizationServer() + server.init_app(app, query_client, save_token) + """ + metadata_class = AuthorizationServerMetadata + + def __init__(self, app=None, query_client=None, save_token=None): + super(AuthorizationServer, self).__init__( + query_client=query_client, + save_token=save_token, + ) + self.config = {} + if app is not None: + self.init_app(app) + + def init_app(self, app, query_client=None, save_token=None): + """Initialize later with Flask app instance.""" + if query_client is not None: + self.query_client = query_client + if save_token is not None: + self.save_token = save_token + + self.generate_token = self.create_bearer_token_generator(app.config) + + metadata_file = app.config.get('OAUTH2_METADATA_FILE') + if metadata_file: + with open(metadata_file) as f: + metadata = self.metadata_class(json.load(f)) + metadata.validate() + self.metadata = metadata + + self.config.setdefault('error_uris', app.config.get('OAUTH2_ERROR_URIS')) + if app.config.get('OAUTH2_JWT_ENABLED'): + deprecate('Define "get_jwt_config" in OpenID Connect grants', '1.0') + self.init_jwt_config(app.config) + + def init_jwt_config(self, config): + """Initialize JWT related configuration.""" + jwt_iss = config.get('OAUTH2_JWT_ISS') + if not jwt_iss: + raise RuntimeError('Missing "OAUTH2_JWT_ISS" configuration.') + + jwt_key_path = config.get('OAUTH2_JWT_KEY_PATH') + if jwt_key_path: + with open(jwt_key_path, 'r') as f: + if jwt_key_path.endswith('.json'): + jwt_key = json.load(f) + else: + jwt_key = to_unicode(f.read()) + else: + jwt_key = config.get('OAUTH2_JWT_KEY') + + if not jwt_key: + raise RuntimeError('Missing "OAUTH2_JWT_KEY" configuration.') + + jwt_alg = config.get('OAUTH2_JWT_ALG') + if not jwt_alg: + raise RuntimeError('Missing "OAUTH2_JWT_ALG" configuration.') + + jwt_exp = config.get('OAUTH2_JWT_EXP', 3600) + self.config.setdefault('jwt_iss', jwt_iss) + self.config.setdefault('jwt_key', jwt_key) + self.config.setdefault('jwt_alg', jwt_alg) + self.config.setdefault('jwt_exp', jwt_exp) + + def get_error_uris(self, request): + error_uris = self.config.get('error_uris') + if error_uris: + return dict(error_uris) + + def create_oauth2_request(self, request): + return create_oauth_request(request, OAuth2Request) + + def create_json_request(self, request): + return create_oauth_request(request, HttpRequest, True) + + def handle_response(self, status_code, payload, headers): + if isinstance(payload, dict): + payload = json.dumps(payload) + return Response(payload, status=status_code, headers=headers) + + def send_signal(self, name, *args, **kwargs): + if name == 'after_authenticate_client': + client_authenticated.send(self, *args, **kwargs) + elif name == 'after_revoke_token': + token_revoked.send(self, *args, **kwargs) + + def create_token_expires_in_generator(self, config): + """Create a generator function for generating ``expires_in`` value. + Developers can re-implement this method with a subclass if other means + required. The default expires_in value is defined by ``grant_type``, + different ``grant_type`` has different value. It can be configured + with:: + + OAUTH2_TOKEN_EXPIRES_IN = { + 'authorization_code': 864000, + 'urn:ietf:params:oauth:grant-type:jwt-bearer': 3600, + } + """ + expires_conf = config.get('OAUTH2_TOKEN_EXPIRES_IN') + return create_token_expires_in_generator(expires_conf) + + def create_bearer_token_generator(self, config): + """Create a generator function for generating ``token`` value. This + method will create a Bearer Token generator with + :class:`authlib.oauth2.rfc6750.BearerToken`. By default, it will not + generate ``refresh_token``, which can be turn on by configuration + ``OAUTH2_REFRESH_TOKEN_GENERATOR=True``. + """ + conf = config.get('OAUTH2_ACCESS_TOKEN_GENERATOR', True) + access_token_generator = create_token_generator(conf, 42) + + conf = config.get('OAUTH2_REFRESH_TOKEN_GENERATOR', False) + refresh_token_generator = create_token_generator(conf, 48) + + expires_generator = self.create_token_expires_in_generator(config) + return BearerToken( + access_token_generator, + refresh_token_generator, + expires_generator + ) + + def validate_consent_request(self, request=None, end_user=None): + """Validate current HTTP request for authorization page. This page + is designed for resource owner to grant or deny the authorization:: + + @app.route('/authorize', methods=['GET']) + def authorize(): + try: + grant = server.validate_consent_request(end_user=current_user) + return render_template( + 'authorize.html', + grant=grant, + user=current_user + ) + except OAuth2Error as error: + return render_template( + 'error.html', + error=error + ) + """ + req = self.create_oauth2_request(request) + req.user = end_user + + grant = self.get_authorization_grant(req) + grant.validate_consent_request() + if not hasattr(grant, 'prompt'): + grant.prompt = None + return grant + + +def create_token_expires_in_generator(expires_in_conf=None): + data = {} + data.update(BearerToken.GRANT_TYPES_EXPIRES_IN) + if expires_in_conf: + data.update(expires_in_conf) + + def expires_in(client, grant_type): + return data.get(grant_type, BearerToken.DEFAULT_EXPIRES_IN) + + return expires_in + + +def create_token_generator(token_generator_conf, length=42): + if callable(token_generator_conf): + return token_generator_conf + + if isinstance(token_generator_conf, str): + return import_string(token_generator_conf) + elif token_generator_conf is True: + def token_generator(*args, **kwargs): + return generate_token(length) + return token_generator diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth2/errors.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth2/errors.py new file mode 100644 index 0000000..e9c9fde --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth2/errors.py @@ -0,0 +1,20 @@ +from werkzeug.exceptions import HTTPException + + +class _HTTPException(HTTPException): + def __init__(self, code, body, headers, response=None): + super(_HTTPException, self).__init__(None, response) + self.code = code + + self.body = body + self.headers = headers + + def get_body(self, environ=None): + return self.body + + def get_headers(self, environ=None): + return self.headers + + +def raise_http_exception(status, body, headers): + raise _HTTPException(status, body, headers) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth2/resource_protector.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth2/resource_protector.py new file mode 100644 index 0000000..41535f3 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth2/resource_protector.py @@ -0,0 +1,123 @@ +import functools +from contextlib import contextmanager +from flask import json +from flask import request as _req +from flask import _app_ctx_stack +from werkzeug.local import LocalProxy +from authlib.oauth2 import ( + OAuth2Error, + ResourceProtector as _ResourceProtector +) +from authlib.oauth2.rfc6749 import ( + MissingAuthorizationError, + HttpRequest, +) +from .signals import token_authenticated +from .errors import raise_http_exception + + +class ResourceProtector(_ResourceProtector): + """A protecting method for resource servers. Creating a ``require_oauth`` + decorator easily with ResourceProtector:: + + from authlib.integrations.flask_oauth2 import ResourceProtector + + require_oauth = ResourceProtector() + + # add bearer token validator + from authlib.oauth2.rfc6750 import BearerTokenValidator + from project.models import Token + + class MyBearerTokenValidator(BearerTokenValidator): + def authenticate_token(self, token_string): + return Token.query.filter_by(access_token=token_string).first() + + def request_invalid(self, request): + return False + + def token_revoked(self, token): + return False + + require_oauth.register_token_validator(MyBearerTokenValidator()) + + # protect resource with require_oauth + + @app.route('/user') + @require_oauth('profile') + def user_profile(): + user = User.query.get(current_token.user_id) + return jsonify(user.to_dict()) + + """ + def raise_error_response(self, error): + """Raise HTTPException for OAuth2Error. Developers can re-implement + this method to customize the error response. + + :param error: OAuth2Error + :raise: HTTPException + """ + status = error.status_code + body = json.dumps(dict(error.get_body())) + headers = error.get_headers() + raise_http_exception(status, body, headers) + + def acquire_token(self, scope=None, operator='AND'): + """A method to acquire current valid token with the given scope. + + :param scope: string or list of scope values + :param operator: value of "AND" or "OR" + :return: token object + """ + request = HttpRequest( + _req.method, + _req.full_path, + _req.data, + _req.headers + ) + if not callable(operator): + operator = operator.upper() + token = self.validate_request(scope, request, operator) + token_authenticated.send(self, token=token) + ctx = _app_ctx_stack.top + ctx.authlib_server_oauth2_token = token + return token + + @contextmanager + def acquire(self, scope=None, operator='AND'): + """The with statement of ``require_oauth``. Instead of using a + decorator, you can use a with statement instead:: + + @app.route('/api/user') + def user_api(): + with require_oauth.acquire('profile') as token: + user = User.query.get(token.user_id) + return jsonify(user.to_dict()) + """ + try: + yield self.acquire_token(scope, operator) + except OAuth2Error as error: + self.raise_error_response(error) + + def __call__(self, scope=None, operator='AND', optional=False): + def wrapper(f): + @functools.wraps(f) + def decorated(*args, **kwargs): + try: + self.acquire_token(scope, operator) + except MissingAuthorizationError as error: + if optional: + return f(*args, **kwargs) + self.raise_error_response(error) + except OAuth2Error as error: + self.raise_error_response(error) + return f(*args, **kwargs) + return decorated + return wrapper + + +def _get_current_token(): + ctx = _app_ctx_stack.top + return getattr(ctx, 'authlib_server_oauth2_token', None) + + +current_token = LocalProxy(_get_current_token) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth2/signals.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth2/signals.py new file mode 100644 index 0000000..c61e011 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/flask_oauth2/signals.py @@ -0,0 +1,12 @@ +from flask.signals import Namespace + +_signal = Namespace() + +#: signal when client is authenticated +client_authenticated = _signal.signal('client_authenticated') + +#: signal when token is revoked +token_revoked = _signal.signal('token_revoked') + +#: signal when token is authenticated +token_authenticated = _signal.signal('token_authenticated') diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/httpx_client/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/httpx_client/__init__.py new file mode 100644 index 0000000..3b5437c --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/httpx_client/__init__.py @@ -0,0 +1,25 @@ +from authlib.oauth1 import ( + SIGNATURE_HMAC_SHA1, + SIGNATURE_RSA_SHA1, + SIGNATURE_PLAINTEXT, + SIGNATURE_TYPE_HEADER, + SIGNATURE_TYPE_QUERY, + SIGNATURE_TYPE_BODY, +) +from .oauth1_client import OAuth1Auth, AsyncOAuth1Client, OAuth1Client +from .oauth2_client import ( + OAuth2Auth, OAuth2Client, OAuth2ClientAuth, + AsyncOAuth2Client, +) +from .assertion_client import AssertionClient, AsyncAssertionClient +from ..base_client import OAuthError + + +__all__ = [ + 'OAuthError', + 'OAuth1Auth', 'AsyncOAuth1Client', + 'SIGNATURE_HMAC_SHA1', 'SIGNATURE_RSA_SHA1', 'SIGNATURE_PLAINTEXT', + 'SIGNATURE_TYPE_HEADER', 'SIGNATURE_TYPE_QUERY', 'SIGNATURE_TYPE_BODY', + 'OAuth2Auth', 'OAuth2ClientAuth', 'OAuth2Client', 'AsyncOAuth2Client', + 'AssertionClient', 'AsyncAssertionClient', +] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/httpx_client/assertion_client.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/httpx_client/assertion_client.py new file mode 100644 index 0000000..cc0f908 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/httpx_client/assertion_client.py @@ -0,0 +1,89 @@ +from httpx import AsyncClient, Client +try: + from httpx._config import UNSET +except ImportError: + UNSET = None +from authlib.oauth2.rfc7521 import AssertionClient as _AssertionClient +from authlib.oauth2.rfc7523 import JWTBearerGrant +from authlib.oauth2 import OAuth2Error +from .utils import extract_client_kwargs +from .oauth2_client import OAuth2Auth + +__all__ = ['AsyncAssertionClient'] + + +class AsyncAssertionClient(_AssertionClient, AsyncClient): + token_auth_class = OAuth2Auth + JWT_BEARER_GRANT_TYPE = JWTBearerGrant.GRANT_TYPE + ASSERTION_METHODS = { + JWT_BEARER_GRANT_TYPE: JWTBearerGrant.sign, + } + DEFAULT_GRANT_TYPE = JWT_BEARER_GRANT_TYPE + + def __init__(self, token_endpoint, issuer, subject, audience=None, grant_type=None, + claims=None, token_placement='header', scope=None, **kwargs): + + client_kwargs = extract_client_kwargs(kwargs) + AsyncClient.__init__(self, **client_kwargs) + + _AssertionClient.__init__( + self, session=None, + token_endpoint=token_endpoint, issuer=issuer, subject=subject, + audience=audience, grant_type=grant_type, claims=claims, + token_placement=token_placement, scope=scope, **kwargs + ) + + async def request(self, method, url, withhold_token=False, auth=None, **kwargs): + """Send request with auto refresh token feature.""" + if not withhold_token and auth is UNSET: + if not self.token or self.token.is_expired(): + await self.refresh_token() + + auth = self.token_auth + return await super(AsyncAssertionClient, self).request( + method, url, auth=auth, **kwargs) + + async def _refresh_token(self, data): + resp = await self.request( + 'POST', self.token_endpoint, data=data, withhold_token=True) + + token = resp.json() + if 'error' in token: + raise OAuth2Error( + error=token['error'], + description=token.get('error_description') + ) + self.token = token + return self.token + + +class AssertionClient(_AssertionClient, Client): + token_auth_class = OAuth2Auth + JWT_BEARER_GRANT_TYPE = JWTBearerGrant.GRANT_TYPE + ASSERTION_METHODS = { + JWT_BEARER_GRANT_TYPE: JWTBearerGrant.sign, + } + DEFAULT_GRANT_TYPE = JWT_BEARER_GRANT_TYPE + + def __init__(self, token_endpoint, issuer, subject, audience=None, grant_type=None, + claims=None, token_placement='header', scope=None, **kwargs): + + client_kwargs = extract_client_kwargs(kwargs) + Client.__init__(self, **client_kwargs) + + _AssertionClient.__init__( + self, session=self, + token_endpoint=token_endpoint, issuer=issuer, subject=subject, + audience=audience, grant_type=grant_type, claims=claims, + token_placement=token_placement, scope=scope, **kwargs + ) + + def request(self, method, url, withhold_token=False, auth=None, **kwargs): + """Send request with auto refresh token feature.""" + if not withhold_token and auth is UNSET: + if not self.token or self.token.is_expired(): + self.refresh_token() + + auth = self.token_auth + return super(AssertionClient, self).request( + method, url, auth=auth, **kwargs) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/httpx_client/oauth1_client.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/httpx_client/oauth1_client.py new file mode 100644 index 0000000..7aee4e5 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/httpx_client/oauth1_client.py @@ -0,0 +1,101 @@ +import typing +from httpx import AsyncClient, Auth, Client, Request, Response +from authlib.oauth1 import ( + SIGNATURE_HMAC_SHA1, + SIGNATURE_TYPE_HEADER, +) +from authlib.common.encoding import to_unicode +from authlib.oauth1 import ClientAuth +from authlib.oauth1.client import OAuth1Client as _OAuth1Client +from .utils import extract_client_kwargs +from ..base_client import OAuthError + + +class OAuth1Auth(Auth, ClientAuth): + """Signs the httpx request using OAuth 1 (RFC5849)""" + requires_request_body = True + + def auth_flow(self, request: Request) -> typing.Generator[Request, Response, None]: + url, headers, body = self.prepare( + request.method, str(request.url), request.headers, request.content) + headers['Content-Length'] = str(len(body)) + yield Request(method=request.method, url=url, headers=headers, data=body) + + +class AsyncOAuth1Client(_OAuth1Client, AsyncClient): + auth_class = OAuth1Auth + + def __init__(self, client_id, client_secret=None, + token=None, token_secret=None, + redirect_uri=None, rsa_key=None, verifier=None, + signature_method=SIGNATURE_HMAC_SHA1, + signature_type=SIGNATURE_TYPE_HEADER, + force_include_body=False, **kwargs): + + _client_kwargs = extract_client_kwargs(kwargs) + AsyncClient.__init__(self, **_client_kwargs) + + _OAuth1Client.__init__( + self, None, + client_id=client_id, client_secret=client_secret, + token=token, token_secret=token_secret, + redirect_uri=redirect_uri, rsa_key=rsa_key, verifier=verifier, + signature_method=signature_method, signature_type=signature_type, + force_include_body=force_include_body, **kwargs) + + async def fetch_access_token(self, url, verifier=None, **kwargs): + """Method for fetching an access token from the token endpoint. + + This is the final step in the OAuth 1 workflow. An access token is + obtained using all previously obtained credentials, including the + verifier from the authorization step. + + :param url: Access Token endpoint. + :param verifier: A verifier string to prove authorization was granted. + :param kwargs: Extra parameters to include for fetching access token. + :return: A token dict. + """ + if verifier: + self.auth.verifier = verifier + if not self.auth.verifier: + self.handle_error('missing_verifier', 'Missing "verifier" value') + token = await self._fetch_token(url, **kwargs) + self.auth.verifier = None + return token + + async def _fetch_token(self, url, **kwargs): + resp = await self.post(url, **kwargs) + text = await resp.aread() + token = self.parse_response_token(resp.status_code, to_unicode(text)) + self.token = token + return token + + @staticmethod + def handle_error(error_type, error_description): + raise OAuthError(error_type, error_description) + + +class OAuth1Client(_OAuth1Client, Client): + auth_class = OAuth1Auth + + def __init__(self, client_id, client_secret=None, + token=None, token_secret=None, + redirect_uri=None, rsa_key=None, verifier=None, + signature_method=SIGNATURE_HMAC_SHA1, + signature_type=SIGNATURE_TYPE_HEADER, + force_include_body=False, **kwargs): + + _client_kwargs = extract_client_kwargs(kwargs) + Client.__init__(self, **_client_kwargs) + + _OAuth1Client.__init__( + self, self, + client_id=client_id, client_secret=client_secret, + token=token, token_secret=token_secret, + redirect_uri=redirect_uri, rsa_key=rsa_key, verifier=verifier, + signature_method=signature_method, signature_type=signature_type, + force_include_body=force_include_body, **kwargs) + + @staticmethod + def handle_error(error_type, error_description): + raise OAuthError(error_type, error_description) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/httpx_client/oauth2_client.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/httpx_client/oauth2_client.py new file mode 100644 index 0000000..923a773 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/httpx_client/oauth2_client.py @@ -0,0 +1,214 @@ +import asyncio +import typing +from httpx import AsyncClient, Auth, Client, Request, Response +try: + from httpx._config import UNSET +except ImportError: + UNSET = None +from authlib.common.urls import url_decode +from authlib.oauth2.client import OAuth2Client as _OAuth2Client +from authlib.oauth2.auth import ClientAuth, TokenAuth +from .utils import HTTPX_CLIENT_KWARGS +from ..base_client import ( + OAuthError, + InvalidTokenError, + MissingTokenError, + UnsupportedTokenTypeError, +) + +__all__ = [ + 'OAuth2Auth', 'OAuth2ClientAuth', + 'AsyncOAuth2Client', +] + + +class OAuth2Auth(Auth, TokenAuth): + """Sign requests for OAuth 2.0, currently only bearer token is supported.""" + requires_request_body = True + + def auth_flow(self, request: Request) -> typing.Generator[Request, Response, None]: + try: + url, headers, body = self.prepare( + str(request.url), request.headers, request.content) + yield Request(method=request.method, url=url, headers=headers, data=body) + except KeyError as error: + description = 'Unsupported token_type: {}'.format(str(error)) + raise UnsupportedTokenTypeError(description=description) + + +class OAuth2ClientAuth(Auth, ClientAuth): + requires_request_body = True + + def auth_flow(self, request: Request) -> typing.Generator[Request, Response, None]: + url, headers, body = self.prepare( + request.method, str(request.url), request.headers, request.content) + yield Request(method=request.method, url=url, headers=headers, data=body) + + +class AsyncOAuth2Client(_OAuth2Client, AsyncClient): + SESSION_REQUEST_PARAMS = HTTPX_CLIENT_KWARGS + + client_auth_class = OAuth2ClientAuth + token_auth_class = OAuth2Auth + + def __init__(self, client_id=None, client_secret=None, + token_endpoint_auth_method=None, + revocation_endpoint_auth_method=None, + scope=None, redirect_uri=None, + token=None, token_placement='header', + update_token=None, **kwargs): + + # extract httpx.Client kwargs + client_kwargs = self._extract_session_request_params(kwargs) + AsyncClient.__init__(self, **client_kwargs) + + # We use a "reverse" Event to synchronize coroutines to prevent + # multiple concurrent attempts to refresh the same token + self._token_refresh_event = asyncio.Event() + self._token_refresh_event.set() + + _OAuth2Client.__init__( + self, session=None, + client_id=client_id, client_secret=client_secret, + token_endpoint_auth_method=token_endpoint_auth_method, + revocation_endpoint_auth_method=revocation_endpoint_auth_method, + scope=scope, redirect_uri=redirect_uri, + token=token, token_placement=token_placement, + update_token=update_token, **kwargs + ) + + @staticmethod + def handle_error(error_type, error_description): + raise OAuthError(error_type, error_description) + + async def request(self, method, url, withhold_token=False, auth=UNSET, **kwargs): + if not withhold_token and auth is UNSET: + if not self.token: + raise MissingTokenError() + + if self.token.is_expired(): + await self.ensure_active_token() + + auth = self.token_auth + + return await super(AsyncOAuth2Client, self).request( + method, url, auth=auth, **kwargs) + + async def ensure_active_token(self): + if self._token_refresh_event.is_set(): + # Unset the event so other coroutines don't try to update the token + self._token_refresh_event.clear() + refresh_token = self.token.get('refresh_token') + url = self.metadata.get('token_endpoint') + if refresh_token and url: + await self.refresh_token(url, refresh_token=refresh_token) + elif self.metadata.get('grant_type') == 'client_credentials': + access_token = self.token['access_token'] + token = await self.fetch_token(url, grant_type='client_credentials') + if self.update_token: + await self.update_token(token, access_token=access_token) + else: + raise InvalidTokenError() + # Notify coroutines that token is refreshed + self._token_refresh_event.set() + return + await self._token_refresh_event.wait() # wait until the token is ready + + async def _fetch_token(self, url, body='', headers=None, auth=UNSET, + method='POST', **kwargs): + if method.upper() == 'POST': + resp = await self.post( + url, data=dict(url_decode(body)), headers=headers, + auth=auth, **kwargs) + else: + if '?' in url: + url = '&'.join([url, body]) + else: + url = '?'.join([url, body]) + resp = await self.get(url, headers=headers, auth=auth, **kwargs) + + for hook in self.compliance_hook['access_token_response']: + resp = hook(resp) + + return self.parse_response_token(resp.json()) + + async def _refresh_token(self, url, refresh_token=None, body='', + headers=None, auth=UNSET, **kwargs): + resp = await self.post( + url, data=dict(url_decode(body)), headers=headers, + auth=auth, **kwargs) + + for hook in self.compliance_hook['refresh_token_response']: + resp = hook(resp) + + token = self.parse_response_token(resp.json()) + if 'refresh_token' not in token: + self.token['refresh_token'] = refresh_token + + if self.update_token: + await self.update_token(self.token, refresh_token=refresh_token) + + return self.token + + def _http_post(self, url, body=None, auth=UNSET, headers=None, **kwargs): + return self.post( + url, data=dict(url_decode(body)), + headers=headers, auth=auth, **kwargs) + + +class OAuth2Client(_OAuth2Client, Client): + SESSION_REQUEST_PARAMS = HTTPX_CLIENT_KWARGS + + client_auth_class = OAuth2ClientAuth + token_auth_class = OAuth2Auth + + def __init__(self, client_id=None, client_secret=None, + token_endpoint_auth_method=None, + revocation_endpoint_auth_method=None, + scope=None, redirect_uri=None, + token=None, token_placement='header', + update_token=None, **kwargs): + + # extract httpx.Client kwargs + client_kwargs = self._extract_session_request_params(kwargs) + Client.__init__(self, **client_kwargs) + + _OAuth2Client.__init__( + self, session=self, + client_id=client_id, client_secret=client_secret, + token_endpoint_auth_method=token_endpoint_auth_method, + revocation_endpoint_auth_method=revocation_endpoint_auth_method, + scope=scope, redirect_uri=redirect_uri, + token=token, token_placement=token_placement, + update_token=update_token, **kwargs + ) + + @staticmethod + def handle_error(error_type, error_description): + raise OAuthError(error_type, error_description) + + def request(self, method, url, withhold_token=False, auth=UNSET, **kwargs): + if not withhold_token and auth is UNSET: + if not self.token: + raise MissingTokenError() + + if self.token.is_expired(): + self.ensure_active_token() + + auth = self.token_auth + + return super(OAuth2Client, self).request( + method, url, auth=auth, **kwargs) + + def ensure_active_token(self): + refresh_token = self.token.get('refresh_token') + url = self.metadata.get('token_endpoint') + if refresh_token and url: + self.refresh_token(url, refresh_token=refresh_token) + elif self.metadata.get('grant_type') == 'client_credentials': + access_token = self.token['access_token'] + token = self.fetch_token(url, grant_type='client_credentials') + if self.update_token: + self.update_token(token, access_token=access_token) + else: + raise InvalidTokenError() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/httpx_client/utils.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/httpx_client/utils.py new file mode 100644 index 0000000..907aa6c --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/httpx_client/utils.py @@ -0,0 +1,14 @@ +HTTPX_CLIENT_KWARGS = [ + 'headers', 'cookies', 'verify', 'cert', 'http_versions', + 'proxies', 'timeout', 'pool_limits', 'max_redirects', + 'base_url', 'dispatch', 'app', 'backend', 'trust_env', + 'json', +] + + +def extract_client_kwargs(kwargs): + client_kwargs = {} + for k in HTTPX_CLIENT_KWARGS: + if k in kwargs: + client_kwargs[k] = kwargs.pop(k) + return client_kwargs diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/requests_client/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/requests_client/__init__.py new file mode 100644 index 0000000..fcbdec3 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/requests_client/__init__.py @@ -0,0 +1,22 @@ +from .oauth1_session import OAuth1Session, OAuth1Auth +from .oauth2_session import OAuth2Session, OAuth2Auth +from .assertion_session import AssertionSession +from ..base_client import OAuthError +from authlib.oauth1 import ( + SIGNATURE_HMAC_SHA1, + SIGNATURE_RSA_SHA1, + SIGNATURE_PLAINTEXT, + SIGNATURE_TYPE_HEADER, + SIGNATURE_TYPE_QUERY, + SIGNATURE_TYPE_BODY, +) + + +__all__ = [ + 'OAuthError', + 'OAuth1Session', 'OAuth1Auth', + 'SIGNATURE_HMAC_SHA1', 'SIGNATURE_RSA_SHA1', 'SIGNATURE_PLAINTEXT', + 'SIGNATURE_TYPE_HEADER', 'SIGNATURE_TYPE_QUERY', 'SIGNATURE_TYPE_BODY', + 'OAuth2Session', 'OAuth2Auth', + 'AssertionSession', +] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/requests_client/assertion_session.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/requests_client/assertion_session.py new file mode 100644 index 0000000..1b95ea2 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/requests_client/assertion_session.py @@ -0,0 +1,48 @@ +from requests import Session +from authlib.deprecate import deprecate +from authlib.oauth2.rfc7521 import AssertionClient +from authlib.oauth2.rfc7523 import JWTBearerGrant +from .oauth2_session import OAuth2Auth + + +class AssertionAuth(OAuth2Auth): + def ensure_active_token(self): + if not self.token or self.token.is_expired() and self.client: + return self.client.refresh_token() + + +class AssertionSession(AssertionClient, Session): + """Constructs a new Assertion Framework for OAuth 2.0 Authorization Grants + per RFC7521_. + + .. _RFC7521: https://tools.ietf.org/html/rfc7521 + """ + token_auth_class = AssertionAuth + JWT_BEARER_GRANT_TYPE = JWTBearerGrant.GRANT_TYPE + ASSERTION_METHODS = { + JWT_BEARER_GRANT_TYPE: JWTBearerGrant.sign, + } + DEFAULT_GRANT_TYPE = JWT_BEARER_GRANT_TYPE + + def __init__(self, token_endpoint, issuer, subject, audience=None, grant_type=None, + claims=None, token_placement='header', scope=None, **kwargs): + Session.__init__(self) + + token_url = kwargs.pop('token_url', None) + if token_url: + deprecate('Use "token_endpoint" instead of "token_url"', '1.0') + token_endpoint = token_url + + AssertionClient.__init__( + self, session=self, + token_endpoint=token_endpoint, issuer=issuer, subject=subject, + audience=audience, grant_type=grant_type, claims=claims, + token_placement=token_placement, scope=scope, **kwargs + ) + + def request(self, method, url, withhold_token=False, auth=None, **kwargs): + """Send request with auto refresh token feature.""" + if not withhold_token and auth is None: + auth = self.token_auth + return super(AssertionSession, self).request( + method, url, auth=auth, **kwargs) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/requests_client/oauth1_session.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/requests_client/oauth1_session.py new file mode 100644 index 0000000..26a12ac --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/requests_client/oauth1_session.py @@ -0,0 +1,58 @@ +# -*- coding: utf-8 -*- +from requests import Session +from requests.auth import AuthBase +from authlib.oauth1 import ( + SIGNATURE_HMAC_SHA1, + SIGNATURE_TYPE_HEADER, +) +from authlib.common.encoding import to_native +from authlib.oauth1 import ClientAuth +from authlib.oauth1.client import OAuth1Client +from ..base_client import OAuthError + + +class OAuth1Auth(AuthBase, ClientAuth): + """Signs the request using OAuth 1 (RFC5849)""" + + def __call__(self, req): + url, headers, body = self.prepare( + req.method, req.url, req.headers, req.body) + + req.url = to_native(url) + req.prepare_headers(headers) + if body: + req.body = body + return req + + +class OAuth1Session(OAuth1Client, Session): + auth_class = OAuth1Auth + + def __init__(self, client_id, client_secret=None, + token=None, token_secret=None, + redirect_uri=None, rsa_key=None, verifier=None, + signature_method=SIGNATURE_HMAC_SHA1, + signature_type=SIGNATURE_TYPE_HEADER, + force_include_body=False, **kwargs): + Session.__init__(self) + OAuth1Client.__init__( + self, session=self, + client_id=client_id, client_secret=client_secret, + token=token, token_secret=token_secret, + redirect_uri=redirect_uri, rsa_key=rsa_key, verifier=verifier, + signature_method=signature_method, signature_type=signature_type, + force_include_body=force_include_body, **kwargs) + + def rebuild_auth(self, prepared_request, response): + """When being redirected we should always strip Authorization + header, since nonce may not be reused as per OAuth spec. + """ + if 'Authorization' in prepared_request.headers: + # If we get redirected to a new host, we should strip out + # any authentication headers. + prepared_request.headers.pop('Authorization', True) + prepared_request.prepare_auth(self.auth) + + @staticmethod + def handle_error(error_type, error_description): + raise OAuthError(error_type, error_description) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/requests_client/oauth2_session.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/requests_client/oauth2_session.py new file mode 100644 index 0000000..835487d --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/requests_client/oauth2_session.py @@ -0,0 +1,117 @@ +from requests import Session +from requests.auth import AuthBase +from authlib.oauth2.client import OAuth2Client +from authlib.oauth2.auth import ClientAuth, TokenAuth +from ..base_client import ( + OAuthError, + InvalidTokenError, + MissingTokenError, + UnsupportedTokenTypeError, +) + +__all__ = ['OAuth2Session', 'OAuth2Auth'] + + +class OAuth2Auth(AuthBase, TokenAuth): + """Sign requests for OAuth 2.0, currently only bearer token is supported.""" + + def ensure_active_token(self): + if self.client and self.token.is_expired(): + refresh_token = self.token.get('refresh_token') + client = self.client + url = client.metadata.get('token_endpoint') + if refresh_token and url: + client.refresh_token(url, refresh_token=refresh_token) + elif client.metadata.get('grant_type') == 'client_credentials': + access_token = self.token['access_token'] + token = client.fetch_token(url, grant_type='client_credentials') + if client.update_token: + client.update_token(token, access_token=access_token) + else: + raise InvalidTokenError() + + def __call__(self, req): + self.ensure_active_token() + try: + req.url, req.headers, req.body = self.prepare( + req.url, req.headers, req.body) + except KeyError as error: + description = 'Unsupported token_type: {}'.format(str(error)) + raise UnsupportedTokenTypeError(description=description) + return req + + +class OAuth2ClientAuth(AuthBase, ClientAuth): + """Attaches OAuth Client Authentication to the given Request object. + """ + def __call__(self, req): + req.url, req.headers, req.body = self.prepare( + req.method, req.url, req.headers, req.body + ) + return req + + +class OAuth2Session(OAuth2Client, Session): + """Construct a new OAuth 2 client requests session. + + :param client_id: Client ID, which you get from client registration. + :param client_secret: Client Secret, which you get from registration. + :param authorization_endpoint: URL of the authorization server's + authorization endpoint. + :param token_endpoint: URL of the authorization server's token endpoint. + :param token_endpoint_auth_method: client authentication method for + token endpoint. + :param revocation_endpoint: URL of the authorization server's OAuth 2.0 + revocation endpoint. + :param revocation_endpoint_auth_method: client authentication method for + revocation endpoint. + :param scope: Scope that you needed to access user resources. + :param redirect_uri: Redirect URI you registered as callback. + :param token: A dict of token attributes such as ``access_token``, + ``token_type`` and ``expires_at``. + :param token_placement: The place to put token in HTTP request. Available + values: "header", "body", "uri". + :param update_token: A function for you to update token. It accept a + :class:`OAuth2Token` as parameter. + """ + client_auth_class = OAuth2ClientAuth + token_auth_class = OAuth2Auth + SESSION_REQUEST_PARAMS = ( + 'allow_redirects', 'timeout', 'cookies', 'files', + 'proxies', 'hooks', 'stream', 'verify', 'cert', 'json' + ) + + def __init__(self, client_id=None, client_secret=None, + token_endpoint_auth_method=None, + revocation_endpoint_auth_method=None, + scope=None, redirect_uri=None, + token=None, token_placement='header', + update_token=None, **kwargs): + + Session.__init__(self) + OAuth2Client.__init__( + self, session=self, + client_id=client_id, client_secret=client_secret, + token_endpoint_auth_method=token_endpoint_auth_method, + revocation_endpoint_auth_method=revocation_endpoint_auth_method, + scope=scope, redirect_uri=redirect_uri, + token=token, token_placement=token_placement, + update_token=update_token, **kwargs + ) + + def fetch_access_token(self, url=None, **kwargs): + """Alias for fetch_token.""" + return self.fetch_token(url, **kwargs) + + def request(self, method, url, withhold_token=False, auth=None, **kwargs): + """Send request with auto refresh token feature (if available).""" + if not withhold_token and auth is None: + if not self.token: + raise MissingTokenError() + auth = self.token_auth + return super(OAuth2Session, self).request( + method, url, auth=auth, **kwargs) + + @staticmethod + def handle_error(error_type, error_description): + raise OAuthError(error_type, error_description) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth1/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth1/__init__.py new file mode 100644 index 0000000..75f7730 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth1/__init__.py @@ -0,0 +1,17 @@ +# flake8: noqa + +from .mixins import ( + OAuth1ClientMixin, + OAuth1TemporaryCredentialMixin, + OAuth1TimestampNonceMixin, + OAuth1TokenCredentialMixin, +) +from .functions import ( + create_query_client_func, + create_query_token_func, + register_temporary_credential_hooks, + create_exists_nonce_func, + register_nonce_hooks, + register_token_credential_hooks, + register_authorization_hooks, +) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth1/functions.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth1/functions.py new file mode 100644 index 0000000..31bb48e --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth1/functions.py @@ -0,0 +1,154 @@ +def create_query_client_func(session, model_class): + """Create an ``query_client`` function that can be used in authorization + server and resource protector. + + :param session: SQLAlchemy session + :param model_class: Client class + """ + def query_client(client_id): + q = session.query(model_class) + return q.filter_by(client_id=client_id).first() + return query_client + + +def create_query_token_func(session, model_class): + """Create an ``query_token`` function that can be used in + resource protector. + + :param session: SQLAlchemy session + :param model_class: TokenCredential class + """ + def query_token(client_id, oauth_token): + q = session.query(model_class) + return q.filter_by( + client_id=client_id, oauth_token=oauth_token).first() + return query_token + + +def register_temporary_credential_hooks( + authorization_server, session, model_class): + """Register temporary credential related hooks to authorization server. + + :param authorization_server: AuthorizationServer instance + :param session: SQLAlchemy session + :param model_class: TemporaryCredential class + """ + + def create_temporary_credential(token, client_id, redirect_uri): + item = model_class( + client_id=client_id, + oauth_token=token['oauth_token'], + oauth_token_secret=token['oauth_token_secret'], + oauth_callback=redirect_uri, + ) + session.add(item) + session.commit() + return item + + def get_temporary_credential(oauth_token): + q = session.query(model_class).filter_by(oauth_token=oauth_token) + return q.first() + + def delete_temporary_credential(oauth_token): + q = session.query(model_class).filter_by(oauth_token=oauth_token) + q.delete(synchronize_session=False) + session.commit() + + def create_authorization_verifier(credential, grant_user, verifier): + credential.set_user_id(grant_user.get_user_id()) + credential.oauth_verifier = verifier + session.add(credential) + session.commit() + return credential + + authorization_server.register_hook( + 'create_temporary_credential', create_temporary_credential) + authorization_server.register_hook( + 'get_temporary_credential', get_temporary_credential) + authorization_server.register_hook( + 'delete_temporary_credential', delete_temporary_credential) + authorization_server.register_hook( + 'create_authorization_verifier', create_authorization_verifier) + + +def create_exists_nonce_func(session, model_class): + """Create an ``exists_nonce`` function that can be used in hooks and + resource protector. + + :param session: SQLAlchemy session + :param model_class: TimestampNonce class + """ + def exists_nonce(nonce, timestamp, client_id, oauth_token): + q = session.query(model_class.nonce).filter_by( + nonce=nonce, + timestamp=timestamp, + client_id=client_id, + ) + if oauth_token: + q = q.filter_by(oauth_token=oauth_token) + rv = q.first() + if rv: + return True + + item = model_class( + nonce=nonce, + timestamp=timestamp, + client_id=client_id, + oauth_token=oauth_token, + ) + session.add(item) + session.commit() + return False + return exists_nonce + + +def register_nonce_hooks(authorization_server, session, model_class): + """Register nonce related hooks to authorization server. + + :param authorization_server: AuthorizationServer instance + :param session: SQLAlchemy session + :param model_class: TimestampNonce class + """ + exists_nonce = create_exists_nonce_func(session, model_class) + authorization_server.register_hook('exists_nonce', exists_nonce) + + +def register_token_credential_hooks( + authorization_server, session, model_class): + """Register token credential related hooks to authorization server. + + :param authorization_server: AuthorizationServer instance + :param session: SQLAlchemy session + :param model_class: TokenCredential class + """ + def create_token_credential(token, temporary_credential): + item = model_class( + oauth_token=token['oauth_token'], + oauth_token_secret=token['oauth_token_secret'], + client_id=temporary_credential.get_client_id() + ) + item.set_user_id(temporary_credential.get_user_id()) + session.add(item) + session.commit() + return item + + authorization_server.register_hook( + 'create_token_credential', create_token_credential) + + +def register_authorization_hooks( + authorization_server, session, + token_credential_model, + temporary_credential_model=None, + timestamp_nonce_model=None): + + register_token_credential_hooks( + authorization_server, session, token_credential_model) + + if temporary_credential_model is not None: + register_temporary_credential_hooks( + authorization_server, session, temporary_credential_model) + + if timestamp_nonce_model is not None: + register_nonce_hooks( + authorization_server, session, timestamp_nonce_model) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth1/mixins.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth1/mixins.py new file mode 100644 index 0000000..a72dd01 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth1/mixins.py @@ -0,0 +1,97 @@ +from sqlalchemy import Column, UniqueConstraint +from sqlalchemy import String, Integer, Text +from authlib.oauth1 import ( + ClientMixin, + TemporaryCredentialMixin, + TokenCredentialMixin, +) + + +class OAuth1ClientMixin(ClientMixin): + client_id = Column(String(48), index=True) + client_secret = Column(String(120), nullable=False) + default_redirect_uri = Column(Text, nullable=False, default='') + + def get_default_redirect_uri(self): + return self.default_redirect_uri + + def get_client_secret(self): + return self.client_secret + + def get_rsa_public_key(self): + return None + + +class OAuth1TemporaryCredentialMixin(TemporaryCredentialMixin): + client_id = Column(String(48), index=True) + oauth_token = Column(String(84), unique=True, index=True) + oauth_token_secret = Column(String(84)) + oauth_verifier = Column(String(84)) + oauth_callback = Column(Text, default='') + + def get_user_id(self): + """A method to get the grant user information of this temporary + credential. For instance, grant user is stored in database on + ``user_id`` column:: + + def get_user_id(self): + return self.user_id + + :return: User ID + """ + if hasattr(self, 'user_id'): + return self.user_id + else: + raise NotImplementedError() + + def set_user_id(self, user_id): + if hasattr(self, 'user_id'): + setattr(self, 'user_id', user_id) + else: + raise NotImplementedError() + + def get_client_id(self): + return self.client_id + + def get_redirect_uri(self): + return self.oauth_callback + + def check_verifier(self, verifier): + return self.oauth_verifier == verifier + + def get_oauth_token(self): + return self.oauth_token + + def get_oauth_token_secret(self): + return self.oauth_token_secret + + +class OAuth1TimestampNonceMixin(object): + __table_args__ = ( + UniqueConstraint( + 'client_id', 'timestamp', 'nonce', 'oauth_token', + name='unique_nonce' + ), + ) + client_id = Column(String(48), nullable=False) + timestamp = Column(Integer, nullable=False) + nonce = Column(String(48), nullable=False) + oauth_token = Column(String(84)) + + +class OAuth1TokenCredentialMixin(TokenCredentialMixin): + client_id = Column(String(48), index=True) + oauth_token = Column(String(84), unique=True, index=True) + oauth_token_secret = Column(String(84)) + + def set_user_id(self, user_id): + if hasattr(self, 'user_id'): + setattr(self, 'user_id', user_id) + else: + raise NotImplementedError() + + def get_oauth_token(self): + return self.oauth_token + + def get_oauth_token_secret(self): + return self.oauth_token_secret diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth2/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth2/__init__.py new file mode 100644 index 0000000..1964aa1 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth2/__init__.py @@ -0,0 +1,17 @@ +from .client_mixin import OAuth2ClientMixin +from .tokens_mixins import OAuth2AuthorizationCodeMixin, OAuth2TokenMixin +from .functions import ( + create_query_client_func, + create_save_token_func, + create_query_token_func, + create_revocation_endpoint, + create_bearer_token_validator, +) + + +__all__ = [ + 'OAuth2ClientMixin', 'OAuth2AuthorizationCodeMixin', 'OAuth2TokenMixin', + 'create_query_client_func', 'create_save_token_func', + 'create_query_token_func', 'create_revocation_endpoint', + 'create_bearer_token_validator', +] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth2/client_mixin.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth2/client_mixin.py new file mode 100644 index 0000000..b88b4ad --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth2/client_mixin.py @@ -0,0 +1,134 @@ +from sqlalchemy import Column, String, Text, Integer +from authlib.common.encoding import json_loads, json_dumps +from authlib.oauth2.rfc6749 import ClientMixin +from authlib.oauth2.rfc6749.util import scope_to_list, list_to_scope + + +class OAuth2ClientMixin(ClientMixin): + client_id = Column(String(48), index=True) + client_secret = Column(String(120)) + client_id_issued_at = Column(Integer, nullable=False, default=0) + client_secret_expires_at = Column(Integer, nullable=False, default=0) + _client_metadata = Column('client_metadata', Text) + + @property + def client_info(self): + """Implementation for Client Info in OAuth 2.0 Dynamic Client + Registration Protocol via `Section 3.2.1`_. + + .. _`Section 3.2.1`: https://tools.ietf.org/html/rfc7591#section-3.2.1 + """ + return dict( + client_id=self.client_id, + client_secret=self.client_secret, + client_id_issued_at=self.client_id_issued_at, + client_secret_expires_at=self.client_secret_expires_at, + ) + + @property + def client_metadata(self): + if 'client_metadata' in self.__dict__: + return self.__dict__['client_metadata'] + if self._client_metadata: + data = json_loads(self._client_metadata) + self.__dict__['client_metadata'] = data + return data + return {} + + def set_client_metadata(self, value): + self._client_metadata = json_dumps(value) + + @property + def redirect_uris(self): + return self.client_metadata.get('redirect_uris', []) + + @property + def token_endpoint_auth_method(self): + return self.client_metadata.get( + 'token_endpoint_auth_method', + 'client_secret_basic' + ) + + @property + def grant_types(self): + return self.client_metadata.get('grant_types', []) + + @property + def response_types(self): + return self.client_metadata.get('response_types', []) + + @property + def client_name(self): + return self.client_metadata.get('client_name') + + @property + def client_uri(self): + return self.client_metadata.get('client_uri') + + @property + def logo_uri(self): + return self.client_metadata.get('logo_uri') + + @property + def scope(self): + return self.client_metadata.get('scope', '') + + @property + def contacts(self): + return self.client_metadata.get('contacts', []) + + @property + def tos_uri(self): + return self.client_metadata.get('tos_uri') + + @property + def policy_uri(self): + return self.client_metadata.get('policy_uri') + + @property + def jwks_uri(self): + return self.client_metadata.get('jwks_uri') + + @property + def jwks(self): + return self.client_metadata.get('jwks', []) + + @property + def software_id(self): + return self.client_metadata.get('software_id') + + @property + def software_version(self): + return self.client_metadata.get('software_version') + + def get_client_id(self): + return self.client_id + + def get_default_redirect_uri(self): + if self.redirect_uris: + return self.redirect_uris[0] + + def get_allowed_scope(self, scope): + if not scope: + return '' + allowed = set(self.scope.split()) + scopes = scope_to_list(scope) + return list_to_scope([s for s in scopes if s in allowed]) + + def check_redirect_uri(self, redirect_uri): + return redirect_uri in self.redirect_uris + + def has_client_secret(self): + return bool(self.client_secret) + + def check_client_secret(self, client_secret): + return self.client_secret == client_secret + + def check_token_endpoint_auth_method(self, method): + return self.token_endpoint_auth_method == method + + def check_response_type(self, response_type): + return response_type in self.response_types + + def check_grant_type(self, grant_type): + return grant_type in self.grant_types diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth2/functions.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth2/functions.py new file mode 100644 index 0000000..f79337b --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth2/functions.py @@ -0,0 +1,101 @@ +def create_query_client_func(session, client_model): + """Create an ``query_client`` function that can be used in authorization + server. + + :param session: SQLAlchemy session + :param client_model: Client model class + """ + def query_client(client_id): + q = session.query(client_model) + return q.filter_by(client_id=client_id).first() + return query_client + + +def create_save_token_func(session, token_model): + """Create an ``save_token`` function that can be used in authorization + server. + + :param session: SQLAlchemy session + :param token_model: Token model class + """ + def save_token(token, request): + if request.user: + user_id = request.user.get_user_id() + else: + user_id = None + client = request.client + item = token_model( + client_id=client.client_id, + user_id=user_id, + **token + ) + session.add(item) + session.commit() + return save_token + + +def create_query_token_func(session, token_model): + """Create an ``query_token`` function for revocation, introspection + token endpoints. + + :param session: SQLAlchemy session + :param token_model: Token model class + """ + def query_token(token, token_type_hint, client): + q = session.query(token_model) + q = q.filter_by(client_id=client.client_id, revoked=False) + if token_type_hint == 'access_token': + return q.filter_by(access_token=token).first() + elif token_type_hint == 'refresh_token': + return q.filter_by(refresh_token=token).first() + # without token_type_hint + item = q.filter_by(access_token=token).first() + if item: + return item + return q.filter_by(refresh_token=token).first() + return query_token + + +def create_revocation_endpoint(session, token_model): + """Create a revocation endpoint class with SQLAlchemy session + and token model. + + :param session: SQLAlchemy session + :param token_model: Token model class + """ + from authlib.oauth2.rfc7009 import RevocationEndpoint + query_token = create_query_token_func(session, token_model) + + class _RevocationEndpoint(RevocationEndpoint): + def query_token(self, token, token_type_hint, client): + return query_token(token, token_type_hint, client) + + def revoke_token(self, token): + token.revoked = True + session.add(token) + session.commit() + + return _RevocationEndpoint + + +def create_bearer_token_validator(session, token_model): + """Create an bearer token validator class with SQLAlchemy session + and token model. + + :param session: SQLAlchemy session + :param token_model: Token model class + """ + from authlib.oauth2.rfc6750 import BearerTokenValidator + + class _BearerTokenValidator(BearerTokenValidator): + def authenticate_token(self, token_string): + q = session.query(token_model) + return q.filter_by(access_token=token_string).first() + + def request_invalid(self, request): + return False + + def token_revoked(self, token): + return token.revoked + + return _BearerTokenValidator diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth2/tokens_mixins.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth2/tokens_mixins.py new file mode 100644 index 0000000..fcd28e2 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/sqla_oauth2/tokens_mixins.py @@ -0,0 +1,62 @@ +import time +from sqlalchemy import Column, String, Boolean, Text, Integer +from authlib.oauth2.rfc6749 import ( + TokenMixin, + AuthorizationCodeMixin, +) + + +class OAuth2AuthorizationCodeMixin(AuthorizationCodeMixin): + code = Column(String(120), unique=True, nullable=False) + client_id = Column(String(48)) + redirect_uri = Column(Text, default='') + response_type = Column(Text, default='') + scope = Column(Text, default='') + nonce = Column(Text) + auth_time = Column( + Integer, nullable=False, + default=lambda: int(time.time()) + ) + + code_challenge = Column(Text) + code_challenge_method = Column(String(48)) + + def is_expired(self): + return self.auth_time + 300 < time.time() + + def get_redirect_uri(self): + return self.redirect_uri + + def get_scope(self): + return self.scope + + def get_auth_time(self): + return self.auth_time + + def get_nonce(self): + return self.nonce + + +class OAuth2TokenMixin(TokenMixin): + client_id = Column(String(48)) + token_type = Column(String(40)) + access_token = Column(String(255), unique=True, nullable=False) + refresh_token = Column(String(255), index=True) + scope = Column(Text, default='') + revoked = Column(Boolean, default=False) + issued_at = Column( + Integer, nullable=False, default=lambda: int(time.time()) + ) + expires_in = Column(Integer, nullable=False, default=0) + + def get_client_id(self): + return self.client_id + + def get_scope(self): + return self.scope + + def get_expires_in(self): + return self.expires_in + + def get_expires_at(self): + return self.issued_at + self.expires_in diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/starlette_client/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/starlette_client/__init__.py new file mode 100644 index 0000000..c4dbe9f --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/starlette_client/__init__.py @@ -0,0 +1,20 @@ +# flake8: noqa + +from ..base_client import BaseOAuth, OAuthError +from .integration import StartletteIntegration, StarletteRemoteApp + + +class OAuth(BaseOAuth): + framework_client_cls = StarletteRemoteApp + framework_integration_cls = StartletteIntegration + + def __init__(self, config=None, cache=None, fetch_token=None, update_token=None): + super(OAuth, self).__init__(fetch_token, update_token) + self.cache = cache + self.config = config + + +__all__ = [ + 'OAuth', 'StartletteIntegration', 'StarletteRemoteApp', + 'OAuthError', +] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/starlette_client/integration.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/starlette_client/integration.py new file mode 100644 index 0000000..ef2ff47 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/integrations/starlette_client/integration.py @@ -0,0 +1,72 @@ +from starlette.responses import RedirectResponse +from ..httpx_client import AsyncOAuth1Client, AsyncOAuth2Client +from ..base_client import FrameworkIntegration, OAuthError +from ..base_client.async_app import AsyncRemoteApp + + +class StartletteIntegration(FrameworkIntegration): + oauth1_client_cls = AsyncOAuth1Client + oauth2_client_cls = AsyncOAuth2Client + + def update_token(self, token, refresh_token=None, access_token=None): + pass + + def generate_access_token_params(self, request_token_url, request): + if request_token_url: + return dict(request.query_params) + + error = request.query_params.get('error') + if error: + description = request.query_params.get('error_description') + raise OAuthError(error=error, description=description) + + return { + 'code': request.query_params.get('code'), + 'state': request.query_params.get('state'), + } + + @staticmethod + def load_config(oauth, name, params): + if not oauth.config: + return {} + + rv = {} + for k in params: + conf_key = '{}_{}'.format(name, k).upper() + v = oauth.config.get(conf_key, default=None) + if v is not None: + rv[k] = v + return rv + + +class StarletteRemoteApp(AsyncRemoteApp): + + async def authorize_redirect(self, request, redirect_uri=None, **kwargs): + """Create a HTTP Redirect for Authorization Endpoint. + + :param request: Starlette Request instance. + :param redirect_uri: Callback or redirect URI for authorization. + :param kwargs: Extra parameters to include. + :return: Starlette ``RedirectResponse`` instance. + """ + rv = await self.create_authorization_url(redirect_uri, **kwargs) + self.save_authorize_data(request, redirect_uri=redirect_uri, **rv) + return RedirectResponse(rv['url'], status_code=302) + + async def authorize_access_token(self, request, **kwargs): + """Fetch an access token. + + :param request: Starlette Request instance. + :return: A token dict. + """ + params = self.retrieve_access_token_params(request) + params.update(kwargs) + return await self.fetch_access_token(**params) + + async def parse_id_token(self, request, token, claims_options=None): + """Return an instance of UserInfo from token's ``id_token``.""" + if 'id_token' not in token: + return None + + nonce = self.framework.get_session_data(request, 'nonce') + return await self._parse_id_token(token, nonce, claims_options) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/__init__.py new file mode 100644 index 0000000..c023ae2 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/__init__.py @@ -0,0 +1,74 @@ +""" + authlib.jose + ~~~~~~~~~~~~ + + JOSE implementation in Authlib. Tracking the status of JOSE specs at + https://tools.ietf.org/wg/jose/ +""" +from .rfc7515 import ( + JsonWebSignature, JWSAlgorithm, JWSHeader, JWSObject, +) +from .rfc7516 import ( + JsonWebEncryption, JWEAlgorithm, JWEEncAlgorithm, JWEZipAlgorithm, +) +from .rfc7517 import Key, KeySet, JsonWebKey +from .rfc7518 import ( + register_jws_rfc7518, + register_jwe_rfc7518, + ECDHAlgorithm, + OctKey, + RSAKey, + ECKey, +) +from .rfc7519 import JsonWebToken, BaseClaims, JWTClaims +from .rfc8037 import OKPKey, register_jws_rfc8037 +from .drafts import register_jwe_draft + +from .errors import JoseError + +# register algorithms +register_jws_rfc7518() +register_jwe_rfc7518() +register_jws_rfc8037() +register_jwe_draft() + +# attach algorithms +ECDHAlgorithm.ALLOWED_KEY_CLS = (ECKey, OKPKey) + +# register supported keys +JsonWebKey.JWK_KEY_CLS = { + OctKey.kty: OctKey, + RSAKey.kty: RSAKey, + ECKey.kty: ECKey, + OKPKey.kty: OKPKey, +} + +# compatible constants +JWS_ALGORITHMS = list(JsonWebSignature.ALGORITHMS_REGISTRY.keys()) +JWE_ALG_ALGORITHMS = list(JsonWebEncryption.ALG_REGISTRY.keys()) +JWE_ENC_ALGORITHMS = list(JsonWebEncryption.ENC_REGISTRY.keys()) +JWE_ZIP_ALGORITHMS = list(JsonWebEncryption.ZIP_REGISTRY.keys()) +JWE_ALGORITHMS = JWE_ALG_ALGORITHMS + JWE_ENC_ALGORITHMS + JWE_ZIP_ALGORITHMS + +# compatible imports +JWS = JsonWebSignature +JWE = JsonWebEncryption +JWK = JsonWebKey +JWT = JsonWebToken + +jwt = JsonWebToken() + + +__all__ = [ + 'JoseError', + + 'JWS', 'JsonWebSignature', 'JWSAlgorithm', 'JWSHeader', 'JWSObject', + 'JWE', 'JsonWebEncryption', 'JWEAlgorithm', 'JWEEncAlgorithm', 'JWEZipAlgorithm', + + 'JWK', 'JsonWebKey', 'Key', 'KeySet', + + 'OctKey', 'RSAKey', 'ECKey', 'OKPKey', + + 'JWT', 'JsonWebToken', 'BaseClaims', 'JWTClaims', + 'jwt', +] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/drafts/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/drafts/__init__.py new file mode 100644 index 0000000..b160138 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/drafts/__init__.py @@ -0,0 +1,3 @@ +from ._jwe_enc_cryptography import register_jwe_draft + +__all__ = ['register_jwe_draft'] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/drafts/_jwe_enc_cryptography.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/drafts/_jwe_enc_cryptography.py new file mode 100644 index 0000000..806eab9 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/drafts/_jwe_enc_cryptography.py @@ -0,0 +1,54 @@ +""" + authlib.jose.draft + ~~~~~~~~~~~~~~~~~~~~ + + Content Encryption per `Section 4`_. + + .. _`Section 4`: https://tools.ietf.org/html/draft-amringer-jose-chacha-02#section-4 +""" +from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305 +from authlib.jose.rfc7516 import JWEEncAlgorithm, JsonWebEncryption + + +class C20PEncAlgorithm(JWEEncAlgorithm): + # Use of an IV of size 96 bits is REQUIRED with this algorithm. + # https://tools.ietf.org/html/draft-amringer-jose-chacha-02#section-2.2.1 + IV_SIZE = 96 + + def __init__(self, key_size): + self.name = 'C20P' + self.description = 'ChaCha20-Poly1305' + self.key_size = key_size + self.CEK_SIZE = key_size + + def encrypt(self, msg, aad, iv, key): + """Key Encryption with AES GCM + + :param msg: text to be encrypt in bytes + :param aad: additional authenticated data in bytes + :param iv: initialization vector in bytes + :param key: encrypted key in bytes + :return: (ciphertext, tag) + """ + self.check_iv(iv) + chacha = ChaCha20Poly1305(key) + ciphertext = chacha.encrypt(iv, msg, aad) + return ciphertext[:-16], ciphertext[-16:] + + def decrypt(self, ciphertext, aad, iv, tag, key): + """Key Decryption with AES GCM + + :param ciphertext: ciphertext in bytes + :param aad: additional authenticated data in bytes + :param iv: initialization vector in bytes + :param tag: authentication tag in bytes + :param key: encrypted key in bytes + :return: message + """ + self.check_iv(iv) + chacha = ChaCha20Poly1305(key) + return chacha.decrypt(iv, ciphertext + tag, aad) + + +def register_jwe_draft(): + JsonWebEncryption.register_algorithm(C20PEncAlgorithm(256)) # C20P diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/errors.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/errors.py new file mode 100644 index 0000000..2174b42 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/errors.py @@ -0,0 +1,88 @@ +from authlib.common.errors import AuthlibBaseError + + +class JoseError(AuthlibBaseError): + pass + + +class DecodeError(JoseError): + error = 'decode_error' + + +class MissingAlgorithmError(JoseError): + error = 'missing_algorithm' + + +class UnsupportedAlgorithmError(JoseError): + error = 'unsupported_algorithm' + + +class BadSignatureError(JoseError): + error = 'bad_signature' + + def __init__(self, result): + super(BadSignatureError, self).__init__() + self.result = result + + +class InvalidHeaderParameterName(JoseError): + error = 'invalid_header_parameter_name' + + def __init__(self, name): + description = 'Invalid Header Parameter Names: {}'.format(name) + super(InvalidHeaderParameterName, self).__init__( + description=description) + + +class MissingEncryptionAlgorithmError(JoseError): + error = 'missing_encryption_algorithm' + description = 'Missing "enc" in header' + + +class UnsupportedEncryptionAlgorithmError(JoseError): + error = 'unsupported_encryption_algorithm' + description = 'Unsupported "enc" value in header' + + +class UnsupportedCompressionAlgorithmError(JoseError): + error = 'unsupported_compression_algorithm' + description = 'Unsupported "zip" value in header' + + +class InvalidUseError(JoseError): + error = 'invalid_use' + description = 'Key "use" is not valid for your usage' + + +class InvalidClaimError(JoseError): + error = 'invalid_claim' + + def __init__(self, claim): + description = 'Invalid claim "{}"'.format(claim) + super(InvalidClaimError, self).__init__(description=description) + + +class MissingClaimError(JoseError): + error = 'missing_claim' + + def __init__(self, claim): + description = 'Missing "{}" claim'.format(claim) + super(MissingClaimError, self).__init__(description=description) + + +class InsecureClaimError(JoseError): + error = 'insecure_claim' + + def __init__(self, claim): + description = 'Insecure claim "{}"'.format(claim) + super(InsecureClaimError, self).__init__(description=description) + + +class ExpiredTokenError(JoseError): + error = 'expired_token' + description = 'The token is expired' + + +class InvalidTokenError(JoseError): + error = 'invalid_token' + description = 'The token is not valid yet' diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/jwk.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/jwk.py new file mode 100644 index 0000000..02dbbab --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/jwk.py @@ -0,0 +1,19 @@ +from .rfc7517 import JsonWebKey + + +def loads(obj, kid=None): + # TODO: deprecate + key_set = JsonWebKey.import_key_set(obj) + if key_set: + return key_set.find_by_kid(kid) + return JsonWebKey.import_key(obj) + + +def dumps(key, kty=None, **params): + # TODO: deprecate + if kty: + params['kty'] = kty + + key = JsonWebKey.import_key(key, params) + data = key.as_dict() + return data diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7515/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7515/__init__.py new file mode 100644 index 0000000..5f8e0f5 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7515/__init__.py @@ -0,0 +1,18 @@ +""" + authlib.jose.rfc7515 + ~~~~~~~~~~~~~~~~~~~~~ + + This module represents a direct implementation of + JSON Web Signature (JWS). + + https://tools.ietf.org/html/rfc7515 +""" + +from .jws import JsonWebSignature +from .models import JWSAlgorithm, JWSHeader, JWSObject + + +__all__ = [ + 'JsonWebSignature', + 'JWSAlgorithm', 'JWSHeader', 'JWSObject' +] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7515/jws.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7515/jws.py new file mode 100644 index 0000000..2092055 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7515/jws.py @@ -0,0 +1,318 @@ +from authlib.common.encoding import ( + to_bytes, + to_unicode, + urlsafe_b64encode, + json_b64encode, + json_loads, +) +from authlib.jose.util import ( + extract_header, + extract_segment, +) +from authlib.jose.errors import ( + DecodeError, + MissingAlgorithmError, + UnsupportedAlgorithmError, + BadSignatureError, + InvalidHeaderParameterName, +) +from .models import JWSHeader, JWSObject + + +class JsonWebSignature(object): + + #: Registered Header Parameter Names defined by Section 4.1 + REGISTERED_HEADER_PARAMETER_NAMES = frozenset([ + 'alg', 'jku', 'jwk', 'kid', + 'x5u', 'x5c', 'x5t', 'x5t#S256', + 'typ', 'cty', 'crit' + ]) + + #: Defined available JWS algorithms in the registry + ALGORITHMS_REGISTRY = {} + + def __init__(self, algorithms=None, private_headers=None): + self._private_headers = private_headers + self._algorithms = algorithms + + @classmethod + def register_algorithm(cls, algorithm): + if not algorithm or algorithm.algorithm_type != 'JWS': + raise ValueError( + 'Invalid algorithm for JWS, {!r}'.format(algorithm)) + cls.ALGORITHMS_REGISTRY[algorithm.name] = algorithm + + def serialize_compact(self, protected, payload, key): + """Generate a JWS Compact Serialization. The JWS Compact Serialization + represents digitally signed or MACed content as a compact, URL-safe + string, per `Section 7.1`_. + + .. code-block:: text + + BASE64URL(UTF8(JWS Protected Header)) || '.' || + BASE64URL(JWS Payload) || '.' || + BASE64URL(JWS Signature) + + :param protected: A dict of protected header + :param payload: A bytes/string of payload + :param key: Private key used to generate signature + :return: byte + """ + jws_header = JWSHeader(protected, None) + self._validate_private_headers(protected) + algorithm, key = self._prepare_algorithm_key(protected, payload, key) + + protected_segment = json_b64encode(jws_header.protected) + payload_segment = urlsafe_b64encode(to_bytes(payload)) + + # calculate signature + signing_input = b'.'.join([protected_segment, payload_segment]) + signature = urlsafe_b64encode(algorithm.sign(signing_input, key)) + return b'.'.join([protected_segment, payload_segment, signature]) + + def deserialize_compact(self, s, key, decode=None): + """Exact JWS Compact Serialization, and validate with the given key. + If key is not provided, the returned dict will contain the signature, + and signing input values. Via `Section 7.1`_. + + :param s: text of JWS Compact Serialization + :param key: key used to verify the signature + :param decode: a function to decode payload data + :return: JWSObject + :raise: BadSignatureError + + .. _`Section 7.1`: https://tools.ietf.org/html/rfc7515#section-7.1 + """ + try: + s = to_bytes(s) + signing_input, signature_segment = s.rsplit(b'.', 1) + protected_segment, payload_segment = signing_input.split(b'.', 1) + except ValueError: + raise DecodeError('Not enough segments') + + protected = _extract_header(protected_segment) + jws_header = JWSHeader(protected, None) + + payload = _extract_payload(payload_segment) + if decode: + payload = decode(payload) + + signature = _extract_signature(signature_segment) + rv = JWSObject(jws_header, payload, 'compact') + algorithm, key = self._prepare_algorithm_key(jws_header, payload, key) + if algorithm.verify(signing_input, signature, key): + return rv + raise BadSignatureError(rv) + + def serialize_json(self, header_obj, payload, key): + """Generate a JWS JSON Serialization. The JWS JSON Serialization + represents digitally signed or MACed content as a JSON object, + per `Section 7.2`_. + + :param header_obj: A dict/list of header + :param payload: A string/dict of payload + :param key: Private key used to generate signature + :return: JWSObject + + Example ``header_obj`` of JWS JSON Serialization:: + + { + "protected: {"alg": "HS256"}, + "header": {"kid": "jose"} + } + + Pass a dict to generate flattened JSON Serialization, pass a list of + header dict to generate standard JSON Serialization. + """ + payload_segment = json_b64encode(payload) + + def _sign(jws_header): + self._validate_private_headers(jws_header) + _alg, _key = self._prepare_algorithm_key(jws_header, payload, key) + + protected_segment = json_b64encode(jws_header.protected) + signing_input = b'.'.join([protected_segment, payload_segment]) + signature = urlsafe_b64encode(_alg.sign(signing_input, _key)) + + rv = { + 'protected': to_unicode(protected_segment), + 'signature': to_unicode(signature) + } + if jws_header.header is not None: + rv['header'] = jws_header.header + return rv + + if isinstance(header_obj, dict): + data = _sign(JWSHeader.from_dict(header_obj)) + data['payload'] = to_unicode(payload_segment) + return data + + signatures = [_sign(JWSHeader.from_dict(h)) for h in header_obj] + return { + 'payload': to_unicode(payload_segment), + 'signatures': signatures + } + + def deserialize_json(self, obj, key, decode=None): + """Exact JWS JSON Serialization, and validate with the given key. + If key is not provided, it will return a dict without signature + verification. Header will still be validated. Via `Section 7.2`_. + + :param obj: text of JWS JSON Serialization + :param key: key used to verify the signature + :param decode: a function to decode payload data + :return: JWSObject + :raise: BadSignatureError + + .. _`Section 7.2`: https://tools.ietf.org/html/rfc7515#section-7.2 + """ + obj = _ensure_dict(obj) + + payload_segment = obj.get('payload') + if not payload_segment: + raise DecodeError('Missing "payload" value') + + payload_segment = to_bytes(payload_segment) + payload = _extract_payload(payload_segment) + if decode: + payload = decode(payload) + + if 'signatures' not in obj: + # flattened JSON JWS + jws_header, valid = self._validate_json_jws( + payload_segment, payload, obj, key) + + rv = JWSObject(jws_header, payload, 'flat') + if valid: + return rv + raise BadSignatureError(rv) + + headers = [] + is_valid = True + for header_obj in obj['signatures']: + jws_header, valid = self._validate_json_jws( + payload_segment, payload, header_obj, key) + headers.append(jws_header) + if not valid: + is_valid = False + + rv = JWSObject(headers, payload, 'json') + if is_valid: + return rv + raise BadSignatureError(rv) + + def serialize(self, header, payload, key): + """Generate a JWS Serialization. It will automatically generate a + Compact or JSON Serialization depending on the given header. If a + header is in a JSON header format, it will call + :meth:`serialize_json`, otherwise it will call + :meth:`serialize_compact`. + + :param header: A dict/list of header + :param payload: A string/dict of payload + :param key: Private key used to generate signature + :return: byte/dict + """ + if isinstance(header, (list, tuple)): + return self.serialize_json(header, payload, key) + if 'protected' in header: + return self.serialize_json(header, payload, key) + return self.serialize_compact(header, payload, key) + + def deserialize(self, s, key, decode=None): + """Deserialize JWS Serialization, both compact and JSON format. + It will automatically deserialize depending on the given JWS. + + :param s: text of JWS Compact/JSON Serialization + :param key: key used to verify the signature + :param decode: a function to decode payload data + :return: dict + :raise: BadSignatureError + + If key is not provided, it will still deserialize the serialization + without verification. + """ + if isinstance(s, dict): + return self.deserialize_json(s, key, decode) + + s = to_bytes(s) + if s.startswith(b'{') and s.endswith(b'}'): + return self.deserialize_json(s, key, decode) + return self.deserialize_compact(s, key, decode) + + def _prepare_algorithm_key(self, header, payload, key): + if 'alg' not in header: + raise MissingAlgorithmError() + + alg = header['alg'] + if self._algorithms and alg not in self._algorithms: + raise UnsupportedAlgorithmError() + if alg not in self.ALGORITHMS_REGISTRY: + raise UnsupportedAlgorithmError() + + algorithm = self.ALGORITHMS_REGISTRY[alg] + if callable(key): + key = key(header, payload) + elif 'jwk' in header: + key = header['jwk'] + key = algorithm.prepare_key(key) + return algorithm, key + + def _validate_private_headers(self, header): + # only validate private headers when developers set + # private headers explicitly + if self._private_headers is not None: + names = self.REGISTERED_HEADER_PARAMETER_NAMES.copy() + names = names.union(self._private_headers) + + for k in header: + if k not in names: + raise InvalidHeaderParameterName(k) + + def _validate_json_jws(self, payload_segment, payload, header_obj, key): + protected_segment = header_obj.get('protected') + if not protected_segment: + raise DecodeError('Missing "protected" value') + + signature_segment = header_obj.get('signature') + if not signature_segment: + raise DecodeError('Missing "signature" value') + + protected_segment = to_bytes(protected_segment) + protected = _extract_header(protected_segment) + header = header_obj.get('header') + if header and not isinstance(header, dict): + raise DecodeError('Invalid "header" value') + + jws_header = JWSHeader(protected, header) + algorithm, key = self._prepare_algorithm_key(jws_header, payload, key) + signing_input = b'.'.join([protected_segment, payload_segment]) + signature = _extract_signature(to_bytes(signature_segment)) + if algorithm.verify(signing_input, signature, key): + return jws_header, True + return jws_header, False + + +def _extract_header(header_segment): + return extract_header(header_segment, DecodeError) + + +def _extract_signature(signature_segment): + return extract_segment(signature_segment, DecodeError, 'signature') + + +def _extract_payload(payload_segment): + return extract_segment(payload_segment, DecodeError, 'payload') + + +def _ensure_dict(s): + if not isinstance(s, dict): + try: + s = json_loads(to_unicode(s)) + except (ValueError, TypeError): + raise DecodeError('Invalid JWS') + + if not isinstance(s, dict): + raise DecodeError('Invalid JWS') + + return s diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7515/models.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7515/models.py new file mode 100644 index 0000000..caccfb4 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7515/models.py @@ -0,0 +1,81 @@ +class JWSAlgorithm(object): + """Interface for JWS algorithm. JWA specification (RFC7518) SHOULD + implement the algorithms for JWS with this base implementation. + """ + name = None + description = None + algorithm_type = 'JWS' + algorithm_location = 'alg' + + def prepare_key(self, raw_data): + """Prepare key for signing and verifying signature.""" + raise NotImplementedError() + + def sign(self, msg, key): + """Sign the text msg with a private/sign key. + + :param msg: message bytes to be signed + :param key: private key to sign the message + :return: bytes + """ + raise NotImplementedError + + def verify(self, msg, sig, key): + """Verify the signature of text msg with a public/verify key. + + :param msg: message bytes to be signed + :param sig: result signature to be compared + :param key: public key to verify the signature + :return: boolean + """ + raise NotImplementedError + + +class JWSHeader(dict): + """Header object for JWS. It combine the protected header and unprotected + header together. JWSHeader itself is a dict of the combined dict. e.g. + + >>> protected = {'alg': 'HS256'} + >>> header = {'kid': 'a'} + >>> jws_header = JWSHeader(protected, header) + >>> print(jws_header) + {'alg': 'HS256', 'kid': 'a'} + >>> jws_header.protected == protected + >>> jws_header.header == header + + :param protected: dict of protected header + :param header: dict of unprotected header + """ + def __init__(self, protected, header): + obj = {} + if protected: + obj.update(protected) + if header: + obj.update(header) + super(JWSHeader, self).__init__(obj) + self.protected = protected + self.header = header + + @classmethod + def from_dict(cls, obj): + if isinstance(obj, cls): + return obj + return cls(obj.get('protected'), obj.get('header')) + + +class JWSObject(dict): + """A dict instance to represent a JWS object.""" + def __init__(self, header, payload, type='compact'): + super(JWSObject, self).__init__( + header=header, + payload=payload, + ) + self.header = header + self.payload = payload + self.type = type + + @property + def headers(self): + """Alias of ``header`` for JSON typed JWS.""" + if self.type == 'json': + return self['header'] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7516/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7516/__init__.py new file mode 100644 index 0000000..f7f3c31 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7516/__init__.py @@ -0,0 +1,18 @@ +""" + authlib.jose.rfc7516 + ~~~~~~~~~~~~~~~~~~~~~ + + This module represents a direct implementation of + JSON Web Encryption (JWE). + + https://tools.ietf.org/html/rfc7516 +""" + +from .jwe import JsonWebEncryption +from .models import JWEAlgorithm, JWEEncAlgorithm, JWEZipAlgorithm + + +__all__ = [ + 'JsonWebEncryption', + 'JWEAlgorithm', 'JWEEncAlgorithm', 'JWEZipAlgorithm' +] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7516/jwe.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7516/jwe.py new file mode 100644 index 0000000..0e5d84d --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7516/jwe.py @@ -0,0 +1,207 @@ +from authlib.common.encoding import ( + to_bytes, urlsafe_b64encode, json_b64encode +) +from authlib.jose.util import ( + extract_header, + extract_segment, +) +from authlib.jose.errors import ( + DecodeError, + MissingAlgorithmError, + UnsupportedAlgorithmError, + MissingEncryptionAlgorithmError, + UnsupportedEncryptionAlgorithmError, + UnsupportedCompressionAlgorithmError, + InvalidHeaderParameterName, +) + + +class JsonWebEncryption(object): + #: Registered Header Parameter Names defined by Section 4.1 + REGISTERED_HEADER_PARAMETER_NAMES = frozenset([ + 'alg', 'enc', 'zip', + 'jku', 'jwk', 'kid', + 'x5u', 'x5c', 'x5t', 'x5t#S256', + 'typ', 'cty', 'crit' + ]) + + ALG_REGISTRY = {} + ENC_REGISTRY = {} + ZIP_REGISTRY = {} + + def __init__(self, algorithms=None, private_headers=None): + self._algorithms = algorithms + self._private_headers = private_headers + + @classmethod + def register_algorithm(cls, algorithm): + """Register an algorithm for ``alg`` or ``enc`` or ``zip`` of JWE.""" + if not algorithm or algorithm.algorithm_type != 'JWE': + raise ValueError( + 'Invalid algorithm for JWE, {!r}'.format(algorithm)) + + if algorithm.algorithm_location == 'alg': + cls.ALG_REGISTRY[algorithm.name] = algorithm + elif algorithm.algorithm_location == 'enc': + cls.ENC_REGISTRY[algorithm.name] = algorithm + elif algorithm.algorithm_location == 'zip': + cls.ZIP_REGISTRY[algorithm.name] = algorithm + + def serialize_compact(self, protected, payload, key): + """Generate a JWE Compact Serialization. The JWE Compact Serialization + represents encrypted content as a compact, URL-safe string. This + string is: + + BASE64URL(UTF8(JWE Protected Header)) || '.' || + BASE64URL(JWE Encrypted Key) || '.' || + BASE64URL(JWE Initialization Vector) || '.' || + BASE64URL(JWE Ciphertext) || '.' || + BASE64URL(JWE Authentication Tag) + + Only one recipient is supported by the JWE Compact Serialization and + it provides no syntax to represent JWE Shared Unprotected Header, JWE + Per-Recipient Unprotected Header, or JWE AAD values. + + :param protected: A dict of protected header + :param payload: A string/dict of payload + :param key: Private key used to generate signature + :return: byte + """ + + # step 1: Prepare algorithms & key + alg = self.get_header_alg(protected) + enc = self.get_header_enc(protected) + zip_alg = self.get_header_zip(protected) + self._validate_private_headers(protected, alg) + + key = prepare_key(alg, protected, key) + + # self._post_validate_header(protected, algorithm) + + # step 2: Generate a random Content Encryption Key (CEK) + # use enc_alg.generate_cek() in .wrap method + + # step 3: Encrypt the CEK with the recipient's public key + wrapped = alg.wrap(enc, protected, key) + cek = wrapped['cek'] + ek = wrapped['ek'] + if 'header' in wrapped: + protected.update(wrapped['header']) + + # step 4: Generate a random JWE Initialization Vector + iv = enc.generate_iv() + + # step 5: Let the Additional Authenticated Data encryption parameter + # be ASCII(BASE64URL(UTF8(JWE Protected Header))) + protected_segment = json_b64encode(protected) + aad = to_bytes(protected_segment, 'ascii') + + # step 6: compress message if required + if zip_alg: + msg = zip_alg.compress(to_bytes(payload)) + else: + msg = to_bytes(payload) + + # step 7: perform encryption + ciphertext, tag = enc.encrypt(msg, aad, iv, cek) + return b'.'.join([ + protected_segment, + urlsafe_b64encode(ek), + urlsafe_b64encode(iv), + urlsafe_b64encode(ciphertext), + urlsafe_b64encode(tag) + ]) + + def deserialize_compact(self, s, key, decode=None): + """Exact JWS Compact Serialization, and validate with the given key. + + :param s: text of JWS Compact Serialization + :param key: key used to verify the signature + :param decode: a function to decode plaintext data + :return: dict + """ + try: + s = to_bytes(s) + protected_s, ek_s, iv_s, ciphertext_s, tag_s = s.rsplit(b'.') + except ValueError: + raise DecodeError('Not enough segments') + + protected = extract_header(protected_s, DecodeError) + ek = extract_segment(ek_s, DecodeError, 'encryption key') + iv = extract_segment(iv_s, DecodeError, 'initialization vector') + ciphertext = extract_segment(ciphertext_s, DecodeError, 'ciphertext') + tag = extract_segment(tag_s, DecodeError, 'authentication tag') + + alg = self.get_header_alg(protected) + enc = self.get_header_enc(protected) + zip_alg = self.get_header_zip(protected) + self._validate_private_headers(protected, alg) + + key = prepare_key(alg, protected, key) + + cek = alg.unwrap(enc, ek, protected, key) + aad = to_bytes(protected_s, 'ascii') + msg = enc.decrypt(ciphertext, aad, iv, tag, cek) + + if zip_alg: + payload = zip_alg.decompress(to_bytes(msg)) + else: + payload = msg + + if decode: + payload = decode(payload) + return {'header': protected, 'payload': payload} + + def get_header_alg(self, header): + if 'alg' not in header: + raise MissingAlgorithmError() + + alg = header['alg'] + if self._algorithms and alg not in self._algorithms: + raise UnsupportedAlgorithmError() + if alg not in self.ALG_REGISTRY: + raise UnsupportedAlgorithmError() + return self.ALG_REGISTRY[alg] + + def get_header_enc(self, header): + if 'enc' not in header: + raise MissingEncryptionAlgorithmError() + enc = header['enc'] + if self._algorithms and enc not in self._algorithms: + raise UnsupportedEncryptionAlgorithmError() + if enc not in self.ENC_REGISTRY: + raise UnsupportedEncryptionAlgorithmError() + return self.ENC_REGISTRY[enc] + + def get_header_zip(self, header): + if 'zip' in header: + z = header['zip'] + if self._algorithms and z not in self._algorithms: + raise UnsupportedCompressionAlgorithmError() + if z not in self.ZIP_REGISTRY: + raise UnsupportedCompressionAlgorithmError() + return self.ZIP_REGISTRY[z] + + def _validate_private_headers(self, header, alg): + # only validate private headers when developers set + # private headers explicitly + if self._private_headers is None: + return + + names = self.REGISTERED_HEADER_PARAMETER_NAMES.copy() + names = names.union(self._private_headers) + + if alg.EXTRA_HEADERS: + names = names.union(alg.EXTRA_HEADERS) + + for k in header: + if k not in names: + raise InvalidHeaderParameterName(k) + + +def prepare_key(alg, header, key): + if callable(key): + key = key(header, None) + elif 'jwk' in header: + key = header['jwk'] + return alg.prepare_key(key) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7516/models.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7516/models.py new file mode 100644 index 0000000..5eab89c --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7516/models.py @@ -0,0 +1,78 @@ +import os + + +class JWEAlgorithm(object): + """Interface for JWE algorithm. JWA specification (RFC7518) SHOULD + implement the algorithms for JWE with this base implementation. + """ + EXTRA_HEADERS = None + + name = None + description = None + algorithm_type = 'JWE' + algorithm_location = 'alg' + + def prepare_key(self, raw_data): + raise NotImplementedError + + def wrap(self, enc_alg, headers, key): + raise NotImplementedError + + def unwrap(self, enc_alg, ek, headers, key): + raise NotImplementedError + + +class JWEEncAlgorithm(object): + name = None + description = None + algorithm_type = 'JWE' + algorithm_location = 'enc' + + IV_SIZE = None + CEK_SIZE = None + + def generate_cek(self): + return os.urandom(self.CEK_SIZE // 8) + + def generate_iv(self): + return os.urandom(self.IV_SIZE // 8) + + def check_iv(self, iv): + if len(iv) * 8 != self.IV_SIZE: + raise ValueError('Invalid "iv" size') + + def encrypt(self, msg, aad, iv, key): + """Encrypt the given "msg" text. + + :param msg: text to be encrypt in bytes + :param aad: additional authenticated data in bytes + :param iv: initialization vector in bytes + :param key: encrypted key in bytes + :return: (ciphertext, iv, tag) + """ + raise NotImplementedError + + def decrypt(self, ciphertext, aad, iv, tag, key): + """Decrypt the given cipher text. + + :param ciphertext: ciphertext in bytes + :param aad: additional authenticated data in bytes + :param iv: initialization vector in bytes + :param tag: authentication tag in bytes + :param key: encrypted key in bytes + :return: message + """ + raise NotImplementedError + + +class JWEZipAlgorithm(object): + name = None + description = None + algorithm_type = 'JWE' + algorithm_location = 'zip' + + def compress(self, s): + raise NotImplementedError + + def decompress(self, s): + raise NotImplementedError diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7517/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7517/__init__.py new file mode 100644 index 0000000..e2f1595 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7517/__init__.py @@ -0,0 +1,15 @@ +""" + authlib.jose.rfc7517 + ~~~~~~~~~~~~~~~~~~~~~ + + This module represents a direct implementation of + JSON Web Key (JWK). + + https://tools.ietf.org/html/rfc7517 +""" +from .models import Key, KeySet +from ._cryptography_key import load_pem_key +from .jwk import JsonWebKey + + +__all__ = ['Key', 'KeySet', 'JsonWebKey', 'load_pem_key'] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7517/_cryptography_key.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7517/_cryptography_key.py new file mode 100644 index 0000000..f7194a3 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7517/_cryptography_key.py @@ -0,0 +1,34 @@ +from cryptography.x509 import load_pem_x509_certificate +from cryptography.hazmat.primitives.serialization import ( + load_pem_private_key, load_pem_public_key, load_ssh_public_key, +) +from cryptography.hazmat.backends import default_backend +from authlib.common.encoding import to_bytes + + +def load_pem_key(raw, ssh_type=None, key_type=None, password=None): + raw = to_bytes(raw) + + if ssh_type and raw.startswith(ssh_type): + return load_ssh_public_key(raw, backend=default_backend()) + + if key_type == 'public': + return load_pem_public_key(raw, backend=default_backend()) + + if key_type == 'private' or password is not None: + return load_pem_private_key(raw, password=password, backend=default_backend()) + + if b'PUBLIC' in raw: + return load_pem_public_key(raw, backend=default_backend()) + + if b'PRIVATE' in raw: + return load_pem_private_key(raw, password=password, backend=default_backend()) + + if b'CERTIFICATE' in raw: + cert = load_pem_x509_certificate(raw, default_backend()) + return cert.public_key() + + try: + return load_pem_private_key(raw, password=password, backend=default_backend()) + except ValueError: + return load_pem_public_key(raw, backend=default_backend()) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7517/jwk.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7517/jwk.py new file mode 100644 index 0000000..b52d319 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7517/jwk.py @@ -0,0 +1,63 @@ +from authlib.common.encoding import text_types, json_loads +from ._cryptography_key import load_pem_key +from .models import KeySet + + +class JsonWebKey(object): + JWK_KEY_CLS = {} + + @classmethod + def generate_key(cls, kty, crv_or_size, options=None, is_private=False): + """Generate a Key with the given key type, curve name or bit size. + + :param kty: string of ``oct``, ``RSA``, ``EC``, ``OKP`` + :param crv_or_size: curve name or bit size + :param options: a dict of other options for Key + :param is_private: create a private key or public key + :return: Key instance + """ + key_cls = cls.JWK_KEY_CLS[kty] + return key_cls.generate_key(crv_or_size, options, is_private) + + @classmethod + def import_key(cls, raw, options=None): + """Import a Key from bytes, string, PEM or dict. + + :return: Key instance + """ + kty = None + if options is not None: + kty = options.get('kty') + + if kty is None and isinstance(raw, dict): + kty = raw.get('kty') + + if kty is None: + raw_key = load_pem_key(raw) + for _kty in cls.JWK_KEY_CLS: + key_cls = cls.JWK_KEY_CLS[_kty] + if isinstance(raw_key, key_cls.RAW_KEY_CLS): + return key_cls.import_key(raw_key, options) + + key_cls = cls.JWK_KEY_CLS[kty] + return key_cls.import_key(raw, options) + + @classmethod + def import_key_set(cls, raw): + """Import KeySet from string, dict or a list of keys. + + :return: KeySet instance + """ + raw = _transform_raw_key(raw) + if isinstance(raw, dict) and 'keys' in raw: + keys = raw.get('keys') + return KeySet([cls.import_key(k) for k in keys]) + + +def _transform_raw_key(raw): + if isinstance(raw, text_types) and \ + raw.startswith('{') and raw.endswith('}'): + return json_loads(raw) + elif isinstance(raw, (tuple, list)): + return {'keys': raw} + return raw diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7517/models.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7517/models.py new file mode 100644 index 0000000..b3b24f3 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7517/models.py @@ -0,0 +1,156 @@ +import hashlib +from collections import OrderedDict +from authlib.common.encoding import ( + json_dumps, + to_bytes, + to_unicode, + urlsafe_b64encode, +) +from ..errors import InvalidUseError + + +class Key(dict): + """This is the base class for a JSON Web Key.""" + kty = '_' + + ALLOWED_PARAMS = [ + 'use', 'key_ops', 'alg', 'kid', + 'x5u', 'x5c', 'x5t', 'x5t#S256' + ] + + PRIVATE_KEY_OPS = [ + 'sign', 'decrypt', 'unwrapKey', + ] + PUBLIC_KEY_OPS = [ + 'verify', 'encrypt', 'wrapKey', + ] + + REQUIRED_JSON_FIELDS = [] + RAW_KEY_CLS = bytes + + def __init__(self, payload): + super(Key, self).__init__(payload) + + self.key_type = 'secret' + self.raw_key = None + + def get_op_key(self, operation): + """Get the raw key for the given key_op. This method will also + check if the given key_op is supported by this key. + + :param operation: key operation value, such as "sign", "encrypt". + :return: raw key + """ + self.check_key_op(operation) + if operation in self.PUBLIC_KEY_OPS: + return self.get_public_key() + return self.get_private_key() + + def get_public_key(self): + if self.key_type == 'private': + return self.raw_key.public_key() + return self.raw_key + + def get_private_key(self): + if self.key_type == 'private': + return self.raw_key + + def check_key_op(self, operation): + """Check if the given key_op is supported by this key. + + :param operation: key operation value, such as "sign", "encrypt". + :raise: ValueError + """ + key_ops = self.get('key_ops') + if key_ops is not None and operation not in key_ops: + raise ValueError('Unsupported key_op "{}"'.format(operation)) + + if operation in self.PRIVATE_KEY_OPS and self.key_type == 'public': + raise ValueError('Invalid key_op "{}" for public key'.format(operation)) + + use = self.get('use') + if use: + if operation in ['sign', 'verify']: + if use != 'sig': + raise InvalidUseError() + elif operation in ['decrypt', 'encrypt', 'wrapKey', 'unwrapKey']: + if use != 'enc': + raise InvalidUseError() + + def as_key(self): + """Represent this key as raw key.""" + return self.raw_key + + def as_dict(self, add_kid=False): + """Represent this key as a dict of the JSON Web Key.""" + obj = dict(self) + obj['kty'] = self.kty + if add_kid and 'kid' not in obj: + obj['kid'] = self.thumbprint() + return obj + + def as_json(self): + """Represent this key as a JSON string.""" + obj = self.as_dict() + return json_dumps(obj) + + def as_pem(self): + """Represent this key as string in PEM format.""" + raise RuntimeError('Not supported') + + def thumbprint(self): + """Implementation of RFC7638 JSON Web Key (JWK) Thumbprint.""" + fields = list(self.REQUIRED_JSON_FIELDS) + fields.append('kty') + fields.sort() + data = OrderedDict() + + obj = self.as_dict() + for k in fields: + data[k] = obj[k] + + json_data = json_dumps(data) + digest_data = hashlib.sha256(to_bytes(json_data)).digest() + return to_unicode(urlsafe_b64encode(digest_data)) + + @classmethod + def check_required_fields(cls, data): + for k in cls.REQUIRED_JSON_FIELDS: + if k not in data: + raise ValueError('Missing required field: "{}"'.format(k)) + + @classmethod + def generate_key(cls, crv_or_size, options=None, is_private=False): + raise NotImplementedError() + + @classmethod + def import_key(cls, raw, options=None): + raise NotImplementedError() + + +class KeySet(object): + """This class represents a JSON Web Key Set.""" + + def __init__(self, keys): + self.keys = keys + + def as_dict(self): + """Represent this key as a dict of the JSON Web Key Set.""" + return {'keys': [k.as_dict(True) for k in self.keys]} + + def as_json(self): + """Represent this key set as a JSON string.""" + obj = self.as_dict() + return json_dumps(obj) + + def find_by_kid(self, kid): + """Find the key matches the given kid value. + + :param kid: A string of kid + :return: Key instance + :raise: ValueError + """ + for k in self.keys: + if k.get('kid') == kid: + return k + raise ValueError('Invalid JSON Web Key Set') diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/__init__.py new file mode 100644 index 0000000..6587602 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/__init__.py @@ -0,0 +1,19 @@ +from .jws_algorithms import register_jws_rfc7518 +from .jwe_algorithms import register_jwe_rfc7518 +from .oct_key import OctKey +from ._cryptography_backends import ( + RSAKey, ECKey, ECDHAlgorithm, + import_key, load_pem_key, export_key, +) + +__all__ = [ + 'register_jws_rfc7518', + 'register_jwe_rfc7518', + 'ECDHAlgorithm', + 'OctKey', + 'RSAKey', + 'ECKey', + 'import_key', + 'load_pem_key', + 'export_key', +] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/_cryptography_backends/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/_cryptography_backends/__init__.py new file mode 100644 index 0000000..5f8ab16 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/_cryptography_backends/__init__.py @@ -0,0 +1,7 @@ +from ._jws import JWS_ALGORITHMS +from ._jwe_alg import JWE_ALG_ALGORITHMS, ECDHAlgorithm +from ._jwe_enc import JWE_ENC_ALGORITHMS +from ._keys import ( + RSAKey, ECKey, + load_pem_key, import_key, export_key, +) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/_cryptography_backends/_jwe_alg.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/_cryptography_backends/_jwe_alg.py new file mode 100644 index 0000000..8d000d2 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/_cryptography_backends/_jwe_alg.py @@ -0,0 +1,268 @@ +import os +import struct +from cryptography.hazmat.primitives.asymmetric import padding +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives.keywrap import ( + aes_key_wrap, + aes_key_unwrap +) +from cryptography.hazmat.primitives.ciphers import Cipher +from cryptography.hazmat.primitives.ciphers.algorithms import AES +from cryptography.hazmat.primitives.ciphers.modes import GCM +from cryptography.hazmat.primitives.kdf.concatkdf import ConcatKDFHash +from authlib.common.encoding import ( + to_bytes, to_native, + urlsafe_b64decode, + urlsafe_b64encode +) +from authlib.jose.rfc7516 import JWEAlgorithm +from ._keys import RSAKey, ECKey +from ..oct_key import OctKey + + +class RSAAlgorithm(JWEAlgorithm): + #: A key of size 2048 bits or larger MUST be used with these algorithms + #: RSA1_5, RSA-OAEP, RSA-OAEP-256 + key_size = 2048 + + def __init__(self, name, description, pad_fn): + self.name = name + self.description = description + self.padding = pad_fn + + def prepare_key(self, raw_data): + return RSAKey.import_key(raw_data) + + def wrap(self, enc_alg, headers, key): + cek = enc_alg.generate_cek() + op_key = key.get_op_key('wrapKey') + if op_key.key_size < self.key_size: + raise ValueError('A key of size 2048 bits or larger MUST be used') + ek = op_key.encrypt(cek, self.padding) + return {'ek': ek, 'cek': cek} + + def unwrap(self, enc_alg, ek, headers, key): + # it will raise ValueError if failed + op_key = key.get_op_key('unwrapKey') + cek = op_key.decrypt(ek, self.padding) + print(cek, enc_alg.key_size) + if len(cek) * 8 != enc_alg.CEK_SIZE: + raise ValueError('Invalid "cek" length') + return cek + + +class AESAlgorithm(JWEAlgorithm): + def __init__(self, key_size): + self.name = 'A{}KW'.format(key_size) + self.description = 'AES Key Wrap using {}-bit key'.format(key_size) + self.key_size = key_size + + def prepare_key(self, raw_data): + return OctKey.import_key(raw_data) + + def _check_key(self, key): + if len(key) * 8 != self.key_size: + raise ValueError( + 'A key of size {} bits is required.'.format(self.key_size)) + + def wrap(self, enc_alg, headers, key): + cek = enc_alg.generate_cek() + op_key = key.get_op_key('wrapKey') + self._check_key(op_key) + ek = aes_key_wrap(op_key, cek, default_backend()) + return {'ek': ek, 'cek': cek} + + def unwrap(self, enc_alg, ek, headers, key): + op_key = key.get_op_key('unwrapKey') + self._check_key(op_key) + cek = aes_key_unwrap(op_key, ek, default_backend()) + if len(cek) * 8 != enc_alg.CEK_SIZE: + raise ValueError('Invalid "cek" length') + return cek + + +class AESGCMAlgorithm(JWEAlgorithm): + EXTRA_HEADERS = frozenset(['iv', 'tag']) + + def __init__(self, key_size): + self.name = 'A{}GCMKW'.format(key_size) + self.description = 'Key wrapping with AES GCM using {}-bit key'.format(key_size) + self.key_size = key_size + + def prepare_key(self, raw_data): + return OctKey.import_key(raw_data) + + def _check_key(self, key): + if len(key) * 8 != self.key_size: + raise ValueError( + 'A key of size {} bits is required.'.format(self.key_size)) + + def wrap(self, enc_alg, headers, key): + cek = enc_alg.generate_cek() + op_key = key.get_op_key('wrapKey') + self._check_key(op_key) + + #: https://tools.ietf.org/html/rfc7518#section-4.7.1.1 + #: The "iv" (initialization vector) Header Parameter value is the + #: base64url-encoded representation of the 96-bit IV value + iv_size = 96 + iv = os.urandom(iv_size // 8) + + cipher = Cipher(AES(op_key), GCM(iv), backend=default_backend()) + enc = cipher.encryptor() + ek = enc.update(cek) + enc.finalize() + + h = { + 'iv': to_native(urlsafe_b64encode(iv)), + 'tag': to_native(urlsafe_b64encode(enc.tag)) + } + return {'ek': ek, 'cek': cek, 'header': h} + + def unwrap(self, enc_alg, ek, headers, key): + op_key = key.get_op_key('unwrapKey') + self._check_key(op_key) + + iv = headers.get('iv') + if not iv: + raise ValueError('Missing "iv" in headers') + + tag = headers.get('tag') + if not tag: + raise ValueError('Missing "tag" in headers') + + iv = urlsafe_b64decode(to_bytes(iv)) + tag = urlsafe_b64decode(to_bytes(tag)) + + cipher = Cipher(AES(op_key), GCM(iv, tag), backend=default_backend()) + d = cipher.decryptor() + cek = d.update(ek) + d.finalize() + if len(cek) * 8 != enc_alg.CEK_SIZE: + raise ValueError('Invalid "cek" length') + return cek + + +class ECDHAlgorithm(JWEAlgorithm): + EXTRA_HEADERS = ['epk', 'apu', 'apv'] + ALLOWED_KEY_CLS = ECKey + + # https://tools.ietf.org/html/rfc7518#section-4.6 + def __init__(self, key_size=None): + if key_size is None: + self.name = 'ECDH-ES' + self.description = 'ECDH-ES in the Direct Key Agreement mode' + else: + self.name = 'ECDH-ES+A{}KW'.format(key_size) + self.description = ( + 'ECDH-ES using Concat KDF and CEK wrapped ' + 'with A{}KW').format(key_size) + self.key_size = key_size + self.aeskw = AESAlgorithm(key_size) + + def prepare_key(self, raw_data): + if isinstance(raw_data, self.ALLOWED_KEY_CLS): + return raw_data + return ECKey.import_key(raw_data) + + def deliver(self, key, pubkey, headers, bit_size): + # AlgorithmID + if self.key_size is None: + alg_id = _u32be_len_input(headers['enc']) + else: + alg_id = _u32be_len_input(headers['alg']) + + # PartyUInfo + apu_info = _u32be_len_input(headers.get('apu'), True) + + # PartyVInfo + apv_info = _u32be_len_input(headers.get('apv'), True) + + # SuppPubInfo + pub_info = struct.pack('>I', bit_size) + + other_info = alg_id + apu_info + apv_info + pub_info + shared_key = key.exchange_shared_key(pubkey) + ckdf = ConcatKDFHash( + algorithm=hashes.SHA256(), + length=bit_size // 8, + otherinfo=other_info, + backend=default_backend() + ) + return ckdf.derive(shared_key) + + def wrap(self, enc_alg, headers, key): + if self.key_size is None: + bit_size = enc_alg.key_size + else: + bit_size = self.key_size + + epk = key.generate_key(key['crv'], is_private=True) + public_key = key.get_op_key('wrapKey') + dk = self.deliver(epk, public_key, headers, bit_size) + + # REQUIRED_JSON_FIELDS contains only public fields + pub_epk = {k: epk[k] for k in epk.REQUIRED_JSON_FIELDS} + pub_epk['kty'] = epk.kty + h = {'epk': pub_epk} + if self.key_size is None: + return {'ek': b'', 'cek': dk, 'header': h} + + kek = self.aeskw.prepare_key(dk) + rv = self.aeskw.wrap(enc_alg, headers, kek) + rv['header'] = h + return rv + + def unwrap(self, enc_alg, ek, headers, key): + if 'epk' not in headers: + raise ValueError('Missing "epk" in headers') + + if self.key_size is None: + bit_size = enc_alg.key_size + else: + bit_size = self.key_size + + epk = key.import_key(headers['epk']) + public_key = epk.get_op_key('wrapKey') + dk = self.deliver(key, public_key, headers, bit_size) + + if self.key_size is None: + return dk + + kek = self.aeskw.prepare_key(dk) + return self.aeskw.unwrap(enc_alg, ek, headers, kek) + + +def _u32be_len_input(s, base64=False): + if not s: + return b'\x00\x00\x00\x00' + if base64: + s = urlsafe_b64decode(to_bytes(s)) + else: + s = to_bytes(s) + return struct.pack('>I', len(s)) + s + + +JWE_ALG_ALGORITHMS = [ + RSAAlgorithm('RSA1_5', 'RSAES-PKCS1-v1_5', padding.PKCS1v15()), + RSAAlgorithm( + 'RSA-OAEP', 'RSAES OAEP using default parameters', + padding.OAEP(padding.MGF1(hashes.SHA1()), hashes.SHA1(), None)), + RSAAlgorithm( + 'RSA-OAEP-256', 'RSAES OAEP using SHA-256 and MGF1 with SHA-256', + padding.OAEP(padding.MGF1(hashes.SHA256()), hashes.SHA256(), None)), + + AESAlgorithm(128), # A128KW + AESAlgorithm(192), # A192KW + AESAlgorithm(256), # A256KW + AESGCMAlgorithm(128), # A128GCMKW + AESGCMAlgorithm(192), # A192GCMKW + AESGCMAlgorithm(256), # A256GCMKW + ECDHAlgorithm(None), # ECDH-ES + ECDHAlgorithm(128), # ECDH-ES+A128KW + ECDHAlgorithm(192), # ECDH-ES+A192KW + ECDHAlgorithm(256), # ECDH-ES+A256KW +] + +# 'PBES2-HS256+A128KW': '', +# 'PBES2-HS384+A192KW': '', +# 'PBES2-HS512+A256KW': '', diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/_cryptography_backends/_jwe_enc.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/_cryptography_backends/_jwe_enc.py new file mode 100644 index 0000000..f955a7c --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/_cryptography_backends/_jwe_enc.py @@ -0,0 +1,144 @@ +""" + authlib.jose.rfc7518 + ~~~~~~~~~~~~~~~~~~~~ + + Cryptographic Algorithms for Cryptographic Algorithms for Content + Encryption per `Section 5`_. + + .. _`Section 5`: https://tools.ietf.org/html/rfc7518#section-5 +""" +import hmac +import hashlib +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives.ciphers import Cipher +from cryptography.hazmat.primitives.ciphers.algorithms import AES +from cryptography.hazmat.primitives.ciphers.modes import GCM, CBC +from cryptography.hazmat.primitives.padding import PKCS7 +from cryptography.exceptions import InvalidTag +from authlib.jose.rfc7516 import JWEEncAlgorithm +from ..util import encode_int + + +class CBCHS2EncAlgorithm(JWEEncAlgorithm): + # The IV used is a 128-bit value generated randomly or + # pseudo-randomly for use in the cipher. + IV_SIZE = 128 + + def __init__(self, key_size, hash_type): + self.name = 'A{}CBC-HS{}'.format(key_size, hash_type) + tpl = 'AES_{}_CBC_HMAC_SHA_{} authenticated encryption algorithm' + self.description = tpl.format(key_size, hash_type) + + # bit length + self.key_size = key_size + # byte length + self.key_len = key_size // 8 + + self.CEK_SIZE = key_size * 2 + self.hash_alg = getattr(hashlib, 'sha{}'.format(hash_type)) + + def _hmac(self, ciphertext, aad, iv, key): + al = encode_int(len(aad) * 8, 64) + msg = aad + iv + ciphertext + al + d = hmac.new(key, msg, self.hash_alg).digest() + return d[:self.key_len] + + def encrypt(self, msg, aad, iv, key): + """Key Encryption with AES_CBC_HMAC_SHA2. + + :param msg: text to be encrypt in bytes + :param aad: additional authenticated data in bytes + :param iv: initialization vector in bytes + :param key: encrypted key in bytes + :return: (ciphertext, iv, tag) + """ + self.check_iv(iv) + hkey = key[:self.key_len] + ekey = key[self.key_len:] + + pad = PKCS7(AES.block_size).padder() + padded_data = pad.update(msg) + pad.finalize() + + cipher = Cipher(AES(ekey), CBC(iv), backend=default_backend()) + enc = cipher.encryptor() + ciphertext = enc.update(padded_data) + enc.finalize() + tag = self._hmac(ciphertext, aad, iv, hkey) + return ciphertext, tag + + def decrypt(self, ciphertext, aad, iv, tag, key): + """Key Decryption with AES AES_CBC_HMAC_SHA2. + + :param ciphertext: ciphertext in bytes + :param aad: additional authenticated data in bytes + :param iv: initialization vector in bytes + :param tag: authentication tag in bytes + :param key: encrypted key in bytes + :return: message + """ + self.check_iv(iv) + hkey = key[:self.key_len] + dkey = key[self.key_len:] + + _tag = self._hmac(ciphertext, aad, iv, hkey) + if not hmac.compare_digest(_tag, tag): + raise InvalidTag() + + cipher = Cipher(AES(dkey), CBC(iv), backend=default_backend()) + d = cipher.decryptor() + data = d.update(ciphertext) + d.finalize() + unpad = PKCS7(AES.block_size).unpadder() + return unpad.update(data) + unpad.finalize() + + +class GCMEncAlgorithm(JWEEncAlgorithm): + # Use of an IV of size 96 bits is REQUIRED with this algorithm. + # https://tools.ietf.org/html/rfc7518#section-5.3 + IV_SIZE = 96 + + def __init__(self, key_size): + self.name = 'A{}GCM'.format(key_size) + self.description = 'AES GCM using {}-bit key'.format(key_size) + self.key_size = key_size + self.CEK_SIZE = key_size + + def encrypt(self, msg, aad, iv, key): + """Key Encryption with AES GCM + + :param msg: text to be encrypt in bytes + :param aad: additional authenticated data in bytes + :param iv: initialization vector in bytes + :param key: encrypted key in bytes + :return: (ciphertext, iv, tag) + """ + self.check_iv(iv) + cipher = Cipher(AES(key), GCM(iv), backend=default_backend()) + enc = cipher.encryptor() + enc.authenticate_additional_data(aad) + ciphertext = enc.update(msg) + enc.finalize() + return ciphertext, enc.tag + + def decrypt(self, ciphertext, aad, iv, tag, key): + """Key Decryption with AES GCM + + :param ciphertext: ciphertext in bytes + :param aad: additional authenticated data in bytes + :param iv: initialization vector in bytes + :param tag: authentication tag in bytes + :param key: encrypted key in bytes + :return: message + """ + self.check_iv(iv) + cipher = Cipher(AES(key), GCM(iv, tag), backend=default_backend()) + d = cipher.decryptor() + d.authenticate_additional_data(aad) + return d.update(ciphertext) + d.finalize() + + +JWE_ENC_ALGORITHMS = [ + CBCHS2EncAlgorithm(128, 256), # A128CBC-HS256 + CBCHS2EncAlgorithm(192, 384), # A192CBC-HS384 + CBCHS2EncAlgorithm(256, 512), # A256CBC-HS512 + GCMEncAlgorithm(128), # A128GCM + GCMEncAlgorithm(192), # A192GCM + GCMEncAlgorithm(256), # A256GCM +] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/_cryptography_backends/_jws.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/_cryptography_backends/_jws.py new file mode 100644 index 0000000..9caee96 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/_cryptography_backends/_jws.py @@ -0,0 +1,159 @@ +# -*- coding: utf-8 -*- +""" + authlib.jose.rfc7518 + ~~~~~~~~~~~~~~~~~~~~ + + "alg" (Algorithm) Header Parameter Values for JWS per `Section 3`_. + + .. _`Section 3`: https://tools.ietf.org/html/rfc7518#section-3 +""" + +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric.utils import ( + decode_dss_signature, encode_dss_signature +) +from cryptography.hazmat.primitives.asymmetric.ec import ECDSA +from cryptography.hazmat.primitives.asymmetric import padding +from cryptography.exceptions import InvalidSignature +from authlib.jose.rfc7515 import JWSAlgorithm +from ._keys import RSAKey, ECKey +from ..util import encode_int, decode_int + + +class RSAAlgorithm(JWSAlgorithm): + """RSA using SHA algorithms for JWS. Available algorithms: + + - RS256: RSASSA-PKCS1-v1_5 using SHA-256 + - RS384: RSASSA-PKCS1-v1_5 using SHA-384 + - RS512: RSASSA-PKCS1-v1_5 using SHA-512 + """ + SHA256 = hashes.SHA256 + SHA384 = hashes.SHA384 + SHA512 = hashes.SHA512 + + def __init__(self, sha_type): + self.name = 'RS{}'.format(sha_type) + self.description = 'RSASSA-PKCS1-v1_5 using SHA-{}'.format(sha_type) + self.hash_alg = getattr(self, 'SHA{}'.format(sha_type)) + self.padding = padding.PKCS1v15() + + def prepare_key(self, raw_data): + return RSAKey.import_key(raw_data) + + def sign(self, msg, key): + op_key = key.get_op_key('sign') + return op_key.sign(msg, self.padding, self.hash_alg()) + + def verify(self, msg, sig, key): + op_key = key.get_op_key('verify') + try: + op_key.verify(sig, msg, self.padding, self.hash_alg()) + return True + except InvalidSignature: + return False + + +class ECAlgorithm(JWSAlgorithm): + """ECDSA using SHA algorithms for JWS. Available algorithms: + + - ES256: ECDSA using P-256 and SHA-256 + - ES384: ECDSA using P-384 and SHA-384 + - ES512: ECDSA using P-521 and SHA-512 + """ + SHA256 = hashes.SHA256 + SHA384 = hashes.SHA384 + SHA512 = hashes.SHA512 + + def __init__(self, sha_type): + self.name = 'ES{}'.format(sha_type) + self.description = 'ECDSA using P-{} and SHA-{}'.format(sha_type, sha_type) + self.hash_alg = getattr(self, 'SHA{}'.format(sha_type)) + + def prepare_key(self, raw_data): + return ECKey.import_key(raw_data) + + def sign(self, msg, key): + op_key = key.get_op_key('sign') + der_sig = op_key.sign(msg, ECDSA(self.hash_alg())) + r, s = decode_dss_signature(der_sig) + size = key.curve_key_size + return encode_int(r, size) + encode_int(s, size) + + def verify(self, msg, sig, key): + key_size = key.curve_key_size + length = (key_size + 7) // 8 + + if len(sig) != 2 * length: + return False + + r = decode_int(sig[:length]) + s = decode_int(sig[length:]) + der_sig = encode_dss_signature(r, s) + + try: + op_key = key.get_op_key('verify') + op_key.verify(der_sig, msg, ECDSA(self.hash_alg())) + return True + except InvalidSignature: + return False + + +class RSAPSSAlgorithm(JWSAlgorithm): + """RSASSA-PSS using SHA algorithms for JWS. Available algorithms: + + - PS256: RSASSA-PSS using SHA-256 and MGF1 with SHA-256 + - PS384: RSASSA-PSS using SHA-384 and MGF1 with SHA-384 + - PS512: RSASSA-PSS using SHA-512 and MGF1 with SHA-512 + """ + SHA256 = hashes.SHA256 + SHA384 = hashes.SHA384 + SHA512 = hashes.SHA512 + + def __init__(self, sha_type): + self.name = 'PS{}'.format(sha_type) + tpl = 'RSASSA-PSS using SHA-{} and MGF1 with SHA-{}' + self.description = tpl.format(sha_type, sha_type) + self.hash_alg = getattr(self, 'SHA{}'.format(sha_type)) + + def prepare_key(self, raw_data): + return RSAKey.import_key(raw_data) + + def sign(self, msg, key): + op_key = key.get_op_key('sign') + return op_key.sign( + msg, + padding.PSS( + mgf=padding.MGF1(self.hash_alg()), + salt_length=self.hash_alg.digest_size + ), + self.hash_alg() + ) + + def verify(self, msg, sig, key): + op_key = key.get_op_key('verify') + try: + op_key.verify( + sig, + msg, + padding.PSS( + mgf=padding.MGF1(self.hash_alg()), + salt_length=self.hash_alg.digest_size + ), + self.hash_alg() + ) + return True + except InvalidSignature: + return False + + +JWS_ALGORITHMS = [ + RSAAlgorithm(256), # RS256 + RSAAlgorithm(384), # RS384 + RSAAlgorithm(512), # RS512 + ECAlgorithm(256), # ES256 + ECAlgorithm(384), # ES384 + ECAlgorithm(512), # ES512 + RSAPSSAlgorithm(256), # PS256 + RSAPSSAlgorithm(384), # PS384 + RSAPSSAlgorithm(512), # PS512 +] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/_cryptography_backends/_keys.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/_cryptography_backends/_keys.py new file mode 100644 index 0000000..786a49d --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/_cryptography_backends/_keys.py @@ -0,0 +1,306 @@ +from cryptography.hazmat.primitives.serialization import ( + Encoding, PrivateFormat, PublicFormat, + BestAvailableEncryption, NoEncryption, +) +from cryptography.hazmat.primitives.asymmetric import rsa +from cryptography.hazmat.primitives.asymmetric.rsa import ( + RSAPublicKey, RSAPrivateKeyWithSerialization, + RSAPrivateNumbers, RSAPublicNumbers, + rsa_recover_prime_factors, rsa_crt_dmp1, rsa_crt_dmq1, rsa_crt_iqmp +) +from cryptography.hazmat.primitives.asymmetric import ec +from cryptography.hazmat.primitives.asymmetric.ec import ( + EllipticCurvePublicKey, EllipticCurvePrivateKeyWithSerialization, + EllipticCurvePrivateNumbers, EllipticCurvePublicNumbers, + SECP256R1, SECP384R1, SECP521R1, +) +from cryptography.hazmat.backends import default_backend +from authlib.jose.rfc7517 import Key, load_pem_key +from authlib.common.encoding import to_bytes +from authlib.common.encoding import base64_to_int, int_to_base64 + + +class RSAKey(Key): + """Key class of the ``RSA`` key type.""" + + kty = 'RSA' + RAW_KEY_CLS = (RSAPublicKey, RSAPrivateKeyWithSerialization) + REQUIRED_JSON_FIELDS = ['e', 'n'] + + def as_pem(self, is_private=False, password=None): + """Export key into PEM format bytes. + + :param is_private: export private key or public key + :param password: encrypt private key with password + :return: bytes + """ + return export_key(self, is_private=is_private, password=password) + + @staticmethod + def dumps_private_key(raw_key): + numbers = raw_key.private_numbers() + return { + 'n': int_to_base64(numbers.public_numbers.n), + 'e': int_to_base64(numbers.public_numbers.e), + 'd': int_to_base64(numbers.d), + 'p': int_to_base64(numbers.p), + 'q': int_to_base64(numbers.q), + 'dp': int_to_base64(numbers.dmp1), + 'dq': int_to_base64(numbers.dmq1), + 'qi': int_to_base64(numbers.iqmp) + } + + @staticmethod + def dumps_public_key(raw_key): + numbers = raw_key.public_numbers() + return { + 'n': int_to_base64(numbers.n), + 'e': int_to_base64(numbers.e) + } + + @staticmethod + def loads_private_key(obj): + if 'oth' in obj: # pragma: no cover + # https://tools.ietf.org/html/rfc7518#section-6.3.2.7 + raise ValueError('"oth" is not supported yet') + + props = ['p', 'q', 'dp', 'dq', 'qi'] + props_found = [prop in obj for prop in props] + any_props_found = any(props_found) + + if any_props_found and not all(props_found): + raise ValueError( + 'RSA key must include all parameters ' + 'if any are present besides d') + + public_numbers = RSAPublicNumbers( + base64_to_int(obj['e']), base64_to_int(obj['n'])) + + if any_props_found: + numbers = RSAPrivateNumbers( + d=base64_to_int(obj['d']), + p=base64_to_int(obj['p']), + q=base64_to_int(obj['q']), + dmp1=base64_to_int(obj['dp']), + dmq1=base64_to_int(obj['dq']), + iqmp=base64_to_int(obj['qi']), + public_numbers=public_numbers) + else: + d = base64_to_int(obj['d']) + p, q = rsa_recover_prime_factors( + public_numbers.n, d, public_numbers.e) + numbers = RSAPrivateNumbers( + d=d, + p=p, + q=q, + dmp1=rsa_crt_dmp1(d, p), + dmq1=rsa_crt_dmq1(d, q), + iqmp=rsa_crt_iqmp(p, q), + public_numbers=public_numbers) + + return numbers.private_key(default_backend()) + + @staticmethod + def loads_public_key(obj): + numbers = RSAPublicNumbers( + base64_to_int(obj['e']), + base64_to_int(obj['n']) + ) + return numbers.public_key(default_backend()) + + @classmethod + def import_key(cls, raw, options=None): + """Import a key from PEM or dict data.""" + return import_key( + cls, raw, + RSAPublicKey, RSAPrivateKeyWithSerialization, + b'ssh-rsa', options + ) + + @classmethod + def generate_key(cls, key_size=2048, options=None, is_private=False): + if key_size < 512: + raise ValueError('key_size must not be less than 512') + if key_size % 8 != 0: + raise ValueError('Invalid key_size for RSAKey') + raw_key = rsa.generate_private_key( + public_exponent=65537, + key_size=key_size, + backend=default_backend(), + ) + if not is_private: + raw_key = raw_key.public_key() + return cls.import_key(raw_key, options=options) + + +class ECKey(Key): + """Key class of the ``EC`` key type.""" + + kty = 'EC' + DSS_CURVES = { + 'P-256': SECP256R1, + 'P-384': SECP384R1, + 'P-521': SECP521R1, + } + CURVES_DSS = { + SECP256R1.name: 'P-256', + SECP384R1.name: 'P-384', + SECP521R1.name: 'P-521', + } + REQUIRED_JSON_FIELDS = ['crv', 'x', 'y'] + RAW_KEY_CLS = (EllipticCurvePublicKey, EllipticCurvePrivateKeyWithSerialization) + + def as_pem(self, is_private=False, password=None): + """Export key into PEM format bytes. + + :param is_private: export private key or public key + :param password: encrypt private key with password + :return: bytes + """ + return export_key(self, is_private=is_private, password=password) + + def exchange_shared_key(self, pubkey): + # # used in ECDHAlgorithm + if isinstance(self.raw_key, EllipticCurvePrivateKeyWithSerialization): + return self.raw_key.exchange(ec.ECDH(), pubkey) + raise ValueError('Invalid key for exchanging shared key') + + @property + def curve_key_size(self): + return self.raw_key.curve.key_size + + @classmethod + def loads_private_key(cls, obj): + curve = cls.DSS_CURVES[obj['crv']]() + public_numbers = EllipticCurvePublicNumbers( + base64_to_int(obj['x']), + base64_to_int(obj['y']), + curve, + ) + private_numbers = EllipticCurvePrivateNumbers( + base64_to_int(obj['d']), + public_numbers + ) + return private_numbers.private_key(default_backend()) + + @classmethod + def loads_public_key(cls, obj): + curve = cls.DSS_CURVES[obj['crv']]() + public_numbers = EllipticCurvePublicNumbers( + base64_to_int(obj['x']), + base64_to_int(obj['y']), + curve, + ) + return public_numbers.public_key(default_backend()) + + @classmethod + def dumps_private_key(cls, raw_key): + numbers = raw_key.private_numbers() + return { + 'crv': cls.CURVES_DSS[raw_key.curve.name], + 'x': int_to_base64(numbers.public_numbers.x), + 'y': int_to_base64(numbers.public_numbers.y), + 'd': int_to_base64(numbers.private_value), + } + + @classmethod + def dumps_public_key(cls, raw_key): + numbers = raw_key.public_numbers() + return { + 'crv': cls.CURVES_DSS[numbers.curve.name], + 'x': int_to_base64(numbers.x), + 'y': int_to_base64(numbers.y) + } + + @classmethod + def import_key(cls, raw, options=None): + """Import a key from PEM or dict data.""" + return import_key( + cls, raw, + EllipticCurvePublicKey, EllipticCurvePrivateKeyWithSerialization, + b'ecdsa-sha2-', options + ) + + @classmethod + def generate_key(cls, crv='P-256', options=None, is_private=False): + if crv not in cls.DSS_CURVES: + raise ValueError('Invalid crv value: "{}"'.format(crv)) + raw_key = ec.generate_private_key( + curve=cls.DSS_CURVES[crv](), + backend=default_backend(), + ) + if not is_private: + raw_key = raw_key.public_key() + return cls.import_key(raw_key, options=options) + + +def import_key(cls, raw, public_key_cls, private_key_cls, ssh_type=None, options=None): + if isinstance(raw, cls): + if options is not None: + raw.update(options) + return raw + + payload = None + if isinstance(raw, (public_key_cls, private_key_cls)): + raw_key = raw + elif isinstance(raw, dict): + cls.check_required_fields(raw) + payload = raw + if 'd' in payload: + raw_key = cls.loads_private_key(payload) + else: + raw_key = cls.loads_public_key(payload) + else: + if options is not None: + password = options.get('password') + else: + password = None + raw_key = load_pem_key(raw, ssh_type, password=password) + + if isinstance(raw_key, private_key_cls): + if payload is None: + payload = cls.dumps_private_key(raw_key) + key_type = 'private' + elif isinstance(raw_key, public_key_cls): + if payload is None: + payload = cls.dumps_public_key(raw_key) + key_type = 'public' + else: + raise ValueError('Invalid data for importing key') + + obj = cls(payload) + obj.raw_key = raw_key + obj.key_type = key_type + return obj + + +def export_key(key, encoding=None, is_private=False, password=None): + if encoding is None or encoding == 'PEM': + encoding = Encoding.PEM + elif encoding == 'DER': + encoding = Encoding.DER + else: + raise ValueError('Invalid encoding: {!r}'.format(encoding)) + + if is_private: + if key.key_type == 'private': + if password is None: + encryption_algorithm = NoEncryption() + else: + encryption_algorithm = BestAvailableEncryption(to_bytes(password)) + return key.raw_key.private_bytes( + encoding=encoding, + format=PrivateFormat.PKCS8, + encryption_algorithm=encryption_algorithm, + ) + raise ValueError('This is a public key') + + if key.key_type == 'private': + raw_key = key.raw_key.public_key() + else: + raw_key = key.raw_key + + return raw_key.public_bytes( + encoding=encoding, + format=PublicFormat.SubjectPublicKeyInfo, + ) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/jwe_algorithms.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/jwe_algorithms.py new file mode 100644 index 0000000..1e5dc96 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/jwe_algorithms.py @@ -0,0 +1,50 @@ +import zlib +from .oct_key import OctKey +from ._cryptography_backends import JWE_ALG_ALGORITHMS, JWE_ENC_ALGORITHMS +from ..rfc7516 import JWEAlgorithm, JWEZipAlgorithm, JsonWebEncryption + + +class DirectAlgorithm(JWEAlgorithm): + name = 'dir' + description = 'Direct use of a shared symmetric key' + + def prepare_key(self, raw_data): + return OctKey.import_key(raw_data) + + def wrap(self, enc_alg, headers, key): + cek = key.get_op_key('encrypt') + if len(cek) * 8 != enc_alg.CEK_SIZE: + raise ValueError('Invalid "cek" length') + return {'ek': b'', 'cek': cek} + + def unwrap(self, enc_alg, ek, headers, key): + cek = key.get_op_key('decrypt') + if len(cek) * 8 != enc_alg.CEK_SIZE: + raise ValueError('Invalid "cek" length') + return cek + + +class DeflateZipAlgorithm(JWEZipAlgorithm): + name = 'DEF' + description = 'DEFLATE' + + def compress(self, s): + """Compress bytes data with DEFLATE algorithm.""" + data = zlib.compress(s) + # drop gzip headers and tail + return data[2:-4] + + def decompress(self, s): + """Decompress DEFLATE bytes data.""" + return zlib.decompress(s, -zlib.MAX_WBITS) + + +def register_jwe_rfc7518(): + JsonWebEncryption.register_algorithm(DirectAlgorithm()) + JsonWebEncryption.register_algorithm(DeflateZipAlgorithm()) + + for algorithm in JWE_ALG_ALGORITHMS: + JsonWebEncryption.register_algorithm(algorithm) + + for algorithm in JWE_ENC_ALGORITHMS: + JsonWebEncryption.register_algorithm(algorithm) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/jws_algorithms.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/jws_algorithms.py new file mode 100644 index 0000000..6372985 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/jws_algorithms.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- +""" + authlib.jose.rfc7518.jws_algorithms + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + "alg" (Algorithm) Header Parameter Values for JWS per `Section 3`_. + + .. _`Section 3`: https://tools.ietf.org/html/rfc7518#section-3 +""" + +import hmac +import hashlib +from .oct_key import OctKey +from ._cryptography_backends import JWS_ALGORITHMS +from ..rfc7515 import JWSAlgorithm, JsonWebSignature + + +class NoneAlgorithm(JWSAlgorithm): + name = 'none' + description = 'No digital signature or MAC performed' + + def prepare_key(self, raw_data): + return None + + def sign(self, msg, key): + return b'' + + def verify(self, msg, sig, key): + return False + + +class HMACAlgorithm(JWSAlgorithm): + """HMAC using SHA algorithms for JWS. Available algorithms: + + - HS256: HMAC using SHA-256 + - HS384: HMAC using SHA-384 + - HS512: HMAC using SHA-512 + """ + SHA256 = hashlib.sha256 + SHA384 = hashlib.sha384 + SHA512 = hashlib.sha512 + + def __init__(self, sha_type): + self.name = 'HS{}'.format(sha_type) + self.description = 'HMAC using SHA-{}'.format(sha_type) + self.hash_alg = getattr(self, 'SHA{}'.format(sha_type)) + + def prepare_key(self, raw_data): + return OctKey.import_key(raw_data) + + def sign(self, msg, key): + # it is faster than the one in cryptography + op_key = key.get_op_key('sign') + return hmac.new(op_key, msg, self.hash_alg).digest() + + def verify(self, msg, sig, key): + op_key = key.get_op_key('verify') + v_sig = hmac.new(op_key, msg, self.hash_alg).digest() + return hmac.compare_digest(sig, v_sig) + + +def register_jws_rfc7518(): + JsonWebSignature.register_algorithm(NoneAlgorithm()) + JsonWebSignature.register_algorithm(HMACAlgorithm(256)) + JsonWebSignature.register_algorithm(HMACAlgorithm(384)) + JsonWebSignature.register_algorithm(HMACAlgorithm(512)) + for algorithm in JWS_ALGORITHMS: + JsonWebSignature.register_algorithm(algorithm) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/oct_key.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/oct_key.py new file mode 100644 index 0000000..a095ada --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/oct_key.py @@ -0,0 +1,48 @@ +from authlib.common.encoding import ( + to_bytes, to_unicode, + urlsafe_b64encode, urlsafe_b64decode, +) +from authlib.common.security import generate_token +from authlib.jose.rfc7517 import Key + + +class OctKey(Key): + """Key class of the ``oct`` key type.""" + + kty = 'oct' + REQUIRED_JSON_FIELDS = ['k'] + + def get_op_key(self, key_op): + self.check_key_op(key_op) + return self.raw_key + + @classmethod + def import_key(cls, raw, options=None): + """Import a key from bytes, string, or dict data.""" + if isinstance(raw, dict): + cls.check_required_fields(raw) + payload = raw + raw_key = urlsafe_b64decode(to_bytes(payload['k'])) + else: + raw_key = to_bytes(raw) + k = to_unicode(urlsafe_b64encode(raw_key)) + payload = {'k': k} + + if options is not None: + payload.update(options) + + obj = cls(payload) + obj.raw_key = raw_key + obj.key_type = 'secret' + return obj + + @classmethod + def generate_key(cls, key_size=256, options=None, is_private=False): + """Generate a ``OctKey`` with the given bit size.""" + if not is_private: + raise ValueError('oct key can not be generated as public') + + if key_size % 8 != 0: + raise ValueError('Invalid bit size for oct key') + + return cls.import_key(generate_token(key_size // 8), options) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/util.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/util.py new file mode 100644 index 0000000..d2d13ec --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7518/util.py @@ -0,0 +1,12 @@ +import binascii + + +def encode_int(num, bits): + length = ((bits + 7) // 8) * 2 + padded_hex = '%0*x' % (length, num) + big_endian = binascii.a2b_hex(padded_hex.encode('ascii')) + return big_endian + + +def decode_int(b): + return int(binascii.b2a_hex(b), 16) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7519/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7519/__init__.py new file mode 100644 index 0000000..b98efc9 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7519/__init__.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +""" + authlib.jose.rfc7519 + ~~~~~~~~~~~~~~~~~~~~ + + This module represents a direct implementation of + JSON Web Token (JWT). + + https://tools.ietf.org/html/rfc7519 +""" + +from .jwt import JsonWebToken +from .claims import BaseClaims, JWTClaims + + +__all__ = ['JsonWebToken', 'BaseClaims', 'JWTClaims'] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7519/claims.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7519/claims.py new file mode 100644 index 0000000..9e73867 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7519/claims.py @@ -0,0 +1,214 @@ +import time +from authlib.jose.errors import ( + MissingClaimError, + InvalidClaimError, + ExpiredTokenError, + InvalidTokenError, +) + + +class BaseClaims(dict): + """Payload claims for JWT, which contains a validate interface. + + :param payload: the payload dict of JWT + :param header: the header dict of JWT + :param options: validate options + :param params: other params + + An example on ``options`` parameter, the format is inspired by + `OpenID Connect Claims`_:: + + { + "iss": { + "essential": True, + "values": ["https://example.com", "https://example.org"] + }, + "sub": { + "essential": True + "value": "248289761001" + }, + "jti": { + "validate": validate_jti + } + } + + .. _`OpenID Connect Claims`: + http://openid.net/specs/openid-connect-core-1_0.html#IndividualClaimsRequests + """ + REGISTERED_CLAIMS = [] + + def __init__(self, payload, header, options=None, params=None): + super(BaseClaims, self).__init__(payload) + self.header = header + self.options = options or {} + self.params = params or {} + + def __getattr__(self, key): + try: + return object.__getattribute__(self, key) + except AttributeError as error: + if key in self.REGISTERED_CLAIMS: + return self.get(key) + raise error + + def _validate_essential_claims(self): + for k in self.options: + if self.options[k].get('essential') and k not in self: + raise MissingClaimError(k) + + def _validate_claim_value(self, claim_name): + option = self.options.get(claim_name) + value = self.get(claim_name) + if not option or not value: + return + + option_value = option.get('value') + if option_value and value != option_value: + raise InvalidClaimError(claim_name) + + option_values = option.get('values') + if option_values and value not in option_values: + raise InvalidClaimError(claim_name) + + validate = option.get('validate') + if validate and not validate(self, value): + raise InvalidClaimError(claim_name) + + def get_registered_claims(self): + rv = {} + for k in self.REGISTERED_CLAIMS: + if k in self: + rv[k] = self[k] + return rv + + +class JWTClaims(BaseClaims): + REGISTERED_CLAIMS = ['iss', 'sub', 'aud', 'exp', 'nbf', 'iat', 'jti'] + + def validate(self, now=None, leeway=0): + """Validate everything in claims payload.""" + self._validate_essential_claims() + + if now is None: + now = int(time.time()) + + self.validate_iss() + self.validate_sub() + self.validate_aud() + self.validate_exp(now, leeway) + self.validate_nbf(now, leeway) + self.validate_iat(now, leeway) + self.validate_jti() + + def validate_iss(self): + """The "iss" (issuer) claim identifies the principal that issued the + JWT. The processing of this claim is generally application specific. + The "iss" value is a case-sensitive string containing a StringOrURI + value. Use of this claim is OPTIONAL. + """ + self._validate_claim_value('iss') + + def validate_sub(self): + """The "sub" (subject) claim identifies the principal that is the + subject of the JWT. The claims in a JWT are normally statements + about the subject. The subject value MUST either be scoped to be + locally unique in the context of the issuer or be globally unique. + The processing of this claim is generally application specific. The + "sub" value is a case-sensitive string containing a StringOrURI + value. Use of this claim is OPTIONAL. + """ + self._validate_claim_value('sub') + + def validate_aud(self): + """The "aud" (audience) claim identifies the recipients that the JWT is + intended for. Each principal intended to process the JWT MUST + identify itself with a value in the audience claim. If the principal + processing the claim does not identify itself with a value in the + "aud" claim when this claim is present, then the JWT MUST be + rejected. In the general case, the "aud" value is an array of case- + sensitive strings, each containing a StringOrURI value. In the + special case when the JWT has one audience, the "aud" value MAY be a + single case-sensitive string containing a StringOrURI value. The + interpretation of audience values is generally application specific. + Use of this claim is OPTIONAL. + """ + aud_option = self.options.get('aud') + aud = self.get('aud') + if not aud_option or not aud: + return + + aud_values = aud_option.get('values') + if not aud_values: + aud_value = aud_option.get('value') + if aud_value: + aud_values = [aud_value] + + if not aud_values: + return + + if isinstance(self['aud'], list): + aud_list = self['aud'] + else: + aud_list = [self['aud']] + + if not any([v in aud_list for v in aud_values]): + raise InvalidClaimError('aud') + + def validate_exp(self, now, leeway): + """The "exp" (expiration time) claim identifies the expiration time on + or after which the JWT MUST NOT be accepted for processing. The + processing of the "exp" claim requires that the current date/time + MUST be before the expiration date/time listed in the "exp" claim. + Implementers MAY provide for some small leeway, usually no more than + a few minutes, to account for clock skew. Its value MUST be a number + containing a NumericDate value. Use of this claim is OPTIONAL. + """ + if 'exp' in self: + exp = self['exp'] + if not _validate_numeric_time(exp): + raise InvalidClaimError('exp') + if exp < (now - leeway): + raise ExpiredTokenError() + + def validate_nbf(self, now, leeway): + """The "nbf" (not before) claim identifies the time before which the JWT + MUST NOT be accepted for processing. The processing of the "nbf" + claim requires that the current date/time MUST be after or equal to + the not-before date/time listed in the "nbf" claim. Implementers MAY + provide for some small leeway, usually no more than a few minutes, to + account for clock skew. Its value MUST be a number containing a + NumericDate value. Use of this claim is OPTIONAL. + """ + if 'nbf' in self: + nbf = self['nbf'] + if not _validate_numeric_time(nbf): + raise InvalidClaimError('nbf') + if nbf > (now + leeway): + raise InvalidTokenError() + + def validate_iat(self, now, leeway): + """The "iat" (issued at) claim identifies the time at which the JWT was + issued. This claim can be used to determine the age of the JWT. Its + value MUST be a number containing a NumericDate value. Use of this + claim is OPTIONAL. + """ + if 'iat' in self: + iat = self['iat'] + if not _validate_numeric_time(iat): + raise InvalidClaimError('iat') + + def validate_jti(self): + """The "jti" (JWT ID) claim provides a unique identifier for the JWT. + The identifier value MUST be assigned in a manner that ensures that + there is a negligible probability that the same value will be + accidentally assigned to a different data object; if the application + uses multiple issuers, collisions MUST be prevented among values + produced by different issuers as well. The "jti" claim can be used + to prevent the JWT from being replayed. The "jti" value is a case- + sensitive string. Use of this claim is OPTIONAL. + """ + self._validate_claim_value('jti') + + +def _validate_numeric_time(s): + return isinstance(s, (int, float)) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7519/jwt.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7519/jwt.py new file mode 100644 index 0000000..18dc07b --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc7519/jwt.py @@ -0,0 +1,138 @@ +import re +import datetime +import calendar +from authlib.common.encoding import ( + text_types, to_bytes, to_unicode, + json_loads, json_dumps, +) +from .claims import JWTClaims +from ..errors import DecodeError, InsecureClaimError +from ..rfc7515 import JsonWebSignature +from ..rfc7516 import JsonWebEncryption +from ..rfc7517 import KeySet + + +class JsonWebToken(object): + SENSITIVE_NAMES = ('password', 'token', 'secret', 'secret_key') + # Thanks to sentry SensitiveDataFilter + SENSITIVE_VALUES = re.compile(r'|'.join([ + # http://www.richardsramblings.com/regex/credit-card-numbers/ + r'\b(?:3[47]\d|(?:4\d|5[1-5]|65)\d{2}|6011)\d{12}\b', + # various private keys + r'-----BEGIN[A-Z ]+PRIVATE KEY-----.+-----END[A-Z ]+PRIVATE KEY-----', + # social security numbers (US) + r'^\b(?!(000|666|9))\d{3}-(?!00)\d{2}-(?!0000)\d{4}\b', + ]), re.DOTALL) + + def __init__(self, algorithms=None, private_headers=None): + self._jws = JsonWebSignature(algorithms, private_headers=private_headers) + self._jwe = JsonWebEncryption(algorithms, private_headers=private_headers) + + def check_sensitive_data(self, payload): + """Check if payload contains sensitive information.""" + for k in payload: + # check claims key name + if k in self.SENSITIVE_NAMES: + raise InsecureClaimError(k) + + # check claims values + v = payload[k] + if isinstance(v, text_types) and self.SENSITIVE_VALUES.search(v): + raise InsecureClaimError(k) + + def encode(self, header, payload, key, check=True): + """Encode a JWT with the given header, payload and key. + + :param header: A dict of JWS header + :param payload: A dict to be encoded + :param key: key used to sign the signature + :param check: check if sensitive data in payload + :return: bytes + """ + header['typ'] = 'JWT' + + for k in ['exp', 'iat', 'nbf']: + # convert datetime into timestamp + claim = payload.get(k) + if isinstance(claim, datetime.datetime): + payload[k] = calendar.timegm(claim.utctimetuple()) + + if check: + self.check_sensitive_data(payload) + + key = prepare_raw_key(key, header) + if callable(key): + key = key(header, payload) + + text = to_bytes(json_dumps(payload)) + if 'enc' in header: + return self._jwe.serialize_compact(header, text, key) + else: + return self._jws.serialize_compact(header, text, key) + + def decode(self, s, key, claims_cls=None, + claims_options=None, claims_params=None): + """Decode the JWS with the given key. This is similar with + :meth:`verify`, except that it will raise BadSignatureError when + signature doesn't match. + + :param s: text of JWT + :param key: key used to verify the signature + :param claims_cls: class to be used for JWT claims + :param claims_options: `options` parameters for claims_cls + :param claims_params: `params` parameters for claims_cls + :return: claims_cls instance + :raise: BadSignatureError + """ + if claims_cls is None: + claims_cls = JWTClaims + + def load_key(header, payload): + key_func = prepare_raw_key(key, header) + if callable(key_func): + return key_func(header, payload) + return key_func + + s = to_bytes(s) + dot_count = s.count(b'.') + if dot_count == 2: + data = self._jws.deserialize_compact(s, load_key, decode_payload) + elif dot_count == 4: + data = self._jwe.deserialize_compact(s, load_key, decode_payload) + else: + raise DecodeError('Invalid input segments length') + return claims_cls( + data['payload'], data['header'], + options=claims_options, + params=claims_params, + ) + + +def decode_payload(bytes_payload): + try: + payload = json_loads(to_unicode(bytes_payload)) + except ValueError: + raise DecodeError('Invalid payload value') + if not isinstance(payload, dict): + raise DecodeError('Invalid payload type') + return payload + + +def prepare_raw_key(raw, headers): + if isinstance(raw, KeySet): + return raw.find_by_kid(headers.get('kid')) + + if isinstance(raw, text_types) and \ + raw.startswith('{') and raw.endswith('}'): + raw = json_loads(raw) + elif isinstance(raw, (tuple, list)): + raw = {'keys': raw} + + if isinstance(raw, dict) and 'keys' in raw: + keys = raw['keys'] + kid = headers.get('kid') + for k in keys: + if k.get('kid') == kid: + return k + raise ValueError('Invalid JSON Web Key Set') + return raw diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc8037/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc8037/__init__.py new file mode 100644 index 0000000..46a6831 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc8037/__init__.py @@ -0,0 +1,5 @@ +from .okp_key import OKPKey +from ._jws_cryptography import register_jws_rfc8037 + + +__all__ = ['register_jws_rfc8037', 'OKPKey'] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc8037/_jws_cryptography.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc8037/_jws_cryptography.py new file mode 100644 index 0000000..86989fd --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc8037/_jws_cryptography.py @@ -0,0 +1,32 @@ +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.primitives.asymmetric.ed25519 import ( + Ed25519PublicKey, Ed25519PrivateKey +) +from authlib.jose.rfc7515 import JWSAlgorithm, JsonWebSignature +from .okp_key import OKPKey + + +class EdDSAAlgorithm(JWSAlgorithm): + name = 'EdDSA' + description = 'Edwards-curve Digital Signature Algorithm for JWS' + private_key_cls = Ed25519PrivateKey + public_key_cls = Ed25519PublicKey + + def prepare_key(self, raw_data): + return OKPKey.import_key(raw_data) + + def sign(self, msg, key): + op_key = key.get_op_key('sign') + return op_key.sign(msg) + + def verify(self, msg, sig, key): + op_key = key.get_op_key('verify') + try: + op_key.verify(sig, msg) + return True + except InvalidSignature: + return False + + +def register_jws_rfc8037(): + JsonWebSignature.register_algorithm(EdDSAAlgorithm()) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc8037/okp_key.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc8037/okp_key.py new file mode 100644 index 0000000..d8438b3 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/rfc8037/okp_key.py @@ -0,0 +1,130 @@ +from cryptography.hazmat.primitives.asymmetric.ed25519 import ( + Ed25519PublicKey, Ed25519PrivateKey +) +from cryptography.hazmat.primitives.asymmetric.ed448 import ( + Ed448PublicKey, Ed448PrivateKey +) +from cryptography.hazmat.primitives.asymmetric.x25519 import ( + X25519PublicKey, X25519PrivateKey +) +from cryptography.hazmat.primitives.asymmetric.x448 import ( + X448PublicKey, X448PrivateKey +) +from cryptography.hazmat.primitives.serialization import ( + Encoding, PublicFormat, PrivateFormat, NoEncryption +) +from authlib.common.encoding import ( + to_unicode, to_bytes, + urlsafe_b64decode, urlsafe_b64encode, +) +from authlib.jose.rfc7517 import Key +from ..rfc7518 import import_key, export_key + + +PUBLIC_KEYS_MAP = { + 'Ed25519': Ed25519PublicKey, + 'Ed448': Ed448PublicKey, + 'X25519': X25519PublicKey, + 'X448': X448PublicKey, +} +PRIVATE_KEYS_MAP = { + 'Ed25519': Ed25519PrivateKey, + 'Ed448': Ed448PrivateKey, + 'X25519': X25519PrivateKey, + 'X448': X448PrivateKey, +} +PUBLIC_KEY_TUPLE = tuple(PUBLIC_KEYS_MAP.values()) +PRIVATE_KEY_TUPLE = tuple(PRIVATE_KEYS_MAP.values()) + + +class OKPKey(Key): + """Key class of the ``OKP`` key type.""" + + kty = 'OKP' + REQUIRED_JSON_FIELDS = ['crv', 'x'] + RAW_KEY_CLS = ( + Ed25519PublicKey, Ed25519PrivateKey, + Ed448PublicKey, Ed448PrivateKey, + X25519PublicKey, X25519PrivateKey, + X448PublicKey, X448PrivateKey, + ) + + def as_pem(self, is_private=False, password=None): + """Export key into PEM format bytes. + + :param is_private: export private key or public key + :param password: encrypt private key with password + :return: bytes + """ + return export_key(self, is_private=is_private, password=password) + + def exchange_shared_key(self, pubkey): + # used in ECDHAlgorithm + if isinstance(self.raw_key, (X25519PrivateKey, X448PrivateKey)): + return self.raw_key.exchange(pubkey) + raise ValueError('Invalid key for exchanging shared key') + + @property + def curve_key_size(self): + raise NotImplementedError() + + @staticmethod + def get_key_curve(key): + if isinstance(key, (Ed25519PublicKey, Ed25519PrivateKey)): + return 'Ed25519' + elif isinstance(key, (Ed448PublicKey, Ed448PrivateKey)): + return 'Ed448' + elif isinstance(key, (X25519PublicKey, X25519PrivateKey)): + return 'X25519' + elif isinstance(key, (X448PublicKey, X448PrivateKey)): + return 'X448' + + @staticmethod + def loads_private_key(obj): + crv_key = PRIVATE_KEYS_MAP[obj['crv']] + d_bytes = urlsafe_b64decode(to_bytes(obj['d'])) + return crv_key.from_private_bytes(d_bytes) + + @staticmethod + def loads_public_key(obj): + crv_key = PUBLIC_KEYS_MAP[obj['crv']] + x_bytes = urlsafe_b64decode(to_bytes(obj['x'])) + return crv_key.from_public_bytes(x_bytes) + + @staticmethod + def dumps_private_key(raw_key): + obj = OKPKey.dumps_public_key(raw_key.public_key()) + d_bytes = raw_key.private_bytes( + Encoding.Raw, + PrivateFormat.Raw, + NoEncryption() + ) + obj['d'] = to_unicode(urlsafe_b64encode(d_bytes)) + return obj + + @staticmethod + def dumps_public_key(raw_key): + x_bytes = raw_key.public_bytes(Encoding.Raw, PublicFormat.Raw) + return { + 'crv': OKPKey.get_key_curve(raw_key), + 'x': to_unicode(urlsafe_b64encode(x_bytes)), + } + + @classmethod + def import_key(cls, raw, options=None): + """Import a key from PEM or dict data.""" + return import_key( + cls, raw, + PUBLIC_KEY_TUPLE, PRIVATE_KEY_TUPLE, + b'ssh-ed25519', options + ) + + @classmethod + def generate_key(cls, crv='Ed25519', options=None, is_private=False): + if crv not in PRIVATE_KEYS_MAP: + raise ValueError('Invalid crv value: "{}"'.format(crv)) + private_key_cls = PRIVATE_KEYS_MAP[crv] + raw_key = private_key_cls.generate() + if not is_private: + raw_key = raw_key.public_key() + return cls.import_key(raw_key, options=options) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/util.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/util.py new file mode 100644 index 0000000..08414cb --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/jose/util.py @@ -0,0 +1,23 @@ +import binascii +from authlib.common.encoding import urlsafe_b64decode, json_loads + + +def extract_header(header_segment, error_cls): + header_data = extract_segment(header_segment, error_cls, 'header') + + try: + header = json_loads(header_data.decode('utf-8')) + except ValueError as e: + raise error_cls('Invalid header string: {}'.format(e)) + + if not isinstance(header, dict): + raise error_cls('Header must be a json object') + return header + + +def extract_segment(segment, error_cls, name='payload'): + try: + return urlsafe_b64decode(segment) + except (TypeError, binascii.Error): + msg = 'Invalid {} padding'.format(name) + raise error_cls(msg) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/__init__.py new file mode 100644 index 0000000..af1ba07 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/__init__.py @@ -0,0 +1,36 @@ +# coding: utf-8 + +from .rfc5849 import ( + OAuth1Request, + ClientAuth, + SIGNATURE_HMAC_SHA1, + SIGNATURE_RSA_SHA1, + SIGNATURE_PLAINTEXT, + SIGNATURE_TYPE_HEADER, + SIGNATURE_TYPE_QUERY, + SIGNATURE_TYPE_BODY, + ClientMixin, + TemporaryCredentialMixin, + TokenCredentialMixin, + TemporaryCredential, + AuthorizationServer, + ResourceProtector, +) + +__all__ = [ + 'OAuth1Request', + 'ClientAuth', + 'SIGNATURE_HMAC_SHA1', + 'SIGNATURE_RSA_SHA1', + 'SIGNATURE_PLAINTEXT', + 'SIGNATURE_TYPE_HEADER', + 'SIGNATURE_TYPE_QUERY', + 'SIGNATURE_TYPE_BODY', + + 'ClientMixin', + 'TemporaryCredentialMixin', + 'TokenCredentialMixin', + 'TemporaryCredential', + 'AuthorizationServer', + 'ResourceProtector', +] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/client.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/client.py new file mode 100644 index 0000000..7715711 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/client.py @@ -0,0 +1,189 @@ +# -*- coding: utf-8 -*- +from authlib.common.urls import ( + url_decode, + add_params_to_uri, + urlparse, +) +from authlib.common.encoding import json_loads +from .rfc5849 import ( + SIGNATURE_HMAC_SHA1, + SIGNATURE_TYPE_HEADER, + ClientAuth, +) + + +class OAuth1Client(object): + auth_class = ClientAuth + + def __init__(self, session, client_id, client_secret=None, + token=None, token_secret=None, + redirect_uri=None, rsa_key=None, verifier=None, + signature_method=SIGNATURE_HMAC_SHA1, + signature_type=SIGNATURE_TYPE_HEADER, + force_include_body=False, **kwargs): + if not client_id: + raise ValueError('Missing "client_id"') + + self.session = session + self.auth = self.auth_class( + client_id, client_secret=client_secret, + token=token, token_secret=token_secret, + redirect_uri=redirect_uri, + signature_method=signature_method, + signature_type=signature_type, + rsa_key=rsa_key, + verifier=verifier, + force_include_body=force_include_body + ) + self._kwargs = kwargs + + @property + def redirect_uri(self): + return self.auth.redirect_uri + + @redirect_uri.setter + def redirect_uri(self, uri): + self.auth.redirect_uri = uri + + @property + def token(self): + return dict( + oauth_token=self.auth.token, + oauth_token_secret=self.auth.token_secret, + oauth_verifier=self.auth.verifier + ) + + @token.setter + def token(self, token): + """This token setter is designed for an easy integration for + OAuthClient. Make sure both OAuth1Session and OAuth2Session + have token setters. + """ + if token is None: + self.auth.token = None + self.auth.token_secret = None + self.auth.verifier = None + elif 'oauth_token' in token: + self.auth.token = token['oauth_token'] + if 'oauth_token_secret' in token: + self.auth.token_secret = token['oauth_token_secret'] + if 'oauth_verifier' in token: + self.auth.verifier = token['oauth_verifier'] + else: + message = 'oauth_token is missing: {!r}'.format(token) + self.handle_error('missing_token', message) + + def create_authorization_url(self, url, request_token=None, **kwargs): + """Create an authorization URL by appending request_token and optional + kwargs to url. + + This is the second step in the OAuth 1 workflow. The user should be + redirected to this authorization URL, grant access to you, and then + be redirected back to you. The redirection back can either be specified + during client registration or by supplying a callback URI per request. + + :param url: The authorization endpoint URL. + :param request_token: The previously obtained request token. + :param kwargs: Optional parameters to append to the URL. + :returns: The authorization URL with new parameters embedded. + """ + kwargs['oauth_token'] = request_token or self.auth.token + if self.auth.redirect_uri: + kwargs['oauth_callback'] = self.auth.redirect_uri + + self.auth.redirect_uri = None + self.auth.realm = None + return add_params_to_uri(url, kwargs.items()) + + def fetch_request_token(self, url, realm=None, **kwargs): + """Method for fetching an access token from the token endpoint. + + This is the first step in the OAuth 1 workflow. A request token is + obtained by making a signed post request to url. The token is then + parsed from the application/x-www-form-urlencoded response and ready + to be used to construct an authorization url. + + :param url: Request Token endpoint. + :param realm: A string/list/tuple of realm for Authorization header. + :param kwargs: Extra parameters to include for fetching token. + :return: A Request Token dict. + + Note, ``realm`` can also be configured when session created:: + + session = OAuth1Session(client_id, client_secret, ..., realm='') + """ + if realm is None: + realm = self._kwargs.get('realm', None) + if realm: + if isinstance(realm, (tuple, list)): + realm = ' '.join(realm) + self.auth.realm = realm + else: + self.auth.realm = None + + return self._fetch_token(url, **kwargs) + + def fetch_access_token(self, url, verifier=None, **kwargs): + """Method for fetching an access token from the token endpoint. + + This is the final step in the OAuth 1 workflow. An access token is + obtained using all previously obtained credentials, including the + verifier from the authorization step. + + :param url: Access Token endpoint. + :param verifier: A verifier string to prove authorization was granted. + :param kwargs: Extra parameters to include for fetching access token. + :return: A token dict. + """ + if verifier: + self.auth.verifier = verifier + if not self.auth.verifier: + self.handle_error('missing_verifier', 'Missing "verifier" value') + return self._fetch_token(url, **kwargs) + + def parse_authorization_response(self, url): + """Extract parameters from the post authorization redirect + response URL. + + :param url: The full URL that resulted from the user being redirected + back from the OAuth provider to you, the client. + :returns: A dict of parameters extracted from the URL. + """ + token = dict(url_decode(urlparse.urlparse(url).query)) + self.token = token + return token + + def _fetch_token(self, url, **kwargs): + resp = self.session.post(url, auth=self.auth, **kwargs) + token = self.parse_response_token(resp.status_code, resp.text) + self.token = token + self.auth.verifier = None + return token + + def parse_response_token(self, status_code, text): + if status_code >= 400: + message = ( + "Token request failed with code {}, " + "response was '{}'." + ).format(status_code, text) + self.handle_error('fetch_token_denied', message) + + try: + text = text.strip() + if text.startswith('{'): + token = json_loads(text) + else: + token = dict(url_decode(text)) + except (TypeError, ValueError) as e: + error = ( + "Unable to decode token from token response. " + "This is commonly caused by an unsuccessful request where" + " a non urlencoded error message is returned. " + "The decoding error was {}" + ).format(e) + raise ValueError(error) + return token + + @staticmethod + def handle_error(error_type, error_description): + raise ValueError('{}: {}'.format(error_type, error_description)) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/errors.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/errors.py new file mode 100644 index 0000000..e7770da --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/errors.py @@ -0,0 +1,3 @@ +# flake8: noqa + +from .rfc5849.errors import * diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/__init__.py new file mode 100644 index 0000000..1f029fb --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/__init__.py @@ -0,0 +1,45 @@ +""" + authlib.oauth1.rfc5849 + ~~~~~~~~~~~~~~~~~~~~~~ + + This module represents a direct implementation of The OAuth 1.0 Protocol. + + https://tools.ietf.org/html/rfc5849 +""" + +from .wrapper import OAuth1Request +from .client_auth import ClientAuth +from .signature import ( + SIGNATURE_HMAC_SHA1, + SIGNATURE_RSA_SHA1, + SIGNATURE_PLAINTEXT, + SIGNATURE_TYPE_HEADER, + SIGNATURE_TYPE_QUERY, + SIGNATURE_TYPE_BODY, +) +from .models import ( + ClientMixin, + TemporaryCredentialMixin, + TokenCredentialMixin, + TemporaryCredential, +) +from .authorization_server import AuthorizationServer +from .resource_protector import ResourceProtector + +__all__ = [ + 'OAuth1Request', + 'ClientAuth', + 'SIGNATURE_HMAC_SHA1', + 'SIGNATURE_RSA_SHA1', + 'SIGNATURE_PLAINTEXT', + 'SIGNATURE_TYPE_HEADER', + 'SIGNATURE_TYPE_QUERY', + 'SIGNATURE_TYPE_BODY', + + 'ClientMixin', + 'TemporaryCredentialMixin', + 'TokenCredentialMixin', + 'TemporaryCredential', + 'AuthorizationServer', + 'ResourceProtector', +] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/authorization_server.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/authorization_server.py new file mode 100644 index 0000000..be9b985 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/authorization_server.py @@ -0,0 +1,357 @@ +from authlib.common.urls import is_valid_url, add_params_to_uri +from .base_server import BaseServer +from .errors import ( + OAuth1Error, + InvalidRequestError, + MissingRequiredParameterError, + InvalidClientError, + InvalidTokenError, + AccessDeniedError, + MethodNotAllowedError, +) + + +class AuthorizationServer(BaseServer): + TOKEN_RESPONSE_HEADER = [ + ('Content-Type', 'application/x-www-form-urlencoded'), + ('Cache-Control', 'no-store'), + ('Pragma', 'no-cache'), + ] + + TEMPORARY_CREDENTIALS_METHOD = 'POST' + + def _get_client(self, request): + client = self.get_client_by_id(request.client_id) + request.client = client + return client + + def create_oauth1_request(self, request): + raise NotImplementedError() + + def handle_response(self, status_code, payload, headers): + raise NotImplementedError() + + def handle_error_response(self, error): + return self.handle_response( + error.status_code, + error.get_body(), + error.get_headers() + ) + + def validate_temporary_credentials_request(self, request): + """Validate HTTP request for temporary credentials.""" + + # The client obtains a set of temporary credentials from the server by + # making an authenticated (Section 3) HTTP "POST" request to the + # Temporary Credential Request endpoint (unless the server advertises + # another HTTP request method for the client to use). + if request.method.upper() != self.TEMPORARY_CREDENTIALS_METHOD: + raise MethodNotAllowedError() + + # REQUIRED parameter + if not request.client_id: + raise MissingRequiredParameterError('oauth_consumer_key') + + # REQUIRED parameter + oauth_callback = request.redirect_uri + if not request.redirect_uri: + raise MissingRequiredParameterError('oauth_callback') + + # An absolute URI or + # other means (the parameter value MUST be set to "oob" + if oauth_callback != 'oob' and not is_valid_url(oauth_callback): + raise InvalidRequestError('Invalid "oauth_callback" value') + + client = self._get_client(request) + if not client: + raise InvalidClientError() + + self.validate_timestamp_and_nonce(request) + self.validate_oauth_signature(request) + return request + + def create_temporary_credentials_response(self, request=None): + """Validate temporary credentials token request and create response + for temporary credentials token. Assume the endpoint of temporary + credentials request is ``https://photos.example.net/initiate``: + + .. code-block:: http + + POST /initiate HTTP/1.1 + Host: photos.example.net + Authorization: OAuth realm="Photos", + oauth_consumer_key="dpf43f3p2l4k3l03", + oauth_signature_method="HMAC-SHA1", + oauth_timestamp="137131200", + oauth_nonce="wIjqoS", + oauth_callback="http%3A%2F%2Fprinter.example.com%2Fready", + oauth_signature="74KNZJeDHnMBp0EMJ9ZHt%2FXKycU%3D" + + The server validates the request and replies with a set of temporary + credentials in the body of the HTTP response: + + .. code-block:: http + + HTTP/1.1 200 OK + Content-Type: application/x-www-form-urlencoded + + oauth_token=hh5s93j4hdidpola&oauth_token_secret=hdhd0244k9j7ao03& + oauth_callback_confirmed=true + + :param request: OAuth1Request instance. + :returns: (status_code, body, headers) + """ + try: + request = self.create_oauth1_request(request) + self.validate_temporary_credentials_request(request) + except OAuth1Error as error: + return self.handle_error_response(error) + + credential = self.create_temporary_credential(request) + payload = [ + ('oauth_token', credential.get_oauth_token()), + ('oauth_token_secret', credential.get_oauth_token_secret()), + ('oauth_callback_confirmed', True) + ] + return self.handle_response(200, payload, self.TOKEN_RESPONSE_HEADER) + + def validate_authorization_request(self, request): + """Validate the request for resource owner authorization.""" + if not request.token: + raise MissingRequiredParameterError('oauth_token') + + credential = self.get_temporary_credential(request) + if not credential: + raise InvalidTokenError() + + # assign credential for later use + request.credential = credential + return request + + def create_authorization_response(self, request, grant_user=None): + """Validate authorization request and create authorization response. + Assume the endpoint for authorization request is + ``https://photos.example.net/authorize``, the client redirects Jane's + user-agent to the server's Resource Owner Authorization endpoint to + obtain Jane's approval for accessing her private photos:: + + https://photos.example.net/authorize?oauth_token=hh5s93j4hdidpola + + The server requests Jane to sign in using her username and password + and if successful, asks her to approve granting 'printer.example.com' + access to her private photos. Jane approves the request and her + user-agent is redirected to the callback URI provided by the client + in the previous request (line breaks are for display purposes only):: + + http://printer.example.com/ready? + oauth_token=hh5s93j4hdidpola&oauth_verifier=hfdp7dh39dks9884 + + :param request: OAuth1Request instance. + :param grant_user: if granted, pass the grant user, otherwise None. + :returns: (status_code, body, headers) + """ + request = self.create_oauth1_request(request) + # authorize endpoint should try catch this error + self.validate_authorization_request(request) + + temporary_credentials = request.credential + redirect_uri = temporary_credentials.get_redirect_uri() + if not redirect_uri or redirect_uri == 'oob': + client_id = temporary_credentials.get_client_id() + client = self.get_client_by_id(client_id) + redirect_uri = client.get_default_redirect_uri() + + if grant_user is None: + error = AccessDeniedError() + location = add_params_to_uri(redirect_uri, error.get_body()) + return self.handle_response(302, '', [('Location', location)]) + + request.user = grant_user + verifier = self.create_authorization_verifier(request) + + params = [ + ('oauth_token', request.token), + ('oauth_verifier', verifier) + ] + location = add_params_to_uri(redirect_uri, params) + return self.handle_response(302, '', [('Location', location)]) + + def validate_token_request(self, request): + """Validate request for issuing token.""" + + if not request.client_id: + raise MissingRequiredParameterError('oauth_consumer_key') + + client = self._get_client(request) + if not client: + raise InvalidClientError() + + if not request.token: + raise MissingRequiredParameterError('oauth_token') + + token = self.get_temporary_credential(request) + if not token: + raise InvalidTokenError() + + verifier = request.oauth_params.get('oauth_verifier') + if not verifier: + raise MissingRequiredParameterError('oauth_verifier') + + if not token.check_verifier(verifier): + raise InvalidRequestError('Invalid "oauth_verifier"') + + request.credential = token + self.validate_timestamp_and_nonce(request) + self.validate_oauth_signature(request) + return request + + def create_token_response(self, request): + """Validate token request and create token response. Assuming the + endpoint of token request is ``https://photos.example.net/token``, + the callback request informs the client that Jane completed the + authorization process. The client then requests a set of token + credentials using its temporary credentials (over a secure Transport + Layer Security (TLS) channel): + + .. code-block:: http + + POST /token HTTP/1.1 + Host: photos.example.net + Authorization: OAuth realm="Photos", + oauth_consumer_key="dpf43f3p2l4k3l03", + oauth_token="hh5s93j4hdidpola", + oauth_signature_method="HMAC-SHA1", + oauth_timestamp="137131201", + oauth_nonce="walatlh", + oauth_verifier="hfdp7dh39dks9884", + oauth_signature="gKgrFCywp7rO0OXSjdot%2FIHF7IU%3D" + + The server validates the request and replies with a set of token + credentials in the body of the HTTP response: + + .. code-block:: http + + HTTP/1.1 200 OK + Content-Type: application/x-www-form-urlencoded + + oauth_token=nnch734d00sl2jdk&oauth_token_secret=pfkkdhi9sl3r4s00 + + :param request: OAuth1Request instance. + :returns: (status_code, body, headers) + """ + try: + request = self.create_oauth1_request(request) + except OAuth1Error as error: + return self.handle_error_response(error) + + try: + self.validate_token_request(request) + except OAuth1Error as error: + self.delete_temporary_credential(request) + return self.handle_error_response(error) + + credential = self.create_token_credential(request) + payload = [ + ('oauth_token', credential.get_oauth_token()), + ('oauth_token_secret', credential.get_oauth_token_secret()), + ] + self.delete_temporary_credential(request) + return self.handle_response(200, payload, self.TOKEN_RESPONSE_HEADER) + + def create_temporary_credential(self, request): + """Generate and save a temporary credential into database or cache. + A temporary credential is used for exchanging token credential. This + method should be re-implemented:: + + def create_temporary_credential(self, request): + oauth_token = generate_token(36) + oauth_token_secret = generate_token(48) + temporary_credential = TemporaryCredential( + oauth_token=oauth_token, + oauth_token_secret=oauth_token_secret, + client_id=request.client_id, + redirect_uri=request.redirect_uri, + ) + # if the credential has a save method + temporary_credential.save() + return temporary_credential + + :param request: OAuth1Request instance + :return: TemporaryCredential instance + """ + raise NotImplementedError() + + def get_temporary_credential(self, request): + """Get the temporary credential from database or cache. A temporary + credential should share the same methods as described in models of + ``TemporaryCredentialMixin``:: + + def get_temporary_credential(self, request): + key = 'a-key-prefix:{}'.format(request.token) + data = cache.get(key) + # TemporaryCredential shares methods from TemporaryCredentialMixin + return TemporaryCredential(data) + + :param request: OAuth1Request instance + :return: TemporaryCredential instance + """ + raise NotImplementedError() + + def delete_temporary_credential(self, request): + """Delete temporary credential from database or cache. For instance, + if temporary credential is saved in cache:: + + def delete_temporary_credential(self, request): + key = 'a-key-prefix:{}'.format(request.token) + cache.delete(key) + + :param request: OAuth1Request instance + """ + raise NotImplementedError() + + def create_authorization_verifier(self, request): + """Create and bind ``oauth_verifier`` to temporary credential. It + could be re-implemented in this way:: + + def create_authorization_verifier(self, request): + verifier = generate_token(36) + + temporary_credential = request.credential + user_id = request.user.get_user_id() + + temporary_credential.user_id = user_id + temporary_credential.oauth_verifier = verifier + # if the credential has a save method + temporary_credential.save() + + # remember to return the verifier + return verifier + + :param request: OAuth1Request instance + :return: A string of ``oauth_verifier`` + """ + raise NotImplementedError() + + def create_token_credential(self, request): + """Create and save token credential into database. This method would + be re-implemented like this:: + + def create_token_credential(self, request): + oauth_token = generate_token(36) + oauth_token_secret = generate_token(48) + temporary_credential = request.credential + + token_credential = TokenCredential( + oauth_token=oauth_token, + oauth_token_secret=oauth_token_secret, + client_id=temporary_credential.get_client_id(), + user_id=temporary_credential.get_user_id() + ) + # if the credential has a save method + token_credential.save() + return token_credential + + :param request: OAuth1Request instance + :return: TokenCredential instance + """ + raise NotImplementedError() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/base_server.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/base_server.py new file mode 100644 index 0000000..46898bb --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/base_server.py @@ -0,0 +1,119 @@ +import time +from .signature import ( + SIGNATURE_HMAC_SHA1, + SIGNATURE_PLAINTEXT, + SIGNATURE_RSA_SHA1, +) +from .signature import ( + verify_hmac_sha1, + verify_plaintext, + verify_rsa_sha1, +) +from .errors import ( + InvalidRequestError, + MissingRequiredParameterError, + UnsupportedSignatureMethodError, + InvalidNonceError, + InvalidSignatureError, +) + + +class BaseServer(object): + SIGNATURE_METHODS = { + SIGNATURE_HMAC_SHA1: verify_hmac_sha1, + SIGNATURE_RSA_SHA1: verify_rsa_sha1, + SIGNATURE_PLAINTEXT: verify_plaintext, + } + SUPPORTED_SIGNATURE_METHODS = [SIGNATURE_HMAC_SHA1] + EXPIRY_TIME = 300 + + @classmethod + def register_signature_method(cls, name, verify): + """Extend signature method verification. + + :param name: A string to represent signature method. + :param verify: A function to verify signature. + + The ``verify`` method accept ``OAuth1Request`` as parameter:: + + def verify_custom_method(request): + # verify this request, return True or False + return True + + Server.register_signature_method('custom-name', verify_custom_method) + """ + cls.SIGNATURE_METHODS[name] = verify + + def validate_timestamp_and_nonce(self, request): + """Validate ``oauth_timestamp`` and ``oauth_nonce`` in HTTP request. + + :param request: OAuth1Request instance + """ + timestamp = request.oauth_params.get('oauth_timestamp') + nonce = request.oauth_params.get('oauth_nonce') + + if request.signature_method == SIGNATURE_PLAINTEXT: + # The parameters MAY be omitted when using the "PLAINTEXT" + # signature method + if not timestamp and not nonce: + return + + if not timestamp: + raise MissingRequiredParameterError('oauth_timestamp') + + try: + # The timestamp value MUST be a positive integer + timestamp = int(timestamp) + if timestamp < 0: + raise InvalidRequestError('Invalid "oauth_timestamp" value') + + if self.EXPIRY_TIME and time.time() - timestamp > self.EXPIRY_TIME: + raise InvalidRequestError('Invalid "oauth_timestamp" value') + except (ValueError, TypeError): + raise InvalidRequestError('Invalid "oauth_timestamp" value') + + if not nonce: + raise MissingRequiredParameterError('oauth_nonce') + + if self.exists_nonce(nonce, request): + raise InvalidNonceError() + + def validate_oauth_signature(self, request): + """Validate ``oauth_signature`` from HTTP request. + + :param request: OAuth1Request instance + """ + method = request.signature_method + if not method: + raise MissingRequiredParameterError('oauth_signature_method') + + if method not in self.SUPPORTED_SIGNATURE_METHODS: + raise UnsupportedSignatureMethodError() + + if not request.signature: + raise MissingRequiredParameterError('oauth_signature') + + verify = self.SIGNATURE_METHODS.get(method) + if not verify: + raise UnsupportedSignatureMethodError() + + if not verify(request): + raise InvalidSignatureError() + + def get_client_by_id(self, client_id): + """Get client instance with the given ``client_id``. + + :param client_id: A string of client_id + :return: Client instance + """ + raise NotImplementedError() + + def exists_nonce(self, nonce, request): + """The nonce value MUST be unique across all requests with the same + timestamp, client credentials, and token combinations. + + :param nonce: A string value of ``oauth_nonce`` + :param request: OAuth1Request instance + :return: Boolean + """ + raise NotImplementedError() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/client_auth.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/client_auth.py new file mode 100644 index 0000000..504a352 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/client_auth.py @@ -0,0 +1,184 @@ +import time +from authlib.common.security import generate_token +from authlib.common.urls import extract_params +from authlib.common.encoding import to_native +from .wrapper import OAuth1Request +from .signature import ( + SIGNATURE_HMAC_SHA1, + SIGNATURE_PLAINTEXT, + SIGNATURE_RSA_SHA1, + SIGNATURE_TYPE_HEADER, + SIGNATURE_TYPE_BODY, + SIGNATURE_TYPE_QUERY, +) +from .signature import ( + sign_hmac_sha1, + sign_rsa_sha1, + sign_plaintext +) +from .parameters import ( + prepare_form_encoded_body, + prepare_headers, + prepare_request_uri_query, +) + + +CONTENT_TYPE_FORM_URLENCODED = 'application/x-www-form-urlencoded' +CONTENT_TYPE_MULTI_PART = 'multipart/form-data' + + +class ClientAuth(object): + SIGNATURE_METHODS = { + SIGNATURE_HMAC_SHA1: sign_hmac_sha1, + SIGNATURE_RSA_SHA1: sign_rsa_sha1, + SIGNATURE_PLAINTEXT: sign_plaintext, + } + + @classmethod + def register_signature_method(cls, name, sign): + """Extend client signature methods. + + :param name: A string to represent signature method. + :param sign: A function to generate signature. + + The ``sign`` method accept 2 parameters:: + + def custom_sign_method(client, request): + # client is the instance of Client. + return 'your-signed-string' + + Client.register_signature_method('custom-name', custom_sign_method) + """ + cls.SIGNATURE_METHODS[name] = sign + + def __init__(self, client_id, client_secret=None, + token=None, token_secret=None, + redirect_uri=None, rsa_key=None, verifier=None, + signature_method=SIGNATURE_HMAC_SHA1, + signature_type=SIGNATURE_TYPE_HEADER, + realm=None, force_include_body=False): + self.client_id = client_id + self.client_secret = client_secret + self.token = token + self.token_secret = token_secret + self.redirect_uri = redirect_uri + self.signature_method = signature_method + self.signature_type = signature_type + self.rsa_key = rsa_key + self.verifier = verifier + self.realm = realm + self.force_include_body = force_include_body + + def get_oauth_signature(self, method, uri, headers, body): + """Get an OAuth signature to be used in signing a request + + To satisfy `section 3.4.1.2`_ item 2, if the request argument's + headers dict attribute contains a Host item, its value will + replace any netloc part of the request argument's uri attribute + value. + + .. _`section 3.4.1.2`: https://tools.ietf.org/html/rfc5849#section-3.4.1.2 + """ + sign = self.SIGNATURE_METHODS.get(self.signature_method) + if not sign: + raise ValueError('Invalid signature method.') + + request = OAuth1Request(method, uri, body=body, headers=headers) + return sign(self, request) + + def get_oauth_params(self, nonce, timestamp): + oauth_params = [ + ('oauth_nonce', nonce), + ('oauth_timestamp', timestamp), + ('oauth_version', '1.0'), + ('oauth_signature_method', self.signature_method), + ('oauth_consumer_key', self.client_id), + ] + if self.token: + oauth_params.append(('oauth_token', self.token)) + if self.redirect_uri: + oauth_params.append(('oauth_callback', self.redirect_uri)) + if self.verifier: + oauth_params.append(('oauth_verifier', self.verifier)) + return oauth_params + + def _render(self, uri, headers, body, oauth_params): + if self.signature_type == SIGNATURE_TYPE_HEADER: + headers = prepare_headers(oauth_params, headers, realm=self.realm) + elif self.signature_type == SIGNATURE_TYPE_BODY: + if CONTENT_TYPE_FORM_URLENCODED in headers.get('Content-Type', ''): + decoded_body = extract_params(body) or [] + body = prepare_form_encoded_body(oauth_params, decoded_body) + headers['Content-Type'] = CONTENT_TYPE_FORM_URLENCODED + elif self.signature_type == SIGNATURE_TYPE_QUERY: + uri = prepare_request_uri_query(oauth_params, uri) + else: + raise ValueError('Unknown signature type specified.') + return uri, headers, body + + def sign(self, method, uri, headers, body, nonce=None, timestamp=None): + """Sign the HTTP request, add OAuth parameters and signature. + + :param method: HTTP method of the request. + :param uri: URI of the HTTP request. + :param body: Body payload of the HTTP request. + :param headers: Headers of the HTTP request. + :param nonce: A string to represent nonce value. If not configured, + this method will generate one for you. + :param timestamp: Current timestamp. If not configured, this method + will generate one for you. + :return: uri, headers, body + """ + if nonce is None: + nonce = generate_nonce() + if timestamp is None: + timestamp = generate_timestamp() + if body is None: + body = '' + + # transform int to str + timestamp = str(timestamp) + + if headers is None: + headers = {} + + oauth_params = self.get_oauth_params(nonce, timestamp) + uri, headers, body = self._render(uri, headers, body, oauth_params) + + sig = self.get_oauth_signature(method, uri, headers, body) + oauth_params.append(('oauth_signature', sig)) + + uri, headers, body = self._render(uri, headers, body, oauth_params) + return uri, headers, body + + def prepare(self, method, uri, headers, body): + """Add OAuth parameters to the request. + + Parameters may be included from the body if the content-type is + urlencoded, if no content type is set, a guess is made. + """ + content_type = to_native(headers.get('Content-Type', '')) + if self.signature_type == SIGNATURE_TYPE_BODY: + content_type = CONTENT_TYPE_FORM_URLENCODED + elif not content_type and extract_params(body): + content_type = CONTENT_TYPE_FORM_URLENCODED + + if CONTENT_TYPE_FORM_URLENCODED in content_type: + headers['Content-Type'] = CONTENT_TYPE_FORM_URLENCODED + uri, headers, body = self.sign(method, uri, headers, body) + elif self.force_include_body: + # To allow custom clients to work on non form encoded bodies. + uri, headers, body = self.sign(method, uri, headers, body) + else: + # Omit body data in the signing of non form-encoded requests + uri, headers, _ = self.sign(method, uri, headers, '') + body = '' + return uri, headers, body + + +def generate_nonce(): + return generate_token() + + +def generate_timestamp(): + return str(int(time.time())) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/errors.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/errors.py new file mode 100644 index 0000000..1491833 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/errors.py @@ -0,0 +1,100 @@ +""" + authlib.oauth1.rfc5849.errors + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + RFC5849 has no definition on errors. This module is designed by + Authlib based on OAuth 1.0a `Section 10`_ with some changes. + + .. _`Section 10`: https://oauth.net/core/1.0a/#rfc.section.10 +""" +from authlib.common.errors import AuthlibHTTPError +from authlib.common.security import is_secure_transport + + +class OAuth1Error(AuthlibHTTPError): + def __init__(self, description=None, uri=None, status_code=None): + super(OAuth1Error, self).__init__(None, description, uri, status_code) + + def get_headers(self): + """Get a list of headers.""" + return [ + ('Content-Type', 'application/x-www-form-urlencoded'), + ('Cache-Control', 'no-store'), + ('Pragma', 'no-cache') + ] + + +class InsecureTransportError(OAuth1Error): + error = 'insecure_transport' + + def get_error_description(self): + return self.gettext('OAuth 2 MUST utilize https.') + + @classmethod + def check(cls, uri): + if not is_secure_transport(uri): + raise cls() + + +class InvalidRequestError(OAuth1Error): + error = 'invalid_request' + + +class UnsupportedParameterError(OAuth1Error): + error = 'unsupported_parameter' + + +class UnsupportedSignatureMethodError(OAuth1Error): + error = 'unsupported_signature_method' + + +class MissingRequiredParameterError(OAuth1Error): + error = 'missing_required_parameter' + + def __init__(self, key): + super(MissingRequiredParameterError, self).__init__() + self._key = key + + def get_error_description(self): + return self.gettext( + 'missing "%(key)s" in parameters') % dict(key=self._key) + + +class DuplicatedOAuthProtocolParameterError(OAuth1Error): + error = 'duplicated_oauth_protocol_parameter' + + +class InvalidClientError(OAuth1Error): + error = 'invalid_client' + status_code = 401 + + +class InvalidTokenError(OAuth1Error): + error = 'invalid_token' + status_code = 401 + + def get_error_description(self): + return self.gettext('Invalid or expired "oauth_token" in parameters') + + +class InvalidSignatureError(OAuth1Error): + error = 'invalid_signature' + status_code = 401 + + +class InvalidNonceError(OAuth1Error): + error = 'invalid_nonce' + status_code = 401 + + +class AccessDeniedError(OAuth1Error): + error = 'access_denied' + + def get_error_description(self): + return self.gettext( + 'The resource owner or authorization server denied the request') + + +class MethodNotAllowedError(OAuth1Error): + error = 'method_not_allowed' + status_code = 405 diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/models.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/models.py new file mode 100644 index 0000000..76befe9 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/models.py @@ -0,0 +1,109 @@ + +class ClientMixin(object): + def get_default_redirect_uri(self): + """A method to get client default redirect_uri. For instance, the + database table for client has a column called ``default_redirect_uri``:: + + def get_default_redirect_uri(self): + return self.default_redirect_uri + + :return: A URL string + """ + raise NotImplementedError() + + def get_client_secret(self): + """A method to return the client_secret of this client. For instance, + the database table has a column called ``client_secret``:: + + def get_client_secret(self): + return self.client_secret + """ + raise NotImplementedError() + + def get_rsa_public_key(self): + """A method to get the RSA public key for RSA-SHA1 signature method. + For instance, the value is saved on column ``rsa_public_key``:: + + def get_rsa_public_key(self): + return self.rsa_public_key + """ + raise NotImplementedError() + + +class TokenCredentialMixin(object): + def get_oauth_token(self): + """A method to get the value of ``oauth_token``. For instance, the + database table has a column called ``oauth_token``:: + + def get_oauth_token(self): + return self.oauth_token + + :return: A string + """ + raise NotImplementedError() + + def get_oauth_token_secret(self): + """A method to get the value of ``oauth_token_secret``. For instance, + the database table has a column called ``oauth_token_secret``:: + + def get_oauth_token_secret(self): + return self.oauth_token_secret + + :return: A string + """ + raise NotImplementedError() + + +class TemporaryCredentialMixin(TokenCredentialMixin): + def get_client_id(self): + """A method to get the client_id associated with this credential. + For instance, the table in the database has a column ``client_id``:: + + def get_client_id(self): + return self.client_id + """ + raise NotImplementedError() + + def get_redirect_uri(self): + """A method to get temporary credential's ``oauth_callback``. + For instance, the database table for temporary credential has a + column called ``oauth_callback``:: + + def get_redirect_uri(self): + return self.oauth_callback + + :return: A URL string + """ + raise NotImplementedError() + + def check_verifier(self, verifier): + """A method to check if the given verifier matches this temporary + credential. For instance that this temporary credential has recorded + the value in database as column ``oauth_verifier``:: + + def check_verifier(self, verifier): + return self.oauth_verifier == verifier + + :return: Boolean + """ + raise NotImplementedError() + + +class TemporaryCredential(dict, TemporaryCredentialMixin): + def get_client_id(self): + return self.get('client_id') + + def get_user_id(self): + return self.get('user_id') + + def get_redirect_uri(self): + return self.get('oauth_callback') + + def check_verifier(self, verifier): + return self.get('oauth_verifier') == verifier + + def get_oauth_token(self): + return self.get('oauth_token') + + def get_oauth_token_secret(self): + return self.get('oauth_token_secret') diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/parameters.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/parameters.py new file mode 100644 index 0000000..4746aea --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/parameters.py @@ -0,0 +1,103 @@ +# -*- coding: utf-8 -*- + +""" + authlib.spec.rfc5849.parameters + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + This module contains methods related to `section 3.5`_ of the OAuth 1.0a spec. + + .. _`section 3.5`: https://tools.ietf.org/html/rfc5849#section-3.5 +""" +from authlib.common.urls import urlparse, url_encode, extract_params +from .util import escape + + +def prepare_headers(oauth_params, headers=None, realm=None): + """**Prepare the Authorization header.** + Per `section 3.5.1`_ of the spec. + + Protocol parameters can be transmitted using the HTTP "Authorization" + header field as defined by `RFC2617`_ with the auth-scheme name set to + "OAuth" (case insensitive). + + For example:: + + Authorization: OAuth realm="Photos", + oauth_consumer_key="dpf43f3p2l4k3l03", + oauth_signature_method="HMAC-SHA1", + oauth_timestamp="137131200", + oauth_nonce="wIjqoS", + oauth_callback="http%3A%2F%2Fprinter.example.com%2Fready", + oauth_signature="74KNZJeDHnMBp0EMJ9ZHt%2FXKycU%3D", + oauth_version="1.0" + + .. _`section 3.5.1`: https://tools.ietf.org/html/rfc5849#section-3.5.1 + .. _`RFC2617`: https://tools.ietf.org/html/rfc2617 + """ + headers = headers or {} + + # step 1, 2, 3 in Section 3.5.1 + header_parameters = ', '.join([ + '{0}="{1}"'.format(escape(k), escape(v)) for k, v in oauth_params + if k.startswith('oauth_') + ]) + + # 4. The OPTIONAL "realm" parameter MAY be added and interpreted per + # `RFC2617 section 1.2`_. + # + # .. _`RFC2617 section 1.2`: https://tools.ietf.org/html/rfc2617#section-1.2 + if realm: + # NOTE: realm should *not* be escaped + header_parameters = 'realm="{}", '.format(realm) + header_parameters + + # the auth-scheme name set to "OAuth" (case insensitive). + headers['Authorization'] = 'OAuth {}'.format(header_parameters) + return headers + + +def _append_params(oauth_params, params): + """Append OAuth params to an existing set of parameters. + + Both params and oauth_params is must be lists of 2-tuples. + + Per `section 3.5.2`_ and `3.5.3`_ of the spec. + + .. _`section 3.5.2`: https://tools.ietf.org/html/rfc5849#section-3.5.2 + .. _`3.5.3`: https://tools.ietf.org/html/rfc5849#section-3.5.3 + + """ + merged = list(params) + merged.extend(oauth_params) + # The request URI / entity-body MAY include other request-specific + # parameters, in which case, the protocol parameters SHOULD be appended + # following the request-specific parameters, properly separated by an "&" + # character (ASCII code 38) + merged.sort(key=lambda i: i[0].startswith('oauth_')) + return merged + + +def prepare_form_encoded_body(oauth_params, body): + """Prepare the Form-Encoded Body. + + Per `section 3.5.2`_ of the spec. + + .. _`section 3.5.2`: https://tools.ietf.org/html/rfc5849#section-3.5.2 + + """ + # append OAuth params to the existing body + return url_encode(_append_params(oauth_params, body)) + + +def prepare_request_uri_query(oauth_params, uri): + """Prepare the Request URI Query. + + Per `section 3.5.3`_ of the spec. + + .. _`section 3.5.3`: https://tools.ietf.org/html/rfc5849#section-3.5.3 + + """ + # append OAuth params to the existing set of query components + sch, net, path, par, query, fra = urlparse.urlparse(uri) + query = url_encode( + _append_params(oauth_params, extract_params(query) or [])) + return urlparse.urlunparse((sch, net, path, par, query, fra)) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/resource_protector.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/resource_protector.py new file mode 100644 index 0000000..2b5d781 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/resource_protector.py @@ -0,0 +1,41 @@ +from .base_server import BaseServer +from .wrapper import OAuth1Request +from .errors import ( + MissingRequiredParameterError, + InvalidClientError, + InvalidTokenError, +) + + +class ResourceProtector(BaseServer): + def validate_request(self, method, uri, body, headers): + request = OAuth1Request(method, uri, body, headers) + + if not request.client_id: + raise MissingRequiredParameterError('oauth_consumer_key') + + client = self.get_client_by_id(request.client_id) + if not client: + raise InvalidClientError() + request.client = client + + if not request.token: + raise MissingRequiredParameterError('oauth_token') + + token = self.get_token_credential(request) + if not token: + raise InvalidTokenError() + + request.credential = token + self.validate_timestamp_and_nonce(request) + self.validate_oauth_signature(request) + return request + + def get_token_credential(self, request): + """Fetch the token credential from data store like a database, + framework should implement this function. + + :param request: OAuth1Request instance + :return: Token model instance + """ + raise NotImplementedError() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/rsa.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/rsa.py new file mode 100644 index 0000000..3785b0f --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/rsa.py @@ -0,0 +1,29 @@ +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives.serialization import ( + load_pem_private_key, load_pem_public_key +) +from cryptography.hazmat.primitives.asymmetric import padding +from cryptography.exceptions import InvalidSignature +from authlib.common.encoding import to_bytes + + +def sign_sha1(msg, rsa_private_key): + key = load_pem_private_key( + to_bytes(rsa_private_key), + password=None, + backend=default_backend() + ) + return key.sign(msg, padding.PKCS1v15(), hashes.SHA1()) + + +def verify_sha1(sig, msg, rsa_public_key): + key = load_pem_public_key( + to_bytes(rsa_public_key), + backend=default_backend() + ) + try: + key.verify(sig, msg, padding.PKCS1v15(), hashes.SHA1()) + return True + except InvalidSignature: + return False diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/signature.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/signature.py new file mode 100644 index 0000000..6ba67e2 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/signature.py @@ -0,0 +1,387 @@ +# -*- coding: utf-8 -*- +""" + authlib.oauth1.rfc5849.signature + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + This module represents a direct implementation of `section 3.4`_ of the spec. + + .. _`section 3.4`: https://tools.ietf.org/html/rfc5849#section-3.4 +""" +import binascii +import hashlib +import hmac +from authlib.common.urls import urlparse +from authlib.common.encoding import to_unicode, to_bytes +from .util import escape, unescape + +SIGNATURE_HMAC_SHA1 = "HMAC-SHA1" +SIGNATURE_RSA_SHA1 = "RSA-SHA1" +SIGNATURE_PLAINTEXT = "PLAINTEXT" + +SIGNATURE_TYPE_HEADER = 'HEADER' +SIGNATURE_TYPE_QUERY = 'QUERY' +SIGNATURE_TYPE_BODY = 'BODY' + + +def construct_base_string(method, uri, params, host=None): + """Generate signature base string from request, per `Section 3.4.1`_. + + For example, the HTTP request:: + + POST /request?b5=%3D%253D&a3=a&c%40=&a2=r%20b HTTP/1.1 + Host: example.com + Content-Type: application/x-www-form-urlencoded + Authorization: OAuth realm="Example", + oauth_consumer_key="9djdj82h48djs9d2", + oauth_token="kkk9d7dh3k39sjv7", + oauth_signature_method="HMAC-SHA1", + oauth_timestamp="137131201", + oauth_nonce="7d8f3e4a", + oauth_signature="bYT5CMsGcbgUdFHObYMEfcx6bsw%3D" + + c2&a3=2+q + + is represented by the following signature base string (line breaks + are for display purposes only):: + + POST&http%3A%2F%2Fexample.com%2Frequest&a2%3Dr%2520b%26a3%3D2%2520q + %26a3%3Da%26b5%3D%253D%25253D%26c%2540%3D%26c2%3D%26oauth_consumer_ + key%3D9djdj82h48djs9d2%26oauth_nonce%3D7d8f3e4a%26oauth_signature_m + ethod%3DHMAC-SHA1%26oauth_timestamp%3D137131201%26oauth_token%3Dkkk + 9d7dh3k39sjv7 + + .. _`Section 3.4.1`: https://tools.ietf.org/html/rfc5849#section-3.4.1 + """ + + # Create base string URI per Section 3.4.1.2 + base_string_uri = normalize_base_string_uri(uri, host) + + # Cleanup parameter sources per Section 3.4.1.3.1 + unescaped_params = [] + for k, v in params: + # The "oauth_signature" parameter MUST be excluded from the signature + if k in ('oauth_signature', 'realm'): + continue + + # ensure oauth params are unescaped + if k.startswith('oauth_'): + v = unescape(v) + unescaped_params.append((k, v)) + + # Normalize parameters per Section 3.4.1.3.2 + normalized_params = normalize_parameters(unescaped_params) + + # construct base string + return '&'.join([ + escape(method.upper()), + escape(base_string_uri), + escape(normalized_params), + ]) + + +def normalize_base_string_uri(uri, host=None): + """Normalize Base String URI per `Section 3.4.1.2`_. + + For example, the HTTP request:: + + GET /r%20v/X?id=123 HTTP/1.1 + Host: EXAMPLE.COM:80 + + is represented by the base string URI: "http://example.com/r%20v/X". + + In another example, the HTTPS request:: + + GET /?q=1 HTTP/1.1 + Host: www.example.net:8080 + + is represented by the base string URI: "https://www.example.net:8080/". + + .. _`Section 3.4.1.2`: https://tools.ietf.org/html/rfc5849#section-3.4.1.2 + + The host argument overrides the netloc part of the uri argument. + """ + uri = to_unicode(uri) + scheme, netloc, path, params, query, fragment = urlparse.urlparse(uri) + + # The scheme, authority, and path of the request resource URI `RFC3986` + # are included by constructing an "http" or "https" URI representing + # the request resource (without the query or fragment) as follows: + # + # .. _`RFC3986`: https://tools.ietf.org/html/rfc3986 + + if not scheme or not netloc: + raise ValueError('uri must include a scheme and netloc') + + # Per `RFC 2616 section 5.1.2`_: + # + # Note that the absolute path cannot be empty; if none is present in + # the original URI, it MUST be given as "/" (the server root). + # + # .. _`RFC 2616 section 5.1.2`: https://tools.ietf.org/html/rfc2616#section-5.1.2 + if not path: + path = '/' + + # 1. The scheme and host MUST be in lowercase. + scheme = scheme.lower() + netloc = netloc.lower() + + # 2. The host and port values MUST match the content of the HTTP + # request "Host" header field. + if host is not None: + netloc = host.lower() + + # 3. The port MUST be included if it is not the default port for the + # scheme, and MUST be excluded if it is the default. Specifically, + # the port MUST be excluded when making an HTTP request `RFC2616`_ + # to port 80 or when making an HTTPS request `RFC2818`_ to port 443. + # All other non-default port numbers MUST be included. + # + # .. _`RFC2616`: https://tools.ietf.org/html/rfc2616 + # .. _`RFC2818`: https://tools.ietf.org/html/rfc2818 + default_ports = ( + ('http', '80'), + ('https', '443'), + ) + if ':' in netloc: + host, port = netloc.split(':', 1) + if (scheme, port) in default_ports: + netloc = host + + return urlparse.urlunparse((scheme, netloc, path, params, '', '')) + + +def normalize_parameters(params): + """Normalize parameters per `Section 3.4.1.3.2`_. + + For example, the list of parameters from the previous section would + be normalized as follows: + + Encoded:: + + +------------------------+------------------+ + | Name | Value | + +------------------------+------------------+ + | b5 | %3D%253D | + | a3 | a | + | c%40 | | + | a2 | r%20b | + | oauth_consumer_key | 9djdj82h48djs9d2 | + | oauth_token | kkk9d7dh3k39sjv7 | + | oauth_signature_method | HMAC-SHA1 | + | oauth_timestamp | 137131201 | + | oauth_nonce | 7d8f3e4a | + | c2 | | + | a3 | 2%20q | + +------------------------+------------------+ + + Sorted:: + + +------------------------+------------------+ + | Name | Value | + +------------------------+------------------+ + | a2 | r%20b | + | a3 | 2%20q | + | a3 | a | + | b5 | %3D%253D | + | c%40 | | + | c2 | | + | oauth_consumer_key | 9djdj82h48djs9d2 | + | oauth_nonce | 7d8f3e4a | + | oauth_signature_method | HMAC-SHA1 | + | oauth_timestamp | 137131201 | + | oauth_token | kkk9d7dh3k39sjv7 | + +------------------------+------------------+ + + Concatenated Pairs:: + + +-------------------------------------+ + | Name=Value | + +-------------------------------------+ + | a2=r%20b | + | a3=2%20q | + | a3=a | + | b5=%3D%253D | + | c%40= | + | c2= | + | oauth_consumer_key=9djdj82h48djs9d2 | + | oauth_nonce=7d8f3e4a | + | oauth_signature_method=HMAC-SHA1 | + | oauth_timestamp=137131201 | + | oauth_token=kkk9d7dh3k39sjv7 | + +-------------------------------------+ + + and concatenated together into a single string (line breaks are for + display purposes only):: + + a2=r%20b&a3=2%20q&a3=a&b5=%3D%253D&c%40=&c2=&oauth_consumer_key=9dj + dj82h48djs9d2&oauth_nonce=7d8f3e4a&oauth_signature_method=HMAC-SHA1 + &oauth_timestamp=137131201&oauth_token=kkk9d7dh3k39sjv7 + + .. _`Section 3.4.1.3.2`: https://tools.ietf.org/html/rfc5849#section-3.4.1.3.2 + """ + + # 1. First, the name and value of each parameter are encoded + # (`Section 3.6`_). + # + # .. _`Section 3.6`: https://tools.ietf.org/html/rfc5849#section-3.6 + key_values = [(escape(k), escape(v)) for k, v in params] + + # 2. The parameters are sorted by name, using ascending byte value + # ordering. If two or more parameters share the same name, they + # are sorted by their value. + key_values.sort() + + # 3. The name of each parameter is concatenated to its corresponding + # value using an "=" character (ASCII code 61) as a separator, even + # if the value is empty. + parameter_parts = ['{0}={1}'.format(k, v) for k, v in key_values] + + # 4. The sorted name/value pairs are concatenated together into a + # single string by using an "&" character (ASCII code 38) as + # separator. + return '&'.join(parameter_parts) + + +def generate_signature_base_string(request): + """Generate signature base string from request.""" + host = request.headers.get('Host', None) + return construct_base_string( + request.method, request.uri, request.params, host) + + +def hmac_sha1_signature(base_string, client_secret, token_secret): + """Generate signature via HMAC-SHA1 method, per `Section 3.4.2`_. + + The "HMAC-SHA1" signature method uses the HMAC-SHA1 signature + algorithm as defined in `RFC2104`_:: + + digest = HMAC-SHA1 (key, text) + + .. _`RFC2104`: https://tools.ietf.org/html/rfc2104 + .. _`Section 3.4.2`: https://tools.ietf.org/html/rfc5849#section-3.4.2 + """ + + # The HMAC-SHA1 function variables are used in following way: + + # text is set to the value of the signature base string from + # `Section 3.4.1.1`_. + # + # .. _`Section 3.4.1.1`: https://tools.ietf.org/html/rfc5849#section-3.4.1.1 + text = base_string + + # key is set to the concatenated values of: + # 1. The client shared-secret, after being encoded (`Section 3.6`_). + # + # .. _`Section 3.6`: https://tools.ietf.org/html/rfc5849#section-3.6 + key = escape(client_secret or '') + + # 2. An "&" character (ASCII code 38), which MUST be included + # even when either secret is empty. + key += '&' + + # 3. The token shared-secret, after being encoded (`Section 3.6`_). + # + # .. _`Section 3.6`: https://tools.ietf.org/html/rfc5849#section-3.6 + key += escape(token_secret or '') + + signature = hmac.new(to_bytes(key), to_bytes(text), hashlib.sha1) + + # digest is used to set the value of the "oauth_signature" protocol + # parameter, after the result octet string is base64-encoded + # per `RFC2045, Section 6.8`. + # + # .. _`RFC2045, Section 6.8`: https://tools.ietf.org/html/rfc2045#section-6.8 + sig = binascii.b2a_base64(signature.digest())[:-1] + return to_unicode(sig) + + +def rsa_sha1_signature(base_string, rsa_private_key): + """Generate signature via RSA-SHA1 method, per `Section 3.4.3`_. + + The "RSA-SHA1" signature method uses the RSASSA-PKCS1-v1_5 signature + algorithm as defined in `RFC3447, Section 8.2`_ (also known as + PKCS#1), using SHA-1 as the hash function for EMSA-PKCS1-v1_5. To + use this method, the client MUST have established client credentials + with the server that included its RSA public key (in a manner that is + beyond the scope of this specification). + + .. _`Section 3.4.3`: https://tools.ietf.org/html/rfc5849#section-3.4.3 + .. _`RFC3447, Section 8.2`: https://tools.ietf.org/html/rfc3447#section-8.2 + """ + from .rsa import sign_sha1 + base_string = to_bytes(base_string) + s = sign_sha1(to_bytes(base_string), rsa_private_key) + sig = binascii.b2a_base64(s)[:-1] + return to_unicode(sig) + + +def plaintext_signature(client_secret, token_secret): + """Generate signature via PLAINTEXT method, per `Section 3.4.4`_. + + The "PLAINTEXT" method does not employ a signature algorithm. It + MUST be used with a transport-layer mechanism such as TLS or SSL (or + sent over a secure channel with equivalent protections). It does not + utilize the signature base string or the "oauth_timestamp" and + "oauth_nonce" parameters. + + .. _`Section 3.4.4`: https://tools.ietf.org/html/rfc5849#section-3.4.4 + """ + + # The "oauth_signature" protocol parameter is set to the concatenated + # value of: + + # 1. The client shared-secret, after being encoded (`Section 3.6`_). + # + # .. _`Section 3.6`: https://tools.ietf.org/html/rfc5849#section-3.6 + signature = escape(client_secret or '') + + # 2. An "&" character (ASCII code 38), which MUST be included even + # when either secret is empty. + signature += '&' + + # 3. The token shared-secret, after being encoded (`Section 3.6`_). + # + # .. _`Section 3.6`: https://tools.ietf.org/html/rfc5849#section-3.6 + signature += escape(token_secret or '') + + return signature + + +def sign_hmac_sha1(client, request): + """Sign a HMAC-SHA1 signature.""" + base_string = generate_signature_base_string(request) + return hmac_sha1_signature( + base_string, client.client_secret, client.token_secret) + + +def sign_rsa_sha1(client, request): + """Sign a RSASSA-PKCS #1 v1.5 base64 encoded signature.""" + base_string = generate_signature_base_string(request) + return rsa_sha1_signature(base_string, client.rsa_key) + + +def sign_plaintext(client, request): + """Sign a PLAINTEXT signature.""" + return plaintext_signature(client.client_secret, client.token_secret) + + +def verify_hmac_sha1(request): + """Verify a HMAC-SHA1 signature.""" + base_string = generate_signature_base_string(request) + sig = hmac_sha1_signature( + base_string, request.client_secret, request.token_secret) + return hmac.compare_digest(sig, request.signature) + + +def verify_rsa_sha1(request): + """Verify a RSASSA-PKCS #1 v1.5 base64 encoded signature.""" + from .rsa import verify_sha1 + base_string = generate_signature_base_string(request) + sig = binascii.a2b_base64(to_bytes(request.signature)) + return verify_sha1(sig, to_bytes(base_string), request.rsa_public_key) + + +def verify_plaintext(request): + """Verify a PLAINTEXT signature.""" + sig = plaintext_signature(request.client_secret, request.token_secret) + return hmac.compare_digest(sig, request.signature) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/util.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/util.py new file mode 100644 index 0000000..9383e22 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/util.py @@ -0,0 +1,9 @@ +from authlib.common.urls import quote, unquote + + +def escape(s): + return quote(s, safe=b'~') + + +def unescape(s): + return unquote(s) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/wrapper.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/wrapper.py new file mode 100644 index 0000000..9f889a3 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth1/rfc5849/wrapper.py @@ -0,0 +1,129 @@ +from authlib.common.urls import ( + urlparse, extract_params, url_decode, + parse_http_list, parse_keqv_list, +) +from .signature import ( + SIGNATURE_TYPE_QUERY, + SIGNATURE_TYPE_BODY, + SIGNATURE_TYPE_HEADER +) +from .errors import ( + InsecureTransportError, + DuplicatedOAuthProtocolParameterError +) +from .util import unescape + + +class OAuth1Request(object): + def __init__(self, method, uri, body=None, headers=None): + InsecureTransportError.check(uri) + self.method = method + self.uri = uri + self.body = body + self.headers = headers or {} + + # states namespaces + self.client = None + self.credential = None + self.user = None + + self.query = urlparse.urlparse(uri).query + self.query_params = url_decode(self.query) + self.body_params = extract_params(body) or [] + + self.auth_params, self.realm = _parse_authorization_header(headers) + self.signature_type, self.oauth_params = _parse_oauth_params( + self.query_params, self.body_params, self.auth_params) + + params = [] + params.extend(self.query_params) + params.extend(self.body_params) + params.extend(self.auth_params) + self.params = params + + @property + def client_id(self): + return self.oauth_params.get('oauth_consumer_key') + + @property + def client_secret(self): + if self.client: + return self.client.get_client_secret() + + @property + def rsa_public_key(self): + if self.client: + return self.client.get_rsa_public_key() + + @property + def timestamp(self): + return self.oauth_params.get('oauth_timestamp') + + @property + def redirect_uri(self): + return self.oauth_params.get('oauth_callback') + + @property + def signature(self): + return self.oauth_params.get('oauth_signature') + + @property + def signature_method(self): + return self.oauth_params.get('oauth_signature_method') + + @property + def token(self): + return self.oauth_params.get('oauth_token') + + @property + def token_secret(self): + if self.credential: + return self.credential.get_oauth_token_secret() + + +def _filter_oauth(params): + for k, v in params: + if k.startswith('oauth_'): + yield (k, v) + + +def _parse_authorization_header(headers): + """Parse an OAuth authorization header into a list of 2-tuples""" + authorization_header = headers.get('Authorization') + if not authorization_header: + return [], None + + auth_scheme = 'oauth ' + if authorization_header.lower().startswith(auth_scheme): + items = parse_http_list(authorization_header[len(auth_scheme):]) + try: + items = parse_keqv_list(items).items() + auth_params = [(unescape(k), unescape(v)) for k, v in items] + realm = dict(auth_params).get('realm') + return auth_params, realm + except (IndexError, ValueError): + pass + raise ValueError('Malformed authorization header') + + +def _parse_oauth_params(query_params, body_params, auth_params): + oauth_params_set = [ + (SIGNATURE_TYPE_QUERY, list(_filter_oauth(query_params))), + (SIGNATURE_TYPE_BODY, list(_filter_oauth(body_params))), + (SIGNATURE_TYPE_HEADER, list(_filter_oauth(auth_params))) + ] + oauth_params_set = [params for params in oauth_params_set if params[1]] + if len(oauth_params_set) > 1: + found_types = [p[0] for p in oauth_params_set] + raise DuplicatedOAuthProtocolParameterError( + '"oauth_" params must come from only 1 signature type ' + 'but were found in {}'.format(','.join(found_types)) + ) + + if oauth_params_set: + signature_type = oauth_params_set[0][0] + oauth_params = dict(oauth_params_set[0][1]) + else: + signature_type = None + oauth_params = {} + return signature_type, oauth_params diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/__init__.py new file mode 100644 index 0000000..23dea91 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/__init__.py @@ -0,0 +1,16 @@ +from .base import OAuth2Error +from .auth import ClientAuth, TokenAuth +from .client import OAuth2Client +from .rfc6749 import ( + OAuth2Request, + HttpRequest, + AuthorizationServer, + ClientAuthentication, + ResourceProtector, +) + +__all__ = [ + 'OAuth2Error', 'ClientAuth', 'TokenAuth', 'OAuth2Client', + 'OAuth2Request', 'HttpRequest', 'AuthorizationServer', + 'ClientAuthentication', 'ResourceProtector', +] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/auth.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/auth.py new file mode 100644 index 0000000..1d7a655 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/auth.py @@ -0,0 +1,105 @@ +import base64 +from authlib.common.urls import add_params_to_qs, add_params_to_uri +from authlib.common.encoding import to_bytes, to_native +from .rfc6749 import OAuth2Token +from .rfc6750 import add_bearer_token + + +def encode_client_secret_basic(client, method, uri, headers, body): + text = '{}:{}'.format(client.client_id, client.client_secret) + auth = to_native(base64.urlsafe_b64encode(to_bytes(text, 'latin1'))) + headers['Authorization'] = 'Basic {}'.format(auth) + return uri, headers, body + + +def encode_client_secret_post(client, method, uri, headers, body): + body = add_params_to_qs(body or '', [ + ('client_id', client.client_id), + ('client_secret', client.client_secret or '') + ]) + if 'Content-Length' in headers: + headers['Content-Length'] = str(len(body)) + return uri, headers, body + + +def encode_none(client, method, uri, headers, body): + if method == 'GET': + uri = add_params_to_uri(uri, [('client_id', client.client_id)]) + return uri, headers, body + body = add_params_to_qs(body, [('client_id', client.client_id)]) + if 'Content-Length' in headers: + headers['Content-Length'] = str(len(body)) + return uri, headers, body + + +class ClientAuth(object): + """Attaches OAuth Client Information to HTTP requests. + + :param client_id: Client ID, which you get from client registration. + :param client_secret: Client Secret, which you get from registration. + :param auth_method: Client auth method for token endpoint. The supported + methods for now: + + * client_secret_basic (default) + * client_secret_post + * none + """ + DEFAULT_AUTH_METHODS = { + 'client_secret_basic': encode_client_secret_basic, + 'client_secret_post': encode_client_secret_post, + 'none': encode_none, + } + + def __init__(self, client_id, client_secret, auth_method=None): + if auth_method is None: + auth_method = 'client_secret_basic' + + self.client_id = client_id + self.client_secret = client_secret + + if auth_method in self.DEFAULT_AUTH_METHODS: + auth_method = self.DEFAULT_AUTH_METHODS[auth_method] + + self.auth_method = auth_method + + def prepare(self, method, uri, headers, body): + return self.auth_method(self, method, uri, headers, body) + + +class TokenAuth(object): + """Attach token information to HTTP requests. + + :param token: A dict or OAuth2Token instance of an OAuth 2.0 token + :param token_placement: The placement of the token, default is ``header``, + available choices: + + * header (default) + * body + * uri + """ + DEFAULT_TOKEN_TYPE = 'bearer' + SIGN_METHODS = { + 'bearer': add_bearer_token + } + + def __init__(self, token, token_placement='header', client=None): + self.token = OAuth2Token.from_dict(token) + self.token_placement = token_placement + self.client = client + self.hooks = set() + + def set_token(self, token): + self.token = OAuth2Token.from_dict(token) + + def prepare(self, uri, headers, body): + token_type = self.token.get('token_type', self.DEFAULT_TOKEN_TYPE) + sign = self.SIGN_METHODS[token_type.lower()] + uri, headers, body = sign( + self.token['access_token'], + uri, headers, body, + self.token_placement) + + for hook in self.hooks: + uri, headers, body = hook(uri, headers, body) + + return uri, headers, body diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/base.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/base.py new file mode 100644 index 0000000..5fea8e0 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/base.py @@ -0,0 +1,27 @@ +from authlib.common.errors import AuthlibHTTPError +from authlib.common.urls import add_params_to_uri + + +class OAuth2Error(AuthlibHTTPError): + def __init__(self, description=None, uri=None, + status_code=None, state=None, + redirect_uri=None, redirect_fragment=False, error=None): + super(OAuth2Error, self).__init__(error, description, uri, status_code) + self.state = state + self.redirect_uri = redirect_uri + self.redirect_fragment = redirect_fragment + + def get_body(self): + """Get a list of body.""" + error = super(OAuth2Error, self).get_body() + if self.state: + error.append(('state', self.state)) + return error + + def __call__(self, translations=None, error_uris=None): + if self.redirect_uri: + params = self.get_body() + loc = add_params_to_uri( + self.redirect_uri, params, self.redirect_fragment) + return 302, '', [('Location', loc)] + return super(OAuth2Error, self).__call__(translations, error_uris) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/client.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/client.py new file mode 100644 index 0000000..2720d46 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/client.py @@ -0,0 +1,415 @@ +from authlib.common.security import generate_token +from authlib.common.urls import url_decode +from authlib.common.encoding import text_types +from .rfc6749.parameters import ( + prepare_grant_uri, + prepare_token_request, + parse_authorization_code_response, + parse_implicit_response, +) +from .rfc7009 import prepare_revoke_token_request +from .rfc7636 import create_s256_code_challenge +from .auth import TokenAuth, ClientAuth + +DEFAULT_HEADERS = { + 'Accept': 'application/json', + 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' +} + + +class OAuth2Client(object): + """Construct a new OAuth 2 protocol client. + + :param session: Requests session object to communicate with + authorization server. + :param client_id: Client ID, which you get from client registration. + :param client_secret: Client Secret, which you get from registration. + :param token_endpoint_auth_method: client authentication method for + token endpoint. + :param revocation_endpoint_auth_method: client authentication method for + revocation endpoint. + :param scope: Scope that you needed to access user resources. + :param redirect_uri: Redirect URI you registered as callback. + :param code_challenge_method: PKCE method name, only S256 is supported. + :param token: A dict of token attributes such as ``access_token``, + ``token_type`` and ``expires_at``. + :param token_placement: The place to put token in HTTP request. Available + values: "header", "body", "uri". + :param update_token: A function for you to update token. It accept a + :class:`OAuth2Token` as parameter. + """ + client_auth_class = ClientAuth + token_auth_class = TokenAuth + + EXTRA_AUTHORIZE_PARAMS = ( + 'response_mode', 'nonce', 'prompt', 'login_hint' + ) + SESSION_REQUEST_PARAMS = [] + + def __init__(self, session, client_id=None, client_secret=None, + token_endpoint_auth_method=None, + revocation_endpoint_auth_method=None, + scope=None, redirect_uri=None, code_challenge_method=None, + token=None, token_placement='header', update_token=None, **metadata): + + self.session = session + self.client_id = client_id + self.client_secret = client_secret + + if token_endpoint_auth_method is None: + if client_secret: + token_endpoint_auth_method = 'client_secret_basic' + else: + token_endpoint_auth_method = 'none' + + self.token_endpoint_auth_method = token_endpoint_auth_method + + if revocation_endpoint_auth_method is None: + if client_secret: + revocation_endpoint_auth_method = 'client_secret_basic' + else: + revocation_endpoint_auth_method = 'none' + + self.revocation_endpoint_auth_method = revocation_endpoint_auth_method + + self.scope = scope + self.redirect_uri = redirect_uri + self.code_challenge_method = code_challenge_method + + self.token_auth = self.token_auth_class(token, token_placement, self) + self.update_token = update_token + + token_updater = metadata.pop('token_updater', None) + if token_updater: + raise ValueError('update token has been redesigned, checkout the documentation') + + self.metadata = metadata + + self.compliance_hook = { + 'access_token_response': set(), + 'refresh_token_request': set(), + 'refresh_token_response': set(), + 'revoke_token_request': set(), + 'introspect_token_request': set(), + } + self._auth_methods = {} + + def register_client_auth_method(self, auth): + """Extend client authenticate for token endpoint. + + :param auth: an instance to sign the request + """ + if isinstance(auth, tuple): + self._auth_methods[auth[0]] = auth[1] + else: + self._auth_methods[auth.name] = auth + + def client_auth(self, auth_method): + if isinstance(auth_method, text_types) and auth_method in self._auth_methods: + auth_method = self._auth_methods[auth_method] + return self.client_auth_class( + client_id=self.client_id, + client_secret=self.client_secret, + auth_method=auth_method, + ) + + @property + def token(self): + return self.token_auth.token + + @token.setter + def token(self, token): + self.token_auth.set_token(token) + + def create_authorization_url(self, url, state=None, code_verifier=None, **kwargs): + """Generate an authorization URL and state. + + :param url: Authorization endpoint url, must be HTTPS. + :param state: An optional state string for CSRF protection. If not + given it will be generated for you. + :param code_verifier: An optional code_verifier for code challenge. + :param kwargs: Extra parameters to include. + :return: authorization_url, state + """ + if state is None: + state = generate_token() + + response_type = self.metadata.get('response_type', 'code') + response_type = kwargs.pop('response_type', response_type) + if 'redirect_uri' not in kwargs: + kwargs['redirect_uri'] = self.redirect_uri + if 'scope' not in kwargs: + kwargs['scope'] = self.scope + + if code_verifier and response_type == 'code' and self.code_challenge_method == 'S256': + kwargs['code_challenge'] = create_s256_code_challenge(code_verifier) + kwargs['code_challenge_method'] = self.code_challenge_method + + for k in self.EXTRA_AUTHORIZE_PARAMS: + if k not in kwargs and k in self.metadata: + kwargs[k] = self.metadata[k] + + uri = prepare_grant_uri( + url, client_id=self.client_id, response_type=response_type, + state=state, **kwargs) + return uri, state + + def fetch_token(self, url=None, body='', method='POST', headers=None, + auth=None, grant_type=None, **kwargs): + """Generic method for fetching an access token from the token endpoint. + + :param url: Access Token endpoint URL, if not configured, + ``authorization_response`` is used to extract token from + its fragment (implicit way). + :param body: Optional application/x-www-form-urlencoded body to add the + include in the token request. Prefer kwargs over body. + :param method: The HTTP method used to make the request. Defaults + to POST, but may also be GET. Other methods should + be added as needed. + :param headers: Dict to default request headers with. + :param auth: An auth tuple or method as accepted by requests. + :param grant_type: Use specified grant_type to fetch token + :return: A :class:`OAuth2Token` object (a dict too). + """ + # implicit grant_type + authorization_response = kwargs.pop('authorization_response', None) + if authorization_response and '#' in authorization_response: + return self.token_from_fragment(authorization_response, kwargs.get('state')) + + session_kwargs = self._extract_session_request_params(kwargs) + + if authorization_response and 'code=' in authorization_response: + grant_type = 'authorization_code' + params = parse_authorization_code_response( + authorization_response, + state=kwargs.get('state'), + ) + kwargs['code'] = params['code'] + + if grant_type is None: + grant_type = self.metadata.get('grant_type') + + body = self._prepare_token_endpoint_body(body, grant_type, **kwargs) + + if auth is None: + auth = self.client_auth(self.token_endpoint_auth_method) + + if headers is None: + headers = DEFAULT_HEADERS + + if url is None: + url = self.metadata.get('token_endpoint') + + return self._fetch_token( + url, body=body, auth=auth, method=method, + headers=headers, **session_kwargs + ) + + def _fetch_token(self, url, body='', headers=None, auth=None, + method='POST', **kwargs): + if method == 'GET': + if '?' in url: + url = '&'.join([url, body]) + else: + url = '?'.join([url, body]) + body = '' + + if headers is None: + headers = DEFAULT_HEADERS + + resp = self.session.request( + method, url, data=body, headers=headers, auth=auth, **kwargs) + + for hook in self.compliance_hook['access_token_response']: + resp = hook(resp) + + return self.parse_response_token(resp.json()) + + def token_from_fragment(self, authorization_response, state=None): + token = parse_implicit_response(authorization_response, state) + return self.parse_response_token(token) + + def refresh_token(self, url, refresh_token=None, body='', + auth=None, headers=None, **kwargs): + """Fetch a new access token using a refresh token. + + :param url: Refresh Token endpoint, must be HTTPS. + :param refresh_token: The refresh_token to use. + :param body: Optional application/x-www-form-urlencoded body to add the + include in the token request. Prefer kwargs over body. + :param auth: An auth tuple or method as accepted by requests. + :param headers: Dict to default request headers with. + :return: A :class:`OAuth2Token` object (a dict too). + """ + session_kwargs = self._extract_session_request_params(kwargs) + refresh_token = refresh_token or self.token.get('refresh_token') + if 'scope' not in kwargs and self.scope: + kwargs['scope'] = self.scope + body = prepare_token_request( + 'refresh_token', body, + refresh_token=refresh_token, **kwargs + ) + + if headers is None: + headers = DEFAULT_HEADERS + + for hook in self.compliance_hook['refresh_token_request']: + url, headers, body = hook(url, headers, body) + + if auth is None: + auth = self.client_auth(self.token_endpoint_auth_method) + + return self._refresh_token( + url, refresh_token=refresh_token, body=body, headers=headers, + auth=auth, **session_kwargs) + + def _refresh_token(self, url, refresh_token=None, body='', headers=None, + auth=None, **kwargs): + resp = self.session.post( + url, data=dict(url_decode(body)), headers=headers, + auth=auth, **kwargs) + + for hook in self.compliance_hook['refresh_token_response']: + resp = hook(resp) + + token = self.parse_response_token(resp.json()) + if 'refresh_token' not in token: + self.token['refresh_token'] = refresh_token + + if callable(self.update_token): + self.update_token(self.token, refresh_token=refresh_token) + + return self.token + + def revoke_token(self, url, token=None, token_type_hint=None, + body=None, auth=None, headers=None, **kwargs): + """Revoke token method defined via `RFC7009`_. + + :param url: Revoke Token endpoint, must be HTTPS. + :param token: The token to be revoked. + :param token_type_hint: The type of the token that to be revoked. + It can be "access_token" or "refresh_token". + :param body: Optional application/x-www-form-urlencoded body to add the + include in the token request. Prefer kwargs over body. + :param auth: An auth tuple or method as accepted by requests. + :param headers: Dict to default request headers with. + :return: Revocation Response + + .. _`RFC7009`: https://tools.ietf.org/html/rfc7009 + """ + return self._handle_token_hint( + 'revoke_token_request', url, + token=token, token_type_hint=token_type_hint, + body=body, auth=auth, headers=headers, **kwargs) + + def introspect_token(self, url, token=None, token_type_hint=None, + body=None, auth=None, headers=None, **kwargs): + """Implementation of OAuth 2.0 Token Introspection defined via `RFC7662`_. + + :param url: Introspection Endpoint, must be HTTPS. + :param token: The token to be introspected. + :param token_type_hint: The type of the token that to be revoked. + It can be "access_token" or "refresh_token". + :param body: Optional application/x-www-form-urlencoded body to add the + include in the token request. Prefer kwargs over body. + :param auth: An auth tuple or method as accepted by requests. + :param headers: Dict to default request headers with. + :return: Introspection Response + + .. _`RFC7662`: https://tools.ietf.org/html/rfc7662 + """ + return self._handle_token_hint( + 'introspect_token_request', url, + token=token, token_type_hint=token_type_hint, + body=body, auth=auth, headers=headers, **kwargs) + + def _handle_token_hint(self, hook, url, token=None, token_type_hint=None, + body=None, auth=None, headers=None, **kwargs): + if token is None and self.token: + token = self.token.get('refresh_token') or self.token.get('access_token') + + if body is None: + body = '' + + body, headers = prepare_revoke_token_request( + token, token_type_hint, body, headers) + + for hook in self.compliance_hook[hook]: + url, headers, body = hook(url, headers, body) + + if auth is None: + auth = self.client_auth(self.revocation_endpoint_auth_method) + + session_kwargs = self._extract_session_request_params(kwargs) + return self._http_post( + url, body, auth=auth, headers=headers, **session_kwargs) + + def _http_post(self, url, body=None, auth=None, headers=None, **kwargs): + return self.session.post( + url, data=dict(url_decode(body)), + headers=headers, auth=auth, **kwargs) + + def register_compliance_hook(self, hook_type, hook): + """Register a hook for request/response tweaking. + + Available hooks are: + + * access_token_response: invoked before token parsing. + * refresh_token_request: invoked before refreshing token. + * refresh_token_response: invoked before refresh token parsing. + * protected_request: invoked before making a request. + * revoke_token_request: invoked before revoking a token. + * introspect_token_request: invoked before introspecting a token. + """ + if hook_type == 'protected_request': + self.token_auth.hooks.add(hook) + return + + if hook_type not in self.compliance_hook: + raise ValueError('Hook type %s is not in %s.', + hook_type, self.compliance_hook) + self.compliance_hook[hook_type].add(hook) + + def parse_response_token(self, token): + if 'error' not in token: + self.token = token + return self.token + + error = token['error'] + description = token.get('error_description', error) + self.handle_error(error, description) + + def _prepare_token_endpoint_body(self, body, grant_type, **kwargs): + if grant_type is None: + grant_type = _guess_grant_type(kwargs) + + if grant_type == 'authorization_code': + if 'redirect_uri' not in kwargs: + kwargs['redirect_uri'] = self.redirect_uri + return prepare_token_request(grant_type, body, **kwargs) + + if 'scope' not in kwargs and self.scope: + kwargs['scope'] = self.scope + return prepare_token_request(grant_type, body, **kwargs) + + def _extract_session_request_params(self, kwargs): + """Extract parameters for session object from the passing ``**kwargs``.""" + rv = {} + for k in self.SESSION_REQUEST_PARAMS: + if k in kwargs: + rv[k] = kwargs.pop(k) + return rv + + @staticmethod + def handle_error(error_type, error_description): + raise ValueError('{}: {}'.format(error_type, error_description)) + + +def _guess_grant_type(kwargs): + if 'code' in kwargs: + grant_type = 'authorization_code' + elif 'username' in kwargs and 'password' in kwargs: + grant_type = 'password' + else: + grant_type = 'client_credentials' + return grant_type diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/__init__.py new file mode 100644 index 0000000..2994f4f --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/__init__.py @@ -0,0 +1,77 @@ +# -*- coding: utf-8 -*- +""" + authlib.oauth2.rfc6749 + ~~~~~~~~~~~~~~~~~~~~~~ + + This module represents a direct implementation of + The OAuth 2.0 Authorization Framework. + + https://tools.ietf.org/html/rfc6749 +""" + +from .wrappers import OAuth2Request, OAuth2Token, HttpRequest +from .errors import ( + OAuth2Error, + AccessDeniedError, + MissingAuthorizationError, + InvalidGrantError, + InvalidClientError, + InvalidRequestError, + InvalidScopeError, + InsecureTransportError, + UnauthorizedClientError, + UnsupportedGrantTypeError, + UnsupportedTokenTypeError, + # exceptions for clients + MissingCodeException, + MissingTokenException, + MissingTokenTypeException, + MismatchingStateException, +) +from .models import ClientMixin, AuthorizationCodeMixin, TokenMixin +from .authenticate_client import ClientAuthentication +from .authorization_server import AuthorizationServer +from .resource_protector import ResourceProtector +from .token_endpoint import TokenEndpoint +from .grants import ( + BaseGrant, + AuthorizationEndpointMixin, + TokenEndpointMixin, + AuthorizationCodeGrant, + ImplicitGrant, + ResourceOwnerPasswordCredentialsGrant, + ClientCredentialsGrant, + RefreshTokenGrant, +) + +__all__ = [ + 'OAuth2Request', 'OAuth2Token', 'HttpRequest', + 'OAuth2Error', + 'AccessDeniedError', + 'MissingAuthorizationError', + 'InvalidGrantError', + 'InvalidClientError', + 'InvalidRequestError', + 'InvalidScopeError', + 'InsecureTransportError', + 'UnauthorizedClientError', + 'UnsupportedGrantTypeError', + 'UnsupportedTokenTypeError', + 'MissingCodeException', + 'MissingTokenException', + 'MissingTokenTypeException', + 'MismatchingStateException', + 'ClientMixin', 'AuthorizationCodeMixin', 'TokenMixin', + 'ClientAuthentication', + 'AuthorizationServer', + 'ResourceProtector', + 'TokenEndpoint', + 'BaseGrant', + 'AuthorizationEndpointMixin', + 'TokenEndpointMixin', + 'AuthorizationCodeGrant', + 'ImplicitGrant', + 'ResourceOwnerPasswordCredentialsGrant', + 'ClientCredentialsGrant', + 'RefreshTokenGrant', +] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/authenticate_client.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/authenticate_client.py new file mode 100644 index 0000000..d21289a --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/authenticate_client.py @@ -0,0 +1,124 @@ +""" + authlib.oauth2.rfc6749.authenticate_client + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Registry of client authentication methods, with 3 built-in methods: + + 1. client_secret_basic + 2. client_secret_post + 3. none + + The "client_secret_basic" method is used a lot in examples of `RFC6749`_, + but the concept of naming are introduced in `RFC7591`_. + + .. _`RFC6749`: https://tools.ietf.org/html/rfc6749 + .. _`RFC7591`: https://tools.ietf.org/html/rfc7591 +""" + +import logging +from .errors import InvalidClientError +from .util import extract_basic_authorization + +log = logging.getLogger(__name__) + +__all__ = ['ClientAuthentication'] + + +class ClientAuthentication(object): + def __init__(self, query_client): + self.query_client = query_client + self._methods = { + 'none': authenticate_none, + 'client_secret_basic': authenticate_client_secret_basic, + 'client_secret_post': authenticate_client_secret_post, + } + + def register(self, method, func): + self._methods[method] = func + + def authenticate(self, request, methods): + for method in methods: + func = self._methods[method] + client = func(self.query_client, request) + if client: + request.auth_method = method + return client + + if 'client_secret_basic' in methods: + raise InvalidClientError(state=request.state, status_code=401) + raise InvalidClientError(state=request.state) + + def __call__(self, request, methods): + return self.authenticate(request, methods) + + +def authenticate_client_secret_basic(query_client, request): + """Authenticate client by ``client_secret_basic`` method. The client + uses HTTP Basic for authentication. + """ + client_id, client_secret = extract_basic_authorization(request.headers) + if client_id and client_secret: + client = _validate_client(query_client, client_id, request.state, 401) + if client.check_token_endpoint_auth_method('client_secret_basic') \ + and client.check_client_secret(client_secret): + log.debug( + 'Authenticate %s via "client_secret_basic" ' + 'success', client_id + ) + return client + log.debug( + 'Authenticate %s via "client_secret_basic" ' + 'failed', client_id + ) + + +def authenticate_client_secret_post(query_client, request): + """Authenticate client by ``client_secret_post`` method. The client + uses POST parameters for authentication. + """ + data = request.form + client_id = data.get('client_id') + client_secret = data.get('client_secret') + if client_id and client_secret: + client = _validate_client(query_client, client_id, request.state) + if client.check_token_endpoint_auth_method('client_secret_post') \ + and client.check_client_secret(client_secret): + log.debug( + 'Authenticate %s via "client_secret_post" ' + 'success', client_id + ) + return client + log.debug( + 'Authenticate %s via "client_secret_post" ' + 'failed', client_id + ) + + +def authenticate_none(query_client, request): + """Authenticate public client by ``none`` method. The client + does not have a client secret. + """ + client_id = request.client_id + if client_id and 'client_secret' not in request.data: + client = _validate_client(query_client, client_id, request.state) + if client.check_token_endpoint_auth_method('none'): + log.debug( + 'Authenticate %s via "none" ' + 'success', client_id + ) + return client + log.debug( + 'Authenticate {} via "none" ' + 'failed'.format(client_id) + ) + + +def _validate_client(query_client, client_id, state=None, status_code=400): + if client_id is None: + raise InvalidClientError(state=state, status_code=status_code) + + client = query_client(client_id) + if not client: + raise InvalidClientError(state=state, status_code=status_code) + + return client diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/authorization_server.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/authorization_server.py new file mode 100644 index 0000000..c1f3ddc --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/authorization_server.py @@ -0,0 +1,240 @@ +from .authenticate_client import ClientAuthentication +from .errors import ( + OAuth2Error, + InvalidGrantError, + InvalidScopeError, + UnsupportedGrantTypeError, +) +from .util import scope_to_list + + +class AuthorizationServer(object): + """Authorization server that handles Authorization Endpoint and Token + Endpoint. + + :param query_client: A function to get client by client_id. The client + model class MUST implement the methods described by + :class:`~authlib.oauth2.rfc6749.ClientMixin`. + :param save_token: A method to save tokens. + :param generate_token: A method to generate tokens. + :param metadata: A dict of Authorization Server Metadata + """ + def __init__(self, query_client, save_token, generate_token=None, metadata=None): + self.query_client = query_client + self.save_token = save_token + self.generate_token = generate_token + + self.metadata = metadata + self._client_auth = None + self._authorization_grants = [] + self._token_grants = [] + self._endpoints = {} + + def authenticate_client(self, request, methods): + """Authenticate client via HTTP request information with the given + methods, such as ``client_secret_basic``, ``client_secret_post``. + """ + if self._client_auth is None and self.query_client: + self._client_auth = ClientAuthentication(self.query_client) + return self._client_auth(request, methods) + + def register_client_auth_method(self, method, func): + """Add more client auth method. The default methods are: + + * none: The client is a public client and does not have a client secret + * client_secret_post: The client uses the HTTP POST parameters + * client_secret_basic: The client uses HTTP Basic + + :param method: Name of the Auth method + :param func: Function to authenticate the client + + The auth method accept two parameters: ``query_client`` and ``request``, + an example for this method:: + + def authenticate_client_via_custom(query_client, request): + client_id = request.headers['X-Client-Id'] + client = query_client(client_id) + do_some_validation(client) + return client + + authorization_server.register_client_auth_method( + 'custom', authenticate_client_via_custom) + """ + if self._client_auth is None and self.query_client: + self._client_auth = ClientAuthentication(self.query_client) + + self._client_auth.register(method, func) + + def get_translations(self, request): + """Return a translations instance used for i18n error messages. + Framework SHOULD implement this function. + """ + return None + + def get_error_uris(self, request): + """Return a dict of error uris mapping. Framework SHOULD implement + this function. + """ + return None + + def send_signal(self, name, *args, **kwargs): + """Framework integration can re-implement this method to support + signal system. + """ + pass + + def create_oauth2_request(self, request): + """This method MUST be implemented in framework integrations. It is + used to create an OAuth2Request instance. + + :param request: the "request" instance in framework + :return: OAuth2Request instance + """ + raise NotImplementedError() + + def create_json_request(self, request): + """This method MUST be implemented in framework integrations. It is + used to create an HttpRequest instance. + + :param request: the "request" instance in framework + :return: HttpRequest instance + """ + raise NotImplementedError() + + def handle_response(self, status, body, headers): + """Return HTTP response. Framework MUST implement this function.""" + raise NotImplementedError() + + def validate_requested_scope(self, scope, state=None): + """Validate if requested scope is supported by Authorization Server. + Developers CAN re-write this method to meet your needs. + """ + if scope and self.metadata: + scopes_supported = self.metadata.get('scopes_supported') + scopes = set(scope_to_list(scope)) + if scopes_supported and not set(scopes_supported).issuperset(scopes): + raise InvalidScopeError(state=state) + + def register_grant(self, grant_cls, extensions=None): + """Register a grant class into the endpoint registry. Developers + can implement the grants in ``authlib.oauth2.rfc6749.grants`` and + register with this method:: + + class AuthorizationCodeGrant(grants.AuthorizationCodeGrant): + def authenticate_user(self, credential): + # ... + + authorization_server.register_grant(AuthorizationCodeGrant) + + :param grant_cls: a grant class. + :param extensions: extensions for the grant class. + """ + if hasattr(grant_cls, 'check_authorization_endpoint'): + self._authorization_grants.append((grant_cls, extensions)) + if hasattr(grant_cls, 'check_token_endpoint'): + self._token_grants.append((grant_cls, extensions)) + + def register_endpoint(self, endpoint_cls): + """Add extra endpoint to authorization server. e.g. + RevocationEndpoint:: + + authorization_server.register_endpoint(RevocationEndpoint) + + :param endpoint_cls: A endpoint class + """ + self._endpoints[endpoint_cls.ENDPOINT_NAME] = endpoint_cls(self) + + def get_authorization_grant(self, request): + """Find the authorization grant for current request. + + :param request: OAuth2Request instance. + :return: grant instance + """ + for (grant_cls, extensions) in self._authorization_grants: + if grant_cls.check_authorization_endpoint(request): + return _create_grant(grant_cls, extensions, request, self) + raise InvalidGrantError( + 'Response type {!r} is not supported'.format(request.response_type)) + + def get_token_grant(self, request): + """Find the token grant for current request. + + :param request: OAuth2Request instance. + :return: grant instance + """ + for (grant_cls, extensions) in self._token_grants: + if grant_cls.check_token_endpoint(request) and \ + request.method in grant_cls.TOKEN_ENDPOINT_HTTP_METHODS: + return _create_grant(grant_cls, extensions, request, self) + raise UnsupportedGrantTypeError( + 'Grant type {!r} is not supported'.format(request.grant_type)) + + def create_endpoint_response(self, name, request=None): + """Validate endpoint request and create endpoint response. + + :param name: Endpoint name + :param request: HTTP request instance. + :return: Response + """ + if name not in self._endpoints: + raise RuntimeError('There is no "{}" endpoint.'.format(name)) + + endpoint = self._endpoints[name] + request = endpoint.create_endpoint_request(request) + try: + return self.handle_response(*endpoint(request)) + except OAuth2Error as error: + return self.handle_error_response(request, error) + + def create_authorization_response(self, request=None, grant_user=None): + """Validate authorization request and create authorization response. + + :param request: HTTP request instance. + :param grant_user: if granted, it is resource owner. If denied, + it is None. + :returns: Response + """ + request = self.create_oauth2_request(request) + try: + grant = self.get_authorization_grant(request) + except InvalidGrantError as error: + return self.handle_error_response(request, error) + + try: + redirect_uri = grant.validate_authorization_request() + args = grant.create_authorization_response(redirect_uri, grant_user) + return self.handle_response(*args) + except OAuth2Error as error: + return self.handle_error_response(request, error) + + def create_token_response(self, request=None): + """Validate token request and create token response. + + :param request: HTTP request instance + """ + request = self.create_oauth2_request(request) + try: + grant = self.get_token_grant(request) + except UnsupportedGrantTypeError as error: + return self.handle_error_response(request, error) + + try: + grant.validate_token_request() + args = grant.create_token_response() + return self.handle_response(*args) + except OAuth2Error as error: + return self.handle_error_response(request, error) + + def handle_error_response(self, request, error): + return self.handle_response(*error( + translations=self.get_translations(request), + error_uris=self.get_error_uris(request) + )) + + +def _create_grant(grant_cls, extensions, request, server): + grant = grant_cls(request, server) + if extensions: + for ext in extensions: + ext(grant) + return grant diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/errors.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/errors.py new file mode 100644 index 0000000..c2612aa --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/errors.py @@ -0,0 +1,200 @@ +""" + authlib.oauth2.rfc6749.errors + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Implementation for OAuth 2 Error Response. A basic error has + parameters: + + error + REQUIRED. A single ASCII [USASCII] error code. + + error_description + OPTIONAL. Human-readable ASCII [USASCII] text providing + additional information, used to assist the client developer in + understanding the error that occurred. + + error_uri + OPTIONAL. A URI identifying a human-readable web page with + information about the error, used to provide the client + developer with additional information about the error. + Values for the "error_uri" parameter MUST conform to the + URI-reference syntax and thus MUST NOT include characters + outside the set %x21 / %x23-5B / %x5D-7E. + + state + REQUIRED if a "state" parameter was present in the client + authorization request. The exact value received from the + client. + + https://tools.ietf.org/html/rfc6749#section-5.2 + + :copyright: (c) 2017 by Hsiaoming Yang. +""" +from authlib.oauth2.base import OAuth2Error +from authlib.common.security import is_secure_transport + +__all__ = [ + 'OAuth2Error', + 'InsecureTransportError', 'InvalidRequestError', + 'InvalidClientError', 'InvalidGrantError', + 'UnauthorizedClientError', 'UnsupportedGrantTypeError', + 'InvalidScopeError', 'AccessDeniedError', + 'MissingAuthorizationError', 'UnsupportedTokenTypeError', + 'MissingCodeException', 'MissingTokenException', + 'MissingTokenTypeException', 'MismatchingStateException', +] + + +class InsecureTransportError(OAuth2Error): + error = 'insecure_transport' + + def get_error_description(self): + return self.gettext('OAuth 2 MUST utilize https.') + + @classmethod + def check(cls, uri): + """Check and raise InsecureTransportError with the given URI.""" + if not is_secure_transport(uri): + raise cls() + + +class InvalidRequestError(OAuth2Error): + """The request is missing a required parameter, includes an + unsupported parameter value (other than grant type), + repeats a parameter, includes multiple credentials, + utilizes more than one mechanism for authenticating the + client, or is otherwise malformed. + + https://tools.ietf.org/html/rfc6749#section-5.2 + """ + error = 'invalid_request' + + +class InvalidClientError(OAuth2Error): + """Client authentication failed (e.g., unknown client, no + client authentication included, or unsupported + authentication method). The authorization server MAY + return an HTTP 401 (Unauthorized) status code to indicate + which HTTP authentication schemes are supported. If the + client attempted to authenticate via the "Authorization" + request header field, the authorization server MUST + respond with an HTTP 401 (Unauthorized) status code and + include the "WWW-Authenticate" response header field + matching the authentication scheme used by the client. + + https://tools.ietf.org/html/rfc6749#section-5.2 + """ + error = 'invalid_client' + status_code = 400 + + def get_headers(self): + headers = super(InvalidClientError, self).get_headers() + if self.status_code == 401: + error_description = self.get_error_description() + # safe escape + error_description = error_description.replace('"', '|') + extras = [ + 'error="{}"'.format(self.error), + 'error_description="{}"'.format(error_description) + ] + headers.append( + ('WWW-Authenticate', 'Basic ' + ', '.join(extras)) + ) + return headers + + +class InvalidGrantError(OAuth2Error): + """The provided authorization grant (e.g., authorization + code, resource owner credentials) or refresh token is + invalid, expired, revoked, does not match the redirection + URI used in the authorization request, or was issued to + another client. + + https://tools.ietf.org/html/rfc6749#section-5.2 + """ + error = 'invalid_grant' + + +class UnauthorizedClientError(OAuth2Error): + """ The authenticated client is not authorized to use this + authorization grant type. + + https://tools.ietf.org/html/rfc6749#section-5.2 + """ + error = 'unauthorized_client' + + +class UnsupportedGrantTypeError(OAuth2Error): + """The authorization grant type is not supported by the + authorization server. + + https://tools.ietf.org/html/rfc6749#section-5.2 + """ + error = 'unsupported_grant_type' + + +class InvalidScopeError(OAuth2Error): + """The requested scope is invalid, unknown, malformed, or + exceeds the scope granted by the resource owner. + + https://tools.ietf.org/html/rfc6749#section-5.2 + """ + error = 'invalid_scope' + + def get_error_description(self): + return self.gettext( + 'The requested scope is invalid, unknown, or malformed.') + + +class AccessDeniedError(OAuth2Error): + """The resource owner or authorization server denied the request. + + Used in authorization endpoint for "code" and "implicit". Defined in + `Section 4.1.2.1`_. + + .. _`Section 4.1.2.1`: https://tools.ietf.org/html/rfc6749#section-4.1.2.1 + """ + error = 'access_denied' + + def get_error_description(self): + return self.gettext( + 'The resource owner or authorization server denied the request') + + +# -- below are extended errors -- # + + +class MissingAuthorizationError(OAuth2Error): + error = 'missing_authorization' + status_code = 401 + + def get_error_description(self): + return self.gettext('Missing "Authorization" in headers.') + + +class UnsupportedTokenTypeError(OAuth2Error): + error = 'unsupported_token_type' + status_code = 401 + + +# -- exceptions for clients -- # + + +class MissingCodeException(OAuth2Error): + error = 'missing_code' + description = 'Missing "code" in response.' + + +class MissingTokenException(OAuth2Error): + error = 'missing_token' + description = 'Missing "access_token" in response.' + + +class MissingTokenTypeException(OAuth2Error): + error = 'missing_token_type' + description = 'Missing "token_type" in response.' + + +class MismatchingStateException(OAuth2Error): + error = 'mismatching_state' + description = 'CSRF Warning! State not equal in request and response.' diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/__init__.py new file mode 100644 index 0000000..b179756 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/__init__.py @@ -0,0 +1,37 @@ +""" + authlib.oauth2.rfc6749.grants + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Implementation for `Section 4`_ of "Obtaining Authorization". + + To request an access token, the client obtains authorization from the + resource owner. The authorization is expressed in the form of an + authorization grant, which the client uses to request the access + token. OAuth defines four grant types: + + 1. authorization code + 2. implicit + 3. resource owner password credentials + 4. client credentials. + + It also provides an extension mechanism for defining additional grant + types. Authlib defines refresh_token as a grant type too. + + .. _`Section 4`: https://tools.ietf.org/html/rfc6749#section-4 +""" + +# flake8: noqa + +from .base import BaseGrant, AuthorizationEndpointMixin, TokenEndpointMixin +from .authorization_code import AuthorizationCodeGrant +from .implicit import ImplicitGrant +from .resource_owner_password_credentials import ResourceOwnerPasswordCredentialsGrant +from .client_credentials import ClientCredentialsGrant +from .refresh_token import RefreshTokenGrant + +__all__ = [ + 'BaseGrant', 'AuthorizationEndpointMixin', 'TokenEndpointMixin', + 'AuthorizationCodeGrant', 'ImplicitGrant', + 'ResourceOwnerPasswordCredentialsGrant', + 'ClientCredentialsGrant', 'RefreshTokenGrant', +] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/authorization_code.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/authorization_code.py new file mode 100644 index 0000000..10599cb --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/authorization_code.py @@ -0,0 +1,384 @@ +import logging +from authlib.deprecate import deprecate +from authlib.common.urls import add_params_to_uri +from authlib.common.security import generate_token +from .base import BaseGrant, AuthorizationEndpointMixin, TokenEndpointMixin +from ..errors import ( + OAuth2Error, + UnauthorizedClientError, + InvalidClientError, + InvalidRequestError, + AccessDeniedError, +) + +log = logging.getLogger(__name__) + + +class AuthorizationCodeGrant(BaseGrant, AuthorizationEndpointMixin, TokenEndpointMixin): + """The authorization code grant type is used to obtain both access + tokens and refresh tokens and is optimized for confidential clients. + Since this is a redirection-based flow, the client must be capable of + interacting with the resource owner's user-agent (typically a web + browser) and capable of receiving incoming requests (via redirection) + from the authorization server:: + + +----------+ + | Resource | + | Owner | + | | + +----------+ + ^ + | + (B) + +----|-----+ Client Identifier +---------------+ + | -+----(A)-- & Redirection URI ---->| | + | User- | | Authorization | + | Agent -+----(B)-- User authenticates --->| Server | + | | | | + | -+----(C)-- Authorization Code ---<| | + +-|----|---+ +---------------+ + | | ^ v + (A) (C) | | + | | | | + ^ v | | + +---------+ | | + | |>---(D)-- Authorization Code ---------' | + | Client | & Redirection URI | + | | | + | |<---(E)----- Access Token -------------------' + +---------+ (w/ Optional Refresh Token) + """ + #: Allowed client auth methods for token endpoint + TOKEN_ENDPOINT_AUTH_METHODS = ['client_secret_basic', 'client_secret_post'] + + #: Generated "code" length + AUTHORIZATION_CODE_LENGTH = 48 + + RESPONSE_TYPES = {'code'} + GRANT_TYPE = 'authorization_code' + + def validate_authorization_request(self): + """The client constructs the request URI by adding the following + parameters to the query component of the authorization endpoint URI + using the "application/x-www-form-urlencoded" format. + Per `Section 4.1.1`_. + + response_type + REQUIRED. Value MUST be set to "code". + + client_id + REQUIRED. The client identifier as described in Section 2.2. + + redirect_uri + OPTIONAL. As described in Section 3.1.2. + + scope + OPTIONAL. The scope of the access request as described by + Section 3.3. + + state + RECOMMENDED. An opaque value used by the client to maintain + state between the request and callback. The authorization + server includes this value when redirecting the user-agent back + to the client. The parameter SHOULD be used for preventing + cross-site request forgery as described in Section 10.12. + + The client directs the resource owner to the constructed URI using an + HTTP redirection response, or by other means available to it via the + user-agent. + + For example, the client directs the user-agent to make the following + HTTP request using TLS (with extra line breaks for display purposes + only): + + .. code-block:: http + + GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz + &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1 + Host: server.example.com + + The authorization server validates the request to ensure that all + required parameters are present and valid. If the request is valid, + the authorization server authenticates the resource owner and obtains + an authorization decision (by asking the resource owner or by + establishing approval via other means). + + .. _`Section 4.1.1`: https://tools.ietf.org/html/rfc6749#section-4.1.1 + """ + return validate_code_authorization_request(self) + + def create_authorization_response(self, redirect_uri, grant_user): + """If the resource owner grants the access request, the authorization + server issues an authorization code and delivers it to the client by + adding the following parameters to the query component of the + redirection URI using the "application/x-www-form-urlencoded" format. + Per `Section 4.1.2`_. + + code + REQUIRED. The authorization code generated by the + authorization server. The authorization code MUST expire + shortly after it is issued to mitigate the risk of leaks. A + maximum authorization code lifetime of 10 minutes is + RECOMMENDED. The client MUST NOT use the authorization code + more than once. If an authorization code is used more than + once, the authorization server MUST deny the request and SHOULD + revoke (when possible) all tokens previously issued based on + that authorization code. The authorization code is bound to + the client identifier and redirection URI. + state + REQUIRED if the "state" parameter was present in the client + authorization request. The exact value received from the + client. + + For example, the authorization server redirects the user-agent by + sending the following HTTP response. + + .. code-block:: http + + HTTP/1.1 302 Found + Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA + &state=xyz + + .. _`Section 4.1.2`: https://tools.ietf.org/html/rfc6749#section-4.1.2 + + :param redirect_uri: Redirect to the given URI for the authorization + :param grant_user: if resource owner granted the request, pass this + resource owner, otherwise pass None. + :returns: (status_code, body, headers) + """ + if not grant_user: + raise AccessDeniedError(state=self.request.state, redirect_uri=redirect_uri) + + self.request.user = grant_user + if hasattr(self, 'create_authorization_code'): # pragma: no cover + deprecate('Use "generate_authorization_code" instead', '1.0') + client = self.request.client + code = self.create_authorization_code(client, grant_user, self.request) + else: + code = self.generate_authorization_code() + self.save_authorization_code(code, self.request) + + params = [('code', code)] + if self.request.state: + params.append(('state', self.request.state)) + uri = add_params_to_uri(redirect_uri, params) + headers = [('Location', uri)] + return 302, '', headers + + def validate_token_request(self): + """The client makes a request to the token endpoint by sending the + following parameters using the "application/x-www-form-urlencoded" + format per `Section 4.1.3`_: + + grant_type + REQUIRED. Value MUST be set to "authorization_code". + + code + REQUIRED. The authorization code received from the + authorization server. + + redirect_uri + REQUIRED, if the "redirect_uri" parameter was included in the + authorization request as described in Section 4.1.1, and their + values MUST be identical. + + client_id + REQUIRED, if the client is not authenticating with the + authorization server as described in Section 3.2.1. + + If the client type is confidential or the client was issued client + credentials (or assigned other authentication requirements), the + client MUST authenticate with the authorization server as described + in Section 3.2.1. + + For example, the client makes the following HTTP request using TLS: + + .. code-block:: http + + POST /token HTTP/1.1 + Host: server.example.com + Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW + Content-Type: application/x-www-form-urlencoded + + grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA + &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb + + .. _`Section 4.1.3`: https://tools.ietf.org/html/rfc6749#section-4.1.3 + """ + # ignore validate for grant_type, since it is validated by + # check_token_endpoint + + # authenticate the client if client authentication is included + client = self.authenticate_token_endpoint_client() + + log.debug('Validate token request of %r', client) + if not client.check_grant_type(self.GRANT_TYPE): + raise UnauthorizedClientError() + + code = self.request.form.get('code') + if code is None: + raise InvalidRequestError('Missing "code" in request.') + + # ensure that the authorization code was issued to the authenticated + # confidential client, or if the client is public, ensure that the + # code was issued to "client_id" in the request + authorization_code = self.query_authorization_code(code, client) + if not authorization_code: + raise InvalidRequestError('Invalid "code" in request.') + + # validate redirect_uri parameter + log.debug('Validate token redirect_uri of %r', client) + redirect_uri = self.request.redirect_uri + original_redirect_uri = authorization_code.get_redirect_uri() + if original_redirect_uri and redirect_uri != original_redirect_uri: + raise InvalidRequestError('Invalid "redirect_uri" in request.') + + # save for create_token_response + self.request.client = client + self.request.credential = authorization_code + self.execute_hook('after_validate_token_request') + + def create_token_response(self): + """If the access token request is valid and authorized, the + authorization server issues an access token and optional refresh + token as described in Section 5.1. If the request client + authentication failed or is invalid, the authorization server returns + an error response as described in Section 5.2. Per `Section 4.1.4`_. + + An example successful response: + + .. code-block:: http + + HTTP/1.1 200 OK + Content-Type: application/json + Cache-Control: no-store + Pragma: no-cache + + { + "access_token":"2YotnFZFEjr1zCsicMWpAA", + "token_type":"example", + "expires_in":3600, + "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", + "example_parameter":"example_value" + } + + :returns: (status_code, body, headers) + + .. _`Section 4.1.4`: https://tools.ietf.org/html/rfc6749#section-4.1.4 + """ + client = self.request.client + authorization_code = self.request.credential + + user = self.authenticate_user(authorization_code) + if not user: + raise InvalidRequestError('There is no "user" for this code.') + + scope = authorization_code.get_scope() + token = self.generate_token( + user=user, + scope=scope, + include_refresh_token=client.check_grant_type('refresh_token'), + ) + log.debug('Issue token %r to %r', token, client) + + self.request.user = user + self.save_token(token) + self.execute_hook('process_token', token=token) + self.delete_authorization_code(authorization_code) + return 200, token, self.TOKEN_RESPONSE_HEADER + + def generate_authorization_code(self): + """"The method to generate "code" value for authorization code data. + Developers may rewrite this method, or customize the code length with:: + + class MyAuthorizationCodeGrant(AuthorizationCodeGrant): + AUTHORIZATION_CODE_LENGTH = 32 # default is 48 + """ + return generate_token(self.AUTHORIZATION_CODE_LENGTH) + + def save_authorization_code(self, code, request): + """Save authorization_code for later use. Developers MUST implement + it in subclass. Here is an example:: + + def save_authorization_code(self, code, request): + client = request.client + item = AuthorizationCode( + code=code, + client_id=client.client_id, + redirect_uri=request.redirect_uri, + scope=request.scope, + user_id=request.user.id, + ) + item.save() + """ + raise NotImplementedError() + + def query_authorization_code(self, code, client): # pragma: no cover + """Get authorization_code from previously savings. Developers MUST + implement it in subclass:: + + def query_authorization_code(self, code, client): + return Authorization.get(code=code, client_id=client.client_id) + + :param code: a string represent the code. + :param client: client related to this code. + :return: authorization_code object + """ + if hasattr(self, 'parse_authorization_code'): + deprecate('Use "query_authorization_code" instead', '1.0') + return self.parse_authorization_code(code, client) + raise NotImplementedError() + + def delete_authorization_code(self, authorization_code): + """Delete authorization code from database or cache. Developers MUST + implement it in subclass, e.g.:: + + def delete_authorization_code(self, authorization_code): + authorization_code.delete() + + :param authorization_code: the instance of authorization_code + """ + raise NotImplementedError() + + def authenticate_user(self, authorization_code): + """Authenticate the user related to this authorization_code. Developers + MUST implement this method in subclass, e.g.:: + + def authenticate_user(self, authorization_code): + return User.query.get(authorization_code.user_id) + + :param authorization_code: AuthorizationCode object + :return: user + """ + raise NotImplementedError() + + +def validate_code_authorization_request(grant): + client_id = grant.request.client_id + log.debug('Validate authorization request of %r', client_id) + + if client_id is None: + raise InvalidClientError(state=grant.request.state) + + client = grant.server.query_client(client_id) + if not client: + raise InvalidClientError(state=grant.request.state) + + redirect_uri = grant.validate_authorization_redirect_uri(grant.request, client) + response_type = grant.request.response_type + if not client.check_response_type(response_type): + raise UnauthorizedClientError( + 'The client is not authorized to use ' + '"response_type={}"'.format(response_type), + state=grant.request.state, + redirect_uri=redirect_uri, + ) + + try: + grant.request.client = client + grant.validate_requested_scope() + grant.execute_hook('after_validate_authorization_request') + except OAuth2Error as error: + error.redirect_uri = redirect_uri + raise error + return redirect_uri diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/base.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/base.py new file mode 100644 index 0000000..9fe03c9 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/base.py @@ -0,0 +1,151 @@ +from authlib.consts import default_json_headers +from ..errors import InvalidRequestError + + +class BaseGrant(object): + #: Allowed client auth methods for token endpoint + TOKEN_ENDPOINT_AUTH_METHODS = ['client_secret_basic'] + + #: Designed for which "grant_type" + GRANT_TYPE = None + + # NOTE: there is no charset for application/json, since + # application/json should always in UTF-8. + # The example on RFC is incorrect. + # https://tools.ietf.org/html/rfc4627 + TOKEN_RESPONSE_HEADER = default_json_headers + + def __init__(self, request, server): + self.request = request + self.server = server + self._hooks = { + 'after_validate_authorization_request': set(), + 'after_validate_consent_request': set(), + 'after_validate_token_request': set(), + 'process_token': set(), + } + + @property + def client(self): + return self.request.client + + def generate_token(self, user=None, scope=None, grant_type=None, + expires_in=None, include_refresh_token=True): + + if grant_type is None: + grant_type = self.GRANT_TYPE + + client = self.request.client + if scope is not None: + scope = client.get_allowed_scope(scope) + + return self.server.generate_token( + client=client, + grant_type=grant_type, + user=user, + scope=scope, + expires_in=expires_in, + include_refresh_token=include_refresh_token, + ) + + def authenticate_token_endpoint_client(self): + """Authenticate client with the given methods for token endpoint. + + For example, the client makes the following HTTP request using TLS: + + .. code-block:: http + + POST /token HTTP/1.1 + Host: server.example.com + Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW + Content-Type: application/x-www-form-urlencoded + + grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA + &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb + + Default available methods are: "none", "client_secret_basic" and + "client_secret_post". + + :return: client + """ + client = self.server.authenticate_client( + self.request, + self.TOKEN_ENDPOINT_AUTH_METHODS) + self.server.send_signal( + 'after_authenticate_client', + client=client, grant=self) + return client + + def save_token(self, token): + """A method to save token into database.""" + return self.server.save_token(token, self.request) + + def validate_requested_scope(self): + """Validate if requested scope is supported by Authorization Server.""" + scope = self.request.scope + state = self.request.state + return self.server.validate_requested_scope(scope, state) + + def register_hook(self, hook_type, hook): + if hook_type not in self._hooks: + raise ValueError('Hook type %s is not in %s.', + hook_type, self._hooks) + self._hooks[hook_type].add(hook) + + def execute_hook(self, hook_type, *args, **kwargs): + for hook in self._hooks[hook_type]: + hook(self, *args, **kwargs) + + +class TokenEndpointMixin(object): + #: Allowed HTTP methods of this token endpoint + TOKEN_ENDPOINT_HTTP_METHODS = ['POST'] + + #: Designed for which "grant_type" + GRANT_TYPE = None + + @classmethod + def check_token_endpoint(cls, request): + return request.grant_type == cls.GRANT_TYPE + + def validate_token_request(self): + raise NotImplementedError() + + def create_token_response(self): + raise NotImplementedError() + + +class AuthorizationEndpointMixin(object): + RESPONSE_TYPES = set() + ERROR_RESPONSE_FRAGMENT = False + + @classmethod + def check_authorization_endpoint(cls, request): + return request.response_type in cls.RESPONSE_TYPES + + @staticmethod + def validate_authorization_redirect_uri(request, client): + if request.redirect_uri: + if not client.check_redirect_uri(request.redirect_uri): + raise InvalidRequestError( + 'Redirect URI {!r} is not supported by client.'.format(request.redirect_uri), + state=request.state, + ) + return request.redirect_uri + else: + redirect_uri = client.get_default_redirect_uri() + if not redirect_uri: + raise InvalidRequestError( + 'Missing "redirect_uri" in request.' + ) + return redirect_uri + + def validate_consent_request(self): + redirect_uri = self.validate_authorization_request() + self.execute_hook('after_validate_consent_request', redirect_uri) + + def validate_authorization_request(self): + raise NotImplementedError() + + def create_authorization_response(self, redirect_uri, grant_user): + raise NotImplementedError() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/client_credentials.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/client_credentials.py new file mode 100644 index 0000000..784a370 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/client_credentials.py @@ -0,0 +1,103 @@ +import logging +from .base import BaseGrant, TokenEndpointMixin +from ..errors import UnauthorizedClientError + +log = logging.getLogger(__name__) + + +class ClientCredentialsGrant(BaseGrant, TokenEndpointMixin): + """The client can request an access token using only its client + credentials (or other supported means of authentication) when the + client is requesting access to the protected resources under its + control, or those of another resource owner that have been previously + arranged with the authorization server. + + The client credentials grant type MUST only be used by confidential + clients:: + + +---------+ +---------------+ + | | | | + | |>--(A)- Client Authentication --->| Authorization | + | Client | | Server | + | |<--(B)---- Access Token ---------<| | + | | | | + +---------+ +---------------+ + + https://tools.ietf.org/html/rfc6749#section-4.4 + """ + GRANT_TYPE = 'client_credentials' + + def validate_token_request(self): + """The client makes a request to the token endpoint by adding the + following parameters using the "application/x-www-form-urlencoded" + format per Appendix B with a character encoding of UTF-8 in the HTTP + request entity-body: + + grant_type + REQUIRED. Value MUST be set to "client_credentials". + + scope + OPTIONAL. The scope of the access request as described by + Section 3.3. + + The client MUST authenticate with the authorization server as + described in Section 3.2.1. + + For example, the client makes the following HTTP request using + transport-layer security (with extra line breaks for display purposes + only): + + .. code-block:: http + + POST /token HTTP/1.1 + Host: server.example.com + Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW + Content-Type: application/x-www-form-urlencoded + + grant_type=client_credentials + + The authorization server MUST authenticate the client. + """ + + # ignore validate for grant_type, since it is validated by + # check_token_endpoint + client = self.authenticate_token_endpoint_client() + log.debug('Validate token request of %r', client) + + if not client.check_grant_type(self.GRANT_TYPE): + raise UnauthorizedClientError() + + self.request.client = client + self.validate_requested_scope() + + def create_token_response(self): + """If the access token request is valid and authorized, the + authorization server issues an access token as described in + Section 5.1. A refresh token SHOULD NOT be included. If the request + failed client authentication or is invalid, the authorization server + returns an error response as described in Section 5.2. + + An example successful response: + + .. code-block:: http + + HTTP/1.1 200 OK + Content-Type: application/json + Cache-Control: no-store + Pragma: no-cache + + { + "access_token":"2YotnFZFEjr1zCsicMWpAA", + "token_type":"example", + "expires_in":3600, + "example_parameter":"example_value" + } + + :returns: (status_code, body, headers) + """ + client = self.request.client + token = self.generate_token(scope=self.request.scope, include_refresh_token=False) + log.debug('Issue token %r to %r', token, client) + self.save_token(token) + self.execute_hook('process_token', self, token=token) + return 200, token, self.TOKEN_RESPONSE_HEADER diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/implicit.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/implicit.py new file mode 100644 index 0000000..75b12be --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/implicit.py @@ -0,0 +1,229 @@ +import logging +from authlib.common.urls import add_params_to_uri +from .base import BaseGrant, AuthorizationEndpointMixin +from ..errors import ( + OAuth2Error, + UnauthorizedClientError, + AccessDeniedError, +) + +log = logging.getLogger(__name__) + + +class ImplicitGrant(BaseGrant, AuthorizationEndpointMixin): + """The implicit grant type is used to obtain access tokens (it does not + support the issuance of refresh tokens) and is optimized for public + clients known to operate a particular redirection URI. These clients + are typically implemented in a browser using a scripting language + such as JavaScript. + + Since this is a redirection-based flow, the client must be capable of + interacting with the resource owner's user-agent (typically a web + browser) and capable of receiving incoming requests (via redirection) + from the authorization server. + + Unlike the authorization code grant type, in which the client makes + separate requests for authorization and for an access token, the + client receives the access token as the result of the authorization + request. + + The implicit grant type does not include client authentication, and + relies on the presence of the resource owner and the registration of + the redirection URI. Because the access token is encoded into the + redirection URI, it may be exposed to the resource owner and other + applications residing on the same device:: + + +----------+ + | Resource | + | Owner | + | | + +----------+ + ^ + | + (B) + +----|-----+ Client Identifier +---------------+ + | -+----(A)-- & Redirection URI --->| | + | User- | | Authorization | + | Agent -|----(B)-- User authenticates -->| Server | + | | | | + | |<---(C)--- Redirection URI ----<| | + | | with Access Token +---------------+ + | | in Fragment + | | +---------------+ + | |----(D)--- Redirection URI ---->| Web-Hosted | + | | without Fragment | Client | + | | | Resource | + | (F) |<---(E)------- Script ---------<| | + | | +---------------+ + +-|--------+ + | | + (A) (G) Access Token + | | + ^ v + +---------+ + | | + | Client | + | | + +---------+ + """ + #: authorization_code grant type has authorization endpoint + AUTHORIZATION_ENDPOINT = True + #: Allowed client auth methods for token endpoint + TOKEN_ENDPOINT_AUTH_METHODS = ['none'] + + RESPONSE_TYPES = {'token'} + GRANT_TYPE = 'implicit' + ERROR_RESPONSE_FRAGMENT = True + + def validate_authorization_request(self): + """The client constructs the request URI by adding the following + parameters to the query component of the authorization endpoint URI + using the "application/x-www-form-urlencoded" format. + Per `Section 4.2.1`_. + + response_type + REQUIRED. Value MUST be set to "token". + + client_id + REQUIRED. The client identifier as described in Section 2.2. + + redirect_uri + OPTIONAL. As described in Section 3.1.2. + + scope + OPTIONAL. The scope of the access request as described by + Section 3.3. + + state + RECOMMENDED. An opaque value used by the client to maintain + state between the request and callback. The authorization + server includes this value when redirecting the user-agent back + to the client. The parameter SHOULD be used for preventing + cross-site request forgery as described in Section 10.12. + + The client directs the resource owner to the constructed URI using an + HTTP redirection response, or by other means available to it via the + user-agent. + + For example, the client directs the user-agent to make the following + HTTP request using TLS: + + .. code-block:: http + + GET /authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz + &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1 + Host: server.example.com + + .. _`Section 4.2.1`: https://tools.ietf.org/html/rfc6749#section-4.2.1 + """ + # ignore validate for response_type, since it is validated by + # check_authorization_endpoint + + # The implicit grant type is optimized for public clients + client = self.authenticate_token_endpoint_client() + log.debug('Validate authorization request of %r', client) + + redirect_uri = self.validate_authorization_redirect_uri( + self.request, client) + + response_type = self.request.response_type + if not client.check_response_type(response_type): + raise UnauthorizedClientError( + 'The client is not authorized to use ' + '"response_type={}"'.format(response_type), + state=self.request.state, + redirect_uri=redirect_uri, + redirect_fragment=True, + ) + + try: + self.request.client = client + self.validate_requested_scope() + self.execute_hook('after_validate_authorization_request') + except OAuth2Error as error: + error.redirect_uri = redirect_uri + error.redirect_fragment = True + raise error + return redirect_uri + + def create_authorization_response(self, redirect_uri, grant_user): + """If the resource owner grants the access request, the authorization + server issues an access token and delivers it to the client by adding + the following parameters to the fragment component of the redirection + URI using the "application/x-www-form-urlencoded" format. + Per `Section 4.2.2`_. + + access_token + REQUIRED. The access token issued by the authorization server. + + token_type + REQUIRED. The type of the token issued as described in + Section 7.1. Value is case insensitive. + + expires_in + RECOMMENDED. The lifetime in seconds of the access token. For + example, the value "3600" denotes that the access token will + expire in one hour from the time the response was generated. + If omitted, the authorization server SHOULD provide the + expiration time via other means or document the default value. + + scope + OPTIONAL, if identical to the scope requested by the client; + otherwise, REQUIRED. The scope of the access token as + described by Section 3.3. + + state + REQUIRED if the "state" parameter was present in the client + authorization request. The exact value received from the + client. + + The authorization server MUST NOT issue a refresh token. + + For example, the authorization server redirects the user-agent by + sending the following HTTP response: + + .. code-block:: http + + HTTP/1.1 302 Found + Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA + &state=xyz&token_type=example&expires_in=3600 + + Developers should note that some user-agents do not support the + inclusion of a fragment component in the HTTP "Location" response + header field. Such clients will require using other methods for + redirecting the client than a 3xx redirection response -- for + example, returning an HTML page that includes a 'continue' button + with an action linked to the redirection URI. + + .. _`Section 4.2.2`: https://tools.ietf.org/html/rfc6749#section-4.2.2 + + :param redirect_uri: Redirect to the given URI for the authorization + :param grant_user: if resource owner granted the request, pass this + resource owner, otherwise pass None. + :returns: (status_code, body, headers) + """ + state = self.request.state + if grant_user: + self.request.user = grant_user + token = self.generate_token( + user=grant_user, + scope=self.request.scope, + include_refresh_token=False, + ) + log.debug('Grant token %r to %r', token, self.request.client) + + self.save_token(token) + self.execute_hook('process_token', token=token) + params = [(k, token[k]) for k in token] + if state: + params.append(('state', state)) + + uri = add_params_to_uri(redirect_uri, params, fragment=True) + headers = [('Location', uri)] + return 302, '', headers + else: + raise AccessDeniedError( + state=state, + redirect_uri=redirect_uri, + redirect_fragment=True + ) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/refresh_token.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/refresh_token.py new file mode 100644 index 0000000..d29f4f9 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/refresh_token.py @@ -0,0 +1,183 @@ +""" + authlib.oauth2.rfc6749.grants.refresh_token + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + A special grant endpoint for refresh_token grant_type. Refreshing an + Access Token per `Section 6`_. + + .. _`Section 6`: https://tools.ietf.org/html/rfc6749#section-6 +""" + +import logging +from .base import BaseGrant, TokenEndpointMixin +from ..util import scope_to_list +from ..errors import ( + InvalidRequestError, + InvalidScopeError, + InvalidGrantError, + UnauthorizedClientError, +) +log = logging.getLogger(__name__) + + +class RefreshTokenGrant(BaseGrant, TokenEndpointMixin): + """A special grant endpoint for refresh_token grant_type. Refreshing an + Access Token per `Section 6`_. + + .. _`Section 6`: https://tools.ietf.org/html/rfc6749#section-6 + """ + GRANT_TYPE = 'refresh_token' + + #: The authorization server MAY issue a new refresh token + INCLUDE_NEW_REFRESH_TOKEN = False + + def _validate_request_client(self): + # require client authentication for confidential clients or for any + # client that was issued client credentials (or with other + # authentication requirements) + client = self.authenticate_token_endpoint_client() + log.debug('Validate token request of %r', client) + + if not client.check_grant_type(self.GRANT_TYPE): + raise UnauthorizedClientError() + + return client + + def _validate_request_token(self, client): + refresh_token = self.request.form.get('refresh_token') + if refresh_token is None: + raise InvalidRequestError( + 'Missing "refresh_token" in request.', + ) + + token = self.authenticate_refresh_token(refresh_token) + if not token or token.get_client_id() != client.get_client_id(): + raise InvalidGrantError() + return token + + def _validate_token_scope(self, token): + scope = self.request.scope + if not scope: + return + + original_scope = token.get_scope() + if not original_scope: + raise InvalidScopeError() + + original_scope = set(scope_to_list(original_scope)) + if not original_scope.issuperset(set(scope_to_list(scope))): + raise InvalidScopeError() + + def validate_token_request(self): + """If the authorization server issued a refresh token to the client, the + client makes a refresh request to the token endpoint by adding the + following parameters using the "application/x-www-form-urlencoded" + format per Appendix B with a character encoding of UTF-8 in the HTTP + request entity-body, per Section 6: + + grant_type + REQUIRED. Value MUST be set to "refresh_token". + + refresh_token + REQUIRED. The refresh token issued to the client. + + scope + OPTIONAL. The scope of the access request as described by + Section 3.3. The requested scope MUST NOT include any scope + not originally granted by the resource owner, and if omitted is + treated as equal to the scope originally granted by the + resource owner. + + + For example, the client makes the following HTTP request using + transport-layer security (with extra line breaks for display purposes + only): + + .. code-block:: http + + POST /token HTTP/1.1 + Host: server.example.com + Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW + Content-Type: application/x-www-form-urlencoded + + grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA + """ + client = self._validate_request_client() + self.request.client = client + token = self._validate_request_token(client) + self._validate_token_scope(token) + self.request.credential = token + + def create_token_response(self): + """If valid and authorized, the authorization server issues an access + token as described in Section 5.1. If the request failed + verification or is invalid, the authorization server returns an error + response as described in Section 5.2. + """ + credential = self.request.credential + user = self.authenticate_user(credential) + if not user: + raise InvalidRequestError('There is no "user" for this token.') + + client = self.request.client + token = self.issue_token(user, credential) + log.debug('Issue token %r to %r', token, client) + + self.request.user = user + self.save_token(token) + self.execute_hook('process_token', token=token) + self.revoke_old_credential(credential) + return 200, token, self.TOKEN_RESPONSE_HEADER + + def issue_token(self, user, credential): + expires_in = credential.get_expires_in() + scope = self.request.scope + if not scope: + scope = credential.get_scope() + + token = self.generate_token( + user=user, + expires_in=expires_in, + scope=scope, + include_refresh_token=self.INCLUDE_NEW_REFRESH_TOKEN, + ) + return token + + def authenticate_refresh_token(self, refresh_token): + """Get token information with refresh_token string. Developers MUST + implement this method in subclass:: + + def authenticate_refresh_token(self, refresh_token): + item = Token.get(refresh_token=refresh_token) + if item and item.is_refresh_token_active(): + return item + + :param refresh_token: The refresh token issued to the client + :return: token + """ + raise NotImplementedError() + + def authenticate_user(self, credential): + """Authenticate the user related to this credential. Developers MUST + implement this method in subclass:: + + def authenticate_user(self, credential): + return User.query.get(credential.user_id) + + :param credential: Token object + :return: user + """ + raise NotImplementedError() + + def revoke_old_credential(self, credential): + """The authorization server MAY revoke the old refresh token after + issuing a new refresh token to the client. Developers MUST implement + this method in subclass:: + + def revoke_old_credential(self, credential): + credential.revoked = True + credential.save() + + :param credential: Token object + """ + raise NotImplementedError() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/resource_owner_password_credentials.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/resource_owner_password_credentials.py new file mode 100644 index 0000000..df31c86 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/grants/resource_owner_password_credentials.py @@ -0,0 +1,154 @@ +import logging +from .base import BaseGrant, TokenEndpointMixin +from ..errors import ( + UnauthorizedClientError, + InvalidRequestError, +) + +log = logging.getLogger(__name__) + + +class ResourceOwnerPasswordCredentialsGrant(BaseGrant, TokenEndpointMixin): + """The resource owner password credentials grant type is suitable in + cases where the resource owner has a trust relationship with the + client, such as the device operating system or a highly privileged + + application. The authorization server should take special care when + enabling this grant type and only allow it when other flows are not + viable. + + This grant type is suitable for clients capable of obtaining the + resource owner's credentials (username and password, typically using + an interactive form). It is also used to migrate existing clients + using direct authentication schemes such as HTTP Basic or Digest + authentication to OAuth by converting the stored credentials to an + access token:: + + +----------+ + | Resource | + | Owner | + | | + +----------+ + v + | Resource Owner + (A) Password Credentials + | + v + +---------+ +---------------+ + | |>--(B)---- Resource Owner ------->| | + | | Password Credentials | Authorization | + | Client | | Server | + | |<--(C)---- Access Token ---------<| | + | | (w/ Optional Refresh Token) | | + +---------+ +---------------+ + """ + GRANT_TYPE = 'password' + + def validate_token_request(self): + """The client makes a request to the token endpoint by adding the + following parameters using the "application/x-www-form-urlencoded" + format per Appendix B with a character encoding of UTF-8 in the HTTP + request entity-body: + + grant_type + REQUIRED. Value MUST be set to "password". + + username + REQUIRED. The resource owner username. + + password + REQUIRED. The resource owner password. + + scope + OPTIONAL. The scope of the access request as described by + Section 3.3. + + If the client type is confidential or the client was issued client + credentials (or assigned other authentication requirements), the + client MUST authenticate with the authorization server as described + in Section 3.2.1. + + For example, the client makes the following HTTP request using + transport-layer security (with extra line breaks for display purposes + only): + + .. code-block:: http + + POST /token HTTP/1.1 + Host: server.example.com + Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW + Content-Type: application/x-www-form-urlencoded + + grant_type=password&username=johndoe&password=A3ddj3w + """ + # ignore validate for grant_type, since it is validated by + # check_token_endpoint + client = self.authenticate_token_endpoint_client() + log.debug('Validate token request of %r', client) + + if not client.check_grant_type(self.GRANT_TYPE): + raise UnauthorizedClientError() + + params = self.request.form + if 'username' not in params: + raise InvalidRequestError('Missing "username" in request.') + if 'password' not in params: + raise InvalidRequestError('Missing "password" in request.') + + log.debug('Authenticate user of %r', params['username']) + user = self.authenticate_user( + params['username'], + params['password'] + ) + if not user: + raise InvalidRequestError( + 'Invalid "username" or "password" in request.', + ) + self.request.client = client + self.request.user = user + self.validate_requested_scope() + + def create_token_response(self): + """If the access token request is valid and authorized, the + authorization server issues an access token and optional refresh + token as described in Section 5.1. If the request failed client + authentication or is invalid, the authorization server returns an + error response as described in Section 5.2. + + An example successful response: + + .. code-block:: http + + HTTP/1.1 200 OK + Content-Type: application/json + Cache-Control: no-store + Pragma: no-cache + + { + "access_token":"2YotnFZFEjr1zCsicMWpAA", + "token_type":"example", + "expires_in":3600, + "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA", + "example_parameter":"example_value" + } + + :returns: (status_code, body, headers) + """ + user = self.request.user + scope = self.request.scope + token = self.generate_token(user=user, scope=scope) + log.debug('Issue token %r to %r', token, self.request.client) + self.save_token(token) + self.execute_hook('process_token', token=token) + return 200, token, self.TOKEN_RESPONSE_HEADER + + def authenticate_user(self, username, password): + """validate the resource owner password credentials using its + existing password validation algorithm:: + + def authenticate_user(self, username, password): + user = get_user_by_username(username) + if user.check_password(password): + return user + """ + raise NotImplementedError() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/models.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/models.py new file mode 100644 index 0000000..0f86a4a --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/models.py @@ -0,0 +1,212 @@ +""" + authlib.oauth2.rfc6749.models + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + This module defines how to construct Client, AuthorizationCode and Token. +""" + + +class ClientMixin(object): + """Implementation of OAuth 2 Client described in `Section 2`_ with + some methods to help validation. A client has at least these information: + + * client_id: A string represents client identifier. + * client_secret: A string represents client password. + * token_endpoint_auth_method: A way to authenticate client at token + endpoint. + + .. _`Section 2`: https://tools.ietf.org/html/rfc6749#section-2 + """ + + def get_client_id(self): + """A method to return client_id of the client. For instance, the value + in database is saved in a column called ``client_id``:: + + def get_client_id(self): + return self.client_id + + :return: string + """ + raise NotImplementedError() + + def get_default_redirect_uri(self): + """A method to get client default redirect_uri. For instance, the + database table for client has a column called ``default_redirect_uri``:: + + def get_default_redirect_uri(self): + return self.default_redirect_uri + + :return: A URL string + """ + raise NotImplementedError() + + def get_allowed_scope(self, scope): + """A method to return a list of requested scopes which are supported by + this client. For instance, there is a ``scope`` column:: + + def get_allowed_scope(self, scope): + if not scope: + return '' + allowed = set(scope_to_list(self.scope)) + return list_to_scope([s for s in scope.split() if s in allowed]) + + :param scope: the requested scope. + :return: string of scope + """ + raise NotImplementedError() + + def check_redirect_uri(self, redirect_uri): + """Validate redirect_uri parameter in Authorization Endpoints. For + instance, in the client table, there is an ``allowed_redirect_uris`` + column:: + + def check_redirect_uri(self, redirect_uri): + return redirect_uri in self.allowed_redirect_uris + + :param redirect_uri: A URL string for redirecting. + :return: bool + """ + raise NotImplementedError() + + def has_client_secret(self): + """A method returns that if the client has ``client_secret`` value. + If the value is in ``client_secret`` column:: + + def has_client_secret(self): + return bool(self.client_secret) + + :return: bool + """ + raise NotImplementedError() + + def check_client_secret(self, client_secret): + """Check client_secret matching with the client. For instance, in + the client table, the column is called ``client_secret``:: + + def check_client_secret(self, client_secret): + return self.client_secret == client_secret + + :param client_secret: A string of client secret + :return: bool + """ + raise NotImplementedError() + + def check_token_endpoint_auth_method(self, method): + """Check client ``token_endpoint_auth_method`` defined via `RFC7591`_. + Values defined by this specification are: + + * "none": The client is a public client as defined in OAuth 2.0, + and does not have a client secret. + + * "client_secret_post": The client uses the HTTP POST parameters + as defined in OAuth 2.0 + + * "client_secret_basic": The client uses HTTP Basic as defined in + OAuth 2.0 + + .. _`RFC7591`: https://tools.ietf.org/html/rfc7591 + """ + raise NotImplementedError() + + def check_response_type(self, response_type): + """Validate if the client can handle the given response_type. There + are two response types defined by RFC6749: code and token. For + instance, there is a ``allowed_response_types`` column in your client:: + + def check_response_type(self, response_type): + return response_type in self.response_types + + :param response_type: the requested response_type string. + :return: bool + """ + raise NotImplementedError() + + def check_grant_type(self, grant_type): + """Validate if the client can handle the given grant_type. There are + four grant types defined by RFC6749: + + * authorization_code + * implicit + * client_credentials + * password + + For instance, there is a ``allowed_grant_types`` column in your client:: + + def check_grant_type(self, grant_type): + return grant_type in self.grant_types + + :param grant_type: the requested grant_type string. + :return: bool + """ + raise NotImplementedError() + + +class AuthorizationCodeMixin(object): + def get_redirect_uri(self): + """A method to get authorization code's ``redirect_uri``. + For instance, the database table for authorization code has a + column called ``redirect_uri``:: + + def get_redirect_uri(self): + return self.redirect_uri + + :return: A URL string + """ + raise NotImplementedError() + + def get_scope(self): + """A method to get scope of the authorization code. For instance, + the column is called ``scope``:: + + def get_scope(self): + return self.scope + + :return: scope string + """ + raise NotImplementedError() + + +class TokenMixin(object): + def get_client_id(self): + """A method to return client_id of the token. For instance, the value + in database is saved in a column called ``client_id``:: + + def get_client_id(self): + return self.client_id + + :return: string + """ + raise NotImplementedError() + + def get_scope(self): + """A method to get scope of the authorization code. For instance, + the column is called ``scope``:: + + def get_scope(self): + return self.scope + + :return: scope string + """ + raise NotImplementedError() + + def get_expires_in(self): + """A method to get the ``expires_in`` value of the token. e.g. + the column is called ``expires_in``:: + + def get_expires_in(self): + return self.expires_in + + :return: timestamp int + """ + raise NotImplementedError() + + def get_expires_at(self): + """A method to get the value when this token will be expired. e.g. + it would be:: + + def get_expires_at(self): + return self.created_at + self.expires_in + + :return: timestamp int + """ + raise NotImplementedError() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/parameters.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/parameters.py new file mode 100644 index 0000000..20461fd --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/parameters.py @@ -0,0 +1,213 @@ +from authlib.common.urls import ( + urlparse, + add_params_to_uri, + add_params_to_qs, +) +from authlib.common.encoding import to_unicode +from .errors import ( + MissingCodeException, + MissingTokenException, + MissingTokenTypeException, + MismatchingStateException, +) +from .util import list_to_scope + + +def prepare_grant_uri(uri, client_id, response_type, redirect_uri=None, + scope=None, state=None, **kwargs): + """Prepare the authorization grant request URI. + + The client constructs the request URI by adding the following + parameters to the query component of the authorization endpoint URI + using the ``application/x-www-form-urlencoded`` format: + + :param uri: The authorize endpoint to fetch "code" or "token". + :param client_id: The client identifier as described in `Section 2.2`_. + :param response_type: To indicate which OAuth 2 grant/flow is required, + "code" and "token". + :param redirect_uri: The client provided URI to redirect back to after + authorization as described in `Section 3.1.2`_. + :param scope: The scope of the access request as described by + `Section 3.3`_. + :param state: An opaque value used by the client to maintain + state between the request and callback. The authorization + server includes this value when redirecting the user-agent + back to the client. The parameter SHOULD be used for + preventing cross-site request forgery as described in + `Section 10.12`_. + :param kwargs: Extra arguments to embed in the grant/authorization URL. + + An example of an authorization code grant authorization URL:: + + /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz + &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb + + .. _`Section 2.2`: https://tools.ietf.org/html/rfc6749#section-2.2 + .. _`Section 3.1.2`: https://tools.ietf.org/html/rfc6749#section-3.1.2 + .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3 + .. _`section 10.12`: https://tools.ietf.org/html/rfc6749#section-10.12 + """ + params = [ + ('response_type', response_type), + ('client_id', client_id) + ] + + if redirect_uri: + params.append(('redirect_uri', redirect_uri)) + if scope: + params.append(('scope', list_to_scope(scope))) + if state: + params.append(('state', state)) + + for k in kwargs: + if kwargs[k]: + params.append((to_unicode(k), kwargs[k])) + + return add_params_to_uri(uri, params) + + +def prepare_token_request(grant_type, body='', redirect_uri=None, **kwargs): + """Prepare the access token request. Per `Section 4.1.3`_. + + The client makes a request to the token endpoint by adding the + following parameters using the ``application/x-www-form-urlencoded`` + format in the HTTP request entity-body: + + :param grant_type: To indicate grant type being used, i.e. "password", + "authorization_code" or "client_credentials". + :param body: Existing request body to embed parameters in. + :param redirect_uri: If the "redirect_uri" parameter was included in the + authorization request as described in + `Section 4.1.1`_, and their values MUST be identical. + :param kwargs: Extra arguments to embed in the request body. + + An example of an authorization code token request body:: + + grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA + &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb + + .. _`Section 4.1.1`: https://tools.ietf.org/html/rfc6749#section-4.1.1 + .. _`Section 4.1.3`: https://tools.ietf.org/html/rfc6749#section-4.1.3 + """ + params = [('grant_type', grant_type)] + + if redirect_uri: + params.append(('redirect_uri', redirect_uri)) + + if 'scope' in kwargs: + kwargs['scope'] = list_to_scope(kwargs['scope']) + + if grant_type == 'authorization_code' and 'code' not in kwargs: + raise MissingCodeException() + + for k in kwargs: + if kwargs[k]: + params.append((to_unicode(k), kwargs[k])) + + return add_params_to_qs(body, params) + + +def parse_authorization_code_response(uri, state=None): + """Parse authorization grant response URI into a dict. + + If the resource owner grants the access request, the authorization + server issues an authorization code and delivers it to the client by + adding the following parameters to the query component of the + redirection URI using the ``application/x-www-form-urlencoded`` format: + + **code** + REQUIRED. The authorization code generated by the + authorization server. The authorization code MUST expire + shortly after it is issued to mitigate the risk of leaks. A + maximum authorization code lifetime of 10 minutes is + RECOMMENDED. The client MUST NOT use the authorization code + more than once. If an authorization code is used more than + once, the authorization server MUST deny the request and SHOULD + revoke (when possible) all tokens previously issued based on + that authorization code. The authorization code is bound to + the client identifier and redirection URI. + + **state** + REQUIRED if the "state" parameter was present in the client + authorization request. The exact value received from the + client. + + :param uri: The full redirect URL back to the client. + :param state: The state parameter from the authorization request. + + For example, the authorization server redirects the user-agent by + sending the following HTTP response: + + .. code-block:: http + + HTTP/1.1 302 Found + Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA + &state=xyz + + """ + query = urlparse.urlparse(uri).query + params = dict(urlparse.parse_qsl(query)) + + if 'code' not in params: + raise MissingCodeException() + + if state and params.get('state', None) != state: + raise MismatchingStateException() + + return params + + +def parse_implicit_response(uri, state=None): + """Parse the implicit token response URI into a dict. + + If the resource owner grants the access request, the authorization + server issues an access token and delivers it to the client by adding + the following parameters to the fragment component of the redirection + URI using the ``application/x-www-form-urlencoded`` format: + + **access_token** + REQUIRED. The access token issued by the authorization server. + + **token_type** + REQUIRED. The type of the token issued as described in + Section 7.1. Value is case insensitive. + + **expires_in** + RECOMMENDED. The lifetime in seconds of the access token. For + example, the value "3600" denotes that the access token will + expire in one hour from the time the response was generated. + If omitted, the authorization server SHOULD provide the + expiration time via other means or document the default value. + + **scope** + OPTIONAL, if identical to the scope requested by the client, + otherwise REQUIRED. The scope of the access token as described + by Section 3.3. + + **state** + REQUIRED if the "state" parameter was present in the client + authorization request. The exact value received from the + client. + + Similar to the authorization code response, but with a full token provided + in the URL fragment: + + .. code-block:: http + + HTTP/1.1 302 Found + Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA + &state=xyz&token_type=example&expires_in=3600 + """ + fragment = urlparse.urlparse(uri).fragment + params = dict(urlparse.parse_qsl(fragment, keep_blank_values=True)) + + if 'access_token' not in params: + raise MissingTokenException() + + if 'token_type' not in params: + raise MissingTokenTypeException() + + if state and params.get('state', None) != state: + raise MismatchingStateException() + + return params diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/resource_protector.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/resource_protector.py new file mode 100644 index 0000000..4056795 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/resource_protector.py @@ -0,0 +1,37 @@ +""" + authlib.oauth2.rfc6749.resource_protector + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Implementation of Accessing Protected Resources per `Section 7`_. + + .. _`Section 7`: https://tools.ietf.org/html/rfc6749#section-7 +""" + +from .errors import MissingAuthorizationError, UnsupportedTokenTypeError + + +class ResourceProtector(object): + def __init__(self): + self._token_validators = {} + + def register_token_validator(self, validator): + if validator.TOKEN_TYPE not in self._token_validators: + self._token_validators[validator.TOKEN_TYPE] = validator + + def validate_request(self, scope, request, scope_operator='AND'): + auth = request.headers.get('Authorization') + if not auth: + raise MissingAuthorizationError() + + # https://tools.ietf.org/html/rfc6749#section-7.1 + token_parts = auth.split(None, 1) + if len(token_parts) != 2: + raise UnsupportedTokenTypeError() + + token_type, token_string = token_parts + + validator = self._token_validators.get(token_type.lower()) + if not validator: + raise UnsupportedTokenTypeError() + + return validator(token_string, scope, request, scope_operator) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/token_endpoint.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/token_endpoint.py new file mode 100644 index 0000000..726f7e0 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/token_endpoint.py @@ -0,0 +1,34 @@ +class TokenEndpoint(object): + #: Endpoint name to be registered + ENDPOINT_NAME = None + #: Supported token types + SUPPORTED_TOKEN_TYPES = ('access_token', 'refresh_token') + #: Allowed client authenticate methods + CLIENT_AUTH_METHODS = ['client_secret_basic'] + + def __init__(self, server): + self.server = server + + def __call__(self, request): + # make it callable for authorization server + # ``create_endpoint_response`` + return self.create_endpoint_response(request) + + def create_endpoint_request(self, request): + return self.server.create_oauth2_request(request) + + def authenticate_endpoint_client(self, request): + """Authentication client for endpoint with ``CLIENT_AUTH_METHODS``. + """ + client = self.server.authenticate_client( + request=request, + methods=self.CLIENT_AUTH_METHODS, + ) + request.client = client + return client + + def authenticate_endpoint_credential(self, request, client): + raise NotImplementedError() + + def create_endpoint_response(self, request): + raise NotImplementedError() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/util.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/util.py new file mode 100644 index 0000000..a216fbf --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/util.py @@ -0,0 +1,40 @@ +import base64 +import binascii +from authlib.common.encoding import to_unicode + + +def list_to_scope(scope): + """Convert a list of scopes to a space separated string.""" + if isinstance(scope, (set, tuple, list)): + return " ".join([to_unicode(s) for s in scope]) + if scope is None: + return scope + return to_unicode(scope) + + +def scope_to_list(scope): + """Convert a space separated string to a list of scopes.""" + if isinstance(scope, (tuple, list, set)): + return [to_unicode(s) for s in scope] + elif scope is None: + return None + return scope.strip().split() + + +def extract_basic_authorization(headers): + auth = headers.get('Authorization') + if not auth or ' ' not in auth: + return None, None + + auth_type, auth_token = auth.split(None, 1) + if auth_type.lower() != 'basic': + return None, None + + try: + query = to_unicode(base64.b64decode(auth_token)) + except (binascii.Error, TypeError): + return None, None + if ':' in query: + username, password = query.split(':', 1) + return username, password + return query, None diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/wrappers.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/wrappers.py new file mode 100644 index 0000000..a1f4543 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6749/wrappers.py @@ -0,0 +1,96 @@ +import time +from authlib.common.urls import urlparse, url_decode +from .errors import InsecureTransportError + + +class OAuth2Token(dict): + def __init__(self, params): + if params.get('expires_at'): + params['expires_at'] = int(params['expires_at']) + elif params.get('expires_in'): + params['expires_at'] = int(time.time()) + \ + int(params['expires_in']) + super(OAuth2Token, self).__init__(params) + + def is_expired(self): + expires_at = self.get('expires_at') + if not expires_at: + return None + return expires_at < time.time() + + @classmethod + def from_dict(cls, token): + if isinstance(token, dict) and not isinstance(token, cls): + token = cls(token) + return token + + +class OAuth2Request(object): + def __init__(self, method, uri, body=None, headers=None): + InsecureTransportError.check(uri) + #: HTTP method + self.method = method + self.uri = uri + self.body = body + #: HTTP headers + self.headers = headers or {} + + self.query = urlparse.urlparse(uri).query + + self.args = dict(url_decode(self.query)) + self.form = self.body or {} + + #: dict of query and body params + data = {} + data.update(self.args) + data.update(self.form) + self.data = data + + #: authenticate method + self.auth_method = None + #: authenticated user on this request + self.user = None + #: authorization_code or token model instance + self.credential = None + #: client which sending this request + self.client = None + + @property + def client_id(self): + """The authorization server issues the registered client a client + identifier -- a unique string representing the registration + information provided by the client. The value is extracted from + request. + + :return: string + """ + return self.data.get('client_id') + + @property + def response_type(self): + return self.data.get('response_type') + + @property + def grant_type(self): + return self.data.get('grant_type') + + @property + def redirect_uri(self): + return self.data.get('redirect_uri') + + @property + def scope(self): + return self.data.get('scope') + + @property + def state(self): + return self.data.get('state') + + +class HttpRequest(object): + def __init__(self, method, uri, data=None, headers=None): + self.method = method + self.uri = uri + self.data = data + self.headers = headers or {} + self.user = None diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6750/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6750/__init__.py new file mode 100644 index 0000000..4ad0212 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6750/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +""" + authlib.oauth2.rfc6750 + ~~~~~~~~~~~~~~~~~~~~~~ + + This module represents a direct implementation of + The OAuth 2.0 Authorization Framework: Bearer Token Usage. + + https://tools.ietf.org/html/rfc6750 +""" + +from .errors import InvalidRequestError, InvalidTokenError, InsufficientScopeError +from .parameters import add_bearer_token +from .wrappers import BearerToken +from .validator import BearerTokenValidator + + +__all__ = [ + 'InvalidRequestError', 'InvalidTokenError', 'InsufficientScopeError', + 'add_bearer_token', + 'BearerToken', + 'BearerTokenValidator', +] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6750/errors.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6750/errors.py new file mode 100644 index 0000000..543fa9a --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6750/errors.py @@ -0,0 +1,85 @@ +""" + authlib.rfc6750.errors + ~~~~~~~~~~~~~~~~~~~~~~ + + OAuth Extensions Error Registration. When a request fails, + the resource server responds using the appropriate HTTP + status code and includes one of the following error codes + in the response. + + https://tools.ietf.org/html/rfc6750#section-6.2 + + :copyright: (c) 2017 by Hsiaoming Yang. +""" +from ..base import OAuth2Error +from ..rfc6749.errors import InvalidRequestError + +__all__ = [ + 'InvalidRequestError', 'InvalidTokenError', 'InsufficientScopeError' +] + + +class InvalidTokenError(OAuth2Error): + """The access token provided is expired, revoked, malformed, or + invalid for other reasons. The resource SHOULD respond with + the HTTP 401 (Unauthorized) status code. The client MAY + request a new access token and retry the protected resource + request. + + https://tools.ietf.org/html/rfc6750#section-3.1 + """ + error = 'invalid_token' + status_code = 401 + + def __init__(self, description=None, uri=None, status_code=None, + state=None, realm=None): + super(InvalidTokenError, self).__init__( + description, uri, status_code, state) + self.realm = realm + + def get_error_description(self): + return self.gettext( + 'The access token provided is expired, revoked, malformed, ' + 'or invalid for other reasons.' + ) + + def get_headers(self): + """If the protected resource request does not include authentication + credentials or does not contain an access token that enables access + to the protected resource, the resource server MUST include the HTTP + "WWW-Authenticate" response header field; it MAY include it in + response to other conditions as well. + + https://tools.ietf.org/html/rfc6750#section-3 + """ + headers = super(InvalidTokenError, self).get_headers() + + extras = [] + if self.realm: + extras.append('realm="{}"'.format(self.realm)) + extras.append('error="{}"'.format(self.error)) + error_description = self.get_error_description() + extras.append('error_description="{}"'.format(error_description)) + headers.append( + ('WWW-Authenticate', 'Bearer ' + ', '.join(extras)) + ) + return headers + + +class InsufficientScopeError(OAuth2Error): + """The request requires higher privileges than provided by the + access token. The resource server SHOULD respond with the HTTP + 403 (Forbidden) status code and MAY include the "scope" + attribute with the scope necessary to access the protected + resource. + + https://tools.ietf.org/html/rfc6750#section-3.1 + """ + error = 'insufficient_scope' + status_code = 403 + + def get_error_description(self): + return self.gettext( + 'The request requires higher privileges than ' + 'provided by the access token.' + ) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6750/parameters.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6750/parameters.py new file mode 100644 index 0000000..5f4e100 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6750/parameters.py @@ -0,0 +1,41 @@ +from authlib.common.urls import add_params_to_qs, add_params_to_uri + + +def add_to_uri(token, uri): + """Add a Bearer Token to the request URI. + Not recommended, use only if client can't use authorization header or body. + + http://www.example.com/path?access_token=h480djs93hd8 + """ + return add_params_to_uri(uri, [('access_token', token)]) + + +def add_to_headers(token, headers=None): + """Add a Bearer Token to the request URI. + Recommended method of passing bearer tokens. + + Authorization: Bearer h480djs93hd8 + """ + headers = headers or {} + headers['Authorization'] = 'Bearer {}'.format(token) + return headers + + +def add_to_body(token, body=None): + """Add a Bearer Token to the request body. + + access_token=h480djs93hd8 + """ + if body is None: + body = '' + return add_params_to_qs(body, [('access_token', token)]) + + +def add_bearer_token(token, uri, headers, body, placement='header'): + if placement in ('uri', 'url', 'query'): + uri = add_to_uri(token, uri) + elif placement in ('header', 'headers'): + headers = add_to_headers(token, headers) + elif placement == 'body': + body = add_to_body(token, body) + return uri, headers, body diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6750/validator.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6750/validator.py new file mode 100644 index 0000000..31467aa --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6750/validator.py @@ -0,0 +1,99 @@ +""" + authlib.oauth2.rfc6750.validator + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Validate Bearer Token for in request, scope and token. +""" + +import time +from ..rfc6749.util import scope_to_list +from .errors import ( + InvalidRequestError, + InvalidTokenError, + InsufficientScopeError +) + + +class BearerTokenValidator(object): + TOKEN_TYPE = 'bearer' + + def __init__(self, realm=None): + self.realm = realm + + def authenticate_token(self, token_string): + """A method to query token from database with the given token string. + Developers MUST re-implement this method. For instance:: + + def authenticate_token(self, token_string): + return get_token_from_database(token_string) + + :param token_string: A string to represent the access_token. + :return: token + """ + raise NotImplementedError() + + def request_invalid(self, request): + """Check if the HTTP request is valid or not. Developers MUST + re-implement this method. For instance, your server requires a + "X-Device-Version" in the header:: + + def request_invalid(self, request): + return 'X-Device-Version' in request.headers + + Usually, you don't have to detect if the request is valid or not, + you can just return a ``False``. + + :param request: instance of HttpRequest + :return: Boolean + """ + raise NotImplementedError() + + def token_revoked(self, token): + """Check if this token is revoked. Developers MUST re-implement this + method. If there is a column called ``revoked`` on the token table:: + + def token_revoked(self, token): + return token.revoked + + :param token: token instance + :return: Boolean + """ + raise NotImplementedError() + + def token_expired(self, token): + expires_at = token.get_expires_at() + if not expires_at: + return False + return expires_at < time.time() + + def scope_insufficient(self, token, scope, operator='AND'): + if not scope: + return False + + token_scopes = scope_to_list(token.get_scope()) + if not token_scopes: + return True + + token_scopes = set(token_scopes) + resource_scopes = set(scope_to_list(scope)) + if operator == 'AND': + return not token_scopes.issuperset(resource_scopes) + if operator == 'OR': + return not token_scopes & resource_scopes + if callable(operator): + return not operator(token_scopes, resource_scopes) + raise ValueError('Invalid operator value') + + def __call__(self, token_string, scope, request, scope_operator='AND'): + if self.request_invalid(request): + raise InvalidRequestError() + token = self.authenticate_token(token_string) + if not token: + raise InvalidTokenError(realm=self.realm) + if self.token_expired(token): + raise InvalidTokenError(realm=self.realm) + if self.token_revoked(token): + raise InvalidTokenError(realm=self.realm) + if self.scope_insufficient(token, scope, scope_operator): + raise InsufficientScopeError() + return token diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6750/wrappers.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6750/wrappers.py new file mode 100644 index 0000000..9e2c226 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc6750/wrappers.py @@ -0,0 +1,97 @@ + +class BearerToken(object): + """Bearer Token generator which can create the payload for token response + by OAuth 2 server. A typical token response would be: + + .. code-block:: http + + HTTP/1.1 200 OK + Content-Type: application/json;charset=UTF-8 + Cache-Control: no-store + Pragma: no-cache + + { + "access_token":"mF_9.B5f-4.1JqM", + "token_type":"Bearer", + "expires_in":3600, + "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA" + } + + :param access_token_generator: a function to generate access_token. + :param refresh_token_generator: a function to generate refresh_token, + if not provided, refresh_token will not be added into token response. + :param expires_generator: The expires_generator can be an int value or a + function. If it is int, all token expires_in will be this value. If it + is function, it can generate expires_in depending on client and + grant_type:: + + def expires_generator(client, grant_type): + if is_official_client(client): + return 3600 * 1000 + if grant_type == 'implicit': + return 3600 + return 3600 * 10 + :return: Callable + + When BearerToken is initialized, it will be callable:: + + token_generator = BearerToken(access_token_generator) + token = token_generator(client, grant_type, expires_in=None, + scope=None, include_refresh_token=True) + + The callable function that BearerToken created accepts these parameters: + + :param client: the client that making the request. + :param grant_type: current requested grant_type. + :param expires_in: if provided, use this value as expires_in. + :param scope: current requested scope. + :param include_refresh_token: should refresh_token be included. + :return: Token dict + """ + + #: default expires_in value + DEFAULT_EXPIRES_IN = 3600 + #: default expires_in value differentiate by grant_type + GRANT_TYPES_EXPIRES_IN = { + 'authorization_code': 864000, + 'implicit': 3600, + 'password': 864000, + 'client_credentials': 864000 + } + + def __init__(self, access_token_generator, + refresh_token_generator=None, + expires_generator=None): + self.access_token_generator = access_token_generator + self.refresh_token_generator = refresh_token_generator + self.expires_generator = expires_generator + + def _get_expires_in(self, client, grant_type): + if self.expires_generator is None: + expires_in = self.GRANT_TYPES_EXPIRES_IN.get( + grant_type, self.DEFAULT_EXPIRES_IN) + elif callable(self.expires_generator): + expires_in = self.expires_generator(client, grant_type) + elif isinstance(self.expires_generator, int): + expires_in = self.expires_generator + else: + expires_in = self.DEFAULT_EXPIRES_IN + return expires_in + + def __call__(self, client, grant_type, user=None, scope=None, + expires_in=None, include_refresh_token=True): + access_token = self.access_token_generator(client, grant_type, user, scope) + if expires_in is None: + expires_in = self._get_expires_in(client, grant_type) + + token = { + 'token_type': 'Bearer', + 'access_token': access_token, + 'expires_in': expires_in + } + if include_refresh_token and self.refresh_token_generator: + token['refresh_token'] = self.refresh_token_generator( + client, grant_type, user, scope) + if scope: + token['scope'] = scope + return token diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7009/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7009/__init__.py new file mode 100644 index 0000000..0b8bc7f --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7009/__init__.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +""" + authlib.oauth2.rfc7009 + ~~~~~~~~~~~~~~~~~~~~~~ + + This module represents a direct implementation of + OAuth 2.0 Token Revocation. + + https://tools.ietf.org/html/rfc7009 +""" + +from .parameters import prepare_revoke_token_request +from .revocation import RevocationEndpoint + +__all__ = ['prepare_revoke_token_request', 'RevocationEndpoint'] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7009/parameters.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7009/parameters.py new file mode 100644 index 0000000..2a829a7 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7009/parameters.py @@ -0,0 +1,25 @@ +from authlib.common.urls import add_params_to_qs + + +def prepare_revoke_token_request(token, token_type_hint=None, + body=None, headers=None): + """Construct request body and headers for revocation endpoint. + + :param token: access_token or refresh_token string. + :param token_type_hint: Optional, `access_token` or `refresh_token`. + :param body: current request body. + :param headers: current request headers. + :return: tuple of (body, headers) + + https://tools.ietf.org/html/rfc7009#section-2.1 + """ + params = [('token', token)] + if token_type_hint: + params.append(('token_type_hint', token_type_hint)) + + body = add_params_to_qs(body or '', params) + if headers is None: + headers = {} + + headers['Content-Type'] = 'application/x-www-form-urlencoded' + return body, headers diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7009/revocation.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7009/revocation.py new file mode 100644 index 0000000..aafdd37 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7009/revocation.py @@ -0,0 +1,98 @@ +from authlib.consts import default_json_headers +from ..rfc6749 import TokenEndpoint +from ..rfc6749 import ( + InvalidRequestError, + UnsupportedTokenTypeError, +) + + +class RevocationEndpoint(TokenEndpoint): + """Implementation of revocation endpoint which is described in + `RFC7009`_. + + .. _RFC7009: https://tools.ietf.org/html/rfc7009 + """ + #: Endpoint name to be registered + ENDPOINT_NAME = 'revocation' + + def authenticate_endpoint_credential(self, request, client): + """The client constructs the request by including the following + parameters using the "application/x-www-form-urlencoded" format in + the HTTP request entity-body: + + token + REQUIRED. The token that the client wants to get revoked. + + token_type_hint + OPTIONAL. A hint about the type of the token submitted for + revocation. + """ + if 'token' not in request.form: + raise InvalidRequestError() + + token_type = request.form.get('token_type_hint') + if token_type and token_type not in self.SUPPORTED_TOKEN_TYPES: + raise UnsupportedTokenTypeError() + return self.query_token(request.form['token'], token_type, client) + + def create_endpoint_response(self, request): + """Validate revocation request and create the response for revocation. + For example, a client may request the revocation of a refresh token + with the following request:: + + POST /revoke HTTP/1.1 + Host: server.example.com + Content-Type: application/x-www-form-urlencoded + Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW + + token=45ghiukldjahdnhzdauz&token_type_hint=refresh_token + + :returns: (status_code, body, headers) + """ + # The authorization server first validates the client credentials + client = self.authenticate_endpoint_client(request) + + # then verifies whether the token was issued to the client making + # the revocation request + credential = self.authenticate_endpoint_credential(request, client) + + # the authorization server invalidates the token + if credential: + self.revoke_token(credential) + self.server.send_signal( + 'after_revoke_token', + token=credential, + client=client, + ) + return 200, {}, default_json_headers + + def query_token(self, token, token_type_hint, client): + """Get the token from database/storage by the given token string. + Developers should implement this method:: + + def query_token(self, token, token_type_hint, client): + if token_type_hint == 'access_token': + return Token.query_by_access_token(token, client.client_id) + if token_type_hint == 'refresh_token': + return Token.query_by_refresh_token(token, client.client_id) + return Token.query_by_access_token(token, client.client_id) or \ + Token.query_by_refresh_token(token, client.client_id) + """ + raise NotImplementedError() + + def revoke_token(self, token): + """Mark token as revoked. Since token MUST be unique, it would be + dangerous to delete it. Consider this situation: + + 1. Jane obtained a token XYZ + 2. Jane revoked (deleted) token XYZ + 3. Bob generated a new token XYZ + 4. Jane can use XYZ to access Bob's resource + + It would be secure to mark a token as revoked:: + + def revoke_token(self, token): + token.revoked = True + token.save() + """ + raise NotImplementedError() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7521/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7521/__init__.py new file mode 100644 index 0000000..0dbe0b3 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7521/__init__.py @@ -0,0 +1,3 @@ +from .client import AssertionClient + +__all__ = ['AssertionClient'] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7521/client.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7521/client.py new file mode 100644 index 0000000..d1b98ba --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7521/client.py @@ -0,0 +1,84 @@ +from authlib.common.encoding import to_native +from authlib.oauth2.base import OAuth2Error + + +class AssertionClient(object): + """Constructs a new Assertion Framework for OAuth 2.0 Authorization Grants + per RFC7521_. + + .. _RFC7521: https://tools.ietf.org/html/rfc7521 + """ + DEFAULT_GRANT_TYPE = None + ASSERTION_METHODS = {} + token_auth_class = None + + def __init__(self, session, token_endpoint, issuer, subject, + audience=None, grant_type=None, claims=None, + token_placement='header', scope=None, **kwargs): + + self.session = session + + if audience is None: + audience = token_endpoint + + self.token_endpoint = token_endpoint + + if grant_type is None: + grant_type = self.DEFAULT_GRANT_TYPE + + self.grant_type = grant_type + + # https://tools.ietf.org/html/rfc7521#section-5.1 + self.issuer = issuer + self.subject = subject + self.audience = audience + self.claims = claims + self.scope = scope + if self.token_auth_class is not None: + self.token_auth = self.token_auth_class(None, token_placement, self) + self._kwargs = kwargs + + @property + def token(self): + return self.token_auth.token + + @token.setter + def token(self, token): + self.token_auth.set_token(token) + + def refresh_token(self): + """Using Assertions as Authorization Grants to refresh token as + described in `Section 4.1`_. + + .. _`Section 4.1`: https://tools.ietf.org/html/rfc7521#section-4.1 + """ + generate_assertion = self.ASSERTION_METHODS[self.grant_type] + assertion = generate_assertion( + issuer=self.issuer, + subject=self.subject, + audience=self.audience, + claims=self.claims, + **self._kwargs + ) + data = { + 'assertion': to_native(assertion), + 'grant_type': self.grant_type, + } + if self.scope: + data['scope'] = self.scope + + return self._refresh_token(data) + + def _refresh_token(self, data): + resp = self.session.request( + 'POST', self.token_endpoint, data=data, withhold_token=True) + + token = resp.json() + if 'error' in token: + raise OAuth2Error( + error=token['error'], + description=token.get('error_description') + ) + + self.token = token + return self.token diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7523/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7523/__init__.py new file mode 100644 index 0000000..843c075 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7523/__init__.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +""" + authlib.oauth2.rfc7523 + ~~~~~~~~~~~~~~~~~~~~~~ + + This module represents a direct implementation of + JSON Web Token (JWT) Profile for OAuth 2.0 Client + Authentication and Authorization Grants. + + https://tools.ietf.org/html/rfc7523 +""" + +from .jwt_bearer import JWTBearerGrant +from .client import ( + JWTBearerClientAssertion, +) +from .assertion import ( + client_secret_jwt_sign, + private_key_jwt_sign, +) +from .auth import ( + ClientSecretJWT, PrivateKeyJWT, + register_session_client_auth_method, +) + +__all__ = [ + 'JWTBearerGrant', + 'JWTBearerClientAssertion', + 'client_secret_jwt_sign', + 'private_key_jwt_sign', + 'ClientSecretJWT', + 'PrivateKeyJWT', + 'register_session_client_auth_method', +] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7523/assertion.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7523/assertion.py new file mode 100644 index 0000000..0bb9fe7 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7523/assertion.py @@ -0,0 +1,66 @@ +import time +from authlib.jose import jwt +from authlib.common.security import generate_token + + +def sign_jwt_bearer_assertion( + key, issuer, audience, subject=None, issued_at=None, + expires_at=None, claims=None, header=None, **kwargs): + + if header is None: + header = {} + alg = kwargs.pop('alg', None) + if alg: + header['alg'] = alg + if 'alg' not in header: + raise ValueError('Missing "alg" in header') + + payload = {'iss': issuer, 'aud': audience} + + # subject is not required in Google service + if subject: + payload['sub'] = subject + + if not issued_at: + issued_at = int(time.time()) + + expires_in = kwargs.pop('expires_in', 3600) + if not expires_at: + expires_at = issued_at + expires_in + + payload['iat'] = issued_at + payload['exp'] = expires_at + + if claims: + payload.update(claims) + + return jwt.encode(header, payload, key) + + +def client_secret_jwt_sign(client_secret, client_id, token_endpoint, alg='HS256', + claims=None, **kwargs): + return _sign(client_secret, client_id, token_endpoint, alg, claims, **kwargs) + + +def private_key_jwt_sign(private_key, client_id, token_endpoint, alg='RS256', + claims=None, **kwargs): + return _sign(private_key, client_id, token_endpoint, alg, claims, **kwargs) + + +def _sign(key, client_id, token_endpoint, alg, claims=None, **kwargs): + # REQUIRED. Issuer. This MUST contain the client_id of the OAuth Client. + issuer = client_id + # REQUIRED. Subject. This MUST contain the client_id of the OAuth Client. + subject = client_id + # The Audience SHOULD be the URL of the Authorization Server's Token Endpoint. + audience = token_endpoint + + # jti is required + if claims is None: + claims = {} + if 'jti' not in claims: + claims['jti'] = generate_token(36) + + return sign_jwt_bearer_assertion( + key=key, issuer=issuer, audience=audience, subject=subject, + claims=claims, alg=alg, **kwargs) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7523/auth.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7523/auth.py new file mode 100644 index 0000000..dddddc0 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7523/auth.py @@ -0,0 +1,100 @@ +from authlib.common.urls import add_params_to_qs +from authlib.deprecate import deprecate +from .assertion import client_secret_jwt_sign, private_key_jwt_sign +from .client import ASSERTION_TYPE + + +class ClientSecretJWT(object): + """Authentication method for OAuth 2.0 Client. This authentication + method is called ``client_secret_jwt``, which is using ``client_id`` + and ``client_secret`` constructed with JWT to identify a client. + + Here is an example of use ``client_secret_jwt`` with Requests Session:: + + from authlib.integrations.requests_client import OAuth2Session + + token_endpoint = 'https://example.com/oauth/token' + session = OAuth2Session( + 'your-client-id', 'your-client-secret', + token_endpoint_auth_method='client_secret_jwt' + ) + session.register_client_auth_method(ClientSecretJWT(token_endpoint)) + session.fetch_token(token_endpoint) + + :param token_endpoint: A string URL of the token endpoint + :param claims: Extra JWT claims + """ + name = 'client_secret_jwt' + + def __init__(self, token_endpoint=None, claims=None): + self.token_endpoint = token_endpoint + self.claims = claims + + def sign(self, auth, token_endpoint): + return client_secret_jwt_sign( + auth.client_secret, + client_id=auth.client_id, + token_endpoint=token_endpoint, + claims=self.claims, + ) + + def __call__(self, auth, method, uri, headers, body): + token_endpoint = self.token_endpoint + if not token_endpoint: + token_endpoint = uri + + client_assertion = self.sign(auth, token_endpoint) + body = add_params_to_qs(body or '', [ + ('client_assertion_type', ASSERTION_TYPE), + ('client_assertion', client_assertion) + ]) + return uri, headers, body + + +class PrivateKeyJWT(ClientSecretJWT): + """Authentication method for OAuth 2.0 Client. This authentication + method is called ``private_key_jwt``, which is using ``client_id`` + and ``private_key`` constructed with JWT to identify a client. + + Here is an example of use ``private_key_jwt`` with Requests Session:: + + from authlib.integrations.requests_client import OAuth2Session + + token_endpoint = 'https://example.com/oauth/token' + session = OAuth2Session( + 'your-client-id', 'your-client-private-key', + token_endpoint_auth_method='private_key_jwt' + ) + session.register_client_auth_method(PrivateKeyJWT(token_endpoint)) + session.fetch_token(token_endpoint) + + :param token_endpoint: A string URL of the token endpoint + :param claims: Extra JWT claims + """ + name = 'private_key_jwt' + + def sign(self, auth, token_endpoint): + return private_key_jwt_sign( + auth.client_secret, + client_id=auth.client_id, + token_endpoint=token_endpoint, + claims=self.claims, + ) + + +def register_session_client_auth_method(session, token_url=None, **kwargs): # pragma: no cover + """Register "client_secret_jwt" or "private_key_jwt" token endpoint auth + method to OAuth2Session. + + :param session: OAuth2Session instance. + :param token_url: Optional token endpoint url. + """ + deprecate('Use `ClientSecretJWT` and `PrivateKeyJWT` instead', '1.0', 'Jeclj', 'ca') + if session.token_endpoint_auth_method == 'client_secret_jwt': + cls = ClientSecretJWT + elif session.token_endpoint_auth_method == 'private_key_jwt': + cls = PrivateKeyJWT + else: + raise ValueError('Invalid token_endpoint_auth_method') + + session.register_client_auth_method(cls(token_url)) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7523/client.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7523/client.py new file mode 100644 index 0000000..cda82c8 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7523/client.py @@ -0,0 +1,113 @@ +import logging +from authlib.jose import jwt +from authlib.jose.errors import JoseError +from ..rfc6749 import InvalidClientError + +ASSERTION_TYPE = 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer' +log = logging.getLogger(__name__) + + +class JWTBearerClientAssertion(object): + """Implementation of Using JWTs for Client Authentication, which is + defined by RFC7523. + """ + #: Value of ``client_assertion_type`` of JWTs + CLIENT_ASSERTION_TYPE = ASSERTION_TYPE + #: Name of the client authentication method + CLIENT_AUTH_METHOD = 'client_assertion_jwt' + + def __init__(self, token_url, validate_jti=True): + self.token_url = token_url + self._validate_jti = validate_jti + + def __call__(self, query_client, request): + data = request.form + assertion_type = data.get('client_assertion_type') + assertion = data.get('client_assertion') + if assertion_type == ASSERTION_TYPE and assertion: + resolve_key = self.create_resolve_key_func(query_client, request) + self.process_assertion_claims(assertion, resolve_key) + return self.authenticate_client(request.client) + log.debug('Authenticate via %r failed', self.CLIENT_AUTH_METHOD) + + def create_claims_options(self): + """Create a claims_options for verify JWT payload claims. Developers + MAY overwrite this method to create a more strict options.""" + # https://tools.ietf.org/html/rfc7523#section-3 + # The Audience SHOULD be the URL of the Authorization Server's Token Endpoint + options = { + 'iss': {'essential': True, 'validate': _validate_iss}, + 'sub': {'essential': True}, + 'aud': {'essential': True, 'value': self.token_url}, + 'exp': {'essential': True}, + } + if self._validate_jti: + options['jti'] = {'essential': True, 'validate': self.validate_jti} + return options + + def process_assertion_claims(self, assertion, resolve_key): + """Extract JWT payload claims from request "assertion", per + `Section 3.1`_. + + :param assertion: assertion string value in the request + :param resolve_key: function to resolve the sign key + :return: JWTClaims + :raise: InvalidClientError + + .. _`Section 3.1`: https://tools.ietf.org/html/rfc7523#section-3.1 + """ + try: + claims = jwt.decode( + assertion, resolve_key, + claims_options=self.create_claims_options() + ) + claims.validate() + except JoseError as e: + log.debug('Assertion Error: %r', e) + raise InvalidClientError() + return claims + + def authenticate_client(self, client): + if client.check_token_endpoint_auth_method(self.CLIENT_AUTH_METHOD): + return client + raise InvalidClientError() + + def create_resolve_key_func(self, query_client, request): + def resolve_key(headers, payload): + # https://tools.ietf.org/html/rfc7523#section-3 + # For client authentication, the subject MUST be the + # "client_id" of the OAuth client + client_id = payload['sub'] + client = query_client(client_id) + if not client: + raise InvalidClientError() + request.client = client + return self.resolve_client_public_key(client, headers) + return resolve_key + + def validate_jti(self, claims, jti): + """Validate if the given ``jti`` value is used before. Developers + MUST implement this method:: + + def validate_jti(self, claims, jti): + key = 'jti:{}-{}'.format(claims['sub'], jti) + if redis.get(key): + return False + redis.set(key, 1, ex=3600) + return True + """ + raise NotImplementedError() + + def resolve_client_public_key(self, client, headers): + """Resolve the client public key for verifying the JWT signature. + A client may have many public keys, in this case, we can retrieve it + via ``kid`` value in headers. Developers MUST implement this method:: + + def resolve_client_public_key(self, client, headers): + return client.public_key + """ + raise NotImplementedError() + + +def _validate_iss(claims, iss): + return claims['sub'] == iss diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7523/jwt_bearer.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7523/jwt_bearer.py new file mode 100644 index 0000000..a11336d --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7523/jwt_bearer.py @@ -0,0 +1,155 @@ +import logging +from authlib.jose import jwt +from authlib.jose.errors import JoseError +from ..rfc6749 import BaseGrant, TokenEndpointMixin +from ..rfc6749 import ( + UnauthorizedClientError, + InvalidRequestError, + InvalidGrantError +) +from .assertion import sign_jwt_bearer_assertion + +log = logging.getLogger(__name__) +JWT_BEARER_GRANT_TYPE = 'urn:ietf:params:oauth:grant-type:jwt-bearer' + + +class JWTBearerGrant(BaseGrant, TokenEndpointMixin): + GRANT_TYPE = JWT_BEARER_GRANT_TYPE + + @staticmethod + def sign(key, issuer, audience, subject=None, + issued_at=None, expires_at=None, claims=None, **kwargs): + return sign_jwt_bearer_assertion( + key, issuer, audience, subject, issued_at, + expires_at, claims, **kwargs) + + def create_claims_options(self): + """Create a claims_options for verify JWT payload claims. Developers + MAY overwrite this method to create a more strict options. + """ + # https://tools.ietf.org/html/rfc7523#section-3 + return { + 'iss': {'essential': True}, + 'sub': {'essential': True}, + 'aud': {'essential': True}, + 'exp': {'essential': True}, + } + + def process_assertion_claims(self, assertion): + """Extract JWT payload claims from request "assertion", per + `Section 3.1`_. + + :param assertion: assertion string value in the request + :return: JWTClaims + :raise: InvalidGrantError + + .. _`Section 3.1`: https://tools.ietf.org/html/rfc7523#section-3.1 + """ + claims = jwt.decode( + assertion, self.resolve_public_key, + claims_options=self.create_claims_options()) + try: + claims.validate() + except JoseError as e: + log.debug('Assertion Error: %r', e) + raise InvalidGrantError(description=e.description) + return claims + + def validate_token_request(self): + """The client makes a request to the token endpoint by sending the + following parameters using the "application/x-www-form-urlencoded" + format per `Section 2.1`_: + + grant_type + REQUIRED. Value MUST be set to + "urn:ietf:params:oauth:grant-type:jwt-bearer". + + assertion + REQUIRED. Value MUST contain a single JWT. + + scope + OPTIONAL. + + The following example demonstrates an access token request with a JWT + as an authorization grant: + + .. code-block:: http + + POST /token.oauth2 HTTP/1.1 + Host: as.example.com + Content-Type: application/x-www-form-urlencoded + + grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer + &assertion=eyJhbGciOiJFUzI1NiIsImtpZCI6IjE2In0. + eyJpc3Mi[...omitted for brevity...]. + J9l-ZhwP[...omitted for brevity...] + + .. _`Section 2.1`: https://tools.ietf.org/html/rfc7523#section-2.1 + """ + assertion = self.request.form.get('assertion') + if not assertion: + raise InvalidRequestError('Missing "assertion" in request') + + claims = self.process_assertion_claims(assertion) + client = self.authenticate_client(claims) + log.debug('Validate token request of %s', client) + + if not client.check_grant_type(self.GRANT_TYPE): + raise UnauthorizedClientError() + + self.request.client = client + self.validate_requested_scope() + self.request.user = self.authenticate_user(client, claims) + + def create_token_response(self): + """If valid and authorized, the authorization server issues an access + token. + """ + token = self.generate_token( + scope=self.request.scope, + include_refresh_token=False, + ) + log.debug('Issue token %r to %r', token, self.request.client) + self.save_token(token) + return 200, token, self.TOKEN_RESPONSE_HEADER + + def authenticate_user(self, client, claims): + """Authenticate user with the given assertion claims. Developers MUST + implement it in subclass, e.g.:: + + def authenticate_user(self, client, claims): + user = User.get_by_sub(claims['sub']) + if is_authorized_to_client(user, client): + return user + + :param client: OAuth Client instance + :param claims: assertion payload claims + :return: User instance + """ + raise NotImplementedError() + + def authenticate_client(self, claims): + """Authenticate client with the given assertion claims. Developers MUST + implement it in subclass, e.g.:: + + def authenticate_client(self, claims): + return Client.get_by_iss(claims['iss']) + + :param claims: assertion payload claims + :return: Client instance + """ + raise NotImplementedError() + + def resolve_public_key(self, headers, payload): + """Find public key to verify assertion signature. Developers MUST + implement it in subclass, e.g.:: + + def resolve_public_key(self, headers, payload): + jwk_set = get_jwk_set_by_iss(payload['iss']) + return filter_jwk_set(jwk_set, headers['kid']) + + :param headers: JWT headers dict + :param payload: JWT payload dict + :return: A public key + """ + raise NotImplementedError() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7591/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7591/__init__.py new file mode 100644 index 0000000..8ebb070 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7591/__init__.py @@ -0,0 +1,25 @@ +""" + authlib.oauth2.rfc7591 + ~~~~~~~~~~~~~~~~~~~~~~ + + This module represents a direct implementation of + OAuth 2.0 Dynamic Client Registration Protocol. + + https://tools.ietf.org/html/rfc7591 +""" + + +from .claims import ClientMetadataClaims +from .endpoint import ClientRegistrationEndpoint +from .errors import ( + InvalidRedirectURIError, + InvalidClientMetadataError, + InvalidSoftwareStatementError, + UnapprovedSoftwareStatementError, +) + +__all__ = [ + 'ClientMetadataClaims', 'ClientRegistrationEndpoint', + 'InvalidRedirectURIError', 'InvalidClientMetadataError', + 'InvalidSoftwareStatementError', 'UnapprovedSoftwareStatementError', +] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7591/claims.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7591/claims.py new file mode 100644 index 0000000..b6157b5 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7591/claims.py @@ -0,0 +1,218 @@ +from authlib.jose import BaseClaims, JsonWebKey +from authlib.jose.errors import InvalidClaimError +from authlib.common.urls import is_valid_url + + +class ClientMetadataClaims(BaseClaims): + # https://tools.ietf.org/html/rfc7591#section-2 + REGISTERED_CLAIMS = [ + 'redirect_uris', + 'token_endpoint_auth_method', + 'grant_types', + 'response_types', + 'client_name', + 'client_uri', + 'logo_uri', + 'scope', + 'contacts', + 'tos_uri', + 'policy_uri', + 'jwks_uri', + 'jwks', + 'software_id', + 'software_version', + ] + + def validate(self): + self._validate_essential_claims() + self.validate_redirect_uris() + self.validate_token_endpoint_auth_method() + self.validate_grant_types() + self.validate_response_types() + self.validate_client_name() + self.validate_client_uri() + self.validate_logo_uri() + self.validate_scope() + self.validate_contacts() + self.validate_tos_uri() + self.validate_policy_uri() + self.validate_jwks_uri() + self.validate_jwks() + self.validate_software_id() + self.validate_software_version() + + def validate_redirect_uris(self): + """Array of redirection URI strings for use in redirect-based flows + such as the authorization code and implicit flows. As required by + Section 2 of OAuth 2.0 [RFC6749], clients using flows with + redirection MUST register their redirection URI values. + Authorization servers that support dynamic registration for + redirect-based flows MUST implement support for this metadata + value. + """ + uris = self.get('redirect_uris') + if uris: + for uri in uris: + self._validate_uri('redirect_uris', uri) + + def validate_token_endpoint_auth_method(self): + """String indicator of the requested authentication method for the + token endpoint. + """ + # If unspecified or omitted, the default is "client_secret_basic" + if 'token_endpoint_auth_method' not in self: + self['token_endpoint_auth_method'] = 'client_secret_basic' + self._validate_claim_value('token_endpoint_auth_method') + + def validate_grant_types(self): + """Array of OAuth 2.0 grant type strings that the client can use at + the token endpoint. + """ + self._validate_claim_value('grant_types') + + def validate_response_types(self): + """Array of the OAuth 2.0 response type strings that the client can + use at the authorization endpoint. + """ + self._validate_claim_value('response_types') + + def validate_client_name(self): + """Human-readable string name of the client to be presented to the + end-user during authorization. If omitted, the authorization + server MAY display the raw "client_id" value to the end-user + instead. It is RECOMMENDED that clients always send this field. + The value of this field MAY be internationalized, as described in + Section 2.2. + """ + + def validate_client_uri(self): + """URL string of a web page providing information about the client. + If present, the server SHOULD display this URL to the end-user in + a clickable fashion. It is RECOMMENDED that clients always send + this field. The value of this field MUST point to a valid web + page. The value of this field MAY be internationalized, as + described in Section 2.2. + """ + self._validate_uri('client_uri') + + def validate_logo_uri(self): + """URL string that references a logo for the client. If present, the + server SHOULD display this image to the end-user during approval. + The value of this field MUST point to a valid image file. The + value of this field MAY be internationalized, as described in + Section 2.2. + """ + self._validate_uri('logo_uri') + + def validate_scope(self): + """String containing a space-separated list of scope values (as + described in Section 3.3 of OAuth 2.0 [RFC6749]) that the client + can use when requesting access tokens. The semantics of values in + this list are service specific. If omitted, an authorization + server MAY register a client with a default set of scopes. + """ + self._validate_claim_value('scope') + + def validate_contacts(self): + """Array of strings representing ways to contact people responsible + for this client, typically email addresses. The authorization + server MAY make these contact addresses available to end-users for + support requests for the client. See Section 6 for information on + Privacy Considerations. + """ + if 'contacts' in self and not isinstance(self['contacts'], list): + raise InvalidClaimError('contacts') + + def validate_tos_uri(self): + """URL string that points to a human-readable terms of service + document for the client that describes a contractual relationship + between the end-user and the client that the end-user accepts when + authorizing the client. The authorization server SHOULD display + this URL to the end-user if it is provided. The value of this + field MUST point to a valid web page. The value of this field MAY + be internationalized, as described in Section 2.2. + """ + self._validate_uri('tos_uri') + + def validate_policy_uri(self): + """URL string that points to a human-readable privacy policy document + that describes how the deployment organization collects, uses, + retains, and discloses personal data. The authorization server + SHOULD display this URL to the end-user if it is provided. The + value of this field MUST point to a valid web page. The value of + this field MAY be internationalized, as described in Section 2.2. + """ + self._validate_uri('policy_uri') + + def validate_jwks_uri(self): + """URL string referencing the client's JSON Web Key (JWK) Set + [RFC7517] document, which contains the client's public keys. The + value of this field MUST point to a valid JWK Set document. These + keys can be used by higher-level protocols that use signing or + encryption. For instance, these keys might be used by some + applications for validating signed requests made to the token + endpoint when using JWTs for client authentication [RFC7523]. Use + of this parameter is preferred over the "jwks" parameter, as it + allows for easier key rotation. The "jwks_uri" and "jwks" + parameters MUST NOT both be present in the same request or + response. + """ + # TODO: use real HTTP library + self._validate_uri('jwks_uri') + + def validate_jwks(self): + """Client's JSON Web Key Set [RFC7517] document value, which contains + the client's public keys. The value of this field MUST be a JSON + object containing a valid JWK Set. These keys can be used by + higher-level protocols that use signing or encryption. This + parameter is intended to be used by clients that cannot use the + "jwks_uri" parameter, such as native clients that cannot host + public URLs. The "jwks_uri" and "jwks" parameters MUST NOT both + be present in the same request or response. + """ + if 'jwks' in self: + if 'jwks_uri' in self: + # The "jwks_uri" and "jwks" parameters MUST NOT both be present + raise InvalidClaimError('jwks') + + jwks = self['jwks'] + try: + key_set = JsonWebKey.import_key_set(jwks) + if not key_set: + raise InvalidClaimError('jwks') + except ValueError: + raise InvalidClaimError('jwks') + + def validate_software_id(self): + """A unique identifier string (e.g., a Universally Unique Identifier + (UUID)) assigned by the client developer or software publisher + used by registration endpoints to identify the client software to + be dynamically registered. Unlike "client_id", which is issued by + the authorization server and SHOULD vary between instances, the + "software_id" SHOULD remain the same for all instances of the + client software. The "software_id" SHOULD remain the same across + multiple updates or versions of the same piece of software. The + value of this field is not intended to be human readable and is + usually opaque to the client and authorization server. + """ + + def validate_software_version(self): + """A version identifier string for the client software identified by + "software_id". The value of the "software_version" SHOULD change + on any update to the client software identified by the same + "software_id". The value of this field is intended to be compared + using string equality matching and no other comparison semantics + are defined by this specification. The value of this field is + outside the scope of this specification, but it is not intended to + be human readable and is usually opaque to the client and + authorization server. The definition of what constitutes an + update to client software that would trigger a change to this + value is specific to the software itself and is outside the scope + of this specification. + """ + + def _validate_uri(self, key, uri=None): + if uri is None: + uri = self.get(key) + if uri and not is_valid_url(uri): + raise InvalidClaimError(key) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7591/endpoint.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7591/endpoint.py new file mode 100644 index 0000000..eff588c --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7591/endpoint.py @@ -0,0 +1,199 @@ +import os +import time +import binascii +from authlib.consts import default_json_headers +from authlib.common.security import generate_token +from authlib.jose import JsonWebToken, JoseError +from ..rfc6749 import AccessDeniedError, InvalidRequestError +from ..rfc6749.util import scope_to_list +from .claims import ClientMetadataClaims +from .errors import ( + InvalidClientMetadataError, + UnapprovedSoftwareStatementError, + InvalidSoftwareStatementError, +) + + +class ClientRegistrationEndpoint(object): + """The client registration endpoint is an OAuth 2.0 endpoint designed to + allow a client to be registered with the authorization server. + """ + ENDPOINT_NAME = 'client_registration' + + #: The claims validation class + claims_class = ClientMetadataClaims + + #: Rewrite this value with a list to support ``software_statement`` + #: e.g. ``software_statement_alg_values_supported = ['RS256']`` + software_statement_alg_values_supported = None + + def __init__(self, server): + self.server = server + + def __call__(self, request): + return self.create_registration_response(request) + + def create_registration_response(self, request): + token = self.authenticate_token(request) + if not token: + raise AccessDeniedError() + + request.credential = token + + client_metadata = self.extract_client_metadata(request) + client_info = self.generate_client_info() + body = {} + body.update(client_metadata) + body.update(client_info) + client = self.save_client(client_info, client_metadata, request) + registration_info = self.generate_client_registration_info(client, request) + if registration_info: + body.update(registration_info) + return 201, body, default_json_headers + + def extract_client_metadata(self, request): + if not request.data: + raise InvalidRequestError() + + json_data = request.data.copy() + software_statement = json_data.pop('software_statement', None) + if software_statement and self.software_statement_alg_values_supported: + data = self.extract_software_statement(software_statement, request) + json_data.update(data) + + options = self.get_claims_options() + claims = self.claims_class(json_data, {}, options, self.server.metadata) + try: + claims.validate() + except JoseError as error: + raise InvalidClientMetadataError(error.description) + return claims.get_registered_claims() + + def extract_software_statement(self, software_statement, request): + key = self.resolve_public_key(request) + if not key: + raise UnapprovedSoftwareStatementError() + + try: + jwt = JsonWebToken(self.software_statement_alg_values_supported) + claims = jwt.decode(software_statement, key) + # there is no need to validate claims + return claims + except JoseError: + raise InvalidSoftwareStatementError() + + def get_claims_options(self): + """Generate claims options validation from Authorization Server metadata.""" + metadata = self.server.metadata + if not metadata: + return {} + + scopes_supported = metadata.get('scopes_supported') + response_types_supported = metadata.get('response_types_supported') + grant_types_supported = metadata.get('grant_types_supported') + auth_methods_supported = metadata.get('token_endpoint_auth_methods_supported') + options = {} + if scopes_supported is not None: + scopes_supported = set(scopes_supported) + + def _validate_scope(claims, value): + if not value: + return True + scopes = set(scope_to_list(value)) + return scopes_supported.issuperset(scopes) + + options['scope'] = {'validate': _validate_scope} + + if response_types_supported is not None: + response_types_supported = set(response_types_supported) + + def _validate_response_types(claims, value): + return response_types_supported.issuperset(set(value)) + + options['response_types'] = {'validate': _validate_response_types} + + if grant_types_supported is not None: + grant_types_supported = set(grant_types_supported) + + def _validate_grant_types(claims, value): + return grant_types_supported.issuperset(set(value)) + + options['grant_types'] = {'validate': _validate_grant_types} + + if auth_methods_supported is not None: + options['token_endpoint_auth_method'] = {'values': auth_methods_supported} + + return options + + def generate_client_info(self): + # https://tools.ietf.org/html/rfc7591#section-3.2.1 + client_id = self.generate_client_id() + client_secret = self.generate_client_secret() + client_id_issued_at = int(time.time()) + client_secret_expires_at = 0 + return dict( + client_id=client_id, + client_secret=client_secret, + client_id_issued_at=client_id_issued_at, + client_secret_expires_at=client_secret_expires_at, + ) + + def generate_client_registration_info(self, client, request): + """Generate ```registration_client_uri`` and ``registration_access_token`` + for RFC7592. This method returns ``None`` by default. Developers MAY rewrite + this method to return registration information.""" + return None + + def create_endpoint_request(self, request): + return self.server.create_json_request(request) + + def generate_client_id(self): + """Generate ``client_id`` value. Developers MAY rewrite this method + to use their own way to generate ``client_id``. + """ + return generate_token(42) + + def generate_client_secret(self): + """Generate ``client_secret`` value. Developers MAY rewrite this method + to use their own way to generate ``client_secret``. + """ + return binascii.hexlify(os.urandom(24)).decode('ascii') + + def authenticate_token(self, request): + """Authenticate current credential who is requesting to register a client. + Developers MUST implement this method in subclass:: + + def authenticate_token(self, request): + auth = request.headers.get('Authorization') + return get_token_by_auth(auth) + + :return: token instance + """ + raise NotImplementedError() + + def resolve_public_key(self, request): + """Resolve a public key for decoding ``software_statement``. If + ``enable_software_statement=True``, developers MUST implement this + method in subclass:: + + def resolve_public_key(self, request): + return get_public_key_from_user(request.credential) + + :return: JWK or Key string + """ + raise NotImplementedError() + + def save_client(self, client_info, client_metadata, request): + """Save client into database. Developers MUST implement this method + in subclass:: + + def save_client(self, client_info, client_metadata, request): + client = OAuthClient( + client_id=client_info['client_id'], + client_secret=client_info['client_secret'], + ... + ) + client.save() + return client + """ + raise NotImplementedError() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7591/errors.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7591/errors.py new file mode 100644 index 0000000..31693c0 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7591/errors.py @@ -0,0 +1,33 @@ +from ..rfc6749 import OAuth2Error + + +class InvalidRedirectURIError(OAuth2Error): + """The value of one or more redirection URIs is invalid. + https://tools.ietf.org/html/rfc7591#section-3.2.2 + """ + error = 'invalid_redirect_uri' + + +class InvalidClientMetadataError(OAuth2Error): + """The value of one of the client metadata fields is invalid and the + server has rejected this request. Note that an authorization + server MAY choose to substitute a valid value for any requested + parameter of a client's metadata. + https://tools.ietf.org/html/rfc7591#section-3.2.2 + """ + error = 'invalid_client_metadata' + + +class InvalidSoftwareStatementError(OAuth2Error): + """The software statement presented is invalid. + https://tools.ietf.org/html/rfc7591#section-3.2.2 + """ + error = 'invalid_software_statement' + + +class UnapprovedSoftwareStatementError(OAuth2Error): + """The software statement presented is not approved for use by this + authorization server. + https://tools.ietf.org/html/rfc7591#section-3.2.2 + """ + error = 'unapproved_software_statement' diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7592/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7592/__init__.py new file mode 100644 index 0000000..6a6457b --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7592/__init__.py @@ -0,0 +1,13 @@ +""" + authlib.oauth2.rfc7592 + ~~~~~~~~~~~~~~~~~~~~~~ + + This module represents a direct implementation of + OAuth 2.0 Dynamic Client Registration Management Protocol. + + https://tools.ietf.org/html/rfc7592 +""" + +from .endpoint import ClientConfigurationEndpoint + +__all__ = ['ClientConfigurationEndpoint'] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7592/endpoint.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7592/endpoint.py new file mode 100644 index 0000000..5a036d7 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7592/endpoint.py @@ -0,0 +1,172 @@ +from authlib.consts import default_json_headers +from ..rfc6749 import AccessDeniedError +from ..rfc6750 import InvalidTokenError + + +class ClientConfigurationEndpoint(object): + ENDPOINT_NAME = 'client_configuration' + + def __init__(self, server): + self.server = server + + def __call__(self, request): + return self.create_configuration_response(request) + + def create_configuration_response(self, request): + token = self.authenticate_token(request) + if not token: + raise InvalidTokenError() + + request.credential = token + + client = self.authenticate_client(request) + if not client: + # If the client does not exist on this server, the server MUST respond + # with HTTP 401 Unauthorized and the registration access token used to + # make this request SHOULD be immediately revoked. + self.revoke_access_token(request) + raise InvalidTokenError() + + if not self.check_permission(client, request): + # If the client does not have permission to read its record, the server + # MUST return an HTTP 403 Forbidden. + raise AccessDeniedError() + + request.client = client + + if request.method == 'GET': + return self.create_read_client_response(client, request) + elif request.method == 'DELETE': + return self.create_delete_client_response(client, request) + elif request.method == 'PUT': + return self.create_update_client_response(client, request) + + def create_endpoint_request(self, request): + return self.server.create_json_request(request) + + def create_read_client_response(self, client, request): + body = self.introspect_client(client) + info = self.generate_client_registration_info(client, request) + body.update(info) + return 200, body, default_json_headers + + def create_delete_client_response(self, client, request): + """To deprive itself on the authorization server, the client makes + an HTTP DELETE request to the client configuration endpoint. This + request is authenticated by the registration access token issued to + the client. + + The following is a non-normative example request:: + + DELETE /register/s6BhdRkqt3 HTTP/1.1 + Host: server.example.com + Authorization: Bearer reg-23410913-abewfq.123483 + """ + self.delete_client(client, request) + headers = [ + ('Cache-Control', 'no-store'), + ('Pragma', 'no-cache'), + ] + return 204, '', headers + + def create_update_client_response(self, client, request): + """ To update a previously registered client's registration with an + authorization server, the client makes an HTTP PUT request to the + client configuration endpoint with a content type of "application/ + json". + + The following is a non-normative example request:: + + PUT /register/s6BhdRkqt3 HTTP/1.1 + Accept: application/json + Host: server.example.com + Authorization: Bearer reg-23410913-abewfq.123483 + + { + "client_id": "s6BhdRkqt3", + "client_secret": "cf136dc3c1fc93f31185e5885805d", + "redirect_uris": [ + "https://client.example.org/callback", + "https://client.example.org/alt" + ], + "grant_types": ["authorization_code", "refresh_token"], + "token_endpoint_auth_method": "client_secret_basic", + "jwks_uri": "https://client.example.org/my_public_keys.jwks", + "client_name": "My New Example", + "client_name#fr": "Mon Nouvel Exemple", + "logo_uri": "https://client.example.org/newlogo.png", + "logo_uri#fr": "https://client.example.org/fr/newlogo.png" + } + """ + # The updated client metadata fields request MUST NOT include the + # "registration_access_token", "registration_client_uri", + # "client_secret_expires_at", or "client_id_issued_at" fields + must_not_include = ( + 'registration_access_token', 'registration_client_uri', + 'client_secret_expires_at', 'client_id_issued_at', + ) + for k in must_not_include: + if k in request.data: + return + + # The client MUST include its "client_id" field in the request + client_id = request.data.get('client_id') + if not client_id: + raise + if client_id != client.get_client_id(): + raise + + # If the client includes the "client_secret" field in the request, + # the value of this field MUST match the currently issued client + # secret for that client. + if 'client_secret' in request.data: + if not client.check_client_secret(request.data['client_secret']): + raise + + client = self.save_client(client, request) + return self.create_read_client_response(client, request) + + def generate_client_registration_info(self, client, request): + """Generate ```registration_client_uri`` and ``registration_access_token`` + for RFC7592. This method returns ``None`` by default. Developers MAY rewrite + this method to return registration information.""" + raise NotImplementedError() + + def authenticate_token(self, request): + """Authenticate current credential who is requesting to register a client. + Developers MUST implement this method in subclass:: + + def authenticate_token(self, request): + auth = request.headers.get('Authorization') + return get_token_by_auth(auth) + + :return: token instance + """ + raise NotImplementedError() + + def authenticate_client(self, request): + raise NotImplementedError() + + def revoke_access_token(self, request): + raise NotImplementedError() + + def check_permission(self, client, request): + raise NotImplementedError() + + def introspect_client(self, client): + raise NotImplementedError() + + def delete_client(self, client, request): + """Delete authorization code from database or cache. Developers MUST + implement it in subclass, e.g.:: + + def delete_client(self, client, request): + client.delete() + + :param client: the instance of OAuth client + :param request: formatted request instance + """ + raise NotImplementedError() + + def save_client(self, client, request): + raise NotImplementedError() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7636/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7636/__init__.py new file mode 100644 index 0000000..d943f3e --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7636/__init__.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +""" + authlib.oauth2.rfc7636 + ~~~~~~~~~~~~~~~~~~~~~~ + + This module represents a direct implementation of + Proof Key for Code Exchange by OAuth Public Clients. + + https://tools.ietf.org/html/rfc7636 +""" + +from .challenge import CodeChallenge, create_s256_code_challenge + +__all__ = ['CodeChallenge', 'create_s256_code_challenge'] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7636/challenge.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7636/challenge.py new file mode 100644 index 0000000..26159b8 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7636/challenge.py @@ -0,0 +1,134 @@ +import re +import hashlib +from authlib.common.encoding import to_bytes, to_unicode, urlsafe_b64encode +from ..rfc6749.errors import InvalidRequestError, InvalidGrantError + + +CODE_VERIFIER_PATTERN = re.compile(r'^[a-zA-Z0-9\-._~]{43,128}$') + + +def create_s256_code_challenge(code_verifier): + """Create S256 code_challenge with the given code_verifier.""" + data = hashlib.sha256(to_bytes(code_verifier, 'ascii')).digest() + return to_unicode(urlsafe_b64encode(data)) + + +def compare_plain_code_challenge(code_verifier, code_challenge): + # If the "code_challenge_method" from Section 4.3 was "plain", + # they are compared directly + return code_verifier == code_challenge + + +def compare_s256_code_challenge(code_verifier, code_challenge): + # BASE64URL-ENCODE(SHA256(ASCII(code_verifier))) == code_challenge + return create_s256_code_challenge(code_verifier) == code_challenge + + +class CodeChallenge(object): + """CodeChallenge extension to Authorization Code Grant. It is used to + improve the security of Authorization Code flow for public clients by + sending extra "code_challenge" and "code_verifier" to the authorization + server. + + The AuthorizationCodeGrant SHOULD save the ``code_challenge`` and + ``code_challenge_method`` into database when ``save_authorization_code``. + Then register this extension via:: + + server.register_grant( + AuthorizationCodeGrant, + [CodeChallenge(required=True)] + ) + """ + #: defaults to "plain" if not present in the request + DEFAULT_CODE_CHALLENGE_METHOD = 'plain' + #: supported ``code_challenge_method`` + SUPPORTED_CODE_CHALLENGE_METHOD = ['plain', 'S256'] + + CODE_CHALLENGE_METHODS = { + 'plain': compare_plain_code_challenge, + 'S256': compare_s256_code_challenge, + } + + def __init__(self, required=True): + self.required = required + + def __call__(self, grant): + grant.register_hook( + 'after_validate_authorization_request', + self.validate_code_challenge, + ) + grant.register_hook( + 'after_validate_token_request', + self.validate_code_verifier, + ) + + def validate_code_challenge(self, grant): + request = grant.request + challenge = request.args.get('code_challenge') + method = request.args.get('code_challenge_method') + if not challenge and not method: + return + + if not challenge: + raise InvalidRequestError('Missing "code_challenge"') + + if method and method not in self.SUPPORTED_CODE_CHALLENGE_METHOD: + raise InvalidRequestError('Unsupported "code_challenge_method"') + + def validate_code_verifier(self, grant): + request = grant.request + verifier = request.form.get('code_verifier') + + # public client MUST verify code challenge + if self.required and request.auth_method == 'none' and not verifier: + raise InvalidRequestError('Missing "code_verifier"') + + authorization_code = request.credential + challenge = self.get_authorization_code_challenge(authorization_code) + + # ignore, it is the normal RFC6749 authorization_code request + if not challenge and not verifier: + return + + # challenge exists, code_verifier is required + if not verifier: + raise InvalidRequestError('Missing "code_verifier"') + + if not CODE_VERIFIER_PATTERN.match(verifier): + raise InvalidRequestError('Invalid "code_verifier"') + + # 4.6. Server Verifies code_verifier before Returning the Tokens + method = self.get_authorization_code_challenge_method(authorization_code) + if method is None: + method = self.DEFAULT_CODE_CHALLENGE_METHOD + + func = self.CODE_CHALLENGE_METHODS.get(method) + if not func: + raise RuntimeError('No verify method for "{}"'.format(method)) + + # If the values are not equal, an error response indicating + # "invalid_grant" MUST be returned. + if not func(verifier, challenge): + raise InvalidGrantError(description='Code challenge failed.') + + def get_authorization_code_challenge(self, authorization_code): + """Get "code_challenge" associated with this authorization code. + Developers MAY re-implement it in subclass, the default logic:: + + def get_authorization_code_challenge(self, authorization_code): + return authorization_code.code_challenge + + :param authorization_code: the instance of authorization_code + """ + return authorization_code.code_challenge + + def get_authorization_code_challenge_method(self, authorization_code): + """Get "code_challenge_method" associated with this authorization code. + Developers MAY re-implement it in subclass, the default logic:: + + def get_authorization_code_challenge_method(self, authorization_code): + return authorization_code.code_challenge_method + + :param authorization_code: the instance of authorization_code + """ + return authorization_code.code_challenge_method diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7662/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7662/__init__.py new file mode 100644 index 0000000..2837761 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7662/__init__.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +""" + authlib.oauth2.rfc7662 + ~~~~~~~~~~~~~~~~~~~~~~ + + This module represents a direct implementation of + OAuth 2.0 Token Introspection. + + https://tools.ietf.org/html/rfc7662 +""" + +from .introspection import IntrospectionEndpoint +from .models import IntrospectionToken + +__all__ = ['IntrospectionEndpoint', 'IntrospectionToken'] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7662/introspection.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7662/introspection.py new file mode 100644 index 0000000..44c76c8 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7662/introspection.py @@ -0,0 +1,119 @@ +import time +from authlib.consts import default_json_headers +from ..rfc6749 import ( + TokenEndpoint, + InvalidRequestError, + UnsupportedTokenTypeError, +) + + +class IntrospectionEndpoint(TokenEndpoint): + """Implementation of introspection endpoint which is described in + `RFC7662`_. + + .. _RFC7662: https://tools.ietf.org/html/rfc7662 + """ + #: Endpoint name to be registered + ENDPOINT_NAME = 'introspection' + + def authenticate_endpoint_credential(self, request, client): + """The protected resource calls the introspection endpoint using an HTTP + ``POST`` request with parameters sent as + "application/x-www-form-urlencoded" data. The protected resource sends a + parameter representing the token along with optional parameters + representing additional context that is known by the protected resource + to aid the authorization server in its response. + + token + **REQUIRED** The string value of the token. For access tokens, this + is the ``access_token`` value returned from the token endpoint + defined in OAuth 2.0. For refresh tokens, this is the + ``refresh_token`` value returned from the token endpoint as defined + in OAuth 2.0. + + token_type_hint + **OPTIONAL** A hint about the type of the token submitted for + introspection. + """ + params = request.form + if 'token' not in params: + raise InvalidRequestError() + + token_type = params.get('token_type_hint') + if token_type and token_type not in self.SUPPORTED_TOKEN_TYPES: + raise UnsupportedTokenTypeError() + + return self.query_token(params['token'], token_type, client) + + def create_endpoint_response(self, request): + """Validate introspection request and create the response. + + :returns: (status_code, body, headers) + """ + # The authorization server first validates the client credentials + client = self.authenticate_endpoint_client(request) + + # then verifies whether the token was issued to the client making + # the revocation request + credential = self.authenticate_endpoint_credential(request, client) + + # the authorization server invalidates the token + body = self.create_introspection_payload(credential) + return 200, body, default_json_headers + + def create_introspection_payload(self, token): + # the token is not active, does not exist on this server, or the + # protected resource is not allowed to introspect this particular + # token, then the authorization server MUST return an introspection + # response with the "active" field set to "false" + if not token: + return {'active': False} + expires_at = token.get_expires_at() + if expires_at < time.time() or token.revoked: + return {'active': False} + payload = self.introspect_token(token) + if 'active' not in payload: + payload['active'] = True + return payload + + def query_token(self, token, token_type_hint, client): + """Get the token from database/storage by the given token string. + Developers should implement this method:: + + def query_token(self, token, token_type_hint, client): + if token_type_hint == 'access_token': + tok = Token.query_by_access_token(token) + elif token_type_hint == 'refresh_token': + tok = Token.query_by_refresh_token(token) + else: + tok = Token.query_by_access_token(token) + if not tok: + tok = Token.query_by_refresh_token(token) + + if check_client_permission(client, tok): + return tok + """ + raise NotImplementedError() + + def introspect_token(self, token): + """Read given token and return its introspection metadata as a + dictionary following `Section 2.2`_:: + + def introspect_token(self, token): + active = is_token_active(token) + return { + 'active': active, + 'client_id': token.client_id, + 'token_type': token.token_type, + 'username': get_token_username(token), + 'scope': token.get_scope(), + 'sub': get_token_user_sub(token), + 'aud': token.client_id, + 'iss': 'https://server.example.com/', + 'exp': token.expires_at, + 'iat': token.issued_at, + } + + .. _`Section 2.2`: https://tools.ietf.org/html/rfc7662#section-2.2 + """ + raise NotImplementedError() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7662/models.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7662/models.py new file mode 100644 index 0000000..0f4f0c2 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc7662/models.py @@ -0,0 +1,30 @@ +from ..rfc6749 import TokenMixin + + +class IntrospectionToken(dict, TokenMixin): + def get_client_id(self): + return self.get('client_id') + + def get_scope(self): + return self.get('scope') + + def get_expires_in(self): + # this method is only used in refresh token, + # no need to implement it + return 0 + + def get_expires_at(self): + return self.get('exp', 0) + + def __getattr__(self, key): + # https://tools.ietf.org/html/rfc7662#section-2.2 + available_keys = { + 'active', 'scope', 'client_id', 'username', 'token_type', + 'exp', 'iat', 'nbf', 'sub', 'aud', 'iss', 'jti' + } + try: + return object.__getattribute__(self, key) + except AttributeError as error: + if key in available_keys: + return self.get(key) + raise error diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8414/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8414/__init__.py new file mode 100644 index 0000000..2cdbfbd --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8414/__init__.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +""" + authlib.oauth2.rfc8414 + ~~~~~~~~~~~~~~~~~~~~~~ + + This module represents a direct implementation of + OAuth 2.0 Authorization Server Metadata. + + https://tools.ietf.org/html/rfc8414 +""" + +from .models import AuthorizationServerMetadata +from .well_known import get_well_known_url + + +__all__ = ['AuthorizationServerMetadata', 'get_well_known_url'] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8414/models.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8414/models.py new file mode 100644 index 0000000..3e89a5c --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8414/models.py @@ -0,0 +1,368 @@ +from authlib.common.urls import urlparse, is_valid_url +from authlib.common.security import is_secure_transport + + +class AuthorizationServerMetadata(dict): + """Define Authorization Server Metadata via `Section 2`_ in RFC8414_. + + .. _RFC8414: https://tools.ietf.org/html/rfc8414 + .. _`Section 2`: https://tools.ietf.org/html/rfc8414#section-2 + """ + REGISTRY_KEYS = [ + 'issuer', 'authorization_endpoint', 'token_endpoint', + 'jwks_uri', 'registration_endpoint', 'scopes_supported', + 'response_types_supported', 'response_modes_supported', + 'grant_types_supported', 'token_endpoint_auth_methods_supported', + 'token_endpoint_auth_signing_alg_values_supported', + 'service_documentation', 'ui_locales_supported', + 'op_policy_uri', 'op_tos_uri', 'revocation_endpoint', + 'revocation_endpoint_auth_methods_supported', + 'revocation_endpoint_auth_signing_alg_values_supported', + 'introspection_endpoint', + 'introspection_endpoint_auth_methods_supported', + 'introspection_endpoint_auth_signing_alg_values_supported', + 'code_challenge_methods_supported', + ] + + def validate_issuer(self): + """REQUIRED. The authorization server's issuer identifier, which is + a URL that uses the "https" scheme and has no query or fragment + components. + """ + issuer = self.get('issuer') + + #: 1. REQUIRED + if not issuer: + raise ValueError('"issuer" is required') + + parsed = urlparse.urlparse(issuer) + + #: 2. uses the "https" scheme + if not is_secure_transport(issuer): + raise ValueError('"issuer" MUST use "https" scheme') + + #: 3. has no query or fragment + if parsed.query or parsed.fragment: + raise ValueError('"issuer" has no query or fragment') + + def validate_authorization_endpoint(self): + """URL of the authorization server's authorization endpoint + [RFC6749]. This is REQUIRED unless no grant types are supported + that use the authorization endpoint. + """ + url = self.get('authorization_endpoint') + if url: + if not is_secure_transport(url): + raise ValueError( + '"authorization_endpoint" MUST use "https" scheme') + return + + grant_types_supported = set(self.grant_types_supported) + authorization_grant_types = {'authorization_code', 'implicit'} + if grant_types_supported & authorization_grant_types: + raise ValueError('"authorization_endpoint" is required') + + def validate_token_endpoint(self): + """URL of the authorization server's token endpoint [RFC6749]. This + is REQUIRED unless only the implicit grant type is supported. + """ + grant_types_supported = self.get('grant_types_supported') + if grant_types_supported and len(grant_types_supported) == 1 and \ + grant_types_supported[0] == 'implicit': + return + + url = self.get('token_endpoint') + if not url: + raise ValueError('"token_endpoint" is required') + + if not is_secure_transport(url): + raise ValueError('"token_endpoint" MUST use "https" scheme') + + def validate_jwks_uri(self): + """OPTIONAL. URL of the authorization server's JWK Set [JWK] + document. The referenced document contains the signing key(s) the + client uses to validate signatures from the authorization server. + This URL MUST use the "https" scheme. The JWK Set MAY also + contain the server's encryption key or keys, which are used by + clients to encrypt requests to the server. When both signing and + encryption keys are made available, a "use" (public key use) + parameter value is REQUIRED for all keys in the referenced JWK Set + to indicate each key's intended usage. + """ + url = self.get('jwks_uri') + if url and not is_secure_transport(url): + raise ValueError('"jwks_uri" MUST use "https" scheme') + + def validate_registration_endpoint(self): + """OPTIONAL. URL of the authorization server's OAuth 2.0 Dynamic + Client Registration endpoint [RFC7591]. + """ + url = self.get('registration_endpoint') + if url and not is_secure_transport(url): + raise ValueError( + '"registration_endpoint" MUST use "https" scheme') + + def validate_scopes_supported(self): + """RECOMMENDED. JSON array containing a list of the OAuth 2.0 + [RFC6749] "scope" values that this authorization server supports. + Servers MAY choose not to advertise some supported scope values + even when this parameter is used. + """ + validate_array_value(self, 'scopes_supported') + + def validate_response_types_supported(self): + """REQUIRED. JSON array containing a list of the OAuth 2.0 + "response_type" values that this authorization server supports. + The array values used are the same as those used with the + "response_types" parameter defined by "OAuth 2.0 Dynamic Client + Registration Protocol" [RFC7591]. + """ + response_types_supported = self.get('response_types_supported') + if not response_types_supported: + raise ValueError('"response_types_supported" is required') + if not isinstance(response_types_supported, list): + raise ValueError('"response_types_supported" MUST be JSON array') + + def validate_response_modes_supported(self): + """OPTIONAL. JSON array containing a list of the OAuth 2.0 + "response_mode" values that this authorization server supports, as + specified in "OAuth 2.0 Multiple Response Type Encoding Practices" + [OAuth.Responses]. If omitted, the default is "["query", + "fragment"]". The response mode value "form_post" is also defined + in "OAuth 2.0 Form Post Response Mode" [OAuth.Post]. + """ + validate_array_value(self, 'response_modes_supported') + + def validate_grant_types_supported(self): + """OPTIONAL. JSON array containing a list of the OAuth 2.0 grant + type values that this authorization server supports. The array + values used are the same as those used with the "grant_types" + parameter defined by "OAuth 2.0 Dynamic Client Registration + Protocol" [RFC7591]. If omitted, the default value is + "["authorization_code", "implicit"]". + """ + validate_array_value(self, 'grant_types_supported') + + def validate_token_endpoint_auth_methods_supported(self): + """OPTIONAL. JSON array containing a list of client authentication + methods supported by this token endpoint. Client authentication + method values are used in the "token_endpoint_auth_method" + parameter defined in Section 2 of [RFC7591]. If omitted, the + default is "client_secret_basic" -- the HTTP Basic Authentication + Scheme specified in Section 2.3.1 of OAuth 2.0 [RFC6749]. + """ + validate_array_value(self, 'token_endpoint_auth_methods_supported') + + def validate_token_endpoint_auth_signing_alg_values_supported(self): + """OPTIONAL. JSON array containing a list of the JWS signing + algorithms ("alg" values) supported by the token endpoint for the + signature on the JWT [JWT] used to authenticate the client at the + token endpoint for the "private_key_jwt" and "client_secret_jwt" + authentication methods. This metadata entry MUST be present if + either of these authentication methods are specified in the + "token_endpoint_auth_methods_supported" entry. No default + algorithms are implied if this entry is omitted. Servers SHOULD + support "RS256". The value "none" MUST NOT be used. + """ + _validate_alg_values( + self, + 'token_endpoint_auth_signing_alg_values_supported', + self.token_endpoint_auth_methods_supported + ) + + def validate_service_documentation(self): + """OPTIONAL. URL of a page containing human-readable information + that developers might want or need to know when using the + authorization server. In particular, if the authorization server + does not support Dynamic Client Registration, then information on + how to register clients needs to be provided in this + documentation. + """ + value = self.get('service_documentation') + if value and not is_valid_url(value): + raise ValueError('"service_documentation" MUST be a URL') + + def validate_ui_locales_supported(self): + """OPTIONAL. Languages and scripts supported for the user interface, + represented as a JSON array of language tag values from BCP 47 + [RFC5646]. If omitted, the set of supported languages and scripts + is unspecified. + """ + validate_array_value(self, 'ui_locales_supported') + + def validate_op_policy_uri(self): + """OPTIONAL. URL that the authorization server provides to the + person registering the client to read about the authorization + server's requirements on how the client can use the data provided + by the authorization server. The registration process SHOULD + display this URL to the person registering the client if it is + given. As described in Section 5, despite the identifier + "op_policy_uri" appearing to be OpenID-specific, its usage in this + specification is actually referring to a general OAuth 2.0 feature + that is not specific to OpenID Connect. + """ + value = self.get('op_policy_uri') + if value and not is_valid_url(value): + raise ValueError('"op_policy_uri" MUST be a URL') + + def validate_op_tos_uri(self): + """OPTIONAL. URL that the authorization server provides to the + person registering the client to read about the authorization + server's terms of service. The registration process SHOULD + display this URL to the person registering the client if it is + given. As described in Section 5, despite the identifier + "op_tos_uri", appearing to be OpenID-specific, its usage in this + specification is actually referring to a general OAuth 2.0 feature + that is not specific to OpenID Connect. + """ + value = self.get('op_tos_uri') + if value and not is_valid_url(value): + raise ValueError('"op_tos_uri" MUST be a URL') + + def validate_revocation_endpoint(self): + """OPTIONAL. URL of the authorization server's OAuth 2.0 revocation + endpoint [RFC7009].""" + url = self.get('revocation_endpoint') + if url and not is_secure_transport(url): + raise ValueError('"revocation_endpoint" MUST use "https" scheme') + + def validate_revocation_endpoint_auth_methods_supported(self): + """OPTIONAL. JSON array containing a list of client authentication + methods supported by this revocation endpoint. The valid client + authentication method values are those registered in the IANA + "OAuth Token Endpoint Authentication Methods" registry + [IANA.OAuth.Parameters]. If omitted, the default is + "client_secret_basic" -- the HTTP Basic Authentication Scheme + specified in Section 2.3.1 of OAuth 2.0 [RFC6749]. + """ + validate_array_value(self, 'revocation_endpoint_auth_methods_supported') + + def validate_revocation_endpoint_auth_signing_alg_values_supported(self): + """OPTIONAL. JSON array containing a list of the JWS signing + algorithms ("alg" values) supported by the revocation endpoint for + the signature on the JWT [JWT] used to authenticate the client at + the revocation endpoint for the "private_key_jwt" and + "client_secret_jwt" authentication methods. This metadata entry + MUST be present if either of these authentication methods are + specified in the "revocation_endpoint_auth_methods_supported" + entry. No default algorithms are implied if this entry is + omitted. The value "none" MUST NOT be used. + """ + _validate_alg_values( + self, + 'revocation_endpoint_auth_signing_alg_values_supported', + self.revocation_endpoint_auth_methods_supported + ) + + def validate_introspection_endpoint(self): + """OPTIONAL. URL of the authorization server's OAuth 2.0 + introspection endpoint [RFC7662]. + """ + url = self.get('introspection_endpoint') + if url and not is_secure_transport(url): + raise ValueError( + '"introspection_endpoint" MUST use "https" scheme') + + def validate_introspection_endpoint_auth_methods_supported(self): + """OPTIONAL. JSON array containing a list of client authentication + methods supported by this introspection endpoint. The valid + client authentication method values are those registered in the + IANA "OAuth Token Endpoint Authentication Methods" registry + [IANA.OAuth.Parameters] or those registered in the IANA "OAuth + Access Token Types" registry [IANA.OAuth.Parameters]. (These + values are and will remain distinct, due to Section 7.2.) If + omitted, the set of supported authentication methods MUST be + determined by other means. + """ + validate_array_value(self, 'introspection_endpoint_auth_methods_supported') + + def validate_introspection_endpoint_auth_signing_alg_values_supported(self): + """OPTIONAL. JSON array containing a list of the JWS signing + algorithms ("alg" values) supported by the introspection endpoint + for the signature on the JWT [JWT] used to authenticate the client + at the introspection endpoint for the "private_key_jwt" and + "client_secret_jwt" authentication methods. This metadata entry + MUST be present if either of these authentication methods are + specified in the "introspection_endpoint_auth_methods_supported" + entry. No default algorithms are implied if this entry is + omitted. The value "none" MUST NOT be used. + """ + _validate_alg_values( + self, + 'introspection_endpoint_auth_signing_alg_values_supported', + self.introspection_endpoint_auth_methods_supported + ) + + def validate_code_challenge_methods_supported(self): + """OPTIONAL. JSON array containing a list of Proof Key for Code + Exchange (PKCE) [RFC7636] code challenge methods supported by this + authorization server. Code challenge method values are used in + the "code_challenge_method" parameter defined in Section 4.3 of + [RFC7636]. The valid code challenge method values are those + registered in the IANA "PKCE Code Challenge Methods" registry + [IANA.OAuth.Parameters]. If omitted, the authorization server + does not support PKCE. + """ + validate_array_value(self, 'code_challenge_methods_supported') + + @property + def response_modes_supported(self): + #: If omitted, the default is ["query", "fragment"] + return self.get('response_modes_supported', ["query", "fragment"]) + + @property + def grant_types_supported(self): + #: If omitted, the default value is ["authorization_code", "implicit"] + return self.get('grant_types_supported', ["authorization_code", "implicit"]) + + @property + def token_endpoint_auth_methods_supported(self): + #: If omitted, the default is "client_secret_basic" + return self.get('token_endpoint_auth_methods_supported', ["client_secret_basic"]) + + @property + def revocation_endpoint_auth_methods_supported(self): + #: If omitted, the default is "client_secret_basic" + return self.get('revocation_endpoint_auth_methods_supported', ["client_secret_basic"]) + + @property + def introspection_endpoint_auth_methods_supported(self): + #: If omitted, the set of supported authentication methods MUST be + #: determined by other means + #: here, we use "client_secret_basic" + return self.get('introspection_endpoint_auth_methods_supported', ["client_secret_basic"]) + + def validate(self): + """Validate all server metadata value.""" + for key in self.REGISTRY_KEYS: + object.__getattribute__(self, 'validate_{}'.format(key))() + + def __getattr__(self, key): + try: + return object.__getattribute__(self, key) + except AttributeError as error: + if key in self.REGISTRY_KEYS: + return self.get(key) + raise error + + +def _validate_alg_values(data, key, auth_methods_supported): + value = data.get(key) + if value and not isinstance(value, list): + raise ValueError('"{}" MUST be JSON array'.format(key)) + + auth_methods = set(auth_methods_supported) + jwt_auth_methods = {'private_key_jwt', 'client_secret_jwt'} + if auth_methods & jwt_auth_methods: + if not value: + raise ValueError('"{}" is required'.format(key)) + + if value and 'none' in value: + raise ValueError( + 'the value "none" MUST NOT be used in "{}"'.format(key)) + + +def validate_array_value(metadata, key): + values = metadata.get(key) + if values is not None and not isinstance(values, list): + raise ValueError('"{}" MUST be JSON array'.format(key)) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8414/well_known.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8414/well_known.py new file mode 100644 index 0000000..dc948d8 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8414/well_known.py @@ -0,0 +1,22 @@ +from authlib.common.urls import urlparse + + +def get_well_known_url(issuer, external=False, suffix='oauth-authorization-server'): + """Get well-known URI with issuer via `Section 3.1`_. + + .. _`Section 3.1`: https://tools.ietf.org/html/rfc8414#section-3.1 + + :param issuer: URL of the issuer + :param external: return full external url or not + :param suffix: well-known URI suffix for RFC8414 + :return: URL + """ + parsed = urlparse.urlparse(issuer) + path = parsed.path + if path and path != '/': + url_path = '/.well-known/{}{}'.format(suffix, path) + else: + url_path = '/.well-known/{}'.format(suffix) + if not external: + return url_path + return parsed.scheme + '://' + parsed.netloc + url_path diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8628/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8628/__init__.py new file mode 100644 index 0000000..2d4447f --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8628/__init__.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- +""" + authlib.oauth2.rfc8628 + ~~~~~~~~~~~~~~~~~~~~~~ + + This module represents an implementation of + OAuth 2.0 Device Authorization Grant. + + https://tools.ietf.org/html/rfc8628 +""" + +from .endpoint import DeviceAuthorizationEndpoint +from .device_code import DeviceCodeGrant, DEVICE_CODE_GRANT_TYPE +from .models import DeviceCredentialMixin, DeviceCredentialDict +from .errors import AuthorizationPendingError, SlowDownError, ExpiredTokenError + + +__all__ = [ + 'DeviceAuthorizationEndpoint', + 'DeviceCodeGrant', 'DEVICE_CODE_GRANT_TYPE', + 'DeviceCredentialMixin', 'DeviceCredentialDict', + 'AuthorizationPendingError', 'SlowDownError', 'ExpiredTokenError', +] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8628/device_code.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8628/device_code.py new file mode 100644 index 0000000..67be336 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8628/device_code.py @@ -0,0 +1,198 @@ +import time +import logging +from ..rfc6749.errors import ( + InvalidRequestError, + InvalidClientError, + UnauthorizedClientError, + AccessDeniedError, +) +from ..rfc6749 import BaseGrant, TokenEndpointMixin +from .errors import ( + AuthorizationPendingError, + ExpiredTokenError, + SlowDownError, +) + +log = logging.getLogger(__name__) +DEVICE_CODE_GRANT_TYPE = 'urn:ietf:params:oauth:grant-type:device_code' + + +class DeviceCodeGrant(BaseGrant, TokenEndpointMixin): + """This OAuth 2.0 [RFC6749] protocol extension enables OAuth clients to + request user authorization from applications on devices that have + limited input capabilities or lack a suitable browser. Such devices + include smart TVs, media consoles, picture frames, and printers, + which lack an easy input method or a suitable browser required for + traditional OAuth interactions. Here is the authorization flow:: + + +----------+ +----------------+ + | |>---(A)-- Client Identifier --->| | + | | | | + | |<---(B)-- Device Code, ---<| | + | | User Code, | | + | Device | & Verification URI | | + | Client | | | + | | [polling] | | + | |>---(E)-- Device Code --->| | + | | & Client Identifier | | + | | | Authorization | + | |<---(F)-- Access Token ---<| Server | + +----------+ (& Optional Refresh Token) | | + v | | + : | | + (C) User Code & Verification URI | | + : | | + v | | + +----------+ | | + | End User | | | + | at |<---(D)-- End user reviews --->| | + | Browser | authorization request | | + +----------+ +----------------+ + + This DeviceCodeGrant is the implementation of step (E) and (F). + + (E) While the end user reviews the client's request (step D), the + client repeatedly polls the authorization server to find out if + the user completed the user authorization step. The client + includes the device code and its client identifier. + + (F) The authorization server validates the device code provided by + the client and responds with the access token if the client is + granted access, an error if they are denied access, or an + indication that the client should continue to poll. + """ + GRANT_TYPE = DEVICE_CODE_GRANT_TYPE + + def validate_token_request(self): + """After displaying instructions to the user, the client creates an + access token request and sends it to the token endpoint with the + following parameters: + + grant_type + REQUIRED. Value MUST be set to + "urn:ietf:params:oauth:grant-type:device_code". + + device_code + REQUIRED. The device verification code, "device_code" from the + device authorization response. + + client_id + REQUIRED if the client is not authenticating with the + authorization server as described in Section 3.2.1. of [RFC6749]. + The client identifier as described in Section 2.2 of [RFC6749]. + + For example, the client makes the following HTTPS request:: + + POST /token HTTP/1.1 + Host: server.example.com + Content-Type: application/x-www-form-urlencoded + + grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Adevice_code + &device_code=GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS + &client_id=1406020730 + """ + device_code = self.request.data.get('device_code') + if not device_code: + raise InvalidRequestError('Missing "device_code" in payload') + + if not self.request.client_id: + raise InvalidRequestError('Missing "client_id" in payload') + + credential = self.query_device_credential(device_code) + if not credential: + raise InvalidRequestError('Invalid "device_code" in payload') + + if credential.get_client_id() != self.request.client_id: + raise UnauthorizedClientError() + + client = self.authenticate_token_endpoint_client() + if not client.check_grant_type(self.GRANT_TYPE): + raise UnauthorizedClientError() + + user = self.validate_device_credential(credential) + self.request.user = user + self.request.client = client + self.request.credential = credential + + def create_token_response(self): + """If the access token request is valid and authorized, the + authorization server issues an access token and optional refresh + token. + """ + client = self.request.client + scope = self.request.credential.get_scope() + token = self.generate_token( + user=self.request.user, + scope=scope, + include_refresh_token=client.check_grant_type('refresh_token'), + ) + log.debug('Issue token %r to %r', token, client) + self.save_token(token) + self.execute_hook('process_token', token=token) + return 200, token, self.TOKEN_RESPONSE_HEADER + + def validate_device_credential(self, credential): + user_code = credential.get_user_code() + user_grant = self.query_user_grant(user_code) + + if user_grant is not None: + user, approved = user_grant + if not approved: + raise AccessDeniedError() + return user + + exp = credential.get_expires_at() + now = time.time() + if exp < now: + raise ExpiredTokenError() + + if self.should_slow_down(credential, now): + raise SlowDownError() + + raise AuthorizationPendingError() + + def authenticate_token_endpoint_client(self): + client = self.server.query_client(self.request.client_id) + if not client: + raise InvalidClientError() + self.server.send_signal( + 'after_authenticate_client', + client=client, grant=self) + return client + + def query_device_credential(self, device_code): + """Get device credential from previously savings via ``DeviceAuthorizationEndpoint``. + Developers MUST implement it in subclass:: + + def query_device_credential(self, device_code): + return DeviceCredential.query.get(device_code) + + :param device_code: a string represent the code. + :return: DeviceCredential instance + """ + raise NotImplementedError() + + def query_user_grant(self, user_code): + """Get user and grant via the given user code. Developers MUST + implement it in subclass:: + + def query_user_grant(self, user_code): + # e.g. we saved user grant info in redis + data = redis.get('oauth_user_grant:' + user_code) + if not data: + return None + + user_id, allowed = data.split() + user = User.query.get(user_id) + return user, bool(allowed) + + Note, user grant information is saved by verification endpoint. + """ + raise NotImplementedError() + + def should_slow_down(self, credential, now): + """The authorization request is still pending and polling should + continue, but the interval MUST be increased by 5 seconds for this + and all subsequent requests. + """ + raise NotImplementedError() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8628/endpoint.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8628/endpoint.py new file mode 100644 index 0000000..fda5f1a --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8628/endpoint.py @@ -0,0 +1,148 @@ +from authlib.consts import default_json_headers +from authlib.common.security import generate_token +from authlib.common.urls import add_params_to_uri +from ..rfc6749.errors import InvalidRequestError + + +class DeviceAuthorizationEndpoint(object): + """This OAuth 2.0 [RFC6749] protocol extension enables OAuth clients to + request user authorization from applications on devices that have + limited input capabilities or lack a suitable browser. Such devices + include smart TVs, media consoles, picture frames, and printers, + which lack an easy input method or a suitable browser required for + traditional OAuth interactions. Here is the authorization flow:: + + +----------+ +----------------+ + | |>---(A)-- Client Identifier --->| | + | | | | + | |<---(B)-- Device Code, ---<| | + | | User Code, | | + | Device | & Verification URI | | + | Client | | | + | | [polling] | | + | |>---(E)-- Device Code --->| | + | | & Client Identifier | | + | | | Authorization | + | |<---(F)-- Access Token ---<| Server | + +----------+ (& Optional Refresh Token) | | + v | | + : | | + (C) User Code & Verification URI | | + : | | + v | | + +----------+ | | + | End User | | | + | at |<---(D)-- End user reviews --->| | + | Browser | authorization request | | + +----------+ +----------------+ + + This DeviceAuthorizationEndpoint is the implementation of step (A) and (B). + + (A) The client requests access from the authorization server and + includes its client identifier in the request. + + (B) The authorization server issues a device code and an end-user + code and provides the end-user verification URI. + """ + + ENDPOINT_NAME = 'device_authorization' + + #: customize "user_code" type, string or digital + USER_CODE_TYPE = 'string' + + #: The lifetime in seconds of the "device_code" and "user_code" + EXPIRES_IN = 1800 + + #: The minimum amount of time in seconds that the client SHOULD + #: wait between polling requests to the token endpoint. + INTERVAL = 5 + + def __init__(self, server): + self.server = server + + def __call__(self, request): + # make it callable for authorization server + # ``create_endpoint_response`` + return self.create_endpoint_response(request) + + def create_endpoint_request(self, request): + return self.server.create_oauth2_request(request) + + def create_endpoint_response(self, request): + # https://tools.ietf.org/html/rfc8628#section-3.1 + if not request.client_id: + raise InvalidRequestError('Missing "client_id" in payload') + + self.server.validate_requested_scope(request.scope) + + device_code = self.generate_device_code() + user_code = self.generate_user_code() + verification_uri = self.get_verification_uri() + verification_uri_complete = add_params_to_uri( + verification_uri, [('user_code', user_code)]) + + data = { + 'device_code': device_code, + 'user_code': user_code, + 'verification_uri': verification_uri, + 'verification_uri_complete': verification_uri_complete, + 'expires_in': self.EXPIRES_IN, + 'interval': self.INTERVAL, + } + + self.save_device_credential(request.client_id, request.scope, data) + return 200, data, default_json_headers + + def generate_user_code(self): + """A method to generate ``user_code`` value for device authorization + endpoint. This method will generate a random string like MQNA-JPOZ. + Developers can rewrite this method to create their own ``user_code``. + """ + # https://tools.ietf.org/html/rfc8628#section-6.1 + if self.USER_CODE_TYPE == 'digital': + return create_digital_user_code() + return create_string_user_code() + + def generate_device_code(self): + """A method to generate ``device_code`` value for device authorization + endpoint. This method will generate a random string of 42 characters. + Developers can rewrite this method to create their own ``device_code``. + """ + return generate_token(42) + + def get_verification_uri(self): + """Define the ``verification_uri`` of device authorization endpoint. + Developers MUST implement this method in subclass:: + + def get_verification_uri(self): + return 'https://your-company.com/active' + """ + raise NotImplementedError() + + def save_device_credential(self, client_id, scope, data): + """Save device token into database for later use. Developers MUST + implement this method in subclass:: + + def save_device_credential(self, client_id, scope, data): + item = DeviceCredential( + client_id=client_id, + scope=scope, + **data + ) + item.save() + """ + raise NotImplementedError() + + +def create_string_user_code(): + base = 'BCDFGHJKLMNPQRSTVWXZ' + return '-'.join([generate_token(4, base), generate_token(4, base)]) + + +def create_digital_user_code(): + base = '0123456789' + return '-'.join([ + generate_token(3, base), + generate_token(3, base), + generate_token(3, base), + ]) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8628/errors.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8628/errors.py new file mode 100644 index 0000000..4a63db8 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8628/errors.py @@ -0,0 +1,27 @@ +from ..rfc6749.errors import OAuth2Error + +# https://tools.ietf.org/html/rfc8628#section-3.5 + + +class AuthorizationPendingError(OAuth2Error): + """The authorization request is still pending as the end user hasn't + yet completed the user-interaction steps (Section 3.3). + """ + error = 'authorization_pending' + + +class SlowDownError(OAuth2Error): + """A variant of "authorization_pending", the authorization request is + still pending and polling should continue, but the interval MUST + be increased by 5 seconds for this and all subsequent requests. + """ + error = 'slow_down' + + +class ExpiredTokenError(OAuth2Error): + """The "device_code" has expired, and the device authorization + session has concluded. The client MAY commence a new device + authorization request but SHOULD wait for user interaction before + restarting to avoid unnecessary polling. + """ + error = 'expired_token' diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8628/models.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8628/models.py new file mode 100644 index 0000000..4090ed6 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8628/models.py @@ -0,0 +1,27 @@ + +class DeviceCredentialMixin(object): + def get_client_id(self): + raise NotImplementedError() + + def get_scope(self): + raise NotImplementedError() + + def get_user_code(self): + raise NotImplementedError() + + def get_expires_at(self): + raise NotImplementedError() + + +class DeviceCredentialDict(dict, DeviceCredentialMixin): + def get_client_id(self): + return self['client_id'] + + def get_scope(self): + return self.get('scope') + + def get_user_code(self): + return self['user_code'] + + def get_expires_at(self): + return self.get('expires_at') diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8693/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8693/__init__.py new file mode 100644 index 0000000..110b387 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oauth2/rfc8693/__init__.py @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +""" + authlib.oauth2.rfc8693 + ~~~~~~~~~~~~~~~~~~~~~~ + + This module represents an implementation of + OAuth 2.0 Token Exchange. + + https://tools.ietf.org/html/rfc8693 +""" diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/__init__.py new file mode 100644 index 0000000..8ee628f --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/__init__.py @@ -0,0 +1,23 @@ +""" + authlib.oidc.core + ~~~~~~~~~~~~~~~~~ + + OpenID Connect Core 1.0 Implementation. + + http://openid.net/specs/openid-connect-core-1_0.html +""" + +from .models import AuthorizationCodeMixin +from .claims import ( + IDToken, CodeIDToken, ImplicitIDToken, HybridIDToken, + UserInfo, get_claim_cls_by_response_type, +) +from .grants import OpenIDCode, OpenIDHybridGrant, OpenIDImplicitGrant + + +__all__ = [ + 'AuthorizationCodeMixin', + 'IDToken', 'CodeIDToken', 'ImplicitIDToken', 'HybridIDToken', + 'UserInfo', 'get_claim_cls_by_response_type', + 'OpenIDCode', 'OpenIDHybridGrant', 'OpenIDImplicitGrant', +] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/claims.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/claims.py new file mode 100644 index 0000000..dc3a843 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/claims.py @@ -0,0 +1,242 @@ +import time +import hmac +from authlib.common.encoding import to_bytes +from authlib.jose import JWTClaims +from authlib.jose.errors import ( + MissingClaimError, + InvalidClaimError, +) +from .util import create_half_hash + +__all__ = [ + 'IDToken', 'CodeIDToken', 'ImplicitIDToken', 'HybridIDToken', + 'UserInfo', 'get_claim_cls_by_response_type' +] + +_REGISTERED_CLAIMS = [ + 'iss', 'sub', 'aud', 'exp', 'nbf', 'iat', + 'auth_time', 'nonce', 'acr', 'amr', 'azp', + 'at_hash', +] + + +class IDToken(JWTClaims): + ESSENTIAL_CLAIMS = ['iss', 'sub', 'aud', 'exp', 'iat'] + + def validate(self, now=None, leeway=0): + for k in self.ESSENTIAL_CLAIMS: + if k not in self: + raise MissingClaimError(k) + + self._validate_essential_claims() + if now is None: + now = int(time.time()) + + self.validate_iss() + self.validate_sub() + self.validate_aud() + self.validate_exp(now, leeway) + self.validate_nbf(now, leeway) + self.validate_iat(now, leeway) + self.validate_auth_time() + self.validate_nonce() + self.validate_acr() + self.validate_amr() + self.validate_azp() + self.validate_at_hash() + + def validate_auth_time(self): + """Time when the End-User authentication occurred. Its value is a JSON + number representing the number of seconds from 1970-01-01T0:0:0Z as + measured in UTC until the date/time. When a max_age request is made or + when auth_time is requested as an Essential Claim, then this Claim is + REQUIRED; otherwise, its inclusion is OPTIONAL. + """ + auth_time = self.get('auth_time') + if self.params.get('max_age') and not auth_time: + raise MissingClaimError('auth_time') + + if auth_time and not isinstance(auth_time, int): + raise InvalidClaimError('auth_time') + + def validate_nonce(self): + """String value used to associate a Client session with an ID Token, + and to mitigate replay attacks. The value is passed through unmodified + from the Authentication Request to the ID Token. If present in the ID + Token, Clients MUST verify that the nonce Claim Value is equal to the + value of the nonce parameter sent in the Authentication Request. If + present in the Authentication Request, Authorization Servers MUST + include a nonce Claim in the ID Token with the Claim Value being the + nonce value sent in the Authentication Request. Authorization Servers + SHOULD perform no other processing on nonce values used. The nonce + value is a case sensitive string. + """ + nonce_value = self.params.get('nonce') + if nonce_value: + if 'nonce' not in self: + raise MissingClaimError('nonce') + if nonce_value != self['nonce']: + raise InvalidClaimError('nonce') + + def validate_acr(self): + """OPTIONAL. Authentication Context Class Reference. String specifying + an Authentication Context Class Reference value that identifies the + Authentication Context Class that the authentication performed + satisfied. The value "0" indicates the End-User authentication did not + meet the requirements of `ISO/IEC 29115`_ level 1. Authentication + using a long-lived browser cookie, for instance, is one example where + the use of "level 0" is appropriate. Authentications with level 0 + SHOULD NOT be used to authorize access to any resource of any monetary + value. An absolute URI or an `RFC 6711`_ registered name SHOULD be + used as the acr value; registered names MUST NOT be used with a + different meaning than that which is registered. Parties using this + claim will need to agree upon the meanings of the values used, which + may be context-specific. The acr value is a case sensitive string. + + .. _`ISO/IEC 29115`: https://www.iso.org/standard/45138.html + .. _`RFC 6711`: https://tools.ietf.org/html/rfc6711 + """ + return self._validate_claim_value('acr') + + def validate_amr(self): + """OPTIONAL. Authentication Methods References. JSON array of strings + that are identifiers for authentication methods used in the + authentication. For instance, values might indicate that both password + and OTP authentication methods were used. The definition of particular + values to be used in the amr Claim is beyond the scope of this + specification. Parties using this claim will need to agree upon the + meanings of the values used, which may be context-specific. The amr + value is an array of case sensitive strings. + """ + amr = self.get('amr') + if amr and not isinstance(self['amr'], list): + raise InvalidClaimError('amr') + + def validate_azp(self): + """OPTIONAL. Authorized party - the party to which the ID Token was + issued. If present, it MUST contain the OAuth 2.0 Client ID of this + party. This Claim is only needed when the ID Token has a single + audience value and that audience is different than the authorized + party. It MAY be included even when the authorized party is the same + as the sole audience. The azp value is a case sensitive string + containing a StringOrURI value. + """ + aud = self.get('aud') + client_id = self.params.get('client_id') + required = False + if aud and client_id: + if isinstance(aud, list) and len(aud) == 1: + aud = aud[0] + if aud != client_id: + required = True + + azp = self.get('azp') + if required and not azp: + raise MissingClaimError('azp') + + if azp and client_id and azp != client_id: + raise InvalidClaimError('azp') + + def validate_at_hash(self): + """OPTIONAL. Access Token hash value. Its value is the base64url + encoding of the left-most half of the hash of the octets of the ASCII + representation of the access_token value, where the hash algorithm + used is the hash algorithm used in the alg Header Parameter of the + ID Token's JOSE Header. For instance, if the alg is RS256, hash the + access_token value with SHA-256, then take the left-most 128 bits and + base64url encode them. The at_hash value is a case sensitive string. + """ + access_token = self.params.get('access_token') + at_hash = self.get('at_hash') + if at_hash and access_token: + if not _verify_hash(at_hash, access_token, self.header['alg']): + raise InvalidClaimError('at_hash') + + +class CodeIDToken(IDToken): + RESPONSE_TYPES = ('code',) + REGISTERED_CLAIMS = _REGISTERED_CLAIMS + + +class ImplicitIDToken(IDToken): + RESPONSE_TYPES = ('id_token', 'id_token token') + ESSENTIAL_CLAIMS = ['iss', 'sub', 'aud', 'exp', 'iat', 'nonce'] + REGISTERED_CLAIMS = _REGISTERED_CLAIMS + + def validate_at_hash(self): + """If the ID Token is issued from the Authorization Endpoint with an + access_token value, which is the case for the response_type value + id_token token, this is REQUIRED; it MAY NOT be used when no Access + Token is issued, which is the case for the response_type value + id_token. + """ + access_token = self.params.get('access_token') + if access_token and 'at_hash' not in self: + raise MissingClaimError('at_hash') + super(ImplicitIDToken, self).validate_at_hash() + + +class HybridIDToken(ImplicitIDToken): + RESPONSE_TYPES = ('code id_token', 'code token', 'code id_token token') + REGISTERED_CLAIMS = _REGISTERED_CLAIMS + ['c_hash'] + + def validate(self, now=None, leeway=0): + super(HybridIDToken, self).validate(now=now, leeway=leeway) + self.validate_c_hash() + + def validate_c_hash(self): + """Code hash value. Its value is the base64url encoding of the + left-most half of the hash of the octets of the ASCII representation + of the code value, where the hash algorithm used is the hash algorithm + used in the alg Header Parameter of the ID Token's JOSE Header. For + instance, if the alg is HS512, hash the code value with SHA-512, then + take the left-most 256 bits and base64url encode them. The c_hash + value is a case sensitive string. + If the ID Token is issued from the Authorization Endpoint with a code, + which is the case for the response_type values code id_token and code + id_token token, this is REQUIRED; otherwise, its inclusion is OPTIONAL. + """ + code = self.params.get('code') + c_hash = self.get('c_hash') + if code: + if not c_hash: + raise MissingClaimError('c_hash') + if not _verify_hash(c_hash, code, self.header['alg']): + raise InvalidClaimError('c_hash') + + +class UserInfo(dict): + """The standard claims of a UserInfo object. Defined per `Section 5.1`_. + + .. _`Section 5.1`: http://openid.net/specs/openid-connect-core-1_0.html#StandardClaims + """ + + #: registered claims that UserInfo supports + REGISTERED_CLAIMS = [ + 'sub', 'name', 'given_name', 'family_name', 'middle_name', 'nickname', + 'preferred_username', 'profile', 'picture', 'website', 'email', + 'email_verified', 'gender', 'birthdate', 'zoneinfo', 'locale', + 'phone_number', 'phone_number_verified', 'address', 'updated_at', + ] + + def __getattr__(self, key): + try: + return object.__getattribute__(self, key) + except AttributeError as error: + if key in self.REGISTERED_CLAIMS: + return self.get(key) + raise error + + +def get_claim_cls_by_response_type(response_type): + claims_classes = (CodeIDToken, ImplicitIDToken, HybridIDToken) + for claims_cls in claims_classes: + if response_type in claims_cls.RESPONSE_TYPES: + return claims_cls + + +def _verify_hash(signature, s, alg): + hash_value = create_half_hash(s, alg) + if not hash_value: + return True + return hmac.compare_digest(hash_value, to_bytes(signature)) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/errors.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/errors.py new file mode 100644 index 0000000..e5fb630 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/errors.py @@ -0,0 +1,78 @@ +from authlib.oauth2 import OAuth2Error + + +class InteractionRequiredError(OAuth2Error): + """The Authorization Server requires End-User interaction of some form + to proceed. This error MAY be returned when the prompt parameter value + in the Authentication Request is none, but the Authentication Request + cannot be completed without displaying a user interface for End-User + interaction. + + http://openid.net/specs/openid-connect-core-1_0.html#AuthError + """ + error = 'interaction_required' + + +class LoginRequiredError(OAuth2Error): + """The Authorization Server requires End-User authentication. This error + MAY be returned when the prompt parameter value in the Authentication + Request is none, but the Authentication Request cannot be completed + without displaying a user interface for End-User authentication. + + http://openid.net/specs/openid-connect-core-1_0.html#AuthError + """ + error = 'login_required' + + +class AccountSelectionRequiredError(OAuth2Error): + """The End-User is REQUIRED to select a session at the Authorization + Server. The End-User MAY be authenticated at the Authorization Server + with different associated accounts, but the End-User did not select a + session. This error MAY be returned when the prompt parameter value in + the Authentication Request is none, but the Authentication Request cannot + be completed without displaying a user interface to prompt for a session + to use. + + http://openid.net/specs/openid-connect-core-1_0.html#AuthError + """ + error = 'account_selection_required' + + +class ConsentRequiredError(OAuth2Error): + """The Authorization Server requires End-User consent. This error MAY be + returned when the prompt parameter value in the Authentication Request is + none, but the Authentication Request cannot be completed without + displaying a user interface for End-User consent. + + http://openid.net/specs/openid-connect-core-1_0.html#AuthError + """ + error = 'consent_required' + + +class InvalidRequestURIError(OAuth2Error): + """The request_uri in the Authorization Request returns an error or + contains invalid data. + + http://openid.net/specs/openid-connect-core-1_0.html#AuthError + """ + error = 'invalid_request_uri' + + +class InvalidRequestObjectError(OAuth2Error): + """The request parameter contains an invalid Request Object.""" + error = 'invalid_request_object' + + +class RequestNotSupportedError(OAuth2Error): + """The OP does not support use of the request parameter.""" + error = 'request_not_supported' + + +class RequestURINotSupportedError(OAuth2Error): + """The OP does not support use of the request_uri parameter.""" + error = 'request_uri_not_supported' + + +class RegistrationNotSupportedError(OAuth2Error): + """The OP does not support use of the registration parameter.""" + error = 'registration_not_supported' diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/grants/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/grants/__init__.py new file mode 100644 index 0000000..fb60bb7 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/grants/__init__.py @@ -0,0 +1,9 @@ +from .code import OpenIDCode +from .implicit import OpenIDImplicitGrant +from .hybrid import OpenIDHybridGrant + +__all__ = [ + 'OpenIDCode', + 'OpenIDImplicitGrant', + 'OpenIDHybridGrant', +] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/grants/code.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/grants/code.py new file mode 100644 index 0000000..7fb3265 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/grants/code.py @@ -0,0 +1,119 @@ +""" + authlib.oidc.core.grants.code + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Implementation of Authentication using the Authorization Code Flow + per `Section 3.1`_. + + .. _`Section 3.1`: http://openid.net/specs/openid-connect-core-1_0.html#CodeFlowAuth +""" + +import logging +from .util import ( + is_openid_scope, + validate_nonce, + validate_request_prompt, + generate_id_token, +) + +log = logging.getLogger(__name__) + + +class OpenIDCode(object): + """An extension from OpenID Connect for "grant_type=code" request. + """ + def __init__(self, require_nonce=False): + self.require_nonce = require_nonce + + def exists_nonce(self, nonce, request): + """Check if the given nonce is existing in your database. Developers + MUST implement this method in subclass, e.g.:: + + def exists_nonce(self, nonce, request): + exists = AuthorizationCode.query.filter_by( + client_id=request.client_id, nonce=nonce + ).first() + return bool(exists) + + :param nonce: A string of "nonce" parameter in request + :param request: OAuth2Request instance + :return: Boolean + """ + raise NotImplementedError() + + def get_jwt_config(self, grant): # pragma: no cover + """Get the JWT configuration for OpenIDCode extension. The JWT + configuration will be used to generate ``id_token``. Developers + MUST implement this method in subclass, e.g.:: + + def get_jwt_config(self, grant): + return { + 'key': read_private_key_file(key_path), + 'alg': 'RS512', + 'iss': 'issuer-identity', + 'exp': 3600 + } + + :param grant: AuthorizationCodeGrant instance + :return: dict + """ + raise NotImplementedError() + + def generate_user_info(self, user, scope): # pragma: no cover + """Provide user information for the given scope. Developers + MUST implement this method in subclass, e.g.:: + + from authlib.oidc.core import UserInfo + + def generate_user_info(self, user, scope): + user_info = UserInfo(sub=user.id, name=user.name) + if 'email' in scope: + user_info['email'] = user.email + return user_info + + :param user: user instance + :param scope: scope of the token + :return: ``authlib.oidc.core.UserInfo`` instance + """ + raise NotImplementedError() + + def get_audiences(self, request): + """Parse `aud` value for id_token, default value is client id. Developers + MAY rewrite this method to provide a customized audience value. + """ + client = request.client + return [client.get_client_id()] + + def process_token(self, grant, token): + scope = token.get('scope') + if not scope or not is_openid_scope(scope): + # standard authorization code flow + return token + + request = grant.request + credential = request.credential + + config = self.get_jwt_config(grant) + config['aud'] = self.get_audiences(request) + config['nonce'] = credential.get_nonce() + config['auth_time'] = credential.get_auth_time() + + user_info = self.generate_user_info(request.user, token['scope']) + id_token = generate_id_token(token, user_info, **config) + token['id_token'] = id_token + return token + + def validate_openid_authorization_request(self, grant): + validate_nonce(grant.request, self.exists_nonce, self.require_nonce) + + def __call__(self, grant): + grant.register_hook('process_token', self.process_token) + if is_openid_scope(grant.request.scope): + grant.register_hook( + 'after_validate_authorization_request', + self.validate_openid_authorization_request + ) + grant.register_hook( + 'after_validate_consent_request', + validate_request_prompt + ) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/grants/hybrid.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/grants/hybrid.py new file mode 100644 index 0000000..d2c14ac --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/grants/hybrid.py @@ -0,0 +1,97 @@ +import logging +from authlib.deprecate import deprecate +from authlib.common.security import generate_token +from authlib.oauth2.rfc6749 import InvalidScopeError +from authlib.oauth2.rfc6749.grants.authorization_code import ( + validate_code_authorization_request +) +from .implicit import OpenIDImplicitGrant +from .util import is_openid_scope, validate_nonce + +log = logging.getLogger(__name__) + + +class OpenIDHybridGrant(OpenIDImplicitGrant): + #: Generated "code" length + AUTHORIZATION_CODE_LENGTH = 48 + + RESPONSE_TYPES = {'code id_token', 'code token', 'code id_token token'} + GRANT_TYPE = 'code' + DEFAULT_RESPONSE_MODE = 'fragment' + + def generate_authorization_code(self): + """"The method to generate "code" value for authorization code data. + Developers may rewrite this method, or customize the code length with:: + + class MyAuthorizationCodeGrant(AuthorizationCodeGrant): + AUTHORIZATION_CODE_LENGTH = 32 # default is 48 + """ + return generate_token(self.AUTHORIZATION_CODE_LENGTH) + + def save_authorization_code(self, code, request): + """Save authorization_code for later use. Developers MUST implement + it in subclass. Here is an example:: + + def save_authorization_code(self, code, request): + client = request.client + item = AuthorizationCode( + code=code, + client_id=client.client_id, + redirect_uri=request.redirect_uri, + scope=request.scope, + nonce=request.data.get('nonce'), + user_id=request.user.id, + ) + item.save() + """ + raise NotImplementedError() + + def validate_authorization_request(self): + if not is_openid_scope(self.request.scope): + raise InvalidScopeError( + 'Missing "openid" scope', + redirect_uri=self.request.redirect_uri, + redirect_fragment=True, + ) + self.register_hook( + 'after_validate_authorization_request', + lambda grant: validate_nonce( + grant.request, grant.exists_nonce, required=True) + ) + return validate_code_authorization_request(self) + + def create_granted_params(self, grant_user): + self.request.user = grant_user + client = self.request.client + + if hasattr(self, 'create_authorization_code'): # pragma: no cover + deprecate('Use "generate_authorization_code" instead', '1.0') + code = self.create_authorization_code(client, grant_user, self.request) + else: + code = self.generate_authorization_code() + self.save_authorization_code(code, self.request) + + params = [('code', code)] + token = self.generate_token( + grant_type='implicit', + user=grant_user, + scope=self.request.scope, + include_refresh_token=False + ) + + response_types = self.request.response_type.split() + if 'token' in response_types: + log.debug('Grant token %r to %r', token, client) + self.server.save_token(token, self.request) + if 'id_token' in response_types: + token = self.process_implicit_token(token, code) + else: + # response_type is "code id_token" + token = { + 'expires_in': token['expires_in'], + 'scope': token['scope'] + } + token = self.process_implicit_token(token, code) + + params.extend([(k, token[k]) for k in token]) + return params diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/grants/implicit.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/grants/implicit.py new file mode 100644 index 0000000..ac1a763 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/grants/implicit.py @@ -0,0 +1,151 @@ +import logging +from authlib.oauth2.rfc6749 import ( + OAuth2Error, + InvalidScopeError, + AccessDeniedError, + ImplicitGrant, +) +from .util import ( + is_openid_scope, + validate_nonce, + validate_request_prompt, + create_response_mode_response, + generate_id_token, +) + +log = logging.getLogger(__name__) + + +class OpenIDImplicitGrant(ImplicitGrant): + RESPONSE_TYPES = {'id_token token', 'id_token'} + DEFAULT_RESPONSE_MODE = 'fragment' + + def exists_nonce(self, nonce, request): + """Check if the given nonce is existing in your database. Developers + should implement this method in subclass, e.g.:: + + def exists_nonce(self, nonce, request): + exists = AuthorizationCode.query.filter_by( + client_id=request.client_id, nonce=nonce + ).first() + return bool(exists) + + :param nonce: A string of "nonce" parameter in request + :param request: OAuth2Request instance + :return: Boolean + """ + raise NotImplementedError() + + def get_jwt_config(self): + """Get the JWT configuration for OpenIDImplicitGrant. The JWT + configuration will be used to generate ``id_token``. Developers + MUST implement this method in subclass, e.g.:: + + def get_jwt_config(self): + return { + 'key': read_private_key_file(key_path), + 'alg': 'RS512', + 'iss': 'issuer-identity', + 'exp': 3600 + } + + :return: dict + """ + raise NotImplementedError() + + def generate_user_info(self, user, scope): + """Provide user information for the given scope. Developers + MUST implement this method in subclass, e.g.:: + + from authlib.oidc.core import UserInfo + + def generate_user_info(self, user, scope): + user_info = UserInfo(sub=user.id, name=user.name) + if 'email' in scope: + user_info['email'] = user.email + return user_info + + :param user: user instance + :param scope: scope of the token + :return: ``authlib.oidc.core.UserInfo`` instance + """ + raise NotImplementedError() + + def get_audiences(self, request): + """Parse `aud` value for id_token, default value is client id. Developers + MAY rewrite this method to provide a customized audience value. + """ + client = request.client + return [client.get_client_id()] + + def validate_authorization_request(self): + if not is_openid_scope(self.request.scope): + raise InvalidScopeError( + 'Missing "openid" scope', + redirect_uri=self.request.redirect_uri, + redirect_fragment=True, + ) + redirect_uri = super( + OpenIDImplicitGrant, self).validate_authorization_request() + try: + validate_nonce(self.request, self.exists_nonce, required=True) + except OAuth2Error as error: + error.redirect_uri = redirect_uri + error.redirect_fragment = True + raise error + return redirect_uri + + def validate_consent_request(self): + redirect_uri = self.validate_authorization_request() + validate_request_prompt(self, redirect_uri, redirect_fragment=True) + + def create_authorization_response(self, redirect_uri, grant_user): + state = self.request.state + if grant_user: + params = self.create_granted_params(grant_user) + if state: + params.append(('state', state)) + else: + error = AccessDeniedError(state=state) + params = error.get_body() + + # http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html#ResponseModes + response_mode = self.request.data.get('response_mode', self.DEFAULT_RESPONSE_MODE) + return create_response_mode_response( + redirect_uri=redirect_uri, + params=params, + response_mode=response_mode, + ) + + def create_granted_params(self, grant_user): + self.request.user = grant_user + client = self.request.client + token = self.generate_token( + user=grant_user, + scope=self.request.scope, + include_refresh_token=False + ) + if self.request.response_type == 'id_token': + token = { + 'expires_in': token['expires_in'], + 'scope': token['scope'], + } + token = self.process_implicit_token(token) + else: + log.debug('Grant token %r to %r', token, client) + self.server.save_token(token, self.request) + token = self.process_implicit_token(token) + params = [(k, token[k]) for k in token] + return params + + def process_implicit_token(self, token, code=None): + config = self.get_jwt_config() + config['aud'] = self.get_audiences(self.request) + config['nonce'] = self.request.data.get('nonce') + if code is not None: + config['code'] = code + + user_info = self.generate_user_info(self.request.user, token['scope']) + id_token = generate_id_token(token, user_info, **config) + token['id_token'] = id_token + return token diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/grants/util.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/grants/util.py new file mode 100644 index 0000000..a83a2c9 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/grants/util.py @@ -0,0 +1,155 @@ +import time +import random +from authlib.oauth2.rfc6749 import InvalidRequestError +from authlib.oauth2.rfc6749.util import scope_to_list +from authlib.jose import JWT +from authlib.common.encoding import to_native +from authlib.common.urls import add_params_to_uri, quote_url +from ..util import create_half_hash +from ..errors import ( + LoginRequiredError, + AccountSelectionRequiredError, + ConsentRequiredError, +) + + +def is_openid_scope(scope): + scopes = scope_to_list(scope) + return scopes and 'openid' in scopes + + +def validate_request_prompt(grant, redirect_uri, redirect_fragment=False): + prompt = grant.request.data.get('prompt') + end_user = grant.request.user + if not prompt: + if not end_user: + grant.prompt = 'login' + return grant + + if prompt == 'none' and not end_user: + raise LoginRequiredError( + redirect_uri=redirect_uri, + redirect_fragment=redirect_fragment) + + prompts = prompt.split() + if 'none' in prompts and len(prompts) > 1: + # If this parameter contains none with any other value, + # an error is returned + raise InvalidRequestError( + 'Invalid "prompt" parameter.', + redirect_uri=redirect_uri, + redirect_fragment=redirect_fragment) + + prompt = _guess_prompt_value( + end_user, prompts, redirect_uri, redirect_fragment=redirect_fragment) + if prompt: + grant.prompt = prompt + return grant + + +def validate_nonce(request, exists_nonce, required=False): + nonce = request.data.get('nonce') + if not nonce: + if required: + raise InvalidRequestError('Missing "nonce" in request.') + return True + + if exists_nonce(nonce, request): + raise InvalidRequestError('Replay attack') + + +def generate_id_token( + token, user_info, key, alg, iss, aud, exp, + nonce=None, auth_time=None, code=None): + + payload = _generate_id_token_payload( + alg=alg, iss=iss, aud=aud, exp=exp, nonce=nonce, + auth_time=auth_time, code=code, + access_token=token.get('access_token'), + ) + payload.update(user_info) + return _jwt_encode(alg, payload, key) + + +def create_response_mode_response(redirect_uri, params, response_mode): + if response_mode == 'form_post': + tpl = ( + 'Redirecting' + '' + '
    {}
    ' + ) + inputs = ''.join([ + ''.format( + quote_url(k), quote_url(v)) + for k, v in params + ]) + body = tpl.format(quote_url(redirect_uri), inputs) + return 200, body, [('Content-Type', 'text/html; charset=utf-8')] + + if response_mode == 'query': + uri = add_params_to_uri(redirect_uri, params, fragment=False) + elif response_mode == 'fragment': + uri = add_params_to_uri(redirect_uri, params, fragment=True) + else: + raise InvalidRequestError('Invalid "response_mode" value') + + return 302, '', [('Location', uri)] + + +def _guess_prompt_value(end_user, prompts, redirect_uri, redirect_fragment): + # http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest + + if not end_user and 'login' in prompts: + return 'login' + + if 'consent' in prompts: + if not end_user: + raise ConsentRequiredError( + redirect_uri=redirect_uri, + redirect_fragment=redirect_fragment) + return 'consent' + elif 'select_account' in prompts: + if not end_user: + raise AccountSelectionRequiredError( + redirect_uri=redirect_uri, + redirect_fragment=redirect_fragment) + return 'select_account' + + +def _generate_id_token_payload( + alg, iss, aud, exp, nonce=None, auth_time=None, + code=None, access_token=None): + now = int(time.time()) + if auth_time is None: + auth_time = now + + payload = { + 'iss': iss, + 'aud': aud, + 'iat': now, + 'exp': now + exp, + 'auth_time': auth_time, + } + if nonce: + payload['nonce'] = nonce + + if code: + payload['c_hash'] = to_native(create_half_hash(code, alg)) + + if access_token: + payload['at_hash'] = to_native(create_half_hash(access_token, alg)) + return payload + + +def _jwt_encode(alg, payload, key): + jwt = JWT(algorithms=alg) + header = {'alg': alg} + if isinstance(key, dict): + # JWK set format + if 'keys' in key: + key = random.choice(key['keys']) + header['kid'] = key['kid'] + elif 'kid' in key: + header['kid'] = key['kid'] + + return to_native(jwt.encode(header, payload, key)) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/models.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/models.py new file mode 100644 index 0000000..5f41405 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/models.py @@ -0,0 +1,13 @@ +from authlib.oauth2.rfc6749 import ( + AuthorizationCodeMixin as _AuthorizationCodeMixin +) + + +class AuthorizationCodeMixin(_AuthorizationCodeMixin): + def get_nonce(self): + """Get "nonce" value of the authorization code object.""" + raise NotImplementedError() + + def get_auth_time(self): + """Get "auth_time" value of the authorization code object.""" + raise NotImplementedError() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/util.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/util.py new file mode 100644 index 0000000..37d23de --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/core/util.py @@ -0,0 +1,12 @@ +import hashlib +from authlib.common.encoding import to_bytes, urlsafe_b64encode + + +def create_half_hash(s, alg): + hash_type = 'sha{}'.format(alg[2:]) + hash_alg = getattr(hashlib, hash_type, None) + if not hash_alg: + return None + data_digest = hash_alg(to_bytes(s)).digest() + slice_index = int(len(data_digest) / 2) + return urlsafe_b64encode(data_digest[:slice_index]) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/discovery/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/discovery/__init__.py new file mode 100644 index 0000000..1e76401 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/discovery/__init__.py @@ -0,0 +1,13 @@ +""" + authlib.oidc.discover + ~~~~~~~~~~~~~~~~~~~~~ + + OpenID Connect Discovery 1.0 Implementation. + + https://openid.net/specs/openid-connect-discovery-1_0.html +""" + +from .models import OpenIDProviderMetadata +from .well_known import get_well_known_url + +__all__ = ['OpenIDProviderMetadata', 'get_well_known_url'] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/discovery/models.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/discovery/models.py new file mode 100644 index 0000000..db1a804 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/discovery/models.py @@ -0,0 +1,283 @@ +from authlib.oauth2.rfc8414 import AuthorizationServerMetadata +from authlib.oauth2.rfc8414.models import validate_array_value + + +class OpenIDProviderMetadata(AuthorizationServerMetadata): + REGISTRY_KEYS = [ + 'issuer', 'authorization_endpoint', 'token_endpoint', + 'jwks_uri', 'registration_endpoint', 'scopes_supported', + 'response_types_supported', 'response_modes_supported', + 'grant_types_supported', + 'token_endpoint_auth_methods_supported', + 'token_endpoint_auth_signing_alg_values_supported', + 'service_documentation', 'ui_locales_supported', + 'op_policy_uri', 'op_tos_uri', + + # added by OpenID + 'acr_values_supported', 'subject_types_supported', + 'id_token_signing_alg_values_supported', + 'id_token_encryption_alg_values_supported', + 'id_token_encryption_enc_values_supported', + 'userinfo_signing_alg_values_supported', + 'userinfo_encryption_alg_values_supported', + 'userinfo_encryption_enc_values_supported', + 'request_object_signing_alg_values_supported', + 'request_object_encryption_alg_values_supported', + 'request_object_encryption_enc_values_supported', + 'display_values_supported', + 'claim_types_supported', + 'claims_supported', + 'claims_locales_supported', + 'claims_parameter_supported', + 'request_parameter_supported', + 'request_uri_parameter_supported', + 'require_request_uri_registration', + + # not defined by OpenID + # 'revocation_endpoint', + # 'revocation_endpoint_auth_methods_supported', + # 'revocation_endpoint_auth_signing_alg_values_supported', + # 'introspection_endpoint', + # 'introspection_endpoint_auth_methods_supported', + # 'introspection_endpoint_auth_signing_alg_values_supported', + # 'code_challenge_methods_supported', + ] + + def validate_jwks_uri(self): + # REQUIRED in OpenID Connect + jwks_uri = self.get('jwks_uri') + if jwks_uri is None: + raise ValueError('"jwks_uri" is required') + return super(OpenIDProviderMetadata, self).validate_jwks_uri() + + def validate_acr_values_supported(self): + """OPTIONAL. JSON array containing a list of the Authentication + Context Class References that this OP supports. + """ + validate_array_value(self, 'acr_values_supported') + + def validate_subject_types_supported(self): + """REQUIRED. JSON array containing a list of the Subject Identifier + types that this OP supports. Valid types include pairwise and public. + """ + # 1. REQUIRED + values = self.get('subject_types_supported') + if values is None: + raise ValueError('"subject_types_supported" is required') + + # 2. JSON array + if not isinstance(values, list): + raise ValueError('"subject_types_supported" MUST be JSON array') + + # 3. Valid types include pairwise and public + valid_types = {'pairwise', 'public'} + if not valid_types.issuperset(set(values)): + raise ValueError( + '"subject_types_supported" contains invalid values') + + def validate_id_token_signing_alg_values_supported(self): + """REQUIRED. JSON array containing a list of the JWS signing + algorithms (alg values) supported by the OP for the ID Token to + encode the Claims in a JWT [JWT]. The algorithm RS256 MUST be + included. The value none MAY be supported, but MUST NOT be used + unless the Response Type used returns no ID Token from the + Authorization Endpoint (such as when using the Authorization + Code Flow). + """ + # 1. REQUIRED + values = self.get('id_token_signing_alg_values_supported') + if values is None: + raise ValueError('"id_token_signing_alg_values_supported" is required') + + # 2. JSON array + if not isinstance(values, list): + raise ValueError('"id_token_signing_alg_values_supported" MUST be JSON array') + + # 3. The algorithm RS256 MUST be included + if 'RS256' not in values: + raise ValueError( + '"RS256" MUST be included in "id_token_signing_alg_values_supported"') + + def validate_id_token_encryption_alg_values_supported(self): + """OPTIONAL. JSON array containing a list of the JWE encryption + algorithms (alg values) supported by the OP for the ID Token to + encode the Claims in a JWT. + """ + validate_array_value(self, 'id_token_encryption_alg_values_supported') + + def validate_id_token_encryption_enc_values_supported(self): + """OPTIONAL. JSON array containing a list of the JWE encryption + algorithms (enc values) supported by the OP for the ID Token to + encode the Claims in a JWT. + """ + validate_array_value(self, 'id_token_encryption_enc_values_supported') + + def validate_userinfo_signing_alg_values_supported(self): + """OPTIONAL. JSON array containing a list of the JWS signing + algorithms (alg values) [JWA] supported by the UserInfo Endpoint + to encode the Claims in a JWT. The value none MAY be included. + """ + validate_array_value(self, 'userinfo_signing_alg_values_supported') + + def validate_userinfo_encryption_alg_values_supported(self): + """OPTIONAL. JSON array containing a list of the JWE encryption + algorithms (alg values) [JWA] supported by the UserInfo Endpoint + to encode the Claims in a JWT. + """ + validate_array_value(self, 'userinfo_encryption_alg_values_supported') + + def validate_userinfo_encryption_enc_values_supported(self): + """OPTIONAL. JSON array containing a list of the JWE encryption + algorithms (enc values) [JWA] supported by the UserInfo Endpoint + to encode the Claims in a JWT. + """ + validate_array_value(self, 'userinfo_encryption_enc_values_supported') + + def validate_request_object_signing_alg_values_supported(self): + """OPTIONAL. JSON array containing a list of the JWS signing + algorithms (alg values) supported by the OP for Request Objects, + which are described in Section 6.1 of OpenID Connect Core 1.0. + These algorithms are used both when the Request Object is passed + by value (using the request parameter) and when it is passed by + reference (using the request_uri parameter). Servers SHOULD support + none and RS256. + """ + values = self.get('request_object_signing_alg_values_supported') + if not values: + return + + if not isinstance(values, list): + raise ValueError('"request_object_signing_alg_values_supported" MUST be JSON array') + + # Servers SHOULD support none and RS256 + if 'none' not in values or 'RS256' not in values: + raise ValueError( + '"request_object_signing_alg_values_supported" ' + 'SHOULD support none and RS256') + + def validate_request_object_encryption_alg_values_supported(self): + """OPTIONAL. JSON array containing a list of the JWE encryption + algorithms (alg values) supported by the OP for Request Objects. + These algorithms are used both when the Request Object is passed + by value and when it is passed by reference. + """ + validate_array_value(self, 'request_object_encryption_alg_values_supported') + + def validate_request_object_encryption_enc_values_supported(self): + """OPTIONAL. JSON array containing a list of the JWE encryption + algorithms (enc values) supported by the OP for Request Objects. + These algorithms are used both when the Request Object is passed + by value and when it is passed by reference. + """ + validate_array_value(self, 'request_object_encryption_enc_values_supported') + + def validate_display_values_supported(self): + """OPTIONAL. JSON array containing a list of the display parameter + values that the OpenID Provider supports. These values are described + in Section 3.1.2.1 of OpenID Connect Core 1.0. + """ + values = self.get('display_values_supported') + if not values: + return + + if not isinstance(values, list): + raise ValueError('"display_values_supported" MUST be JSON array') + + valid_values = {'page', 'popup', 'touch', 'wap'} + if not valid_values.issuperset(set(values)): + raise ValueError('"display_values_supported" contains invalid values') + + def validate_claim_types_supported(self): + """OPTIONAL. JSON array containing a list of the Claim Types that + the OpenID Provider supports. These Claim Types are described in + Section 5.6 of OpenID Connect Core 1.0. Values defined by this + specification are normal, aggregated, and distributed. If omitted, + the implementation supports only normal Claims. + """ + values = self.get('claim_types_supported') + if not values: + return + + if not isinstance(values, list): + raise ValueError('"claim_types_supported" MUST be JSON array') + + valid_values = {'normal', 'aggregated', 'distributed'} + if not valid_values.issuperset(set(values)): + raise ValueError('"claim_types_supported" contains invalid values') + + def validate_claims_supported(self): + """RECOMMENDED. JSON array containing a list of the Claim Names + of the Claims that the OpenID Provider MAY be able to supply values + for. Note that for privacy or other reasons, this might not be an + exhaustive list. + """ + validate_array_value(self, 'claims_supported') + + def validate_claims_locales_supported(self): + """OPTIONAL. Languages and scripts supported for values in Claims + being returned, represented as a JSON array of BCP47 [RFC5646] + language tag values. Not all languages and scripts are necessarily + supported for all Claim values. + """ + validate_array_value(self, 'claims_locales_supported') + + def validate_claims_parameter_supported(self): + """OPTIONAL. Boolean value specifying whether the OP supports use of + the claims parameter, with true indicating support. If omitted, the + default value is false. + """ + _validate_boolean_value(self, 'claims_parameter_supported') + + def validate_request_parameter_supported(self): + """OPTIONAL. Boolean value specifying whether the OP supports use of + the request parameter, with true indicating support. If omitted, the + default value is false. + """ + _validate_boolean_value(self, 'request_parameter_supported') + + def validate_request_uri_parameter_supported(self): + """OPTIONAL. Boolean value specifying whether the OP supports use of + the request_uri parameter, with true indicating support. If omitted, + the default value is true. + """ + _validate_boolean_value(self, 'request_uri_parameter_supported') + + def validate_require_request_uri_registration(self): + """OPTIONAL. Boolean value specifying whether the OP requires any + request_uri values used to be pre-registered using the request_uris + registration parameter. Pre-registration is REQUIRED when the value + is true. If omitted, the default value is false. + """ + _validate_boolean_value(self, 'require_request_uri_registration') + + @property + def claim_types_supported(self): + # If omitted, the implementation supports only normal Claims + return self.get('claim_types_supported', ['normal']) + + @property + def claims_parameter_supported(self): + # If omitted, the default value is false. + return self.get('claims_parameter_supported', False) + + @property + def request_parameter_supported(self): + # If omitted, the default value is false. + return self.get('request_parameter_supported', False) + + @property + def request_uri_parameter_supported(self): + # If omitted, the default value is true. + return self.get('request_uri_parameter_supported', True) + + @property + def require_request_uri_registration(self): + # If omitted, the default value is false. + return self.get('require_request_uri_registration', False) + + +def _validate_boolean_value(metadata, key): + if key not in metadata: + return + if metadata[key] not in (True, False): + raise ValueError('"{}" MUST be boolean'.format(key)) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/discovery/well_known.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/discovery/well_known.py new file mode 100644 index 0000000..e3087a1 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/authlib/oidc/discovery/well_known.py @@ -0,0 +1,17 @@ +from authlib.common.urls import urlparse + + +def get_well_known_url(issuer, external=False): + """Get well-known URI with issuer via Section 4.1. + + :param issuer: URL of the issuer + :param external: return full external url or not + :return: URL + """ + # https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfigurationRequest + if external: + return issuer.rstrip('/') + '/.well-known/openid-configuration' + + parsed = urlparse.urlparse(issuer) + path = parsed.path + return path.rstrip('/') + '/.well-known/openid-configuration' diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi-2020.11.8.dist-info/INSTALLER b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi-2020.11.8.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi-2020.11.8.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi-2020.11.8.dist-info/LICENSE b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi-2020.11.8.dist-info/LICENSE new file mode 100644 index 0000000..802b53f --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi-2020.11.8.dist-info/LICENSE @@ -0,0 +1,21 @@ +This packge contains a modified version of ca-bundle.crt: + +ca-bundle.crt -- Bundle of CA Root Certificates + +Certificate data from Mozilla as of: Thu Nov 3 19:04:19 2011# +This is a bundle of X.509 certificates of public Certificate Authorities +(CA). These were automatically extracted from Mozilla's root certificates +file (certdata.txt). This file can be found in the mozilla source tree: +http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1# +It contains the certificates in PEM format and therefore +can be directly used with curl / libcurl / php_curl, or with +an Apache+mod_ssl webserver for SSL client authentication. +Just configure this file as the SSLCACertificateFile.# + +***** BEGIN LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public License, +v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain +one at http://mozilla.org/MPL/2.0/. + +***** END LICENSE BLOCK ***** +@(#) $RCSfile: certdata.txt,v $ $Revision: 1.80 $ $Date: 2011/11/03 15:11:58 $ diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi-2020.11.8.dist-info/METADATA b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi-2020.11.8.dist-info/METADATA new file mode 100644 index 0000000..e25ee75 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi-2020.11.8.dist-info/METADATA @@ -0,0 +1,83 @@ +Metadata-Version: 2.1 +Name: certifi +Version: 2020.11.8 +Summary: Python package for providing Mozilla's CA Bundle. +Home-page: https://certifiio.readthedocs.io/en/latest/ +Author: Kenneth Reitz +Author-email: me@kennethreitz.com +License: MPL-2.0 +Project-URL: Documentation, https://certifiio.readthedocs.io/en/latest/ +Project-URL: Source, https://github.com/certifi/python-certifi +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0) +Classifier: Natural Language :: English +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 + +Certifi: Python SSL Certificates +================================ + +`Certifi`_ provides Mozilla's carefully curated collection of Root Certificates for +validating the trustworthiness of SSL certificates while verifying the identity +of TLS hosts. It has been extracted from the `Requests`_ project. + +Installation +------------ + +``certifi`` is available on PyPI. Simply install it with ``pip``:: + + $ pip install certifi + +Usage +----- + +To reference the installed certificate authority (CA) bundle, you can use the +built-in function:: + + >>> import certifi + + >>> certifi.where() + '/usr/local/lib/python3.7/site-packages/certifi/cacert.pem' + +Or from the command line:: + + $ python -m certifi + /usr/local/lib/python3.7/site-packages/certifi/cacert.pem + +Enjoy! + +1024-bit Root Certificates +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Browsers and certificate authorities have concluded that 1024-bit keys are +unacceptably weak for certificates, particularly root certificates. For this +reason, Mozilla has removed any weak (i.e. 1024-bit key) certificate from its +bundle, replacing it with an equivalent strong (i.e. 2048-bit or greater key) +certificate from the same CA. Because Mozilla removed these certificates from +its bundle, ``certifi`` removed them as well. + +In previous versions, ``certifi`` provided the ``certifi.old_where()`` function +to intentionally re-add the 1024-bit roots back into your bundle. This was not +recommended in production and therefore was removed at the end of 2018. + +.. _`Certifi`: https://certifiio.readthedocs.io/en/latest/ +.. _`Requests`: https://requests.readthedocs.io/en/master/ + +Addition/Removal of Certificates +-------------------------------- + +Certifi does not support any addition/removal or other modification of the +CA trust store content. This project is intended to provide a reliable and +highly portable root of trust to python deployments. Look to upstream projects +for methods to use alternate trust. + + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi-2020.11.8.dist-info/RECORD b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi-2020.11.8.dist-info/RECORD new file mode 100644 index 0000000..4d8d513 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi-2020.11.8.dist-info/RECORD @@ -0,0 +1,13 @@ +certifi-2020.11.8.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +certifi-2020.11.8.dist-info/LICENSE,sha256=anCkv2sBABbVmmS4rkrY3H9e8W8ftFPMLs13HFo0ETE,1048 +certifi-2020.11.8.dist-info/METADATA,sha256=LBPr6g1-mGhOtrMGg8DFzNp-V76vs5J38EKLzzJDbOM,2994 +certifi-2020.11.8.dist-info/RECORD,, +certifi-2020.11.8.dist-info/WHEEL,sha256=ADKeyaGyKF5DwBNE0sRE5pvW-bSkFMJfBuhzZ3rceP4,110 +certifi-2020.11.8.dist-info/top_level.txt,sha256=KMu4vUCfsjLrkPbSNdgdekS-pVJzBAJFO__nI8NF6-U,8 +certifi/__init__.py,sha256=TocBfHrqAkQK91W5jNYhRH8KKizxkkXZBk68DTHj0xo,62 +certifi/__main__.py,sha256=xBBoj905TUWBLRGANOcf7oi6e-3dMP4cEoG9OyMs11g,243 +certifi/__pycache__/__init__.cpython-38.pyc,, +certifi/__pycache__/__main__.cpython-38.pyc,, +certifi/__pycache__/core.cpython-38.pyc,, +certifi/cacert.pem,sha256=U7iFT4_n-7XCfHpc8I46ad5kHuGvDSedla2fdbQoQUo,281608 +certifi/core.py,sha256=V0uyxKOYdz6ulDSusclrLmjbPgOXsD0BnEf0SQ7OnoE,2303 diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi-2020.11.8.dist-info/WHEEL b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi-2020.11.8.dist-info/WHEEL new file mode 100644 index 0000000..6d38aa0 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi-2020.11.8.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.35.1) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi-2020.11.8.dist-info/top_level.txt b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi-2020.11.8.dist-info/top_level.txt new file mode 100644 index 0000000..963eac5 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi-2020.11.8.dist-info/top_level.txt @@ -0,0 +1 @@ +certifi diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi/__init__.py new file mode 100644 index 0000000..4e5133b --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi/__init__.py @@ -0,0 +1,3 @@ +from .core import contents, where + +__version__ = "2020.11.08" diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi/__main__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi/__main__.py new file mode 100644 index 0000000..8945b5d --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi/__main__.py @@ -0,0 +1,12 @@ +import argparse + +from certifi import contents, where + +parser = argparse.ArgumentParser() +parser.add_argument("-c", "--contents", action="store_true") +args = parser.parse_args() + +if args.contents: + print(contents()) +else: + print(where()) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi/cacert.pem b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi/cacert.pem new file mode 100644 index 0000000..a107208 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi/cacert.pem @@ -0,0 +1,4606 @@ + +# Issuer: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA +# Subject: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA +# Label: "GlobalSign Root CA" +# Serial: 4835703278459707669005204 +# MD5 Fingerprint: 3e:45:52:15:09:51:92:e1:b7:5d:37:9f:b1:87:29:8a +# SHA1 Fingerprint: b1:bc:96:8b:d4:f4:9d:62:2a:a8:9a:81:f2:15:01:52:a4:1d:82:9c +# SHA256 Fingerprint: eb:d4:10:40:e4:bb:3e:c7:42:c9:e3:81:d3:1e:f2:a4:1a:48:b6:68:5c:96:e7:ce:f3:c1:df:6c:d4:33:1c:99 +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw +MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT +aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ +jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp +xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp +1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG +snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ +U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 +9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B +AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz +yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE +38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP +AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad +DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME +HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2 +# Label: "GlobalSign Root CA - R2" +# Serial: 4835703278459682885658125 +# MD5 Fingerprint: 94:14:77:7e:3e:5e:fd:8f:30:bd:41:b0:cf:e7:d0:30 +# SHA1 Fingerprint: 75:e0:ab:b6:13:85:12:27:1c:04:f8:5f:dd:de:38:e4:b7:24:2e:fe +# SHA256 Fingerprint: ca:42:dd:41:74:5f:d0:b8:1e:b9:02:36:2c:f9:d8:bf:71:9d:a1:bd:1b:1e:fc:94:6f:5b:4c:99:f4:2c:1b:9e +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 +MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL +v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 +eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq +tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd +C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa +zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB +mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH +V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n +bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG +3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs +J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO +291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS +ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd +AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 +TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== +-----END CERTIFICATE----- + +# Issuer: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited +# Subject: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited +# Label: "Entrust.net Premium 2048 Secure Server CA" +# Serial: 946069240 +# MD5 Fingerprint: ee:29:31:bc:32:7e:9a:e6:e8:b5:f7:51:b4:34:71:90 +# SHA1 Fingerprint: 50:30:06:09:1d:97:d4:f5:ae:39:f7:cb:e7:92:7d:7d:65:2d:34:31 +# SHA256 Fingerprint: 6d:c4:71:72:e0:1c:bc:b0:bf:62:58:0d:89:5f:e2:b8:ac:9a:d4:f8:73:80:1e:0c:10:b9:c8:37:d2:1e:b1:77 +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML +RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp +bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 +IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 +MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 +LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp +YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG +A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq +K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe +sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX +MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT +XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ +HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH +4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub +j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo +U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf +zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b +u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ +bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er +fF6adulZkMV8gzURZVE= +-----END CERTIFICATE----- + +# Issuer: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust +# Subject: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust +# Label: "Baltimore CyberTrust Root" +# Serial: 33554617 +# MD5 Fingerprint: ac:b6:94:a5:9c:17:e0:d7:91:52:9b:b1:97:06:a6:e4 +# SHA1 Fingerprint: d4:de:20:d0:5e:66:fc:53:fe:1a:50:88:2c:78:db:28:52:ca:e4:74 +# SHA256 Fingerprint: 16:af:57:a9:f6:76:b0:ab:12:60:95:aa:5e:ba:de:f2:2a:b3:11:19:d6:44:ac:95:cd:4b:93:db:f3:f2:6a:eb +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX +DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y +ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy +VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr +mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr +IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK +mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu +XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy +dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye +jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 +BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 +DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 +9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx +jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 +Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz +ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS +R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- + +# Issuer: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. +# Subject: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. +# Label: "Entrust Root Certification Authority" +# Serial: 1164660820 +# MD5 Fingerprint: d6:a5:c3:ed:5d:dd:3e:00:c1:3d:87:92:1f:1d:3f:e4 +# SHA1 Fingerprint: b3:1e:b1:b7:40:e3:6c:84:02:da:dc:37:d4:4d:f5:d4:67:49:52:f9 +# SHA256 Fingerprint: 73:c1:76:43:4f:1b:c6:d5:ad:f4:5b:0e:76:e7:27:28:7c:8d:e5:76:16:c1:e6:e6:14:1a:2b:2c:bc:7d:8e:4c +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 +Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW +KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw +NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw +NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy +ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV +BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo +Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 +4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 +KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI +rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi +94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB +sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi +gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo +kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE +vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t +O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua +AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP +9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ +eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m +0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- + +# Issuer: CN=GeoTrust Global CA O=GeoTrust Inc. +# Subject: CN=GeoTrust Global CA O=GeoTrust Inc. +# Label: "GeoTrust Global CA" +# Serial: 144470 +# MD5 Fingerprint: f7:75:ab:29:fb:51:4e:b7:77:5e:ff:05:3c:99:8e:f5 +# SHA1 Fingerprint: de:28:f4:a4:ff:e5:b9:2f:a3:c5:03:d1:a3:49:a7:f9:96:2a:82:12 +# SHA256 Fingerprint: ff:85:6a:2d:25:1d:cd:88:d3:66:56:f4:50:12:67:98:cf:ab:aa:de:40:79:9c:72:2d:e4:d2:b5:db:36:a7:3a +-----BEGIN CERTIFICATE----- +MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i +YWwgQ0EwHhcNMDIwNTIxMDQwMDAwWhcNMjIwNTIxMDQwMDAwWjBCMQswCQYDVQQG +EwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEbMBkGA1UEAxMSR2VvVHJ1c3Qg +R2xvYmFsIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2swYYzD9 +9BcjGlZ+W988bDjkcbd4kdS8odhM+KhDtgPpTSEHCIjaWC9mOSm9BXiLnTjoBbdq +fnGk5sRgprDvgOSJKA+eJdbtg/OtppHHmMlCGDUUna2YRpIuT8rxh0PBFpVXLVDv +iS2Aelet8u5fa9IAjbkU+BQVNdnARqN7csiRv8lVK83Qlz6cJmTM386DGXHKTubU +1XupGc1V3sjs0l44U+VcT4wt/lAjNvxm5suOpDkZALeVAjmRCw7+OC7RHQWa9k0+ +bw8HHa8sHo9gOeL6NlMTOdReJivbPagUvTLrGAMoUgRx5aszPeE4uwc2hGKceeoW +MPRfwCvocWvk+QIDAQABo1MwUTAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTA +ephojYn7qwVkDBF9qn1luMrMTjAfBgNVHSMEGDAWgBTAephojYn7qwVkDBF9qn1l +uMrMTjANBgkqhkiG9w0BAQUFAAOCAQEANeMpauUvXVSOKVCUn5kaFOSPeCpilKIn +Z57QzxpeR+nBsqTP3UEaBU6bS+5Kb1VSsyShNwrrZHYqLizz/Tt1kL/6cdjHPTfS +tQWVYrmm3ok9Nns4d0iXrKYgjy6myQzCsplFAMfOEVEiIuCl6rYVSAlk6l5PdPcF +PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un +hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV +5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw== +-----END CERTIFICATE----- + +# Issuer: CN=GeoTrust Universal CA O=GeoTrust Inc. +# Subject: CN=GeoTrust Universal CA O=GeoTrust Inc. +# Label: "GeoTrust Universal CA" +# Serial: 1 +# MD5 Fingerprint: 92:65:58:8b:a2:1a:31:72:73:68:5c:b4:a5:7a:07:48 +# SHA1 Fingerprint: e6:21:f3:35:43:79:05:9a:4b:68:30:9d:8a:2f:74:22:15:87:ec:79 +# SHA256 Fingerprint: a0:45:9b:9f:63:b2:25:59:f5:fa:5d:4c:6d:b3:f9:f7:2f:f1:93:42:03:35:78:f0:73:bf:1d:1b:46:cb:b9:12 +-----BEGIN CERTIFICATE----- +MIIFaDCCA1CgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMQswCQYDVQQGEwJVUzEW +MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgVW5pdmVy +c2FsIENBMB4XDTA0MDMwNDA1MDAwMFoXDTI5MDMwNDA1MDAwMFowRTELMAkGA1UE +BhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xHjAcBgNVBAMTFUdlb1RydXN0 +IFVuaXZlcnNhbCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAKYV +VaCjxuAfjJ0hUNfBvitbtaSeodlyWL0AG0y/YckUHUWCq8YdgNY96xCcOq9tJPi8 +cQGeBvV8Xx7BDlXKg5pZMK4ZyzBIle0iN430SppyZj6tlcDgFgDgEB8rMQ7XlFTT +QjOgNB0eRXbdT8oYN+yFFXoZCPzVx5zw8qkuEKmS5j1YPakWaDwvdSEYfyh3peFh +F7em6fgemdtzbvQKoiFs7tqqhZJmr/Z6a4LauiIINQ/PQvE1+mrufislzDoR5G2v +c7J2Ha3QsnhnGqQ5HFELZ1aD/ThdDc7d8Lsrlh/eezJS/R27tQahsiFepdaVaH/w +mZ7cRQg+59IJDTWU3YBOU5fXtQlEIGQWFwMCTFMNaN7VqnJNk22CDtucvc+081xd +VHppCZbW2xHBjXWotM85yM48vCR85mLK4b19p71XZQvk/iXttmkQ3CgaRr0BHdCX +teGYO8A3ZNY9lO4L4fUorgtWv3GLIylBjobFS1J72HGrH4oVpjuDWtdYAVHGTEHZ +f9hBZ3KiKN9gg6meyHv8U3NyWfWTehd2Ds735VzZC1U0oqpbtWpU5xPKV+yXbfRe +Bi9Fi1jUIxaS5BZuKGNZMN9QAZxjiRqf2xeUgnA3wySemkfWWspOqGmJch+RbNt+ +nhutxx9z3SxPGWX9f5NAEC7S8O08ni4oPmkmM8V7AgMBAAGjYzBhMA8GA1UdEwEB +/wQFMAMBAf8wHQYDVR0OBBYEFNq7LqqwDLiIJlF0XG0D08DYj3rWMB8GA1UdIwQY +MBaAFNq7LqqwDLiIJlF0XG0D08DYj3rWMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG +9w0BAQUFAAOCAgEAMXjmx7XfuJRAyXHEqDXsRh3ChfMoWIawC/yOsjmPRFWrZIRc +aanQmjg8+uUfNeVE44B5lGiku8SfPeE0zTBGi1QrlaXv9z+ZhP015s8xxtxqv6fX +IwjhmF7DWgh2qaavdy+3YL1ERmrvl/9zlcGO6JP7/TG37FcREUWbMPEaiDnBTzyn +ANXH/KttgCJwpQzgXQQpAvvLoJHRfNbDflDVnVi+QTjruXU8FdmbyUqDWcDaU/0z +uzYYm4UPFd3uLax2k7nZAY1IEKj79TiG8dsKxr2EoyNB3tZ3b4XUhRxQ4K5RirqN +Pnbiucon8l+f725ZDQbYKxek0nxru18UGkiPGkzns0ccjkxFKyDuSN/n3QmOGKja +QI2SJhFTYXNd673nxE0pN2HrrDktZy4W1vUAg4WhzH92xH3kt0tm7wNFYGm2DFKW +koRepqO1pD4r2czYG0eq8kTaT/kD6PAUyz/zg97QwVTjt+gKN02LIFkDMBmhLMi9 +ER/frslKxfMnZmaGrGiR/9nmUxwPi1xpZQomyB40w11Re9epnAahNt3ViZS82eQt +DF4JbAiXfKM9fJP/P6EUp8+1Xevb2xzEdt+Iub1FBZUbrvxGakyvSOPOrg/Sfuvm +bJxPgWp6ZKy7PtXny3YuxadIwVyQD8vIP/rmMuGNG2+k5o7Y+SlIis5z/iw= +-----END CERTIFICATE----- + +# Issuer: CN=GeoTrust Universal CA 2 O=GeoTrust Inc. +# Subject: CN=GeoTrust Universal CA 2 O=GeoTrust Inc. +# Label: "GeoTrust Universal CA 2" +# Serial: 1 +# MD5 Fingerprint: 34:fc:b8:d0:36:db:9e:14:b3:c2:f2:db:8f:e4:94:c7 +# SHA1 Fingerprint: 37:9a:19:7b:41:85:45:35:0c:a6:03:69:f3:3c:2e:af:47:4f:20:79 +# SHA256 Fingerprint: a0:23:4f:3b:c8:52:7c:a5:62:8e:ec:81:ad:5d:69:89:5d:a5:68:0d:c9:1d:1c:b8:47:7f:33:f8:78:b9:5b:0b +-----BEGIN CERTIFICATE----- +MIIFbDCCA1SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBHMQswCQYDVQQGEwJVUzEW +MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1c3QgVW5pdmVy +c2FsIENBIDIwHhcNMDQwMzA0MDUwMDAwWhcNMjkwMzA0MDUwMDAwWjBHMQswCQYD +VQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEgMB4GA1UEAxMXR2VvVHJ1 +c3QgVW5pdmVyc2FsIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQCzVFLByT7y2dyxUxpZKeexw0Uo5dfR7cXFS6GqdHtXr0om/Nj1XqduGdt0DE81 +WzILAePb63p3NeqqWuDW6KFXlPCQo3RWlEQwAx5cTiuFJnSCegx2oG9NzkEtoBUG +FF+3Qs17j1hhNNwqCPkuwwGmIkQcTAeC5lvO0Ep8BNMZcyfwqph/Lq9O64ceJHdq +XbboW0W63MOhBW9Wjo8QJqVJwy7XQYci4E+GymC16qFjwAGXEHm9ADwSbSsVsaxL +se4YuU6W3Nx2/zu+z18DwPw76L5GG//aQMJS9/7jOvdqdzXQ2o3rXhhqMcceujwb +KNZrVMaqW9eiLBsZzKIC9ptZvTdrhrVtgrrY6slWvKk2WP0+GfPtDCapkzj4T8Fd +IgbQl+rhrcZV4IErKIM6+vR7IVEAvlI4zs1meaj0gVbi0IMJR1FbUGrP20gaXT73 +y/Zl92zxlfgCOzJWgjl6W70viRu/obTo/3+NjN8D8WBOWBFM66M/ECuDmgFz2ZRt +hAAnZqzwcEAJQpKtT5MNYQlRJNiS1QuUYbKHsu3/mjX/hVTK7URDrBs8FmtISgoc +QIgfksILAAX/8sgCSqSqqcyZlpwvWOB94b67B9xfBHJcMTTD7F8t4D1kkCLm0ey4 +Lt1ZrtmhN79UNdxzMk+MBB4zsslG8dhcyFVQyWi9qLo2CQIDAQABo2MwYTAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAfBgNV +HSMEGDAWgBR281Xh+qQ2+/CfXGJx7Tz0RzgQKzAOBgNVHQ8BAf8EBAMCAYYwDQYJ +KoZIhvcNAQEFBQADggIBAGbBxiPz2eAubl/oz66wsCVNK/g7WJtAJDday6sWSf+z +dXkzoS9tcBc0kf5nfo/sm+VegqlVHy/c1FEHEv6sFj4sNcZj/NwQ6w2jqtB8zNHQ +L1EuxBRa3ugZ4T7GzKQp5y6EqgYweHZUcyiYWTjgAA1i00J9IZ+uPTqM1fp3DRgr +Fg5fNuH8KrUwJM/gYwx7WBr+mbpCErGR9Hxo4sjoryzqyX6uuyo9DRXcNJW2GHSo +ag/HtPQTxORb7QrSpJdMKu0vbBKJPfEncKpqA1Ihn0CoZ1Dy81of398j9tx4TuaY +T1U6U+Pv8vSfx3zYWK8pIpe44L2RLrB27FcRz+8pRPPphXpgY+RdM4kX2TGq2tbz +GDVyz4crL2MjhF2EjD9XoIj8mZEoJmmZ1I+XRL6O1UixpCgp8RW04eWe3fiPpm8m +1wk8OhwRDqZsN/etRIcsKMfYdIKz0G9KV7s1KSegi+ghp4dkNl3M2Basx7InQJJV +OCiNUW7dFGdTbHFcJoRNdVq2fmBWqU2t+5sel/MN2dKXVHfaPRK34B7vCAas+YWH +6aLcr34YEoP9VhdBLtUpgn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwX +QMAJKOSLakhT2+zNVVXxxvjpoixMptEmX36vWkzaH6byHCx+rgIW0lbQL1dTR+iS +-----END CERTIFICATE----- + +# Issuer: CN=AAA Certificate Services O=Comodo CA Limited +# Subject: CN=AAA Certificate Services O=Comodo CA Limited +# Label: "Comodo AAA Services root" +# Serial: 1 +# MD5 Fingerprint: 49:79:04:b0:eb:87:19:ac:47:b0:bc:11:51:9b:74:d0 +# SHA1 Fingerprint: d1:eb:23:a4:6d:17:d6:8f:d9:25:64:c2:f1:f1:60:17:64:d8:e3:49 +# SHA256 Fingerprint: d7:a7:a0:fb:5d:7e:27:31:d7:71:e9:48:4e:bc:de:f7:1d:5f:0c:3e:0a:29:48:78:2b:c8:3e:e0:ea:69:9e:f4 +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb +MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow +GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj +YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM +GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua +BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe +3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 +YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR +rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm +ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU +oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v +QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t +b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF +AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q +GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 +G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi +l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 +smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root Certification Authority O=QuoVadis Limited OU=Root Certification Authority +# Subject: CN=QuoVadis Root Certification Authority O=QuoVadis Limited OU=Root Certification Authority +# Label: "QuoVadis Root CA" +# Serial: 985026699 +# MD5 Fingerprint: 27:de:36:fe:72:b7:00:03:00:9d:f4:f0:1e:6c:04:24 +# SHA1 Fingerprint: de:3f:40:bd:50:93:d3:9b:6c:60:f6:da:bc:07:62:01:00:89:76:c9 +# SHA256 Fingerprint: a4:5e:de:3b:bb:f0:9c:8a:e1:5c:72:ef:c0:72:68:d6:93:a2:1c:99:6f:d5:1e:67:ca:07:94:60:fd:6d:88:73 +-----BEGIN CERTIFICATE----- +MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC +TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTEuMCwGA1UEAxMlUXVvVmFkaXMgUm9vdCBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wMTAzMTkxODMzMzNaFw0yMTAzMTcxODMz +MzNaMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMSUw +IwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYDVQQDEyVR +dW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2G1lVO6V/z68mcLOhrfEYBklbTRvM16z/Yp +li4kVEAkOPcahdxYTMukJ0KX0J+DisPkBgNbAKVRHnAEdOLB1Dqr1607BxgFjv2D +rOpm2RgbaIr1VxqYuvXtdj182d6UajtLF8HVj71lODqV0D1VNk7feVcxKh7YWWVJ +WCCYfqtffp/p1k3sg3Spx2zY7ilKhSoGFPlU5tPaZQeLYzcS19Dsw3sgQUSj7cug +F+FxZc4dZjH3dgEZyH0DWLaVSR2mEiboxgx24ONmy+pdpibu5cxfvWenAScOospU +xbF6lR1xHkopigPcakXBpBlebzbNw6Kwt/5cOOJSvPhEQ+aQuwIDAQABo4ICUjCC +Ak4wPQYIKwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwczovL29jc3AucXVv +dmFkaXNvZmZzaG9yZS5jb20wDwYDVR0TAQH/BAUwAwEB/zCCARoGA1UdIASCAREw +ggENMIIBCQYJKwYBBAG+WAABMIH7MIHUBggrBgEFBQcCAjCBxxqBxFJlbGlhbmNl +IG9uIHRoZSBRdW9WYWRpcyBSb290IENlcnRpZmljYXRlIGJ5IGFueSBwYXJ0eSBh +c3N1bWVzIGFjY2VwdGFuY2Ugb2YgdGhlIHRoZW4gYXBwbGljYWJsZSBzdGFuZGFy +ZCB0ZXJtcyBhbmQgY29uZGl0aW9ucyBvZiB1c2UsIGNlcnRpZmljYXRpb24gcHJh +Y3RpY2VzLCBhbmQgdGhlIFF1b1ZhZGlzIENlcnRpZmljYXRlIFBvbGljeS4wIgYI +KwYBBQUHAgEWFmh0dHA6Ly93d3cucXVvdmFkaXMuYm0wHQYDVR0OBBYEFItLbe3T +KbkGGew5Oanwl4Rqy+/fMIGuBgNVHSMEgaYwgaOAFItLbe3TKbkGGew5Oanwl4Rq +y+/foYGEpIGBMH8xCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1p +dGVkMSUwIwYDVQQLExxSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MS4wLAYD +VQQDEyVRdW9WYWRpcyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggQ6tlCL +MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOCAQEAitQUtf70mpKnGdSk +fnIYj9lofFIk3WdvOXrEql494liwTXCYhGHoG+NpGA7O+0dQoE7/8CQfvbLO9Sf8 +7C9TqnN7Az10buYWnuulLsS/VidQK2K6vkscPFVcQR0kvoIgR13VRH56FmjffU1R +cHhXHTMe/QKZnAzNCgVPx7uOpHX6Sm2xgI4JVrmcGmD+XcHXetwReNDWXcG31a0y +mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW +xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK +SnQ2+Q== +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 2 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 2 O=QuoVadis Limited +# Label: "QuoVadis Root CA 2" +# Serial: 1289 +# MD5 Fingerprint: 5e:39:7b:dd:f8:ba:ec:82:e9:ac:62:ba:0c:54:00:2b +# SHA1 Fingerprint: ca:3a:fb:cf:12:40:36:4b:44:b2:16:20:88:80:48:39:19:93:7c:f7 +# SHA256 Fingerprint: 85:a0:dd:7d:d7:20:ad:b7:ff:05:f8:3d:54:2b:20:9d:c7:ff:45:28:f7:d6:77:b1:83:89:fe:a5:e5:c4:9e:86 +-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa +GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg +Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J +WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB +rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp ++ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 +ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i +Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz +PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og +/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH +oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI +yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud +EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 +A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL +MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT +ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f +BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn +g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl +fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K +WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha +B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc +hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR +TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD +mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z +ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y +4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza +8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 3 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 3 O=QuoVadis Limited +# Label: "QuoVadis Root CA 3" +# Serial: 1478 +# MD5 Fingerprint: 31:85:3c:62:94:97:63:b9:aa:fd:89:4e:af:6f:e0:cf +# SHA1 Fingerprint: 1f:49:14:f7:d8:74:95:1d:dd:ae:02:c0:be:fd:3a:2d:82:75:51:85 +# SHA256 Fingerprint: 18:f1:fc:7f:20:5d:f8:ad:dd:eb:7f:e0:07:dd:57:e3:af:37:5a:9c:4d:8d:73:54:6b:f4:f1:fe:d1:e1:8d:35 +-----BEGIN CERTIFICATE----- +MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM +V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB +4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr +H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd +8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv +vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT +mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe +btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc +T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt +WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ +c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A +4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD +VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG +CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 +aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 +aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu +dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw +czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G +A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC +TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg +Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 +7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem +d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd ++LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B +4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN +t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x +DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 +k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s +zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j +Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT +mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK +4SVhM7JZG+Ju1zdXtg2pEto= +-----END CERTIFICATE----- + +# Issuer: O=SECOM Trust.net OU=Security Communication RootCA1 +# Subject: O=SECOM Trust.net OU=Security Communication RootCA1 +# Label: "Security Communication Root CA" +# Serial: 0 +# MD5 Fingerprint: f1:bc:63:6a:54:e0:b5:27:f5:cd:e7:1a:e3:4d:6e:4a +# SHA1 Fingerprint: 36:b1:2b:49:f9:81:9e:d7:4c:9e:bc:38:0f:c6:56:8f:5d:ac:b2:f7 +# SHA256 Fingerprint: e7:5e:72:ed:9f:56:0e:ec:6e:b4:80:00:73:a4:3f:c3:ad:19:19:5a:39:22:82:01:78:95:97:4a:99:02:6b:6c +-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY +MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t +dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5 +WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD +VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8 +9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ +DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9 +Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N +QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ +xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G +A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG +kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr +Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5 +Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU +JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot +RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw== +-----END CERTIFICATE----- + +# Issuer: CN=Sonera Class2 CA O=Sonera +# Subject: CN=Sonera Class2 CA O=Sonera +# Label: "Sonera Class 2 Root CA" +# Serial: 29 +# MD5 Fingerprint: a3:ec:75:0f:2e:88:df:fa:48:01:4e:0b:5c:48:6f:fb +# SHA1 Fingerprint: 37:f7:6d:e6:07:7c:90:c5:b1:3e:93:1a:b7:41:10:b4:f2:e4:9a:27 +# SHA256 Fingerprint: 79:08:b4:03:14:c1:38:10:0b:51:8d:07:35:80:7f:fb:fc:f8:51:8a:00:95:33:71:05:ba:38:6b:15:3d:d9:27 +-----BEGIN CERTIFICATE----- +MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP +MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx +MDQwNjA3Mjk0MFoXDTIxMDQwNjA3Mjk0MFowOTELMAkGA1UEBhMCRkkxDzANBgNV +BAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJhIENsYXNzMiBDQTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAJAXSjWdyvANlsdE+hY3/Ei9vX+ALTU74W+o +Z6m/AxxNjG8yR9VBaKQTBME1DJqEQ/xcHf+Js+gXGM2RX/uJ4+q/Tl18GybTdXnt +5oTjV+WtKcT0OijnpXuENmmz/V52vaMtmdOQTiMofRhj8VQ7Jp12W5dCsv+u8E7s +3TmVToMGf+dJQMjFAbJUWmYdPfz56TwKnoG4cPABi+QjVHzIrviQHgCWctRUz2Ej +vOr7nQKV0ba5cTppCD8PtOFCx4j1P5iop7oc4HFx71hXgVB6XGt0Rg6DA5jDjqhu +8nYybieDwnPz3BjotJPqdURrBGAgcVeHnfO+oJAjPYok4doh28MCAwEAAaMzMDEw +DwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQISqCqWITTXjwwCwYDVR0PBAQDAgEG +MA0GCSqGSIb3DQEBBQUAA4IBAQBazof5FnIVV0sd2ZvnoiYw7JNn39Yt0jSv9zil +zqsWuasvfDXLrNAPtEwr/IDva4yRXzZ299uzGxnq9LIR/WFxRL8oszodv7ND6J+/ +3DEIcbCdjdY0RzKQxmUk96BKfARzjzlvF4xytb1LyHr4e4PDKE6cCepnP7JnBBvD +FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6 +Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2 +ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M +-----END CERTIFICATE----- + +# Issuer: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com +# Subject: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com +# Label: "XRamp Global CA Root" +# Serial: 107108908803651509692980124233745014957 +# MD5 Fingerprint: a1:0b:44:b3:ca:10:d8:00:6e:9d:0f:d8:0f:92:0a:d1 +# SHA1 Fingerprint: b8:01:86:d1:eb:9c:86:a5:41:04:cf:30:54:f3:4c:52:b7:e5:58:c6 +# SHA256 Fingerprint: ce:cd:dc:90:50:99:d8:da:df:c5:b1:d2:09:b7:37:cb:e2:c1:8c:fb:2c:10:c0:ff:0b:cf:0d:32:86:fc:1a:a2 +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB +gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk +MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY +UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx +NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3 +dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy +dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6 +38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP +KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q +DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4 +qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa +JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi +PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P +BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs +jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0 +eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD +ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR +vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt +qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa +IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy +i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ +O+7ETPTsJ3xCwnR8gooJybQDJbw= +-----END CERTIFICATE----- + +# Issuer: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority +# Subject: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority +# Label: "Go Daddy Class 2 CA" +# Serial: 0 +# MD5 Fingerprint: 91:de:06:25:ab:da:fd:32:17:0c:bb:25:17:2a:84:67 +# SHA1 Fingerprint: 27:96:ba:e6:3f:18:01:e2:77:26:1b:a0:d7:77:70:02:8f:20:ee:e4 +# SHA256 Fingerprint: c3:84:6b:f2:4b:9e:93:ca:64:27:4c:0e:c6:7c:1e:cc:5e:02:4f:fc:ac:d2:d7:40:19:35:0e:81:fe:54:6a:e4 +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh +MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE +YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 +MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo +ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg +MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN +ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA +PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w +wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi +EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY +avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ +YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE +sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h +/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 +IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD +ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy +OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P +TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER +dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf +ReYNnyicsbkqWletNw+vHX/bvZ8= +-----END CERTIFICATE----- + +# Issuer: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority +# Subject: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority +# Label: "Starfield Class 2 CA" +# Serial: 0 +# MD5 Fingerprint: 32:4a:4b:bb:c8:63:69:9b:be:74:9a:c6:dd:1d:46:24 +# SHA1 Fingerprint: ad:7e:1c:28:b0:64:ef:8f:60:03:40:20:14:c3:d0:e3:37:0e:b5:8a +# SHA256 Fingerprint: 14:65:fa:20:53:97:b8:76:fa:a6:f0:a9:95:8e:55:90:e4:0f:cc:7f:aa:4f:b7:c2:c8:67:75:21:fb:5f:b6:58 +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl +MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp +U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw +NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE +ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp +ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 +DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf +8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN ++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 +X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa +K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA +1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G +A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR +zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 +YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD +bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 +L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D +eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp +VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY +WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Assured ID Root CA" +# Serial: 17154717934120587862167794914071425081 +# MD5 Fingerprint: 87:ce:0b:7b:2a:0e:49:00:e1:58:71:9b:37:a8:93:72 +# SHA1 Fingerprint: 05:63:b8:63:0d:62:d7:5a:bb:c8:ab:1e:4b:df:b5:a8:99:b2:4d:43 +# SHA256 Fingerprint: 3e:90:99:b5:01:5e:8f:48:6c:00:bc:ea:9d:11:1e:e7:21:fa:ba:35:5a:89:bc:f1:df:69:56:1e:3d:c6:32:5c +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c +JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP +mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ +wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 +VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ +AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB +AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun +pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC +dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf +fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm +NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx +H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Global Root CA" +# Serial: 10944719598952040374951832963794454346 +# MD5 Fingerprint: 79:e4:a9:84:0d:7d:3a:96:d7:c0:4f:e2:43:4c:89:2e +# SHA1 Fingerprint: a8:98:5d:3a:65:e5:e5:c4:b2:d7:d6:6d:40:c6:dd:2f:b1:9c:54:36 +# SHA256 Fingerprint: 43:48:a0:e9:44:4c:78:cb:26:5e:05:8d:5e:89:44:b4:d8:4f:96:62:bd:26:db:25:7f:89:34:a4:43:c7:01:61 +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert High Assurance EV Root CA" +# Serial: 3553400076410547919724730734378100087 +# MD5 Fingerprint: d4:74:de:57:5c:39:b2:d3:9c:85:83:c5:c0:65:49:8a +# SHA1 Fingerprint: 5f:b7:ee:06:33:e2:59:db:ad:0c:4c:9a:e6:d3:8f:1a:61:c7:dc:25 +# SHA256 Fingerprint: 74:31:e5:f4:c3:c1:ce:46:90:77:4f:0b:61:e0:54:40:88:3b:a9:a0:1e:d0:0b:a6:ab:d7:80:6e:d3:b1:18:cf +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug +RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm ++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW +PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM +xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB +Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 +hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg +EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA +FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec +nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z +eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF +hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 +Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep ++OkuE6N36B9K +-----END CERTIFICATE----- + +# Issuer: CN=DST Root CA X3 O=Digital Signature Trust Co. +# Subject: CN=DST Root CA X3 O=Digital Signature Trust Co. +# Label: "DST Root CA X3" +# Serial: 91299735575339953335919266965803778155 +# MD5 Fingerprint: 41:03:52:dc:0f:f7:50:1b:16:f0:02:8e:ba:6f:45:c5 +# SHA1 Fingerprint: da:c9:02:4f:54:d8:f6:df:94:93:5f:b1:73:26:38:ca:6a:d7:7c:13 +# SHA256 Fingerprint: 06:87:26:03:31:a7:24:03:d9:09:f1:05:e6:9b:cf:0d:32:e1:bd:24:93:ff:c6:d9:20:6d:11:bc:d6:77:07:39 +-----BEGIN CERTIFICATE----- +MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow +PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD +Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O +rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq +OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b +xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw +7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD +aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG +SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 +ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr +AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz +R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 +JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo +Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ +-----END CERTIFICATE----- + +# Issuer: CN=SwissSign Gold CA - G2 O=SwissSign AG +# Subject: CN=SwissSign Gold CA - G2 O=SwissSign AG +# Label: "SwissSign Gold CA - G2" +# Serial: 13492815561806991280 +# MD5 Fingerprint: 24:77:d9:a8:91:d1:3b:fa:88:2d:c2:ff:f8:cd:33:93 +# SHA1 Fingerprint: d8:c5:38:8a:b7:30:1b:1b:6e:d4:7a:e6:45:25:3a:6f:9f:1a:27:61 +# SHA256 Fingerprint: 62:dd:0b:e9:b9:f5:0a:16:3e:a0:f8:e7:5c:05:3b:1e:ca:57:ea:55:c8:68:8f:64:7c:68:81:f2:c8:35:7b:95 +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +# Issuer: CN=SwissSign Silver CA - G2 O=SwissSign AG +# Subject: CN=SwissSign Silver CA - G2 O=SwissSign AG +# Label: "SwissSign Silver CA - G2" +# Serial: 5700383053117599563 +# MD5 Fingerprint: e0:06:a1:c9:7d:cf:c9:fc:0d:c0:56:75:96:d8:62:13 +# SHA1 Fingerprint: 9b:aa:e5:9f:56:ee:21:cb:43:5a:be:25:93:df:a7:f0:40:d1:1d:cb +# SHA256 Fingerprint: be:6c:4d:a2:bb:b9:ba:59:b6:f3:93:97:68:37:42:46:c3:c0:05:99:3f:a9:8f:02:0d:1d:ed:be:d4:8a:81:d5 +-----BEGIN CERTIFICATE----- +MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE +BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu +IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow +RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY +U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv +Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br +YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF +nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH +6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt +eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/ +c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ +MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH +HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf +jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6 +5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB +rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU +F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c +wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 +cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB +AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp +WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9 +xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ +2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ +IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8 +aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X +em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR +dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/ +OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+ +hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy +tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u +-----END CERTIFICATE----- + +# Issuer: CN=GeoTrust Primary Certification Authority O=GeoTrust Inc. +# Subject: CN=GeoTrust Primary Certification Authority O=GeoTrust Inc. +# Label: "GeoTrust Primary Certification Authority" +# Serial: 32798226551256963324313806436981982369 +# MD5 Fingerprint: 02:26:c3:01:5e:08:30:37:43:a9:d0:7d:cf:37:e6:bf +# SHA1 Fingerprint: 32:3c:11:8e:1b:f7:b8:b6:52:54:e2:e2:10:0d:d6:02:90:37:f0:96 +# SHA256 Fingerprint: 37:d5:10:06:c5:12:ea:ab:62:64:21:f1:ec:8c:92:01:3f:c5:f8:2a:e9:8e:e5:33:eb:46:19:b8:de:b4:d0:6c +-----BEGIN CERTIFICATE----- +MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY +MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo +R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx +MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK +Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9 +AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA +ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0 +7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W +kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI +mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ +KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1 +6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl +4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K +oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj +UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU +AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk= +-----END CERTIFICATE----- + +# Issuer: CN=thawte Primary Root CA O=thawte, Inc. OU=Certification Services Division/(c) 2006 thawte, Inc. - For authorized use only +# Subject: CN=thawte Primary Root CA O=thawte, Inc. OU=Certification Services Division/(c) 2006 thawte, Inc. - For authorized use only +# Label: "thawte Primary Root CA" +# Serial: 69529181992039203566298953787712940909 +# MD5 Fingerprint: 8c:ca:dc:0b:22:ce:f5:be:72:ac:41:1a:11:a8:d8:12 +# SHA1 Fingerprint: 91:c6:d6:ee:3e:8a:c8:63:84:e5:48:c2:99:29:5c:75:6c:81:7b:81 +# SHA256 Fingerprint: 8d:72:2f:81:a9:c1:13:c0:79:1d:f1:36:a2:96:6d:b2:6c:95:0a:97:1d:b4:6b:41:99:f4:ea:54:b7:8b:fb:9f +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB +qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV +BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw +NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j +LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG +A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl +IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs +W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta +3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk +6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6 +Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J +NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA +MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP +r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU +DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz +YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX +xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2 +/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/ +LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7 +jVaMaA== +-----END CERTIFICATE----- + +# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G5 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2006 VeriSign, Inc. - For authorized use only +# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G5 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2006 VeriSign, Inc. - For authorized use only +# Label: "VeriSign Class 3 Public Primary Certification Authority - G5" +# Serial: 33037644167568058970164719475676101450 +# MD5 Fingerprint: cb:17:e4:31:67:3e:e2:09:fe:45:57:93:f3:0a:fa:1c +# SHA1 Fingerprint: 4e:b6:d5:78:49:9b:1c:cf:5f:58:1e:ad:56:be:3d:9b:67:44:a5:e5 +# SHA256 Fingerprint: 9a:cf:ab:7e:43:c8:d8:80:d0:6b:26:2a:94:de:ee:e4:b4:65:99:89:c3:d0:ca:f1:9b:af:64:05:e4:1a:b7:df +-----BEGIN CERTIFICATE----- +MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB +yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW +ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp +U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 +nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex +t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz +SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG +BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ +rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ +NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E +BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH +BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy +aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv +MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE +p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y +5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK +WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ +4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N +hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq +-----END CERTIFICATE----- + +# Issuer: CN=SecureTrust CA O=SecureTrust Corporation +# Subject: CN=SecureTrust CA O=SecureTrust Corporation +# Label: "SecureTrust CA" +# Serial: 17199774589125277788362757014266862032 +# MD5 Fingerprint: dc:32:c3:a7:6d:25:57:c7:68:09:9d:ea:2d:a9:a2:d1 +# SHA1 Fingerprint: 87:82:c6:c3:04:35:3b:cf:d2:96:92:d2:59:3e:7d:44:d9:34:ff:11 +# SHA256 Fingerprint: f1:c1:b5:0a:e5:a2:0d:d8:03:0e:c9:f6:bc:24:82:3d:d3:67:b5:25:57:59:b4:e7:1b:61:fc:e9:f7:37:5d:73 +-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz +MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv +cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz +Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO +0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao +wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj +7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS +8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT +BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg +JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 +6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ +3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm +D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS +CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE----- + +# Issuer: CN=Secure Global CA O=SecureTrust Corporation +# Subject: CN=Secure Global CA O=SecureTrust Corporation +# Label: "Secure Global CA" +# Serial: 9751836167731051554232119481456978597 +# MD5 Fingerprint: cf:f4:27:0d:d4:ed:dc:65:16:49:6d:3d:da:bf:6e:de +# SHA1 Fingerprint: 3a:44:73:5a:e5:81:90:1f:24:86:61:46:1e:3b:9c:c4:5f:f5:3a:1b +# SHA256 Fingerprint: 42:00:f5:04:3a:c8:59:0e:bb:52:7d:20:9e:d1:50:30:29:fb:cb:d4:1c:a1:b5:06:ec:27:f1:5a:de:7d:ac:69 +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx +MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg +Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ +iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa +/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ +jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI +HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 +sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w +gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw +KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG +AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L +URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO +H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm +I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY +iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW +-----END CERTIFICATE----- + +# Issuer: CN=COMODO Certification Authority O=COMODO CA Limited +# Subject: CN=COMODO Certification Authority O=COMODO CA Limited +# Label: "COMODO Certification Authority" +# Serial: 104350513648249232941998508985834464573 +# MD5 Fingerprint: 5c:48:dc:f7:42:72:ec:56:94:6d:1c:cc:71:35:80:75 +# SHA1 Fingerprint: 66:31:bf:9e:f7:4f:9e:b6:c9:d5:a6:0c:ba:6a:be:d1:f7:bd:ef:7b +# SHA256 Fingerprint: 0c:2c:d6:3d:f7:80:6f:a3:99:ed:e8:09:11:6b:57:5b:f8:79:89:f0:65:18:f9:80:8c:86:05:03:17:8b:af:66 +-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB +gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV +BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw +MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl +YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P +RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 +UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI +2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 +Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp ++2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ +DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O +nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW +/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g +PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u +QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY +SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv +IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 +zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd +BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB +ZQ== +-----END CERTIFICATE----- + +# Issuer: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C. +# Subject: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C. +# Label: "Network Solutions Certificate Authority" +# Serial: 116697915152937497490437556386812487904 +# MD5 Fingerprint: d3:f3:a6:16:c0:fa:6b:1d:59:b1:2d:96:4d:0e:11:2e +# SHA1 Fingerprint: 74:f8:a3:c3:ef:e7:b3:90:06:4b:83:90:3c:21:64:60:20:e5:df:ce +# SHA256 Fingerprint: 15:f0:ba:00:a3:ac:7a:f3:ac:88:4c:07:2b:10:11:a0:77:bd:77:c0:97:f4:01:64:b2:f8:59:8a:bd:83:86:0c +-----BEGIN CERTIFICATE----- +MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi +MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu +MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp +dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV +UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO +ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz +c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP +OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl +mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF +BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4 +qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw +gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu +bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp +dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8 +6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/ +h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH +/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv +wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN +pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey +-----END CERTIFICATE----- + +# Issuer: CN=COMODO ECC Certification Authority O=COMODO CA Limited +# Subject: CN=COMODO ECC Certification Authority O=COMODO CA Limited +# Label: "COMODO ECC Certification Authority" +# Serial: 41578283867086692638256921589707938090 +# MD5 Fingerprint: 7c:62:ff:74:9d:31:53:5e:68:4a:d5:78:aa:1e:bf:23 +# SHA1 Fingerprint: 9f:74:4e:9f:2b:4d:ba:ec:0f:31:2c:50:b6:56:3b:8e:2d:93:c3:11 +# SHA256 Fingerprint: 17:93:92:7a:06:14:54:97:89:ad:ce:2f:8f:34:f7:f0:b6:6d:0f:3a:e3:a3:b8:4d:21:ec:15:db:ba:4f:ad:c7 +-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT +IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw +MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy +ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N +T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR +FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J +cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW +BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm +fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv +GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE----- + +# Issuer: CN=Certigna O=Dhimyotis +# Subject: CN=Certigna O=Dhimyotis +# Label: "Certigna" +# Serial: 18364802974209362175 +# MD5 Fingerprint: ab:57:a6:5b:7d:42:82:19:b5:d8:58:26:28:5e:fd:ff +# SHA1 Fingerprint: b1:2e:13:63:45:86:a4:6f:1a:b2:60:68:37:58:2d:c4:ac:fd:94:97 +# SHA256 Fingerprint: e3:b6:a2:db:2e:d7:ce:48:84:2f:7a:c5:32:41:c7:b7:1d:54:14:4b:fb:40:c1:1f:3f:1d:0b:42:f5:ee:a1:2d +-----BEGIN CERTIFICATE----- +MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV +BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X +DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ +BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4 +QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny +gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw +zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q +130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2 +JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw +ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT +AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj +AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG +9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h +bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc +fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu +HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w +t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw +WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== +-----END CERTIFICATE----- + +# Issuer: CN=Cybertrust Global Root O=Cybertrust, Inc +# Subject: CN=Cybertrust Global Root O=Cybertrust, Inc +# Label: "Cybertrust Global Root" +# Serial: 4835703278459682877484360 +# MD5 Fingerprint: 72:e4:4a:87:e3:69:40:80:77:ea:bc:e3:f4:ff:f0:e1 +# SHA1 Fingerprint: 5f:43:e5:b1:bf:f8:78:8c:ac:1c:c7:ca:4a:9a:c6:22:2b:cc:34:c6 +# SHA256 Fingerprint: 96:0a:df:00:63:e9:63:56:75:0c:29:65:dd:0a:08:67:da:0b:9c:bd:6e:77:71:4a:ea:fb:23:49:ab:39:3d:a3 +-----BEGIN CERTIFICATE----- +MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYG +A1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2Jh +bCBSb290MB4XDTA2MTIxNTA4MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UE +ChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBS +b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+Mi8vRRQZhP/8NN5 +7CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW0ozS +J8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2y +HLtgwEZLAfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iP +t3sMpTjr3kfb1V05/Iin89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNz +FtApD0mpSPCzqrdsxacwOUBdrsTiXSZT8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAY +XSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/ +MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2MDSgMqAw +hi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3Js +MB8GA1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUA +A4IBAQBW7wojoFROlZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMj +Wqd8BfP9IjsO0QbE2zZMcwSO5bAi5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUx +XOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2hO0j9n0Hq0V+09+zv+mKts2o +omcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+TX3EJIrduPuoc +A06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW +WL1WMRJOEcgh4LMRkWXbtKaIOM5V +-----END CERTIFICATE----- + +# Issuer: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority +# Subject: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority +# Label: "ePKI Root Certification Authority" +# Serial: 28956088682735189655030529057352760477 +# MD5 Fingerprint: 1b:2e:00:ca:26:06:90:3d:ad:fe:6f:15:68:d3:6b:b3 +# SHA1 Fingerprint: 67:65:0d:f1:7e:8e:7e:5b:82:40:a4:f4:56:4b:cf:e2:3d:69:c6:f0 +# SHA256 Fingerprint: c0:a6:f4:dc:63:a2:4b:fd:cf:54:ef:2a:6a:08:2a:0a:72:de:35:80:3e:2f:f5:ff:52:7a:e5:d8:72:06:df:d5 +-----BEGIN CERTIFICATE----- +MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe +MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 +ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw +IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL +SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH +SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh +ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X +DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1 +TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ +fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA +sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU +WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS +nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH +dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip +NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC +AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF +MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH +ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB +uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl +PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP +JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/ +gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2 +j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6 +5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB +o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS +/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z +Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE +W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D +hNQ+IIX3Sj0rnP0qCglN6oH4EZw= +-----END CERTIFICATE----- + +# Issuer: O=certSIGN OU=certSIGN ROOT CA +# Subject: O=certSIGN OU=certSIGN ROOT CA +# Label: "certSIGN ROOT CA" +# Serial: 35210227249154 +# MD5 Fingerprint: 18:98:c0:d6:e9:3a:fc:f9:b0:f5:0c:f7:4b:01:44:17 +# SHA1 Fingerprint: fa:b7:ee:36:97:26:62:fb:2d:b0:2a:f6:bf:03:fd:e8:7c:4b:2f:9b +# SHA256 Fingerprint: ea:a9:62:c4:fa:4a:6b:af:eb:e4:15:19:6d:35:1c:cd:88:8d:4f:53:f3:fa:8a:e6:d7:c4:66:a9:4e:60:42:bb +-----BEGIN CERTIFICATE----- +MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT +AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD +QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP +MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do +0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ +UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d +RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ +OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv +JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C +AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O +BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ +LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY +MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ +44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I +Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw +i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN +9u6wWk5JRFRYX0KD +-----END CERTIFICATE----- + +# Issuer: CN=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only +# Subject: CN=GeoTrust Primary Certification Authority - G3 O=GeoTrust Inc. OU=(c) 2008 GeoTrust Inc. - For authorized use only +# Label: "GeoTrust Primary Certification Authority - G3" +# Serial: 28809105769928564313984085209975885599 +# MD5 Fingerprint: b5:e8:34:36:c9:10:44:58:48:70:6d:2e:83:d4:b8:05 +# SHA1 Fingerprint: 03:9e:ed:b8:0b:e7:a0:3c:69:53:89:3b:20:d2:d9:32:3a:4c:2a:fd +# SHA256 Fingerprint: b4:78:b8:12:25:0d:f8:78:63:5c:2a:a7:ec:7d:15:5e:aa:62:5e:e8:29:16:e2:cd:29:43:61:88:6c:d1:fb:d4 +-----BEGIN CERTIFICATE----- +MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB +mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT +MChjKSAyMDA4IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25s +eTE2MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhv +cml0eSAtIEczMB4XDTA4MDQwMjAwMDAwMFoXDTM3MTIwMTIzNTk1OVowgZgxCzAJ +BgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykg +MjAwOCBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0 +BgNVBAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg +LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANziXmJYHTNXOTIz ++uvLh4yn1ErdBojqZI4xmKU4kB6Yzy5jK/BGvESyiaHAKAxJcCGVn2TAppMSAmUm +hsalifD614SgcK9PGpc/BkTVyetyEH3kMSj7HGHmKAdEc5IiaacDiGydY8hS2pgn +5whMcD60yRLBxWeDXTPzAxHsatBT4tG6NmCUgLthY2xbF37fQJQeqw3CIShwiP/W +JmxsYAQlTlV+fe+/lEjetx3dcI0FX4ilm/LC7urRQEFtYjgdVgbFA0dRIBn8exAL +DmKudlW/X3e+PkkBUz2YJQN2JFodtNuJ6nnltrM7P7pMKEF/BqxqjsHQ9gUdfeZC +huOl1UcCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYw +HQYDVR0OBBYEFMR5yo6hTgMdHNxr2zFblD4/MH8tMA0GCSqGSIb3DQEBCwUAA4IB +AQAtxRPPVoB7eni9n64smefv2t+UXglpp+duaIy9cr5HqQ6XErhK8WTTOd8lNNTB +zU6B8A8ExCSzNJbGpqow32hhc9f5joWJ7w5elShKKiePEI4ufIbEAp7aDHdlDkQN +kv39sxY2+hENHYwOB4lqKVb3cvTdFZx3NWZXqxNT2I7BQMXXExZacse3aQHEerGD +AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH +SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G +spki4cErx5z481+oghLrGREt +-----END CERTIFICATE----- + +# Issuer: CN=thawte Primary Root CA - G2 O=thawte, Inc. OU=(c) 2007 thawte, Inc. - For authorized use only +# Subject: CN=thawte Primary Root CA - G2 O=thawte, Inc. OU=(c) 2007 thawte, Inc. - For authorized use only +# Label: "thawte Primary Root CA - G2" +# Serial: 71758320672825410020661621085256472406 +# MD5 Fingerprint: 74:9d:ea:60:24:c4:fd:22:53:3e:cc:3a:72:d9:29:4f +# SHA1 Fingerprint: aa:db:bc:22:23:8f:c4:01:a1:27:bb:38:dd:f4:1d:db:08:9e:f0:12 +# SHA256 Fingerprint: a4:31:0d:50:af:18:a6:44:71:90:37:2a:86:af:af:8b:95:1f:fb:43:1d:83:7f:1e:56:88:b4:59:71:ed:15:57 +-----BEGIN CERTIFICATE----- +MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp +IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi +BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw +MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh +d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig +YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v +dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/ +BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6 +papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K +DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3 +KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox +XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg== +-----END CERTIFICATE----- + +# Issuer: CN=thawte Primary Root CA - G3 O=thawte, Inc. OU=Certification Services Division/(c) 2008 thawte, Inc. - For authorized use only +# Subject: CN=thawte Primary Root CA - G3 O=thawte, Inc. OU=Certification Services Division/(c) 2008 thawte, Inc. - For authorized use only +# Label: "thawte Primary Root CA - G3" +# Serial: 127614157056681299805556476275995414779 +# MD5 Fingerprint: fb:1b:5d:43:8a:94:cd:44:c6:76:f2:43:4b:47:e7:31 +# SHA1 Fingerprint: f1:8b:53:8d:1b:e9:03:b6:a6:f0:56:43:5b:17:15:89:ca:f3:6b:f2 +# SHA256 Fingerprint: 4b:03:f4:58:07:ad:70:f2:1b:fc:2c:ae:71:c9:fd:e4:60:4c:06:4c:f5:ff:b6:86:ba:e5:db:aa:d7:fd:d3:4c +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB +rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf +Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw +MDggdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAiBgNV +BAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMzAeFw0wODA0MDIwMDAwMDBa +Fw0zNzEyMDEyMzU5NTlaMIGuMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhhd3Rl +LCBJbmMuMSgwJgYDVQQLEx9DZXJ0aWZpY2F0aW9uIFNlcnZpY2VzIERpdmlzaW9u +MTgwNgYDVQQLEy8oYykgMjAwOCB0aGF3dGUsIEluYy4gLSBGb3IgYXV0aG9yaXpl +ZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9vdCBDQSAtIEcz +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsr8nLPvb2FvdeHsbnndm +gcs+vHyu86YnmjSjaDFxODNi5PNxZnmxqWWjpYvVj2AtP0LMqmsywCPLLEHd5N/8 +YZzic7IilRFDGF/Eth9XbAoFWCLINkw6fKXRz4aviKdEAhN0cXMKQlkC+BsUa0Lf +b1+6a4KinVvnSr0eAXLbS3ToO39/fR8EtCab4LRarEc9VbjXsCZSKAExQGbY2SS9 +9irY7CFJXJv2eul/VTV+lmuNk5Mny5K76qxAwJ/C+IDPXfRa3M50hqY+bAtTyr2S +zhkGcuYMXDhpxwTWvGzOW/b3aJzcJRVIiKHpqfiYnODz1TEoYRFsZ5aNOZnLwkUk +OQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNV +HQ4EFgQUrWyqlGCc7eT/+j4KdCtjA/e2Wb8wDQYJKoZIhvcNAQELBQADggEBABpA +2JVlrAmSicY59BDlqQ5mU1143vokkbvnRFHfxhY0Cu9qRFHqKweKA3rD6z8KLFIW +oCtDuSWQP3CpMyVtRRooOyfPqsMpQhvfO0zAMzRbQYi/aytlryjvsvXDqmbOe1bu +t8jLZ8HJnBoYuMTDSQPxYA5QzUbF83d597YV4Djbxy8ooAw/dyZ02SUS2jHaGh7c +KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM +m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu +MdRAGmI0Nj81Aa6sY6A= +-----END CERTIFICATE----- + +# Issuer: CN=GeoTrust Primary Certification Authority - G2 O=GeoTrust Inc. OU=(c) 2007 GeoTrust Inc. - For authorized use only +# Subject: CN=GeoTrust Primary Certification Authority - G2 O=GeoTrust Inc. OU=(c) 2007 GeoTrust Inc. - For authorized use only +# Label: "GeoTrust Primary Certification Authority - G2" +# Serial: 80682863203381065782177908751794619243 +# MD5 Fingerprint: 01:5e:d8:6b:bd:6f:3d:8e:a1:31:f8:12:e0:98:73:6a +# SHA1 Fingerprint: 8d:17:84:d5:37:f3:03:7d:ec:70:fe:57:8b:51:9a:99:e6:10:d7:b0 +# SHA256 Fingerprint: 5e:db:7a:c4:3b:82:a0:6a:87:61:e8:d7:be:49:79:eb:f2:61:1f:7d:d7:9b:f9:1c:1c:6b:56:6a:21:9e:d7:66 +-----BEGIN CERTIFICATE----- +MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL +MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj +KSAyMDA3IEdlb1RydXN0IEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTE2 +MDQGA1UEAxMtR2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 +eSAtIEcyMB4XDTA3MTEwNTAwMDAwMFoXDTM4MDExODIzNTk1OVowgZgxCzAJBgNV +BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMTkwNwYDVQQLEzAoYykgMjAw +NyBHZW9UcnVzdCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxNjA0BgNV +BAMTLUdlb1RydXN0IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBH +MjB2MBAGByqGSM49AgEGBSuBBAAiA2IABBWx6P0DFUPlrOuHNxFi79KDNlJ9RVcL +So17VDs6bl8VAsBQps8lL33KSLjHUGMcKiEIfJo22Av+0SbFWDEwKCXzXV2juLal +tJLtbCyf691DiaI8S0iRHVDsJt/WYC69IaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFBVfNVdRVfslsq0DafwBo/q+EVXVMAoG +CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT +qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz +rD6ogRLQy7rQkgu2npaqBA+K +-----END CERTIFICATE----- + +# Issuer: CN=VeriSign Universal Root Certification Authority O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2008 VeriSign, Inc. - For authorized use only +# Subject: CN=VeriSign Universal Root Certification Authority O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2008 VeriSign, Inc. - For authorized use only +# Label: "VeriSign Universal Root Certification Authority" +# Serial: 85209574734084581917763752644031726877 +# MD5 Fingerprint: 8e:ad:b5:01:aa:4d:81:e4:8c:1d:d1:e1:14:00:95:19 +# SHA1 Fingerprint: 36:79:ca:35:66:87:72:30:4d:30:a5:fb:87:3b:0f:a7:7b:b7:0d:54 +# SHA256 Fingerprint: 23:99:56:11:27:a5:71:25:de:8c:ef:ea:61:0d:df:2f:a0:78:b5:c8:06:7f:4e:82:82:90:bf:b8:60:e8:4b:3c +-----BEGIN CERTIFICATE----- +MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB +vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL +ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwOCBWZXJp +U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MTgwNgYDVQQDEy9W +ZXJpU2lnbiBVbml2ZXJzYWwgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0wODA0MDIwMDAwMDBaFw0zNzEyMDEyMzU5NTlaMIG9MQswCQYDVQQGEwJVUzEX +MBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0 +IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAyMDA4IFZlcmlTaWduLCBJbmMuIC0gRm9y +IGF1dGhvcml6ZWQgdXNlIG9ubHkxODA2BgNVBAMTL1ZlcmlTaWduIFVuaXZlcnNh +bCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEF +AAOCAQ8AMIIBCgKCAQEAx2E3XrEBNNti1xWb/1hajCMj1mCOkdeQmIN65lgZOIzF +9uVkhbSicfvtvbnazU0AtMgtc6XHaXGVHzk8skQHnOgO+k1KxCHfKWGPMiJhgsWH +H26MfF8WIFFE0XBPV+rjHOPMee5Y2A7Cs0WTwCznmhcrewA3ekEzeOEz4vMQGn+H +LL729fdC4uW/h2KJXwBL38Xd5HVEMkE6HnFuacsLdUYI0crSK5XQz/u5QGtkjFdN +/BMReYTtXlT2NJ8IAfMQJQYXStrxHXpma5hgZqTZ79IugvHw7wnqRMkVauIDbjPT +rJ9VAMf2CGqUuV/c4DPxhGD5WycRtPwW8rtWaoAljQIDAQABo4GyMIGvMA8GA1Ud +EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMG0GCCsGAQUFBwEMBGEwX6FdoFsw +WTBXMFUWCWltYWdlL2dpZjAhMB8wBwYFKw4DAhoEFI/l0xqGrI2Oa8PPgGrUSBgs +exkuMCUWI2h0dHA6Ly9sb2dvLnZlcmlzaWduLmNvbS92c2xvZ28uZ2lmMB0GA1Ud +DgQWBBS2d/ppSEefUxLVwuoHMnYH0ZcHGTANBgkqhkiG9w0BAQsFAAOCAQEASvj4 +sAPmLGd75JR3Y8xuTPl9Dg3cyLk1uXBPY/ok+myDjEedO2Pzmvl2MpWRsXe8rJq+ +seQxIcaBlVZaDrHC1LGmWazxY8u4TB1ZkErvkBYoH1quEPuBUDgMbMzxPcP1Y+Oz +4yHJJDnp/RVmRvQbEdBNc6N9Rvk97ahfYtTxP/jgdFcrGJ2BtMQo2pSXpXDrrB2+ +BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR +lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3 +7M2CYfE45k+XmCpajQ== +-----END CERTIFICATE----- + +# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G4 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2007 VeriSign, Inc. - For authorized use only +# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G4 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 2007 VeriSign, Inc. - For authorized use only +# Label: "VeriSign Class 3 Public Primary Certification Authority - G4" +# Serial: 63143484348153506665311985501458640051 +# MD5 Fingerprint: 3a:52:e1:e7:fd:6f:3a:e3:6f:f3:6f:99:1b:f9:22:41 +# SHA1 Fingerprint: 22:d5:d8:df:8f:02:31:d1:8d:f7:9d:b7:cf:8a:2d:64:c9:3f:6c:3a +# SHA256 Fingerprint: 69:dd:d7:ea:90:bb:57:c9:3e:13:5d:c8:5e:a6:fc:d5:48:0b:60:32:39:bd:c4:54:fc:75:8b:2a:26:cf:7f:79 +-----BEGIN CERTIFICATE----- +MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL +MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW +ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2ln +biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp +U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y +aXR5IC0gRzQwHhcNMDcxMTA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCByjELMAkG +A1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJp +U2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNyBWZXJpU2lnbiwg +SW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJpU2ln +biBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +IC0gRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAASnVnp8Utpkmw4tXNherJI9/gHm +GUo9FANL+mAnINmDiWn6VMaaGF5VKmTeBvaNSjutEDxlPZCIBIngMGGzrl0Bp3ve +fLK+ymVhAIau2o970ImtTR1ZmkGxvEeA3J5iw/mjgbIwga8wDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJ +aW1hZ2UvZ2lmMCEwHzAHBgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYj +aHR0cDovL2xvZ28udmVyaXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFLMW +kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC +4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga +FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA== +-----END CERTIFICATE----- + +# Issuer: CN=NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny O=NetLock Kft. OU=Tan\xfas\xedtv\xe1nykiad\xf3k (Certification Services) +# Subject: CN=NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny O=NetLock Kft. OU=Tan\xfas\xedtv\xe1nykiad\xf3k (Certification Services) +# Label: "NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny" +# Serial: 80544274841616 +# MD5 Fingerprint: c5:a1:b7:ff:73:dd:d6:d7:34:32:18:df:fc:3c:ad:88 +# SHA1 Fingerprint: 06:08:3f:59:3f:15:a1:04:a0:69:a4:6b:a9:03:d0:06:b7:97:09:91 +# SHA256 Fingerprint: 6c:61:da:c3:a2:de:f0:31:50:6b:e0:36:d2:a6:fe:40:19:94:fb:d1:3d:f9:c8:d4:66:59:92:74:c4:46:ec:98 +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG +EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 +MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl +cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR +dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB +pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM +b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm +aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz +IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT +lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz +AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5 +VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG +ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2 +BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG +AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M +U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh +bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C ++C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC +bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F +uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 +XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE----- + +# Issuer: CN=Hongkong Post Root CA 1 O=Hongkong Post +# Subject: CN=Hongkong Post Root CA 1 O=Hongkong Post +# Label: "Hongkong Post Root CA 1" +# Serial: 1000 +# MD5 Fingerprint: a8:0d:6f:39:78:b9:43:6d:77:42:6d:98:5a:cc:23:ca +# SHA1 Fingerprint: d6:da:a8:20:8d:09:d2:15:4d:24:b5:2f:cb:34:6e:b2:58:b2:8a:58 +# SHA256 Fingerprint: f9:e6:7d:33:6c:51:00:2a:c0:54:c6:32:02:2d:66:dd:a2:e7:e3:ff:f1:0a:d0:61:ed:31:d8:bb:b4:10:cf:b2 +-----BEGIN CERTIFICATE----- +MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsx +FjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3Qg +Um9vdCBDQSAxMB4XDTAzMDUxNTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkG +A1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdr +b25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1ApzQ +jVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEn +PzlTCeqrauh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjh +ZY4bXSNmO7ilMlHIhqqhqZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9 +nnV0ttgCXjqQesBCNnLsak3c78QA3xMYV18meMjWCnl3v/evt3a5pQuEF10Q6m/h +q5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNVHRMBAf8ECDAGAQH/AgED +MA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7ih9legYsC +mEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI3 +7piol7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clB +oiMBdDhViw+5LmeiIAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJs +EhTkYY2sEJCehFC78JZvRZ+K88psT/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpO +fMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilTc4afU9hDDl3WY4JxHYB0yvbi +AmvZWg== +-----END CERTIFICATE----- + +# Issuer: CN=SecureSign RootCA11 O=Japan Certification Services, Inc. +# Subject: CN=SecureSign RootCA11 O=Japan Certification Services, Inc. +# Label: "SecureSign RootCA11" +# Serial: 1 +# MD5 Fingerprint: b7:52:74:e2:92:b4:80:93:f2:75:e4:cc:d7:f2:ea:26 +# SHA1 Fingerprint: 3b:c4:9f:48:f8:f3:73:a0:9c:1e:bd:f8:5b:b1:c3:65:c7:d8:11:b3 +# SHA256 Fingerprint: bf:0f:ee:fb:9e:3a:58:1a:d5:f9:e9:db:75:89:98:57:43:d2:61:08:5c:4d:31:4f:6f:5d:72:59:aa:42:16:12 +-----BEGIN CERTIFICATE----- +MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDEr +MCkGA1UEChMiSmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoG +A1UEAxMTU2VjdXJlU2lnbiBSb290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0 +MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSswKQYDVQQKEyJKYXBhbiBDZXJ0aWZp +Y2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1cmVTaWduIFJvb3RD +QTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvLTJsz +i1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8 +h9uuywGOwvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOV +MdrAG/LuYpmGYz+/3ZMqg6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9 +UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rPO7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni +8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitAbpSACW22s293bzUIUPsC +h8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZXt94wDgYD +VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB +AKChOBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xm +KbabfSVSSUOrTC4rbnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQ +X5Ucv+2rIrVls4W6ng+4reV6G4pQOh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWr +QbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01y8hSyn+B/tlr0/cR7SXf+Of5 +pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061lgeLKBObjBmN +QSdJQO7e5iNEOdyhIta6A/I= +-----END CERTIFICATE----- + +# Issuer: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. +# Subject: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. +# Label: "Microsec e-Szigno Root CA 2009" +# Serial: 14014712776195784473 +# MD5 Fingerprint: f8:49:f4:03:bc:44:2d:83:be:48:69:7d:29:64:fc:b1 +# SHA1 Fingerprint: 89:df:74:fe:5c:f4:0f:4a:80:f9:e3:37:7d:54:da:91:e1:01:31:8e +# SHA256 Fingerprint: 3c:5f:81:fe:a5:fa:b8:2c:64:bf:a2:ea:ec:af:cd:e8:e0:77:fc:86:20:a7:ca:e5:37:16:3d:f3:6e:db:f3:78 +-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD +VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 +ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G +CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y +OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx +FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp +Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o +dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP +kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc +cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U +fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 +N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC +xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 ++rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM +Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG +SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h +mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk +ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 +tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c +2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t +HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 +# Label: "GlobalSign Root CA - R3" +# Serial: 4835703278459759426209954 +# MD5 Fingerprint: c5:df:b8:49:ca:05:13:55:ee:2d:ba:1a:c3:3e:b0:28 +# SHA1 Fingerprint: d6:9b:56:11:48:f0:1c:77:c5:45:78:c1:09:26:df:5b:85:69:76:ad +# SHA256 Fingerprint: cb:b5:22:d7:b7:f1:27:ad:6a:01:13:86:5b:df:1c:d4:10:2e:7d:07:59:af:63:5a:7c:f4:72:0d:c9:63:c5:3b +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 +MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 +RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT +gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm +KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd +QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ +XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o +LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU +RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp +jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK +6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX +mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs +Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH +WD9f +-----END CERTIFICATE----- + +# Issuer: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 +# Subject: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 +# Label: "Autoridad de Certificacion Firmaprofesional CIF A62634068" +# Serial: 6047274297262753887 +# MD5 Fingerprint: 73:3a:74:7a:ec:bb:a3:96:a6:c2:e4:e2:c8:9b:c0:c3 +# SHA1 Fingerprint: ae:c5:fb:3f:c8:e1:bf:c4:e5:4f:03:07:5a:9a:e8:00:b7:f7:b6:fa +# SHA256 Fingerprint: 04:04:80:28:bf:1f:28:64:d4:8f:9a:d4:d8:32:94:36:6a:82:88:56:55:3f:3b:14:30:3f:90:14:7f:5d:40:ef +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE +BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h +cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy +MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg +Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 +thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM +cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG +L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i +NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h +X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b +m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy +Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja +EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T +KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF +6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh +OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD +VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD +VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp +cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv +ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl +AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF +661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9 +am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1 +ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481 +PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS +3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k +SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF +3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM +ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g +StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz +Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB +jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V +-----END CERTIFICATE----- + +# Issuer: CN=Izenpe.com O=IZENPE S.A. +# Subject: CN=Izenpe.com O=IZENPE S.A. +# Label: "Izenpe.com" +# Serial: 917563065490389241595536686991402621 +# MD5 Fingerprint: a6:b0:cd:85:80:da:5c:50:34:a3:39:90:2f:55:67:73 +# SHA1 Fingerprint: 2f:78:3d:25:52:18:a7:4a:65:39:71:b5:2c:a2:9c:45:15:6f:e9:19 +# SHA256 Fingerprint: 25:30:cc:8e:98:32:15:02:ba:d9:6f:9b:1f:ba:1b:09:9e:2d:29:9e:0f:45:48:bb:91:4f:36:3b:c0:d4:53:1f +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +# Issuer: CN=Chambers of Commerce Root - 2008 O=AC Camerfirma S.A. +# Subject: CN=Chambers of Commerce Root - 2008 O=AC Camerfirma S.A. +# Label: "Chambers of Commerce Root - 2008" +# Serial: 11806822484801597146 +# MD5 Fingerprint: 5e:80:9e:84:5a:0e:65:0b:17:02:f3:55:18:2a:3e:d7 +# SHA1 Fingerprint: 78:6a:74:ac:76:ab:14:7f:9c:6a:30:50:ba:9e:a8:7e:fe:9a:ce:3c +# SHA256 Fingerprint: 06:3e:4a:fa:c4:91:df:d3:32:f3:08:9b:85:42:e9:46:17:d8:93:d7:fe:94:4e:10:a7:93:7e:e2:9d:96:93:c0 +-----BEGIN CERTIFICATE----- +MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYD +VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 +IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 +MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xKTAnBgNVBAMTIENoYW1iZXJz +IG9mIENvbW1lcmNlIFJvb3QgLSAyMDA4MB4XDTA4MDgwMTEyMjk1MFoXDTM4MDcz +MTEyMjk1MFowga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpNYWRyaWQgKHNlZSBj +dXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29tL2FkZHJlc3MpMRIw +EAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVyZmlybWEgUy5BLjEp +MCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAtIDIwMDgwggIiMA0G +CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCvAMtwNyuAWko6bHiUfaN/Gh/2NdW9 +28sNRHI+JrKQUrpjOyhYb6WzbZSm891kDFX29ufyIiKAXuFixrYp4YFs8r/lfTJq +VKAyGVn+H4vXPWCGhSRv4xGzdz4gljUha7MI2XAuZPeEklPWDrCQiorjh40G072Q +DuKZoRuGDtqaCrsLYVAGUvGef3bsyw/QHg3PmTA9HMRFEFis1tPo1+XqxQEHd9ZR +5gN/ikilTWh1uem8nk4ZcfUyS5xtYBkL+8ydddy/Js2Pk3g5eXNeJQ7KXOt3EgfL +ZEFHcpOrUMPrCXZkNNI5t3YRCQ12RcSprj1qr7V9ZS+UWBDsXHyvfuK2GNnQm05a +Sd+pZgvMPMZ4fKecHePOjlO+Bd5gD2vlGts/4+EhySnB8esHnFIbAURRPHsl18Tl +UlRdJQfKFiC4reRB7noI/plvg6aRArBsNlVq5331lubKgdaX8ZSD6e2wsWsSaR6s ++12pxZjptFtYer49okQ6Y1nUCyXeG0+95QGezdIp1Z8XGQpvvwyQ0wlf2eOKNcx5 +Wk0ZN5K3xMGtr/R5JJqyAQuxr1yW84Ay+1w9mPGgP0revq+ULtlVmhduYJ1jbLhj +ya6BXBg14JC7vjxPNyK5fuvPnnchpj04gftI2jE9K+OJ9dC1vX7gUMQSibMjmhAx +hduub+84Mxh2EQIDAQABo4IBbDCCAWgwEgYDVR0TAQH/BAgwBgEB/wIBDDAdBgNV +HQ4EFgQU+SSsD7K1+HnA+mCIG8TZTQKeFxkwgeMGA1UdIwSB2zCB2IAU+SSsD7K1 ++HnA+mCIG8TZTQKeFxmhgbSkgbEwga4xCzAJBgNVBAYTAkVVMUMwQQYDVQQHEzpN +YWRyaWQgKHNlZSBjdXJyZW50IGFkZHJlc3MgYXQgd3d3LmNhbWVyZmlybWEuY29t +L2FkZHJlc3MpMRIwEAYDVQQFEwlBODI3NDMyODcxGzAZBgNVBAoTEkFDIENhbWVy +ZmlybWEgUy5BLjEpMCcGA1UEAxMgQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdCAt +IDIwMDiCCQCj2kJ+pLGu2jAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRV +HSAAMCowKAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20w +DQYJKoZIhvcNAQEFBQADggIBAJASryI1wqM58C7e6bXpeHxIvj99RZJe6dqxGfwW +PJ+0W2aeaufDuV2I6A+tzyMP3iU6XsxPpcG1Lawk0lgH3qLPaYRgM+gQDROpI9CF +5Y57pp49chNyM/WqfcZjHwj0/gF/JM8rLFQJ3uIrbZLGOU8W6jx+ekbURWpGqOt1 +glanq6B8aBMz9p0w8G8nOSQjKpD9kCk18pPfNKXG9/jvjA9iSnyu0/VU+I22mlaH +FoI6M6taIgj3grrqLuBHmrS1RaMFO9ncLkVAO+rcf+g769HsJtg1pDDFOqxXnrN2 +pSB7+R5KBWIBpih1YJeSDW4+TTdDDZIVnBgizVGZoCkaPF+KMjNbMMeJL0eYD6MD +xvbxrN8y8NmBGuScvfaAFPDRLLmF9dijscilIeUcE5fuDr3fKanvNFNb0+RqE4QG +tjICxFKuItLcsiFCGtpA8CnJ7AoMXOLQusxI0zcKzBIKinmwPQN/aUv0NCB9szTq +jktk9T79syNnFQ0EuPAtwQlRPLJsFfClI9eDdOTlLsn+mCdCxqvGnrDQWzilm1De +fhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg +OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZ +d0jQ +-----END CERTIFICATE----- + +# Issuer: CN=Global Chambersign Root - 2008 O=AC Camerfirma S.A. +# Subject: CN=Global Chambersign Root - 2008 O=AC Camerfirma S.A. +# Label: "Global Chambersign Root - 2008" +# Serial: 14541511773111788494 +# MD5 Fingerprint: 9e:80:ff:78:01:0c:2e:c1:36:bd:fe:96:90:6e:08:f3 +# SHA1 Fingerprint: 4a:bd:ee:ec:95:0d:35:9c:89:ae:c7:52:a1:2c:5b:29:f6:d6:aa:0c +# SHA256 Fingerprint: 13:63:35:43:93:34:a7:69:80:16:a0:d3:24:de:72:28:4e:07:9d:7b:52:20:bb:8f:bd:74:78:16:ee:be:ba:ca +-----BEGIN CERTIFICATE----- +MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYD +VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0 +IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAGA1UEBRMJQTgyNzQzMjg3 +MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAlBgNVBAMTHkdsb2JhbCBD +aGFtYmVyc2lnbiBSb290IC0gMjAwODAeFw0wODA4MDExMjMxNDBaFw0zODA3MzEx +MjMxNDBaMIGsMQswCQYDVQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3Vy +cmVudCBhZGRyZXNzIGF0IHd3dy5jYW1lcmZpcm1hLmNvbS9hZGRyZXNzKTESMBAG +A1UEBRMJQTgyNzQzMjg3MRswGQYDVQQKExJBQyBDYW1lcmZpcm1hIFMuQS4xJzAl +BgNVBAMTHkdsb2JhbCBDaGFtYmVyc2lnbiBSb290IC0gMjAwODCCAiIwDQYJKoZI +hvcNAQEBBQADggIPADCCAgoCggIBAMDfVtPkOpt2RbQT2//BthmLN0EYlVJH6xed +KYiONWwGMi5HYvNJBL99RDaxccy9Wglz1dmFRP+RVyXfXjaOcNFccUMd2drvXNL7 +G706tcuto8xEpw2uIRU/uXpbknXYpBI4iRmKt4DS4jJvVpyR1ogQC7N0ZJJ0YPP2 +zxhPYLIj0Mc7zmFLmY/CDNBAspjcDahOo7kKrmCgrUVSY7pmvWjg+b4aqIG7HkF4 +ddPB/gBVsIdU6CeQNR1MM62X/JcumIS/LMmjv9GYERTtY/jKmIhYF5ntRQOXfjyG +HoiMvvKRhI9lNNgATH23MRdaKXoKGCQwoze1eqkBfSbW+Q6OWfH9GzO1KTsXO0G2 +Id3UwD2ln58fQ1DJu7xsepeY7s2MH/ucUa6LcL0nn3HAa6x9kGbo1106DbDVwo3V +yJ2dwW3Q0L9R5OP4wzg2rtandeavhENdk5IMagfeOx2YItaswTXbo6Al/3K1dh3e +beksZixShNBFks4c5eUzHdwHU1SjqoI7mjcv3N2gZOnm3b2u/GSFHTynyQbehP9r +6GsaPMWis0L7iwk+XwhSx2LE1AVxv8Rk5Pihg+g+EpuoHtQ2TS9x9o0o9oOpE9Jh +wZG7SMA0j0GMS0zbaRL/UJScIINZc+18ofLx/d33SdNDWKBWY8o9PeU1VlnpDsog +zCtLkykPAgMBAAGjggFqMIIBZjASBgNVHRMBAf8ECDAGAQH/AgEMMB0GA1UdDgQW +BBS5CcqcHtvTbDprru1U8VuTBjUuXjCB4QYDVR0jBIHZMIHWgBS5CcqcHtvTbDpr +ru1U8VuTBjUuXqGBsqSBrzCBrDELMAkGA1UEBhMCRVUxQzBBBgNVBAcTOk1hZHJp +ZCAoc2VlIGN1cnJlbnQgYWRkcmVzcyBhdCB3d3cuY2FtZXJmaXJtYS5jb20vYWRk +cmVzcykxEjAQBgNVBAUTCUE4Mjc0MzI4NzEbMBkGA1UEChMSQUMgQ2FtZXJmaXJt +YSBTLkEuMScwJQYDVQQDEx5HbG9iYWwgQ2hhbWJlcnNpZ24gUm9vdCAtIDIwMDiC +CQDJzdPp1X0jzjAOBgNVHQ8BAf8EBAMCAQYwPQYDVR0gBDYwNDAyBgRVHSAAMCow +KAYIKwYBBQUHAgEWHGh0dHA6Ly9wb2xpY3kuY2FtZXJmaXJtYS5jb20wDQYJKoZI +hvcNAQEFBQADggIBAICIf3DekijZBZRG/5BXqfEv3xoNa/p8DhxJJHkn2EaqbylZ +UohwEurdPfWbU1Rv4WCiqAm57OtZfMY18dwY6fFn5a+6ReAJ3spED8IXDneRRXoz +X1+WLGiLwUePmJs9wOzL9dWCkoQ10b42OFZyMVtHLaoXpGNR6woBrX/sdZ7LoR/x +fxKxueRkf2fWIyr0uDldmOghp+G9PUIadJpwr2hsUF1Jz//7Dl3mLEfXgTpZALVz +a2Mg9jFFCDkO9HB+QHBaP9BrQql0PSgvAm11cpUJjUhjxsYjV5KTXjXBjfkK9yyd +Yhz2rXzdpjEetrHHfoUm+qRqtdpjMNHvkzeyZi99Bffnt0uYlDXA2TopwZ2yUDMd +SqlapskD7+3056huirRXhOukP9DuqqqHW2Pok+JrqNS4cnhrG+055F3Lm6qH1U9O +AP7Zap88MQ8oAgF9mOinsKJknnn4SPIVqczmyETrP3iZ8ntxPjzxmKfFGBI/5rso +M0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVqc5iJWzouE4ge +v8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z +09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B +-----END CERTIFICATE----- + +# Issuer: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. +# Subject: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. +# Label: "Go Daddy Root Certificate Authority - G2" +# Serial: 0 +# MD5 Fingerprint: 80:3a:bc:22:c1:e6:fb:8d:9b:3b:27:4a:32:1b:9a:01 +# SHA1 Fingerprint: 47:be:ab:c9:22:ea:e8:0e:78:78:34:62:a7:9f:45:c2:54:fd:e6:8b +# SHA256 Fingerprint: 45:14:0b:32:47:eb:9c:c8:c5:b4:f0:d7:b5:30:91:f7:32:92:08:9e:6e:5a:63:e2:74:9d:d3:ac:a9:19:8e:da +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT +EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp +ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz +NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH +EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE +AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD +E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH +/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy +DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh +GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR +tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA +AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX +WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu +9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr +gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo +2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI +4uJEvlz36hz1 +-----END CERTIFICATE----- + +# Issuer: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Subject: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Label: "Starfield Root Certificate Authority - G2" +# Serial: 0 +# MD5 Fingerprint: d6:39:81:c6:52:7e:96:69:fc:fc:ca:66:ed:05:f2:96 +# SHA1 Fingerprint: b5:1c:06:7c:ee:2b:0c:3d:f8:55:ab:2d:92:f4:fe:39:d4:e7:0f:0e +# SHA256 Fingerprint: 2c:e1:cb:0b:f9:d2:f9:e1:02:99:3f:be:21:51:52:c3:b2:dd:0c:ab:de:1c:68:e5:31:9b:83:91:54:db:b7:f5 +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs +ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw +MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj +aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp +Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg +nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 +HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N +Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN +dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 +HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G +CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU +sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 +4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg +8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 +mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- + +# Issuer: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Subject: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Label: "Starfield Services Root Certificate Authority - G2" +# Serial: 0 +# MD5 Fingerprint: 17:35:74:af:7b:61:1c:eb:f4:f9:3c:e2:ee:40:f9:a2 +# SHA1 Fingerprint: 92:5a:8f:8d:2c:6d:04:e0:66:5f:59:6a:ff:22:d8:63:e8:25:6f:3f +# SHA256 Fingerprint: 56:8d:69:05:a2:c8:87:08:a4:b3:02:51:90:ed:cf:ed:b1:97:4a:60:6a:13:c6:e5:29:0f:cb:2a:e6:3e:da:b5 +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs +ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD +VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy +ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy +dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p +OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 +8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K +Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe +hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk +6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw +DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q +AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI +bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB +ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z +qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn +0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN +sSi6 +-----END CERTIFICATE----- + +# Issuer: CN=AffirmTrust Commercial O=AffirmTrust +# Subject: CN=AffirmTrust Commercial O=AffirmTrust +# Label: "AffirmTrust Commercial" +# Serial: 8608355977964138876 +# MD5 Fingerprint: 82:92:ba:5b:ef:cd:8a:6f:a6:3d:55:f9:84:f6:d6:b7 +# SHA1 Fingerprint: f9:b5:b6:32:45:5f:9c:be:ec:57:5f:80:dc:e9:6e:2c:c7:b2:78:b7 +# SHA256 Fingerprint: 03:76:ab:1d:54:c5:f9:80:3c:e4:b2:e2:01:a0:ee:7e:ef:7b:57:b6:36:e8:a9:3c:9b:8d:48:60:c9:6f:5f:a7 +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP +Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr +ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL +MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1 +yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr +VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/ +nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG +XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj +vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt +Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g +N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC +nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE----- + +# Issuer: CN=AffirmTrust Networking O=AffirmTrust +# Subject: CN=AffirmTrust Networking O=AffirmTrust +# Label: "AffirmTrust Networking" +# Serial: 8957382827206547757 +# MD5 Fingerprint: 42:65:ca:be:01:9a:9a:4c:a9:8c:41:49:cd:c0:d5:7f +# SHA1 Fingerprint: 29:36:21:02:8b:20:ed:02:f5:66:c5:32:d1:d6:ed:90:9f:45:00:2f +# SHA256 Fingerprint: 0a:81:ec:5a:92:97:77:f1:45:90:4a:f3:8d:5d:50:9f:66:b5:e2:c5:8f:cd:b5:31:05:8b:0e:17:f3:f0:b4:1b +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y +YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua +kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL +QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp +6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG +yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i +QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO +tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu +QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ +Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u +olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 +x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE----- + +# Issuer: CN=AffirmTrust Premium O=AffirmTrust +# Subject: CN=AffirmTrust Premium O=AffirmTrust +# Label: "AffirmTrust Premium" +# Serial: 7893706540734352110 +# MD5 Fingerprint: c4:5d:0e:48:b6:ac:28:30:4e:0a:bc:f9:38:16:87:57 +# SHA1 Fingerprint: d8:a6:33:2c:e0:03:6f:b1:85:f6:63:4f:7d:6a:06:65:26:32:28:27 +# SHA256 Fingerprint: 70:a7:3f:7f:37:6b:60:07:42:48:90:45:34:b1:14:82:d5:bf:0e:69:8e:cc:49:8d:f5:25:77:eb:f2:e9:3b:9a +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz +dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG +A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U +cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf +qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ +JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ ++jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS +s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5 +HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7 +70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG +V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S +qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S +5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia +C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX +OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE +FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2 +KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B +8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ +MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc +0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ +u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF +u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH +YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8 +GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO +RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e +KeC2uAloGRwYQw== +-----END CERTIFICATE----- + +# Issuer: CN=AffirmTrust Premium ECC O=AffirmTrust +# Subject: CN=AffirmTrust Premium ECC O=AffirmTrust +# Label: "AffirmTrust Premium ECC" +# Serial: 8401224907861490260 +# MD5 Fingerprint: 64:b0:09:55:cf:b1:d5:99:e2:be:13:ab:a6:5d:ea:4d +# SHA1 Fingerprint: b8:23:6b:00:2f:1d:16:86:53:01:55:6c:11:a4:37:ca:eb:ff:c3:bb +# SHA256 Fingerprint: bd:71:fd:f6:da:97:e4:cf:62:d1:64:7a:dd:25:81:b0:7d:79:ad:f8:39:7e:b4:ec:ba:9c:5e:84:88:82:14:23 +-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC +VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ +cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ +BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt +VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D +0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9 +ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G +A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs +aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I +flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== +-----END CERTIFICATE----- + +# Issuer: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Subject: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Label: "Certum Trusted Network CA" +# Serial: 279744 +# MD5 Fingerprint: d5:e9:81:40:c5:18:69:fc:46:2c:89:75:62:0f:aa:78 +# SHA1 Fingerprint: 07:e0:32:e0:20:b7:2c:3f:19:2f:06:28:a2:59:3a:19:a7:0f:06:9e +# SHA256 Fingerprint: 5c:58:46:8d:55:f5:8e:49:7e:74:39:82:d2:b5:00:10:b6:d1:65:37:4a:cf:83:a7:d4:a3:2d:b7:68:c4:40:8e +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM +MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D +ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU +cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 +WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg +Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw +IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH +UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM +TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU +BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM +kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x +AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV +HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y +sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL +I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 +J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY +VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE----- + +# Issuer: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA +# Subject: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA +# Label: "TWCA Root Certification Authority" +# Serial: 1 +# MD5 Fingerprint: aa:08:8f:f6:f9:7b:b7:f2:b1:a7:1e:9b:ea:ea:bd:79 +# SHA1 Fingerprint: cf:9e:87:6d:d3:eb:fc:42:26:97:a3:b5:a3:7a:a0:76:a9:06:23:48 +# SHA256 Fingerprint: bf:d8:8f:e1:10:1c:41:ae:3e:80:1b:f8:be:56:35:0e:e9:ba:d1:a6:b9:bd:51:5e:dc:5c:6d:5b:87:11:ac:44 +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES +MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU +V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz +WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO +LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE +AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH +K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX +RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z +rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx +3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq +hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC +MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls +XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D +lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn +aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ +YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== +-----END CERTIFICATE----- + +# Issuer: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 +# Subject: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 +# Label: "Security Communication RootCA2" +# Serial: 0 +# MD5 Fingerprint: 6c:39:7d:a4:0e:55:59:b2:3f:d6:41:b1:12:50:de:43 +# SHA1 Fingerprint: 5f:3b:8c:f2:f8:10:b3:7d:78:b4:ce:ec:19:19:c3:73:34:b9:c7:74 +# SHA256 Fingerprint: 51:3b:2c:ec:b8:10:d4:cd:e5:dd:85:39:1a:df:c6:c2:dd:60:d8:7b:b7:36:d2:b5:21:48:4a:a4:7a:0e:be:f6 +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl +MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe +U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX +DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy +dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj +YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV +OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr +zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM +VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ +hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO +ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw +awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs +OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF +coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc +okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8 +t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy +1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ +SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 +-----END CERTIFICATE----- + +# Issuer: CN=EC-ACC O=Agencia Catalana de Certificacio (NIF Q-0801176-I) OU=Serveis Publics de Certificacio/Vegeu https://www.catcert.net/verarrel (c)03/Jerarquia Entitats de Certificacio Catalanes +# Subject: CN=EC-ACC O=Agencia Catalana de Certificacio (NIF Q-0801176-I) OU=Serveis Publics de Certificacio/Vegeu https://www.catcert.net/verarrel (c)03/Jerarquia Entitats de Certificacio Catalanes +# Label: "EC-ACC" +# Serial: -23701579247955709139626555126524820479 +# MD5 Fingerprint: eb:f5:9d:29:0d:61:f9:42:1f:7c:c2:ba:6d:e3:15:09 +# SHA1 Fingerprint: 28:90:3a:63:5b:52:80:fa:e6:77:4c:0b:6d:a7:d6:ba:a6:4a:f2:e8 +# SHA256 Fingerprint: 88:49:7f:01:60:2f:31:54:24:6a:e2:8c:4d:5a:ef:10:f1:d8:7e:bb:76:62:6f:4a:e0:b7:f9:5b:a7:96:87:99 +-----BEGIN CERTIFICATE----- +MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB +8zELMAkGA1UEBhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2Vy +dGlmaWNhY2lvIChOSUYgUS0wODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1 +YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYDVQQLEyxWZWdldSBodHRwczovL3d3 +dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UECxMsSmVyYXJxdWlh +IEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMTBkVD +LUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQG +EwJFUzE7MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8g +KE5JRiBRLTA4MDExNzYtSSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBD +ZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZlZ2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQu +bmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJhcnF1aWEgRW50aXRhdHMg +ZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUNDMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R +85iKw5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm +4CgPukLjbo73FCeTae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaV +HMf5NLWUhdWZXqBIoH7nF2W4onW4HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNd +QlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0aE9jD2z3Il3rucO2n5nzbcc8t +lGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw0JDnJwIDAQAB +o4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4 +opvpXY0wfwYDVR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBo +dHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidW +ZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAwDQYJKoZIhvcN +AQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJlF7W2u++AVtd0x7Y +/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNaAl6k +SBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhy +Rp/7SNVel+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOS +Agu+TGbrIP65y7WZf+a2E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xl +nJ2lYJU6Un/10asIbvPuW/mIPX64b24D5EI= +-----END CERTIFICATE----- + +# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2011 O=Hellenic Academic and Research Institutions Cert. Authority +# Subject: CN=Hellenic Academic and Research Institutions RootCA 2011 O=Hellenic Academic and Research Institutions Cert. Authority +# Label: "Hellenic Academic and Research Institutions RootCA 2011" +# Serial: 0 +# MD5 Fingerprint: 73:9f:4c:4b:73:5b:79:e9:fa:ba:1c:ef:6e:cb:d5:c9 +# SHA1 Fingerprint: fe:45:65:9b:79:03:5b:98:a1:61:b5:51:2e:ac:da:58:09:48:22:4d +# SHA256 Fingerprint: bc:10:4f:15:a4:8b:e7:09:dc:a5:42:a7:e1:d4:b9:df:6f:05:45:27:e8:02:ea:a9:2d:59:54:44:25:8a:fe:71 +-----BEGIN CERTIFICATE----- +MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1Ix +RDBCBgNVBAoTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 +dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1p +YyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIFJvb3RDQSAyMDExMB4XDTExMTIw +NjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYTAkdSMUQwQgYDVQQK +EztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIENl +cnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPz +dYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJ +fel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa71HFK9+WXesyHgLacEns +bgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u8yBRQlqD +75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSP +FEDH3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNV +HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp +5dgTBCPuQSUwRwYDVR0eBEAwPqA8MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQu +b3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQub3JnMA0GCSqGSIb3DQEBBQUA +A4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVtXdMiKahsog2p +6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 +TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7 +dIsXRSZMFpGD/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8Acys +Nnq/onN694/BtZqhFLKPM58N7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXI +l7WdmplNsDz4SgCbZN2fOUvRJ9e4 +-----END CERTIFICATE----- + +# Issuer: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 +# Subject: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 +# Label: "Actalis Authentication Root CA" +# Serial: 6271844772424770508 +# MD5 Fingerprint: 69:c1:0d:4f:07:a3:1b:c3:fe:56:3d:04:bc:11:f6:a6 +# SHA1 Fingerprint: f3:73:b3:87:06:5a:28:84:8a:f2:f3:4a:ce:19:2b:dd:c7:8e:9c:ac +# SHA256 Fingerprint: 55:92:60:84:ec:96:3a:64:b9:6e:2a:be:01:ce:0b:a8:6a:64:fb:fe:bc:c7:aa:b5:af:c1:55:b3:7f:d7:60:66 +-----BEGIN CERTIFICATE----- +MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE +BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w +MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 +IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC +SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1 +ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv +UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX +4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9 +KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/ +gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb +rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ +51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F +be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe +KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F +v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn +fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7 +jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz +ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt +ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL +e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70 +jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz +WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V +SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j +pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX +X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok +fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R +K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU +ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU +LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT +LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== +-----END CERTIFICATE----- + +# Issuer: O=Trustis Limited OU=Trustis FPS Root CA +# Subject: O=Trustis Limited OU=Trustis FPS Root CA +# Label: "Trustis FPS Root CA" +# Serial: 36053640375399034304724988975563710553 +# MD5 Fingerprint: 30:c9:e7:1e:6b:e6:14:eb:65:b2:16:69:20:31:67:4d +# SHA1 Fingerprint: 3b:c0:38:0b:33:c3:f6:a6:0c:86:15:22:93:d9:df:f5:4b:81:c0:04 +# SHA256 Fingerprint: c1:b4:82:99:ab:a5:20:8f:e9:63:0a:ce:55:ca:68:a0:3e:da:5a:51:9c:88:02:a0:d3:a6:73:be:8f:8e:55:7d +-----BEGIN CERTIFICATE----- +MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBF +MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQL +ExNUcnVzdGlzIEZQUyBSb290IENBMB4XDTAzMTIyMzEyMTQwNloXDTI0MDEyMTEx +MzY1NFowRTELMAkGA1UEBhMCR0IxGDAWBgNVBAoTD1RydXN0aXMgTGltaXRlZDEc +MBoGA1UECxMTVHJ1c3RpcyBGUFMgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBAMVQe547NdDfxIzNjpvto8A2mfRC6qc+gIMPpqdZh8mQRUN+ +AOqGeSoDvT03mYlmt+WKVoaTnGhLaASMk5MCPjDSNzoiYYkchU59j9WvezX2fihH +iTHcDnlkH5nSW7r+f2C/revnPDgpai/lkQtV/+xvWNUtyd5MZnGPDNcE2gfmHhjj +vSkCqPoc4Vu5g6hBSLwacY3nYuUtsuvffM/bq1rKMfFMIvMFE/eC+XN5DL7XSxzA +0RU8k0Fk0ea+IxciAIleH2ulrG6nS4zto3Lmr2NNL4XSFDWaLk6M6jKYKIahkQlB +OrTh4/L68MkKokHdqeMDx4gVOxzUGpTXn2RZEm0CAwEAAaNTMFEwDwYDVR0TAQH/ +BAUwAwEB/zAfBgNVHSMEGDAWgBS6+nEleYtXQSUhhgtx67JkDoshZzAdBgNVHQ4E +FgQUuvpxJXmLV0ElIYYLceuyZA6LIWcwDQYJKoZIhvcNAQEFBQADggEBAH5Y//01 +GX2cGE+esCu8jowU/yyg2kdbw++BLa8F6nRIW/M+TgfHbcWzk88iNVy2P3UnXwmW +zaD+vkAMXBJV+JOCyinpXj9WV4s4NvdFGkwozZ5BuO1WTISkQMi4sKUraXAEasP4 +1BIy+Q7DsdwyhEQsb8tGD+pmQQ9P8Vilpg0ND2HepZ5dfWWhPBfnqFVO76DH7cZE +f1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHVl/9D7S3B2l0pKoU/rGXuhg8F +jZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYliB6XzCGcKQEN +ZetX2fNXlrtIzYE= +-----END CERTIFICATE----- + +# Issuer: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 +# Subject: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 +# Label: "Buypass Class 2 Root CA" +# Serial: 2 +# MD5 Fingerprint: 46:a7:d2:fe:45:fb:64:5a:a8:59:90:9b:78:44:9b:29 +# SHA1 Fingerprint: 49:0a:75:74:de:87:0a:47:fe:58:ee:f6:c7:6b:eb:c6:0b:12:40:99 +# SHA256 Fingerprint: 9a:11:40:25:19:7c:5b:b9:5d:94:e6:3d:55:cd:43:79:08:47:b6:46:b2:3c:df:11:ad:a4:a0:0e:ff:15:fb:48 +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr +6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV +L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91 +1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx +MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ +QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB +arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr +Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi +FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS +P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN +9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz +uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h +9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s +A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t +OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo ++fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7 +KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2 +DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us +H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ +I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7 +5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h +3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz +Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA= +-----END CERTIFICATE----- + +# Issuer: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 +# Subject: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 +# Label: "Buypass Class 3 Root CA" +# Serial: 2 +# MD5 Fingerprint: 3d:3b:18:9e:2c:64:5a:e8:d5:88:ce:0e:f9:37:c2:ec +# SHA1 Fingerprint: da:fa:f7:fa:66:84:ec:06:8f:14:50:bd:c7:c2:81:a5:bc:a9:64:57 +# SHA256 Fingerprint: ed:f7:eb:bc:a2:7a:2a:38:4d:38:7b:7d:40:10:c6:66:e2:ed:b4:84:3e:4c:29:b4:ae:1d:5b:93:32:e6:b2:4d +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y +ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E +N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9 +tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX +0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c +/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X +KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY +zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS +O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D +34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP +K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3 +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv +Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj +QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV +cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS +IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2 +HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa +O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv +033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u +dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE +kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41 +3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD +u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq +4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc= +-----END CERTIFICATE----- + +# Issuer: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Subject: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Label: "T-TeleSec GlobalRoot Class 3" +# Serial: 1 +# MD5 Fingerprint: ca:fb:40:a8:4e:39:92:8a:1d:fe:8e:2f:c4:27:ea:ef +# SHA1 Fingerprint: 55:a6:72:3e:cb:f2:ec:cd:c3:23:74:70:19:9d:2a:be:11:e3:81:d1 +# SHA256 Fingerprint: fd:73:da:d3:1c:64:4f:f1:b4:3b:ef:0c:cd:da:96:71:0b:9c:d9:87:5e:ca:7e:31:70:7a:f3:e9:6d:52:2b:bd +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN +8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/ +RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4 +hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5 +ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM +EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1 +A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy +WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ +1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30 +6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT +91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml +e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p +TpPDpFQUWw== +-----END CERTIFICATE----- + +# Issuer: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH +# Subject: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH +# Label: "D-TRUST Root Class 3 CA 2 2009" +# Serial: 623603 +# MD5 Fingerprint: cd:e0:25:69:8d:47:ac:9c:89:35:90:f7:fd:51:3d:2f +# SHA1 Fingerprint: 58:e8:ab:b0:36:15:33:fb:80:f7:9b:1b:6d:29:d3:ff:8d:5f:00:f0 +# SHA256 Fingerprint: 49:e7:a4:42:ac:f0:ea:62:87:05:00:54:b5:25:64:b6:50:e4:f4:9e:42:e3:48:d6:aa:38:e0:39:e9:57:b1:c1 +-----BEGIN CERTIFICATE----- +MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha +ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM +HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03 +UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42 +tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R +ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM +lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp +/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G +A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G +A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj +dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy +MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl +cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js +L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL +BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni +acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 +o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K +zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8 +PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y +Johw1+qRzT65ysCQblrGXnRl11z+o+I= +-----END CERTIFICATE----- + +# Issuer: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH +# Subject: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH +# Label: "D-TRUST Root Class 3 CA 2 EV 2009" +# Serial: 623604 +# MD5 Fingerprint: aa:c6:43:2c:5e:2d:cd:c4:34:c0:50:4f:11:02:4f:b6 +# SHA1 Fingerprint: 96:c9:1b:0b:95:b4:10:98:42:fa:d0:d8:22:79:fe:60:fa:b9:16:83 +# SHA256 Fingerprint: ee:c5:49:6b:98:8c:e9:86:25:b9:34:09:2e:ec:29:08:be:d0:b0:f3:16:c2:d4:73:0c:84:ea:f1:f3:d3:48:81 +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw +NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV +BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn +ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0 +3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z +qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR +p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8 +HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw +ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea +HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw +Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh +c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E +RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt +dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku +Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp +3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 +nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF +CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na +xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX +KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1 +-----END CERTIFICATE----- + +# Issuer: CN=CA Disig Root R2 O=Disig a.s. +# Subject: CN=CA Disig Root R2 O=Disig a.s. +# Label: "CA Disig Root R2" +# Serial: 10572350602393338211 +# MD5 Fingerprint: 26:01:fb:d8:27:a7:17:9a:45:54:38:1a:43:01:3b:03 +# SHA1 Fingerprint: b5:61:eb:ea:a4:de:e4:25:4b:69:1a:98:a5:57:47:c2:34:c7:d9:71 +# SHA256 Fingerprint: e2:3d:4a:03:6d:7b:70:e9:f5:95:b1:42:20:79:d2:b9:1e:df:bb:1f:b6:51:a0:63:3e:aa:8a:9d:c5:f8:07:03 +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV +BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu +MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy +MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx +EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe +NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH +PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I +x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe +QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR +yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO +QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912 +H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ +QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD +i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs +nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1 +rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud +DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI +hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM +tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf +GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb +lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka ++elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal +TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i +nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3 +gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr +G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os +zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x +L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL +-----END CERTIFICATE----- + +# Issuer: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV +# Subject: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV +# Label: "ACCVRAIZ1" +# Serial: 6828503384748696800 +# MD5 Fingerprint: d0:a0:5a:ee:05:b6:09:94:21:a1:7d:f1:b2:29:82:02 +# SHA1 Fingerprint: 93:05:7a:88:15:c6:4f:ce:88:2f:fa:91:16:52:28:78:bc:53:64:17 +# SHA256 Fingerprint: 9a:6e:c0:12:e1:a7:da:9d:be:34:19:4d:47:8a:d7:c0:db:18:22:fb:07:1d:f1:29:81:49:6e:d1:04:38:41:13 +-----BEGIN CERTIFICATE----- +MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE +AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw +CQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQ +BgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUND +VjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCb +qau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gMjmoY +HtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWo +G2ioPej0RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpA +lHPrzg5XPAOBOp0KoVdDaaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhr +IA8wKFSVf+DuzgpmndFALW4ir50awQUZ0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/ +0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDGWuzndN9wrqODJerWx5eH +k6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs78yM2x/47 +4KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMO +m3WR5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpa +cXpkatcnYGMN285J9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPl +uUsXQA+xtrn13k/c4LOsOxFwYIRKQ26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYI +KwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRwOi8vd3d3LmFjY3YuZXMvZmls +ZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEuY3J0MB8GCCsG +AQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 +VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeT +VfZW6oHlNsyMHj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIG +CCsGAQUFBwICMIIBFB6CARAAQQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUA +cgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBhAO0AegAgAGQAZQAgAGwAYQAgAEEA +QwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUAYwBuAG8AbABvAGcA +7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBjAHQA +cgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAA +QwBQAFMAIABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUA +czAwBggrBgEFBQcCARYkaHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2Mu +aHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRt +aW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2MV9kZXIuY3JsMA4GA1Ud +DwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZIhvcNAQEF +BQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdp +D70ER9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gU +JyCpZET/LtZ1qmxNYEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+m +AM/EKXMRNt6GGT6d7hmKG9Ww7Y49nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepD +vV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJTS+xJlsndQAJxGJ3KQhfnlms +tn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3sCPdK6jT2iWH +7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h +I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szA +h1xA2syVP1XgNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xF +d3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2H +pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7 +-----END CERTIFICATE----- + +# Issuer: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA +# Subject: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA +# Label: "TWCA Global Root CA" +# Serial: 3262 +# MD5 Fingerprint: f9:03:7e:cf:e6:9e:3c:73:7a:2a:90:07:69:ff:2b:96 +# SHA1 Fingerprint: 9c:bb:48:53:f6:a4:f6:d3:52:a4:e8:32:52:55:60:13:f5:ad:af:65 +# SHA256 Fingerprint: 59:76:90:07:f7:68:5d:0f:cd:50:87:2f:9f:95:d5:75:5a:5b:2b:45:7d:81:f3:69:2b:61:0a:98:67:2f:0e:1b +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx +EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT +VFdDQSBHbG9iYWwgUm9vdCBDQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5 +NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQKEwlUQUlXQU4tQ0ExEDAOBgNVBAsT +B1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3QgQ0EwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2CnJfF +10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz +0ALfUPZVr2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfCh +MBwqoJimFb3u/Rk28OKRQ4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbH +zIh1HrtsBv+baz4X7GGqcXzGHaL3SekVtTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc +46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1WKKD+u4ZqyPpcC1jcxkt2 +yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99sy2sbZCi +laLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYP +oA/pyJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQA +BDzfuBSO6N+pjWxnkjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcE +qYSjMq+u7msXi7Kx/mzhkIyIqJdIzshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm +4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6gcFGn90xHNcgL +1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn +LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WF +H6vPNOw/KP4M8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNo +RI2T9GRwoD2dKAXDOXC4Ynsg/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+ +nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlglPx4mI88k1HtQJAH32RjJMtOcQWh +15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryPA9gK8kxkRr05YuWW +6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3mi4TW +nsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5j +wa19hAM8EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWz +aGHQRiapIVJpLesux+t3zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmy +KwbQBM0= +-----END CERTIFICATE----- + +# Issuer: CN=TeliaSonera Root CA v1 O=TeliaSonera +# Subject: CN=TeliaSonera Root CA v1 O=TeliaSonera +# Label: "TeliaSonera Root CA v1" +# Serial: 199041966741090107964904287217786801558 +# MD5 Fingerprint: 37:41:49:1b:18:56:9a:26:f5:ad:c2:66:fb:40:a5:4c +# SHA1 Fingerprint: 43:13:bb:96:f1:d5:86:9b:c1:4e:6a:92:f6:cf:f6:34:69:87:82:37 +# SHA256 Fingerprint: dd:69:36:fe:21:f8:f0:77:c1:23:a1:a5:21:c1:22:24:f7:22:55:b7:3e:03:a7:26:06:93:e8:a2:4b:0f:a3:89 +-----BEGIN CERTIFICATE----- +MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw +NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv +b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD +VQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9vdCBDQSB2 +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+6yfwIaPzaSZVfp3F +VRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA3GV1 +7CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+X +Z75Ljo1kB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+ +/jXh7VB7qTCNGdMJjmhnXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs +81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxHoLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkm +dtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3F0fUTPHSiXk+TT2YqGHe +Oh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJoWjiUIMu +sDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4 +pgd7gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fs +slESl1MpWtTwEhDcTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQ +arMCpgKIv7NHfirZ1fpoeDVNAgMBAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYD +VR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qWDNXr+nuqF+gTEjANBgkqhkiG +9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNmzqjMDfz1mgbl +dxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx +0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1Tj +TQpgcmLNkQfWpb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBed +Y2gea+zDTYa4EzAvXUYNR0PVG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7 +Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpcc41teyWRyu5FrgZLAMzTsVlQ2jqI +OylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOTJsjrDNYmiLbAJM+7 +vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW +t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn +HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx +SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= +-----END CERTIFICATE----- + +# Issuer: CN=E-Tugra Certification Authority O=E-Tu\u011fra EBG Bili\u015fim Teknolojileri ve Hizmetleri A.\u015e. OU=E-Tugra Sertifikasyon Merkezi +# Subject: CN=E-Tugra Certification Authority O=E-Tu\u011fra EBG Bili\u015fim Teknolojileri ve Hizmetleri A.\u015e. OU=E-Tugra Sertifikasyon Merkezi +# Label: "E-Tugra Certification Authority" +# Serial: 7667447206703254355 +# MD5 Fingerprint: b8:a1:03:63:b0:bd:21:71:70:8a:6f:13:3a:bb:79:49 +# SHA1 Fingerprint: 51:c6:e7:08:49:06:6e:f3:92:d4:5c:a0:0d:6d:a3:62:8f:c3:52:39 +# SHA256 Fingerprint: b0:bf:d5:2b:b0:d7:d9:bd:92:bf:5d:4d:c1:3d:a2:55:c0:2c:54:2f:37:83:65:ea:89:39:11:f5:5e:55:f2:3c +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNV +BAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBC +aWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNV +BAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQDDB9FLVR1 +Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMwNTEyMDk0OFoXDTIz +MDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+ +BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhp +em1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN +ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4vU/kwVRHoViVF56C/UY +B4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vdhQd2h8y/L5VMzH2nPbxH +D5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5KCKpbknSF +Q9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEo +q1+gElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3D +k14opz8n8Y4e0ypQBaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcH +fC425lAcP9tDJMW/hkd5s3kc91r0E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsut +dEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gzrt48Ue7LE3wBf4QOXVGUnhMM +ti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAqjqFGOjGY5RH8 +zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn +rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUX +U8u3Zg5mTPj5dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6 +Jyr+zE7S6E5UMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5 +XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAF +Nzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAKkEh47U6YA5n+KGCR +HTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jOXKqY +GwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c +77NCR807VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3 ++GbHeJAAFS6LrVE1Uweoa2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WK +vJUawSg5TB9D0pH0clmKuVb8P7Sd2nCcdlqMQ1DujjByTd//SffGqWfZbawCEeI6 +FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEVKV0jq9BgoRJP3vQXzTLl +yb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gTDx4JnW2P +AJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpD +y4Q08ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8d +NL/+I5c30jn6PQ0GC7TbO6Orb1wdtn7os4I07QZcJA== +-----END CERTIFICATE----- + +# Issuer: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Subject: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Label: "T-TeleSec GlobalRoot Class 2" +# Serial: 1 +# MD5 Fingerprint: 2b:9b:9e:e4:7b:6c:1f:00:72:1a:cc:c1:77:79:df:6a +# SHA1 Fingerprint: 59:0d:2d:7d:88:4f:40:2e:61:7e:a5:62:32:17:65:cf:17:d8:94:e9 +# SHA256 Fingerprint: 91:e2:f5:78:8d:58:10:eb:a7:ba:58:73:7d:e1:54:8a:8e:ca:cd:01:45:98:bc:0b:14:3e:04:1b:17:05:25:52 +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd +AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC +FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi +1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq +jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ +wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/ +WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy +NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC +uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw +IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6 +g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN +9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP +BSeOE6Fuwg== +-----END CERTIFICATE----- + +# Issuer: CN=Atos TrustedRoot 2011 O=Atos +# Subject: CN=Atos TrustedRoot 2011 O=Atos +# Label: "Atos TrustedRoot 2011" +# Serial: 6643877497813316402 +# MD5 Fingerprint: ae:b9:c4:32:4b:ac:7f:5d:66:cc:77:94:bb:2a:77:56 +# SHA1 Fingerprint: 2b:b1:f5:3e:55:0c:1d:c5:f1:d4:e6:b7:6a:46:4b:55:06:02:ac:21 +# SHA256 Fingerprint: f3:56:be:a2:44:b7:a9:1e:b3:5d:53:ca:9a:d7:86:4a:ce:01:8e:2d:35:d5:f8:f9:6d:df:68:a6:f4:1a:a4:74 +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE +AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG +EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM +FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC +REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp +Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM +VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+ +SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ +4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L +cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi +eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG +A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 +DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j +vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP +DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc +maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D +lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv +KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited +# Label: "QuoVadis Root CA 1 G3" +# Serial: 687049649626669250736271037606554624078720034195 +# MD5 Fingerprint: a4:bc:5b:3f:fe:37:9a:fa:64:f0:e2:fa:05:3d:0b:ab +# SHA1 Fingerprint: 1b:8e:ea:57:96:29:1a:c9:39:ea:b8:0a:81:1a:73:73:c0:93:79:67 +# SHA256 Fingerprint: 8a:86:6f:d1:b2:76:b5:7e:57:8e:92:1c:65:82:8a:2b:ed:58:e9:f2:f2:88:05:41:34:b7:f1:f4:bf:c9:cc:74 +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00 +MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakEPBtV +wedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWe +rNrwU8lmPNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF341 +68Xfuw6cwI2H44g4hWf6Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh +4Pw5qlPafX7PGglTvF0FBM+hSo+LdoINofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXp +UhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/lg6AnhF4EwfWQvTA9xO+o +abw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV7qJZjqlc +3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/G +KubX9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSt +hfbZxbGL0eUQMk1fiyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KO +Tk0k+17kBL5yG6YnLUlamXrXXAkgt3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOt +zCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZIhvcNAQELBQAD +ggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC +MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2 +cDMT/uFPpiN3GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUN +qXsCHKnQO18LwIE6PWThv6ctTr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5 +YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP+V04ikkwj+3x6xn0dxoxGE1nVGwv +b2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh3jRJjehZrJ3ydlo2 +8hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fawx/k +NSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNj +ZgKAvQU6O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhp +q1467HxpvMc7hU6eFbm0FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFt +nh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOVhMJKzRwuJIczYOXD +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited +# Label: "QuoVadis Root CA 2 G3" +# Serial: 390156079458959257446133169266079962026824725800 +# MD5 Fingerprint: af:0c:86:6e:bf:40:2d:7f:0b:3e:12:50:ba:12:3d:06 +# SHA1 Fingerprint: 09:3c:61:f3:8b:8b:dc:7d:55:df:75:38:02:05:00:e1:25:f5:c8:36 +# SHA256 Fingerprint: 8f:e4:fb:0a:f9:3a:4d:0d:67:db:0b:eb:b2:3e:37:c7:1b:f3:25:dc:bc:dd:24:0e:a0:4d:af:58:b4:7e:18:40 +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00 +MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFhZiFf +qq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMW +n4rjyduYNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ym +c5GQYaYDFCDy54ejiK2toIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+ +O7q414AB+6XrW7PFXmAqMaCvN+ggOp+oMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1 +o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+lV0POKa2Mq1W/xPtbAd0j +IaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZoL1NesNKq +IcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz +8eQQsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43eh +vNURG3YBZwjgQQvD6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l +7ZizlWNof/k19N+IxWA1ksB8aRxhlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALG +cC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZIhvcNAQELBQAD +ggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 +AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RC +roijQ1h5fq7KpVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0Ga +W/ZZGYjeVYg3UQt4XAoeo0L9x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4n +lv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgzdWqTHBLmYF5vHX/JHyPLhGGfHoJE ++V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6XU/IyAgkwo1jwDQHV +csaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+NwmNtd +dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg +KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM +HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4 +WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited +# Label: "QuoVadis Root CA 3 G3" +# Serial: 268090761170461462463995952157327242137089239581 +# MD5 Fingerprint: df:7d:b9:ad:54:6f:68:a1:df:89:57:03:97:43:b0:d7 +# SHA1 Fingerprint: 48:12:bd:92:3c:a8:c4:39:06:e7:30:6d:27:96:e6:a4:cf:22:2e:7d +# SHA256 Fingerprint: 88:ef:81:de:20:2e:b0:18:45:2e:43:f8:64:72:5c:ea:5f:bd:1f:c2:d9:d2:05:73:07:09:c5:d8:b8:69:0f:46 +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00 +MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286IxSR +/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNu +FoM7pmRLMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXR +U7Ox7sWTaYI+FrUoRqHe6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+c +ra1AdHkrAj80//ogaX3T7mH1urPnMNA3I4ZyYUUpSFlob3emLoG+B01vr87ERROR +FHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3UVDmrJqMz6nWB2i3ND0/k +A9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f75li59wzw +eyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634Ryl +sSqiMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBp +VzgeAVuNVejH38DMdyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0Q +A4XN8f+MFrXBsj6IbGB/kE+V9/YtrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ +ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZIhvcNAQELBQAD +ggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px +KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnI +FUBhynLWcKzSt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5Wvv +oxXqA/4Ti2Tk08HS6IT7SdEQTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFg +u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP +0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGibIh6BJpsQBJFxwAYf +3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmDhPbl +8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+ +DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN +PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ +ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0 +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Assured ID Root G2" +# Serial: 15385348160840213938643033620894905419 +# MD5 Fingerprint: 92:38:b9:f8:63:24:82:65:2c:57:33:e6:fe:81:8f:9d +# SHA1 Fingerprint: a1:4b:48:d9:43:ee:0a:0e:40:90:4f:3c:e0:a4:c0:91:93:51:5d:3f +# SHA256 Fingerprint: 7d:05:eb:b6:82:33:9f:8c:94:51:ee:09:4e:eb:fe:fa:79:53:a1:14:ed:b2:f4:49:49:45:2f:ab:7d:2f:c1:85 +-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA +n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc +biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp +EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA +bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu +YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB +AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW +BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI +QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I +0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni +lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 +B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv +ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo +IhNzbM8m9Yop5w== +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Assured ID Root G3" +# Serial: 15459312981008553731928384953135426796 +# MD5 Fingerprint: 7c:7f:65:31:0c:81:df:8d:ba:3e:99:e2:5c:ad:6e:fb +# SHA1 Fingerprint: f5:17:a2:4f:9a:48:c6:c9:f8:a2:00:26:9f:dc:0f:48:2c:ab:30:89 +# SHA256 Fingerprint: 7e:37:cb:8b:4c:47:09:0c:ab:36:55:1b:a6:f4:5d:b8:40:68:0f:ba:16:6a:95:2d:b1:00:71:7f:43:05:3f:c2 +-----BEGIN CERTIFICATE----- +MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg +RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf +Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q +RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD +AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY +JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv +6pZjamVFkpUBtA== +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Global Root G2" +# Serial: 4293743540046975378534879503202253541 +# MD5 Fingerprint: e4:a6:8a:c8:54:ac:52:42:46:0a:fd:72:48:1b:2a:44 +# SHA1 Fingerprint: df:3c:24:f9:bf:d6:66:76:1b:26:80:73:fe:06:d1:cc:8d:4f:82:a4 +# SHA256 Fingerprint: cb:3c:cb:b7:60:31:e5:e0:13:8f:8d:d3:9a:23:f9:de:47:ff:c3:5e:43:c1:14:4c:ea:27:d4:6a:5a:b1:cb:5f +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH +MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI +2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx +1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ +q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz +tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ +vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV +5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY +1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 +NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG +Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 +8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe +pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Global Root G3" +# Serial: 7089244469030293291760083333884364146 +# MD5 Fingerprint: f5:5d:a4:50:a5:fb:28:7e:1e:0f:0d:cc:96:57:56:ca +# SHA1 Fingerprint: 7e:04:de:89:6a:3e:66:6d:00:e6:87:d3:3f:fa:d9:3b:e8:3d:34:9e +# SHA256 Fingerprint: 31:ad:66:48:f8:10:41:38:c7:38:f3:9e:a4:32:01:33:39:3e:3a:18:cc:02:29:6e:f9:7c:2a:c9:ef:67:31:d0 +-----BEGIN CERTIFICATE----- +MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe +Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw +EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x +IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG +fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO +Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd +BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx +AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ +oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 +sycX +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Trusted Root G4" +# Serial: 7451500558977370777930084869016614236 +# MD5 Fingerprint: 78:f2:fc:aa:60:1f:2f:b4:eb:c9:37:ba:53:2e:75:49 +# SHA1 Fingerprint: dd:fb:16:cd:49:31:c9:73:a2:03:7d:3f:c8:3a:4d:7d:77:5d:05:e4 +# SHA256 Fingerprint: 55:2f:7b:dc:f1:a7:af:9e:6c:e6:72:01:7f:4f:12:ab:f7:72:40:c7:8e:76:1a:c2:03:d1:d9:d2:0a:c8:99:88 +-----BEGIN CERTIFICATE----- +MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg +RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y +ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If +xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV +ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO +DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ +jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ +CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi +EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM +fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY +uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK +chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t +9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD +ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 +SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd ++SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc +fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa +sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N +cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N +0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie +4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI +r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 +/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm +gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ +-----END CERTIFICATE----- + +# Issuer: CN=COMODO RSA Certification Authority O=COMODO CA Limited +# Subject: CN=COMODO RSA Certification Authority O=COMODO CA Limited +# Label: "COMODO RSA Certification Authority" +# Serial: 101909084537582093308941363524873193117 +# MD5 Fingerprint: 1b:31:b0:71:40:36:cc:14:36:91:ad:c4:3e:fd:ec:18 +# SHA1 Fingerprint: af:e5:d2:44:a8:d1:19:42:30:ff:47:9f:e2:f8:97:bb:cd:7a:8c:b4 +# SHA256 Fingerprint: 52:f0:e1:c4:e5:8e:c6:29:29:1b:60:31:7f:07:46:71:b8:5d:7e:a8:0d:5b:07:27:34:63:53:4b:32:b4:02:34 +-----BEGIN CERTIFICATE----- +MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB +hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV +BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5 +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT +EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR +6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X +pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC +9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV +/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf +Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z ++pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w +qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah +SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC +u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf +Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq +crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E +FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB +/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl +wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM +4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV +2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna +FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ +CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK +boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke +jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL +S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb +QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl +0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB +NVOFBkpdn627G190 +-----END CERTIFICATE----- + +# Issuer: CN=USERTrust RSA Certification Authority O=The USERTRUST Network +# Subject: CN=USERTrust RSA Certification Authority O=The USERTRUST Network +# Label: "USERTrust RSA Certification Authority" +# Serial: 2645093764781058787591871645665788717 +# MD5 Fingerprint: 1b:fe:69:d1:91:b7:19:33:a3:72:a8:0f:e1:55:e5:b5 +# SHA1 Fingerprint: 2b:8f:1b:57:33:0d:bb:a2:d0:7a:6c:51:f7:0e:e9:0d:da:b9:ad:8e +# SHA256 Fingerprint: e7:93:c9:b0:2f:d8:aa:13:e2:1c:31:22:8a:cc:b0:81:19:64:3b:74:9c:89:89:64:b1:74:6d:46:c3:d4:cb:d2 +-----BEGIN CERTIFICATE----- +MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB +iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl +cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV +BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw +MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV +BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B +3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY +tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ +Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 +VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT +79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 +c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT +Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l +c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee +UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE +Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd +BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G +A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF +Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO +VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 +ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs +8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR +iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze +Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ +XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ +qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB +VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB +L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG +jjxDah2nGN59PRbxYvnKkKj9 +-----END CERTIFICATE----- + +# Issuer: CN=USERTrust ECC Certification Authority O=The USERTRUST Network +# Subject: CN=USERTrust ECC Certification Authority O=The USERTRUST Network +# Label: "USERTrust ECC Certification Authority" +# Serial: 123013823720199481456569720443997572134 +# MD5 Fingerprint: fa:68:bc:d9:b5:7f:ad:fd:c9:1d:06:83:28:cc:24:c1 +# SHA1 Fingerprint: d1:cb:ca:5d:b2:d5:2a:7f:69:3b:67:4d:e5:f0:5a:1d:0c:95:7d:f0 +# SHA256 Fingerprint: 4f:f4:60:d5:4b:9c:86:da:bf:bc:fc:57:12:e0:40:0d:2b:ed:3f:bc:4d:4f:bd:aa:86:e0:6a:dc:d2:a9:ad:7a +-----BEGIN CERTIFICATE----- +MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL +MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl +eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT +JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT +Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg +VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo +I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng +o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G +A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB +zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW +RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 +# Label: "GlobalSign ECC Root CA - R4" +# Serial: 14367148294922964480859022125800977897474 +# MD5 Fingerprint: 20:f0:27:68:d1:7e:a0:9d:0e:e6:2a:ca:df:5c:89:8e +# SHA1 Fingerprint: 69:69:56:2e:40:80:f4:24:a1:e7:19:9f:14:ba:f3:ee:58:ab:6a:bb +# SHA256 Fingerprint: be:c9:49:11:c2:95:56:76:db:6c:0a:55:09:86:d7:6e:3b:a0:05:66:7c:44:2c:97:62:b4:fb:b7:73:de:22:8c +-----BEGIN CERTIFICATE----- +MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk +MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH +bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX +DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD +QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ +FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F +uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX +kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs +ewv4n4Q= +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 +# Label: "GlobalSign ECC Root CA - R5" +# Serial: 32785792099990507226680698011560947931244 +# MD5 Fingerprint: 9f:ad:3b:1c:02:1e:8a:ba:17:74:38:81:0c:a2:bc:08 +# SHA1 Fingerprint: 1f:24:c6:30:cd:a4:18:ef:20:69:ff:ad:4f:dd:5f:46:3a:1b:69:aa +# SHA256 Fingerprint: 17:9f:bc:14:8a:3d:d0:0f:d2:4e:a1:34:58:cc:43:bf:a7:f5:9c:81:82:d7:83:a5:13:f6:eb:ec:10:0c:89:24 +-----BEGIN CERTIFICATE----- +MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk +MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH +bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX +DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD +QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc +8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke +hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI +KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg +515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO +xwy8p2Fp8fc74SrL+SvzZpA3 +-----END CERTIFICATE----- + +# Issuer: CN=Staat der Nederlanden Root CA - G3 O=Staat der Nederlanden +# Subject: CN=Staat der Nederlanden Root CA - G3 O=Staat der Nederlanden +# Label: "Staat der Nederlanden Root CA - G3" +# Serial: 10003001 +# MD5 Fingerprint: 0b:46:67:07:db:10:2f:19:8c:35:50:60:d1:0b:f4:37 +# SHA1 Fingerprint: d8:eb:6b:41:51:92:59:e0:f3:e7:85:00:c0:3d:b6:88:97:c9:ee:fc +# SHA256 Fingerprint: 3c:4f:b0:b9:5a:b8:b3:00:32:f4:32:b8:6f:53:5f:e1:72:c1:85:d0:fd:39:86:58:37:cf:36:18:7f:a6:f4:28 +-----BEGIN CERTIFICATE----- +MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO +TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh +dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEczMB4XDTEzMTExNDExMjg0MloX +DTI4MTExMzIzMDAwMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl +ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv +b3QgQ0EgLSBHMzCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAL4yolQP +cPssXFnrbMSkUeiFKrPMSjTysF/zDsccPVMeiAho2G89rcKezIJnByeHaHE6n3WW +IkYFsO2tx1ueKt6c/DrGlaf1F2cY5y9JCAxcz+bMNO14+1Cx3Gsy8KL+tjzk7FqX +xz8ecAgwoNzFs21v0IJyEavSgWhZghe3eJJg+szeP4TrjTgzkApyI/o1zCZxMdFy +KJLZWyNtZrVtB0LrpjPOktvA9mxjeM3KTj215VKb8b475lRgsGYeCasH/lSJEULR +9yS6YHgamPfJEf0WwTUaVHXvQ9Plrk7O53vDxk5hUUurmkVLoR9BvUhTFXFkC4az +5S6+zqQbwSmEorXLCCN2QyIkHxcE1G6cxvx/K2Ya7Irl1s9N9WMJtxU51nus6+N8 +6U78dULI7ViVDAZCopz35HCz33JvWjdAidiFpNfxC95DGdRKWCyMijmev4SH8RY7 +Ngzp07TKbBlBUgmhHbBqv4LvcFEhMtwFdozL92TkA1CvjJFnq8Xy7ljY3r735zHP +bMk7ccHViLVlvMDoFxcHErVc0qsgk7TmgoNwNsXNo42ti+yjwUOH5kPiNL6VizXt +BznaqB16nzaeErAMZRKQFWDZJkBE41ZgpRDUajz9QdwOWke275dhdU/Z/seyHdTt +XUmzqWrLZoQT1Vyg3N9udwbRcXXIV2+vD3dbAgMBAAGjQjBAMA8GA1UdEwEB/wQF +MAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRUrfrHkleuyjWcLhL75Lpd +INyUVzANBgkqhkiG9w0BAQsFAAOCAgEAMJmdBTLIXg47mAE6iqTnB/d6+Oea31BD +U5cqPco8R5gu4RV78ZLzYdqQJRZlwJ9UXQ4DO1t3ApyEtg2YXzTdO2PCwyiBwpwp +LiniyMMB8jPqKqrMCQj3ZWfGzd/TtiunvczRDnBfuCPRy5FOCvTIeuXZYzbB1N/8 +Ipf3YF3qKS9Ysr1YvY2WTxB1v0h7PVGHoTx0IsL8B3+A3MSs/mrBcDCw6Y5p4ixp +gZQJut3+TcCDjJRYwEYgr5wfAvg1VUkvRtTA8KCWAg8zxXHzniN9lLf9OtMJgwYh +/WA9rjLA0u6NpvDntIJ8CsxwyXmA+P5M9zWEGYox+wrZ13+b8KKaa8MFSu1BYBQw +0aoRQm7TIwIEC8Zl3d1Sd9qBa7Ko+gE4uZbqKmxnl4mUnrzhVNXkanjvSr0rmj1A +fsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq +4BZ+Extq1z7XnvwtdbLBFNUjA9tbbws+eC8N3jONFrdI54OagQ97wUNNVQQXOEpR +1VmiiXTTn74eS9fGbbeIJG9gkaSChVtWQbzQRKtqE77RLFi3EjNYsjdj3BP1lB0/ +QFH1T/U67cjF68IeHRaVesd+QnGTbksVtzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM +94B7IWcnMFk= +-----END CERTIFICATE----- + +# Issuer: CN=Staat der Nederlanden EV Root CA O=Staat der Nederlanden +# Subject: CN=Staat der Nederlanden EV Root CA O=Staat der Nederlanden +# Label: "Staat der Nederlanden EV Root CA" +# Serial: 10000013 +# MD5 Fingerprint: fc:06:af:7b:e8:1a:f1:9a:b4:e8:d2:70:1f:c0:f5:ba +# SHA1 Fingerprint: 76:e2:7e:c1:4f:db:82:c1:c0:a6:75:b5:05:be:3d:29:b4:ed:db:bb +# SHA256 Fingerprint: 4d:24:91:41:4c:fe:95:67:46:ec:4c:ef:a6:cf:6f:72:e2:8a:13:29:43:2f:9d:8a:90:7a:c4:cb:5d:ad:c1:5a +-----BEGIN CERTIFICATE----- +MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJO +TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFh +dCBkZXIgTmVkZXJsYW5kZW4gRVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0y +MjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5MMR4wHAYDVQQKDBVTdGFhdCBkZXIg +TmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRlcmxhbmRlbiBFViBS +b290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkkSzrS +M4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nC +UiY4iKTWO0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3d +Z//BYY1jTw+bbRcwJu+r0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46p +rfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13l +pJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gVXJrm0w912fxBmJc+qiXb +j5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr08C+eKxC +KFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS +/ZbV0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0X +cgOPvZuM5l5Tnrmd74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH +1vI4gnPah1vlPNOePqc7nvQDs/nxfRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrP +px9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwaivsnuL8wbqg7 +MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI +eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u +2dfOWBfoqSmuc0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHS +v4ilf0X8rLiltTMMgsT7B/Zq5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTC +wPTxGfARKbalGAKb12NMcIxHowNDXLldRqANb/9Zjr7dn3LDWyvfjFvO5QxGbJKy +CqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tNf1zuacpzEPuKqf2e +vTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi5Dp6 +Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIa +Gl6I6lD4WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeL +eG9QgkRQP2YGiqtDhFZKDyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8 +FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGyeUN51q1veieQA6TqJIc/2b3Z6fJfUEkc +7uzXLg== +-----END CERTIFICATE----- + +# Issuer: CN=IdenTrust Commercial Root CA 1 O=IdenTrust +# Subject: CN=IdenTrust Commercial Root CA 1 O=IdenTrust +# Label: "IdenTrust Commercial Root CA 1" +# Serial: 13298821034946342390520003877796839426 +# MD5 Fingerprint: b3:3e:77:73:75:ee:a0:d3:e3:7e:49:63:49:59:bb:c7 +# SHA1 Fingerprint: df:71:7e:aa:4a:d9:4e:c9:55:84:99:60:2d:48:de:5f:bc:f0:3a:25 +# SHA256 Fingerprint: 5d:56:49:9b:e4:d2:e0:8b:cf:ca:d0:8a:3e:38:72:3d:50:50:3b:de:70:69:48:e4:2f:55:60:30:19:e5:28:ae +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu +VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw +MTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScw +JQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ldhNlT +3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU ++ehcCuz/mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gp +S0l4PJNgiCL8mdo2yMKi1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1 +bVoE/c40yiTcdCMbXTMTEl3EASX2MN0CXZ/g1Ue9tOsbobtJSdifWwLziuQkkORi +T0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl3ZBWzvurpWCdxJ35UrCL +vYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzyNeVJSQjK +Vsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZK +dHzVWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHT +c+XvvqDtMwt0viAgxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hv +l7yTmvmcEpB4eoCHFddydJxVdHixuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5N +iGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZIhvcNAQELBQAD +ggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH +6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwt +LRvM7Kqas6pgghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93 +nAbowacYXVKV7cndJZ5t+qntozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3 ++wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmVYjzlVYA211QC//G5Xc7UI2/YRYRK +W2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUXfeu+h1sXIFRRk0pT +AwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/rokTLq +l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG +4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ +mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A +7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H +-----END CERTIFICATE----- + +# Issuer: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust +# Subject: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust +# Label: "IdenTrust Public Sector Root CA 1" +# Serial: 13298821034946342390521976156843933698 +# MD5 Fingerprint: 37:06:a5:b0:fc:89:9d:ba:f4:6b:8c:1a:64:cd:d5:ba +# SHA1 Fingerprint: ba:29:41:60:77:98:3f:f4:f3:ef:f2:31:05:3b:2e:ea:6d:4d:45:fd +# SHA256 Fingerprint: 30:d0:89:5a:9a:44:8a:26:20:91:63:55:22:d1:f5:20:10:b5:86:7a:ca:e1:2c:78:ef:95:8f:d4:f4:38:9f:2f +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu +VHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcN +MzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0 +MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTyP4o7 +ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGy +RBb06tD6Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlS +bdsHyo+1W/CD80/HLaXIrcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF +/YTLNiCBWS2ab21ISGHKTN9T0a9SvESfqy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R +3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoSmJxZZoY+rfGwyj4GD3vw +EUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFnol57plzy +9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9V +GxyhLrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ +2fjXctscvG29ZV/viDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsV +WaFHVCkugyhfHMKiq3IXAAaOReyL4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gD +W/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMwDQYJKoZIhvcN +AQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj +t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHV +DRDtfULAj+7AmgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9 +TaDKQGXSc3z1i9kKlT/YPyNtGtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8G +lwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFtm6/n6J91eEyrRjuazr8FGF1NFTwW +mhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMxNRF4eKLg6TCMf4Df +WN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4Mhn5 ++bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJ +tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA +GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv +8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c +-----END CERTIFICATE----- + +# Issuer: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only +# Subject: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only +# Label: "Entrust Root Certification Authority - G2" +# Serial: 1246989352 +# MD5 Fingerprint: 4b:e2:c9:91:96:65:0c:f4:0e:5a:93:92:a0:0a:fe:b2 +# SHA1 Fingerprint: 8c:f4:27:fd:79:0c:3a:d1:66:06:8d:e8:1e:57:ef:bb:93:22:72:d4 +# SHA256 Fingerprint: 43:df:57:74:b0:3e:7f:ef:5f:e4:0d:93:1a:7b:ed:f1:bb:2e:6b:42:73:8c:4e:6d:38:41:10:3d:3a:a7:f3:39 +-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 +cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs +IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz +dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy +NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu +dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt +dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 +aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T +RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN +cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW +wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 +U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 +jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN +BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ +jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v +1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R +nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH +VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== +-----END CERTIFICATE----- + +# Issuer: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only +# Subject: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only +# Label: "Entrust Root Certification Authority - EC1" +# Serial: 51543124481930649114116133369 +# MD5 Fingerprint: b6:7e:1d:f0:58:c5:49:6c:24:3b:3d:ed:98:18:ed:bc +# SHA1 Fingerprint: 20:d8:06:40:df:9b:25:f5:12:25:3a:11:ea:f7:59:8a:eb:14:b5:47 +# SHA256 Fingerprint: 02:ed:0e:b2:8c:14:da:45:16:5c:56:67:91:70:0d:64:51:d7:fb:56:f0:b2:ab:1d:3b:8e:b0:70:e5:6e:df:f5 +-----BEGIN CERTIFICATE----- +MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG +A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 +d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu +dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq +RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy +MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD +VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 +L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g +Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi +A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt +ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH +Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC +R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX +hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G +-----END CERTIFICATE----- + +# Issuer: CN=CFCA EV ROOT O=China Financial Certification Authority +# Subject: CN=CFCA EV ROOT O=China Financial Certification Authority +# Label: "CFCA EV ROOT" +# Serial: 407555286 +# MD5 Fingerprint: 74:e1:b6:ed:26:7a:7a:44:30:33:94:ab:7b:27:81:30 +# SHA1 Fingerprint: e2:b8:29:4b:55:84:ab:6b:58:c2:90:46:6c:ac:3f:b8:39:8f:84:83 +# SHA256 Fingerprint: 5c:c3:d7:8e:4e:1d:5e:45:54:7a:04:e6:87:3e:64:f9:0c:f9:53:6d:1c:cc:2e:f8:00:f3:55:c4:c5:fd:70:fd +-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJD +TjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y +aXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkx +MjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5j +aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJP +T1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnVBU03 +sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpL +TIpTUnrD7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5 +/ZOkVIBMUtRSqy5J35DNuF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp +7hZZLDRJGqgG16iI0gNyejLi6mhNbiyWZXvKWfry4t3uMCz7zEasxGPrb382KzRz +EpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7xzbh72fROdOXW3NiGUgt +hxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9fpy25IGvP +a931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqot +aK8KgWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNg +TnYGmE69g60dWIolhdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfV +PKPtl8MeNPo4+QgO48BdK4PRVmrJtqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hv +cWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAfBgNVHSMEGDAWgBTj/i39KNAL +tbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd +BgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB +ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObT +ej/tUxPQ4i9qecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdL +jOztUmCypAbqTuv0axn96/Ua4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBS +ESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sGE5uPhnEFtC+NiWYzKXZUmhH4J/qy +P5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfXBDrDMlI1Dlb4pd19 +xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjnaH9d +Ci77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN +5mydLIhyPDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe +/v5WOaHIz16eGWRGENoXkbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+Z +AAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3CekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ +5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su +-----END CERTIFICATE----- + +# Issuer: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed +# Subject: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed +# Label: "OISTE WISeKey Global Root GB CA" +# Serial: 157768595616588414422159278966750757568 +# MD5 Fingerprint: a4:eb:b9:61:28:2e:b7:2f:98:b0:35:26:90:99:51:1d +# SHA1 Fingerprint: 0f:f9:40:76:18:d3:d7:6a:4b:98:f0:a8:35:9e:0c:fd:27:ac:cc:ed +# SHA256 Fingerprint: 6b:9c:08:e8:6e:b0:f7:67:cf:ad:65:cd:98:b6:21:49:e5:49:4a:67:f5:84:5e:7b:d1:ed:01:9f:27:b8:6b:d6 +-----BEGIN CERTIFICATE----- +MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt +MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg +Rm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9i +YWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAwMzJaFw0zOTEyMDExNTEwMzFaMG0x +CzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBG +b3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh +bCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3 +HEokKtaXscriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGx +WuR51jIjK+FTzJlFXHtPrby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX +1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNk +u7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4oQnc/nSMbsrY9gBQHTC5P +99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvgGUpuuy9r +M2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUB +BAMCAQAwDQYJKoZIhvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrgh +cViXfa43FK8+5/ea4n32cZiZBKpDdHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5 +gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0VQreUGdNZtGn//3ZwLWoo4rO +ZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEuiHZeeevJuQHHf +aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic +Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= +-----END CERTIFICATE----- + +# Issuer: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A. +# Subject: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A. +# Label: "SZAFIR ROOT CA2" +# Serial: 357043034767186914217277344587386743377558296292 +# MD5 Fingerprint: 11:64:c1:89:b0:24:b1:8c:b1:07:7e:89:9e:51:9e:99 +# SHA1 Fingerprint: e2:52:fa:95:3f:ed:db:24:60:bd:6e:28:f3:9c:cc:cf:5e:b3:3f:de +# SHA256 Fingerprint: a1:33:9d:33:28:1a:0b:56:e5:57:d3:d3:2b:1c:e7:f9:36:7e:b0:94:bd:5f:a7:2a:7e:50:04:c8:de:d7:ca:fe +-----BEGIN CERTIFICATE----- +MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQEL +BQAwUTELMAkGA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6 +ZW5pb3dhIFMuQS4xGDAWBgNVBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkw +NzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L +cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYDVQQDDA9TWkFGSVIg +Uk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5QqEvN +QLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT +3PSQ1hNKDJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw +3gAeqDRHu5rr/gsUvTaE2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr6 +3fE9biCloBK0TXC5ztdyO4mTp4CEHCdJckm1/zuVnsHMyAHs6A6KCpbns6aH5db5 +BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwiieDhZNRnvDF5YTy7ykHN +XGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsF +AAOCAQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw +8PRBEew/R40/cof5O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOG +nXkZ7/e7DDWQw4rtTw/1zBLZpD67oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCP +oky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul4+vJhaAlIDf7js4MNIThPIGy +d05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6+/NNIxuZMzSg +LvWpCz/UXeHPhJ/iGcJfitYgHuNztw== +-----END CERTIFICATE----- + +# Issuer: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Subject: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Label: "Certum Trusted Network CA 2" +# Serial: 44979900017204383099463764357512596969 +# MD5 Fingerprint: 6d:46:9e:d9:25:6d:08:23:5b:5e:74:7d:1e:27:db:f2 +# SHA1 Fingerprint: d3:dd:48:3e:2b:bf:4c:05:e8:af:10:f5:fa:76:26:cf:d3:dc:30:92 +# SHA256 Fingerprint: b6:76:f2:ed:da:e8:77:5c:d3:6c:b0:f6:3c:d1:d4:60:39:61:f4:9e:62:65:ba:01:3a:2f:03:07:b6:d0:b8:04 +-----BEGIN CERTIFICATE----- +MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB +gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu +QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIG +A1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMCIYDzIwMTExMDA2MDgz +OTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZ +VW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3 +b3JrIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWA +DGSdhhuWZGc/IjoedQF97/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn +0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+oCgCXhVqqndwpyeI1B+twTUrWwbNWuKFB +OJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40bRr5HMNUuctHFY9rnY3lE +fktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2puTRZCr+E +Sv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1m +o130GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02i +sx7QBlrd9pPPV3WZ9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOW +OZV7bIBaTxNyxtd9KXpEulKkKtVBRgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgez +Tv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pyehizKV/Ma5ciSixqClnrDvFAS +adgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vMBhBgu4M1t15n +3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQ +F/xlhMcQSZDe28cmk4gmb3DWAl45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTf +CVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuAL55MYIR4PSFk1vtBHxgP58l1cb29 +XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMoclm2q8KMZiYcdywm +djWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tMpkT/ +WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jb +AoJnwTnbw3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksq +P/ujmv5zMnHCnsZy4YpoJ/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Ko +b7a6bINDd82Kkhehnlt4Fj1F4jNy3eFmypnTycUm/Q1oBEauttmbjL4ZvrHG8hnj +XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P +5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7zAYspsbi +DrW5viSP +-----END CERTIFICATE----- + +# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Subject: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Label: "Hellenic Academic and Research Institutions RootCA 2015" +# Serial: 0 +# MD5 Fingerprint: ca:ff:e2:db:03:d9:cb:4b:e9:0f:ad:84:fd:7b:18:ce +# SHA1 Fingerprint: 01:0c:06:95:a6:98:19:14:ff:bf:5f:c6:b0:b6:95:ea:29:e9:12:a6 +# SHA256 Fingerprint: a0:40:92:9a:02:ce:53:b4:ac:f4:f2:ff:c6:98:1c:e4:49:6f:75:5e:6d:45:fe:0b:2a:69:2b:cd:52:52:3f:36 +-----BEGIN CERTIFICATE----- +MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1Ix +DzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5k +IFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMT +N0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9v +dENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAxMTIxWjCBpjELMAkG +A1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNh +ZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkx +QDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 +dGlvbnMgUm9vdENBIDIwMTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQDC+Kk/G4n8PDwEXT2QNrCROnk8ZlrvbTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA +4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+ehiGsxr/CL0BgzuNtFajT0 +AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+6PAQZe10 +4S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06C +ojXdFPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV +9Cz82XBST3i4vTwri5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrD +gfgXy5I2XdGj2HUb4Ysn6npIQf1FGQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6 +Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2fu/Z8VFRfS0myGlZYeCsargq +NhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9muiNX6hME6wGko +LfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc +Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVd +ctA4GGqd83EkVAswDQYJKoZIhvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0I +XtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+D1hYc2Ryx+hFjtyp8iY/xnmMsVMI +M4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrMd/K4kPFox/la/vot +9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+yd+2V +Z5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/ea +j8GsGsVn82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnh +X9izjFk0WaSrT2y7HxjbdavYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQ +l033DlZdwJVqwjbDG2jJ9SrcR5q+ss7FJej6A7na+RZukYT1HCjI/CbM1xyQVqdf +bzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVtJ94Cj8rDtSvK6evIIVM4 +pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGaJI7ZjnHK +e7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0 +vm9qp/UsQu0yrbYhnr68 +-----END CERTIFICATE----- + +# Issuer: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Subject: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Label: "Hellenic Academic and Research Institutions ECC RootCA 2015" +# Serial: 0 +# MD5 Fingerprint: 81:e5:b4:17:eb:c2:f5:e1:4b:0d:41:7b:49:92:fe:ef +# SHA1 Fingerprint: 9f:f1:71:8d:92:d5:9a:f3:7d:74:97:b4:bc:6f:84:68:0b:ba:b6:66 +# SHA256 Fingerprint: 44:b5:45:aa:8a:25:e6:5a:73:ca:15:dc:27:fc:36:d2:4c:1c:b9:95:3a:06:65:39:b1:15:82:dc:48:7b:48:33 +-----BEGIN CERTIFICATE----- +MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzAN +BgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hl +bGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgRUNDIFJv +b3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEwMzcxMlowgaoxCzAJ +BgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFj +YWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5 +MUQwQgYDVQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0 +dXRpb25zIEVDQyBSb290Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKg +QehLgoRc4vgxEZmGZE4JJS+dQS8KrjVPdJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJa +jq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoKVlp8aQuqgAkkbH7BRqNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLQi +C4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaep +lSTAGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7Sof +TUwJCA3sS61kFyjndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR +-----END CERTIFICATE----- + +# Issuer: CN=ISRG Root X1 O=Internet Security Research Group +# Subject: CN=ISRG Root X1 O=Internet Security Research Group +# Label: "ISRG Root X1" +# Serial: 172886928669790476064670243504169061120 +# MD5 Fingerprint: 0c:d2:f9:e0:da:17:73:e9:ed:86:4d:a5:e3:70:e7:4e +# SHA1 Fingerprint: ca:bd:2a:79:a1:07:6a:31:f2:1d:25:36:35:cb:03:9d:43:29:a5:e8 +# SHA256 Fingerprint: 96:bc:ec:06:26:49:76:f3:74:60:77:9a:cf:28:c5:a7:cf:e8:a3:c0:aa:e1:1a:8f:fc:ee:05:c0:bd:df:08:c6 +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- + +# Issuer: O=FNMT-RCM OU=AC RAIZ FNMT-RCM +# Subject: O=FNMT-RCM OU=AC RAIZ FNMT-RCM +# Label: "AC RAIZ FNMT-RCM" +# Serial: 485876308206448804701554682760554759 +# MD5 Fingerprint: e2:09:04:b4:d3:bd:d1:a0:14:fd:1a:d2:47:c4:57:1d +# SHA1 Fingerprint: ec:50:35:07:b2:15:c4:95:62:19:e2:a8:9a:5b:42:99:2c:4c:2c:20 +# SHA256 Fingerprint: eb:c5:57:0c:29:01:8c:4d:67:b1:aa:12:7b:af:12:f7:03:b4:61:1e:bc:17:b7:da:b5:57:38:94:17:9b:93:fa +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx +CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ +WiBGTk1ULVJDTTAeFw0wODEwMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJ +BgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBG +Tk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALpxgHpMhm5/ +yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcfqQgf +BBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAz +WHFctPVrbtQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxF +tBDXaEAUwED653cXeuYLj2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z +374jNUUeAlz+taibmSXaXvMiwzn15Cou08YfxGyqxRxqAQVKL9LFwag0Jl1mpdIC +IfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mwWsXmo8RZZUc1g16p6DUL +mbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnTtOmlcYF7 +wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peS +MKGJ47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2 +ZSysV4999AeU14ECll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMet +UqIJ5G+GR4of6ygnXYMgrwTJbFaai0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPd9xf3E6Jobd2Sn9R2gzL+H +YJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwOi8vd3d3 +LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD +nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1 +RXxlDPiyN8+sD8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYM +LVN0V2Ue1bLdI4E7pWYjJ2cJj+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf +77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrTQfv6MooqtyuGC2mDOL7Nii4LcK2N +JpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW+YJF1DngoABd15jm +fZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7Ixjp +6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp +1txyM/1d8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B +9kiABdcPUXmsEKvU7ANm5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wok +RqEIr9baRRmW1FMdW4R58MD3R++Lj8UGrp1MYp3/RgT408m2ECVAdf4WqslKYIYv +uu8wd+RU4riEmViAqhOLUTpPSPaLtrM= +-----END CERTIFICATE----- + +# Issuer: CN=Amazon Root CA 1 O=Amazon +# Subject: CN=Amazon Root CA 1 O=Amazon +# Label: "Amazon Root CA 1" +# Serial: 143266978916655856878034712317230054538369994 +# MD5 Fingerprint: 43:c6:bf:ae:ec:fe:ad:2f:18:c6:88:68:30:fc:c8:e6 +# SHA1 Fingerprint: 8d:a7:f9:65:ec:5e:fc:37:91:0f:1c:6e:59:fd:c1:cc:6a:6e:de:16 +# SHA256 Fingerprint: 8e:cd:e6:88:4f:3d:87:b1:12:5b:a3:1a:c3:fc:b1:3d:70:16:de:7f:57:cc:90:4f:e1:cb:97:c6:ae:98:19:6e +-----BEGIN CERTIFICATE----- +MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj +ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM +9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw +IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 +VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L +93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm +jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA +A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI +U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs +N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv +o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU +5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy +rqXRfboQnoZsG4q5WTP468SQvvG5 +-----END CERTIFICATE----- + +# Issuer: CN=Amazon Root CA 2 O=Amazon +# Subject: CN=Amazon Root CA 2 O=Amazon +# Label: "Amazon Root CA 2" +# Serial: 143266982885963551818349160658925006970653239 +# MD5 Fingerprint: c8:e5:8d:ce:a8:42:e2:7a:c0:2a:5c:7c:9e:26:bf:66 +# SHA1 Fingerprint: 5a:8c:ef:45:d7:a6:98:59:76:7a:8c:8b:44:96:b5:78:cf:47:4b:1a +# SHA256 Fingerprint: 1b:a5:b2:aa:8c:65:40:1a:82:96:01:18:f8:0b:ec:4f:62:30:4d:83:ce:c4:71:3a:19:c3:9c:01:1e:a4:6d:b4 +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK +gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ +W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg +1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K +8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r +2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me +z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR +8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj +mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz +7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6 ++XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI +0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB +Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm +UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2 +LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY ++gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS +k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl +7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm +btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl +urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+ +fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63 +n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE +76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H +9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT +4PsJYGw= +-----END CERTIFICATE----- + +# Issuer: CN=Amazon Root CA 3 O=Amazon +# Subject: CN=Amazon Root CA 3 O=Amazon +# Label: "Amazon Root CA 3" +# Serial: 143266986699090766294700635381230934788665930 +# MD5 Fingerprint: a0:d4:ef:0b:f7:b5:d8:49:95:2a:ec:f5:c4:fc:81:87 +# SHA1 Fingerprint: 0d:44:dd:8c:3c:8c:1a:1a:58:75:64:81:e9:0f:2e:2a:ff:b3:d2:6e +# SHA256 Fingerprint: 18:ce:6c:fe:7b:f1:4e:60:b2:e3:47:b8:df:e8:68:cb:31:d0:2e:bb:3a:da:27:15:69:f5:03:43:b4:6d:b3:a4 +-----BEGIN CERTIFICATE----- +MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl +ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr +ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr +BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM +YyRIHN8wfdVoOw== +-----END CERTIFICATE----- + +# Issuer: CN=Amazon Root CA 4 O=Amazon +# Subject: CN=Amazon Root CA 4 O=Amazon +# Label: "Amazon Root CA 4" +# Serial: 143266989758080763974105200630763877849284878 +# MD5 Fingerprint: 89:bc:27:d5:eb:17:8d:06:6a:69:d5:fd:89:47:b4:cd +# SHA1 Fingerprint: f6:10:84:07:d6:f8:bb:67:98:0c:c2:e2:44:c2:eb:ae:1c:ef:63:be +# SHA256 Fingerprint: e3:5d:28:41:9e:d0:20:25:cf:a6:90:38:cd:62:39:62:45:8d:a5:c6:95:fb:de:a3:c2:2b:0b:fb:25:89:70:92 +-----BEGIN CERTIFICATE----- +MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi +9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk +M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB +MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw +CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW +1KyLa2tJElMzrdfkviT8tQp21KW8EA== +-----END CERTIFICATE----- + +# Issuer: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM +# Subject: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM +# Label: "TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1" +# Serial: 1 +# MD5 Fingerprint: dc:00:81:dc:69:2f:3e:2f:b0:3b:f6:3d:5a:91:8e:49 +# SHA1 Fingerprint: 31:43:64:9b:ec:ce:27:ec:ed:3a:3f:0b:8f:0d:e4:e8:91:dd:ee:ca +# SHA256 Fingerprint: 46:ed:c3:68:90:46:d5:3a:45:3f:b3:10:4a:b8:0d:ca:ec:65:8b:26:60:ea:16:29:dd:7e:86:79:90:64:87:16 +-----BEGIN CERTIFICATE----- +MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx +GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp +bXNlbCB2ZSBUZWtub2xvamlrIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0w +KwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24gTWVya2V6aSAtIEthbXUgU00xNjA0 +BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRpZmlrYXNpIC0gU3Vy +dW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYDVQQG +EwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXll +IEJpbGltc2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklU +QUsxLTArBgNVBAsTJEthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBT +TTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11IFNNIFNTTCBLb2sgU2VydGlmaWthc2kg +LSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr3UwM6q7 +a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y86Ij5iySr +LqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INr +N3wcwv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2X +YacQuFWQfw4tJzh03+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/ +iSIzL+aFCr2lqBs23tPcLG07xxO9WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4f +AJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQUZT/HiobGPN08VFw1+DrtUgxH +V8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh +AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPf +IPP54+M638yclNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4 +lzwDGrpDxpa5RXI4s6ehlj2Re37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c +8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0jq5Rm+K37DwhuJi1/FwcJsoz7UMCf +lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= +-----END CERTIFICATE----- + +# Issuer: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD. +# Subject: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD. +# Label: "GDCA TrustAUTH R5 ROOT" +# Serial: 9009899650740120186 +# MD5 Fingerprint: 63:cc:d9:3d:34:35:5c:6f:53:a3:e2:08:70:48:1f:b4 +# SHA1 Fingerprint: 0f:36:38:5b:81:1a:25:c3:9b:31:4e:83:ca:e9:34:66:70:cc:74:b4 +# SHA256 Fingerprint: bf:ff:8f:d0:44:33:48:7d:6a:8a:a6:0c:1a:29:76:7a:9f:c2:bb:b0:5e:42:0f:71:3a:13:b9:92:89:1d:38:93 +-----BEGIN CERTIFICATE----- +MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE +BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ +IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0 +MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVowYjELMAkGA1UEBhMCQ04xMjAwBgNV +BAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8w +HQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJj +Dp6L3TQsAlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBj +TnnEt1u9ol2x8kECK62pOqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+u +KU49tm7srsHwJ5uu4/Ts765/94Y9cnrrpftZTqfrlYwiOXnhLQiPzLyRuEH3FMEj +qcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ9Cy5WmYqsBebnh52nUpm +MUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQxXABZG12 +ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloP +zgsMR6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3Gk +L30SgLdTMEZeS1SZD2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeC +jGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4oR24qoAATILnsn8JuLwwoC8N9VKejveSswoA +HQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx9hoh49pwBiFYFIeFd3mqgnkC +AwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlRMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg +p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZm +DRd9FBUb1Ov9H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5 +COmSdI31R9KrO9b7eGZONn356ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ry +L3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd+PwyvzeG5LuOmCd+uh8W4XAR8gPf +JWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQHtZa37dG/OaG+svg +IHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBDF8Io +2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV +09tL7ECQ8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQ +XR4EzzffHqhmsYzmIGrv/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrq +T8p+ck0LcIymSLumoRT2+1hEmRSuqguTaaApJUqlyyvdimYHFngVV3Eb7PVHhPOe +MTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== +-----END CERTIFICATE----- + +# Issuer: CN=TrustCor RootCert CA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Subject: CN=TrustCor RootCert CA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Label: "TrustCor RootCert CA-1" +# Serial: 15752444095811006489 +# MD5 Fingerprint: 6e:85:f1:dc:1a:00:d3:22:d5:b2:b2:ac:6b:37:05:45 +# SHA1 Fingerprint: ff:bd:cd:e7:82:c8:43:5e:3c:6f:26:86:5c:ca:a8:3a:45:5b:c3:0a +# SHA256 Fingerprint: d4:0e:9c:86:cd:8f:e4:68:c1:77:69:59:f4:9e:a7:74:fa:54:86:84:b6:c4:06:f3:90:92:61:f4:dc:e2:57:5c +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIJANqb7HHzA7AZMA0GCSqGSIb3DQEBCwUAMIGkMQswCQYD +VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk +MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U +cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRydXN0Q29y +IFJvb3RDZXJ0IENBLTEwHhcNMTYwMjA0MTIzMjE2WhcNMjkxMjMxMTcyMzE2WjCB +pDELMAkGA1UEBhMCUEExDzANBgNVBAgMBlBhbmFtYTEUMBIGA1UEBwwLUGFuYW1h +IENpdHkxJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4gZGUgUi5MLjEnMCUG +A1UECwweVHJ1c3RDb3IgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYDVQQDDBZU +cnVzdENvciBSb290Q2VydCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAv463leLCJhJrMxnHQFgKq1mqjQCj/IDHUHuO1CAmujIS2CNUSSUQIpid +RtLByZ5OGy4sDjjzGiVoHKZaBeYei0i/mJZ0PmnK6bV4pQa81QBeCQryJ3pS/C3V +seq0iWEk8xoT26nPUu0MJLq5nux+AHT6k61sKZKuUbS701e/s/OojZz0JEsq1pme +9J7+wH5COucLlVPat2gOkEz7cD+PSiyU8ybdY2mplNgQTsVHCJCZGxdNuWxu72CV +EY4hgLW9oHPY0LJ3xEXqWib7ZnZ2+AYfYW0PVcWDtxBWcgYHpfOxGgMFZA6dWorW +hnAbJN7+KIor0Gqw/Hqi3LJ5DotlDwIDAQABo2MwYTAdBgNVHQ4EFgQU7mtJPHo/ +DeOxCbeKyKsZn3MzUOcwHwYDVR0jBBgwFoAU7mtJPHo/DeOxCbeKyKsZn3MzUOcw +DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD +ggEBACUY1JGPE+6PHh0RU9otRCkZoB5rMZ5NDp6tPVxBb5UrJKF5mDo4Nvu7Zp5I +/5CQ7z3UuJu0h3U/IJvOcs+hVcFNZKIZBqEHMwwLKeXx6quj7LUKdJDHfXLy11yf +ke+Ri7fc7Waiz45mO7yfOgLgJ90WmMCV1Aqk5IGadZQ1nJBfiDcGrVmVCrDRZ9MZ +yonnMlo2HD6CqFqTvsbQZJG2z9m2GM/bftJlo6bEjhcxwft+dtvTheNYsnd6djts +L1Ac59v2Z3kf9YKVmgenFK+P3CghZwnS1k1aHBkcjndcw5QkPTJrS37UeJSDvjdN +zl/HHk484IkzlQsPpTLWPFp5LBk= +-----END CERTIFICATE----- + +# Issuer: CN=TrustCor RootCert CA-2 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Subject: CN=TrustCor RootCert CA-2 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Label: "TrustCor RootCert CA-2" +# Serial: 2711694510199101698 +# MD5 Fingerprint: a2:e1:f8:18:0b:ba:45:d5:c7:41:2a:bb:37:52:45:64 +# SHA1 Fingerprint: b8:be:6d:cb:56:f1:55:b9:63:d4:12:ca:4e:06:34:c7:94:b2:1c:c0 +# SHA256 Fingerprint: 07:53:e9:40:37:8c:1b:d5:e3:83:6e:39:5d:ae:a5:cb:83:9e:50:46:f1:bd:0e:ae:19:51:cf:10:fe:c7:c9:65 +-----BEGIN CERTIFICATE----- +MIIGLzCCBBegAwIBAgIIJaHfyjPLWQIwDQYJKoZIhvcNAQELBQAwgaQxCzAJBgNV +BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw +IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy +dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEfMB0GA1UEAwwWVHJ1c3RDb3Ig +Um9vdENlcnQgQ0EtMjAeFw0xNjAyMDQxMjMyMjNaFw0zNDEyMzExNzI2MzlaMIGk +MQswCQYDVQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEg +Q2l0eTEkMCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYD +VQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRy +dXN0Q29yIFJvb3RDZXJ0IENBLTIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCnIG7CKqJiJJWQdsg4foDSq8GbZQWU9MEKENUCrO2fk8eHyLAnK0IMPQo+ +QVqedd2NyuCb7GgypGmSaIwLgQ5WoD4a3SwlFIIvl9NkRvRUqdw6VC0xK5mC8tkq +1+9xALgxpL56JAfDQiDyitSSBBtlVkxs1Pu2YVpHI7TYabS3OtB0PAx1oYxOdqHp +2yqlO/rOsP9+aij9JxzIsekp8VduZLTQwRVtDr4uDkbIXvRR/u8OYzo7cbrPb1nK +DOObXUm4TOJXsZiKQlecdu/vvdFoqNL0Cbt3Nb4lggjEFixEIFapRBF37120Hape +az6LMvYHL1cEksr1/p3C6eizjkxLAjHZ5DxIgif3GIJ2SDpxsROhOdUuxTTCHWKF +3wP+TfSvPd9cW436cOGlfifHhi5qjxLGhF5DUVCcGZt45vz27Ud+ez1m7xMTiF88 +oWP7+ayHNZ/zgp6kPwqcMWmLmaSISo5uZk3vFsQPeSghYA2FFn3XVDjxklb9tTNM +g9zXEJ9L/cb4Qr26fHMC4P99zVvh1Kxhe1fVSntb1IVYJ12/+CtgrKAmrhQhJ8Z3 +mjOAPF5GP/fDsaOGM8boXg25NSyqRsGFAnWAoOsk+xWq5Gd/bnc/9ASKL3x74xdh +8N0JqSDIvgmk0H5Ew7IwSjiqqewYmgeCK9u4nBit2uBGF6zPXQIDAQABo2MwYTAd +BgNVHQ4EFgQU2f4hQG6UnrybPZx9mCAZ5YwwYrIwHwYDVR0jBBgwFoAU2f4hQG6U +nrybPZx9mCAZ5YwwYrIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYw +DQYJKoZIhvcNAQELBQADggIBAJ5Fngw7tu/hOsh80QA9z+LqBrWyOrsGS2h60COX +dKcs8AjYeVrXWoSK2BKaG9l9XE1wxaX5q+WjiYndAfrs3fnpkpfbsEZC89NiqpX+ +MWcUaViQCqoL7jcjx1BRtPV+nuN79+TMQjItSQzL/0kMmx40/W5ulop5A7Zv2wnL +/V9lFDfhOPXzYRZY5LVtDQsEGz9QLX+zx3oaFoBg+Iof6Rsqxvm6ARppv9JYx1RX +CI/hOWB3S6xZhBqI8d3LT3jX5+EzLfzuQfogsL7L9ziUwOHQhQ+77Sxzq+3+knYa +ZH9bDTMJBzN7Bj8RpFxwPIXAz+OQqIN3+tvmxYxoZxBnpVIt8MSZj3+/0WvitUfW +2dCFmU2Umw9Lje4AWkcdEQOsQRivh7dvDDqPys/cA8GiCcjl/YBeyGBCARsaU1q7 +N6a3vLqE6R5sGtRk2tRD/pOLS/IseRYQ1JMLiI+h2IYURpFHmygk71dSTlxCnKr3 +Sewn6EAes6aJInKc9Q0ztFijMDvd1GpUk74aTfOTlPf8hAs/hCBcNANExdqtvArB +As8e5ZTZ845b2EzwnexhF7sUMlQMAimTHpKG9n/v55IFDlndmQguLvqcAFLTxWYp +5KeXRKQOKIETNcX2b2TmQcTVL8w0RSXPQQCWPUouwpaYT05KnJe32x+SMsj/D1Fu +1uwJ +-----END CERTIFICATE----- + +# Issuer: CN=TrustCor ECA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Subject: CN=TrustCor ECA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Label: "TrustCor ECA-1" +# Serial: 9548242946988625984 +# MD5 Fingerprint: 27:92:23:1d:0a:f5:40:7c:e9:e6:6b:9d:d8:f5:e7:6c +# SHA1 Fingerprint: 58:d1:df:95:95:67:6b:63:c0:f0:5b:1c:17:4d:8b:84:0b:c8:78:bd +# SHA256 Fingerprint: 5a:88:5d:b1:9c:01:d9:12:c5:75:93:88:93:8c:af:bb:df:03:1a:b2:d4:8e:91:ee:15:58:9b:42:97:1d:03:9c +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIJAISCLF8cYtBAMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYD +VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk +MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U +cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxFzAVBgNVBAMMDlRydXN0Q29y +IEVDQS0xMB4XDTE2MDIwNDEyMzIzM1oXDTI5MTIzMTE3MjgwN1owgZwxCzAJBgNV +BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw +IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy +dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAwwOVHJ1c3RDb3Ig +RUNBLTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPj+ARtZ+odnbb +3w9U73NjKYKtR8aja+3+XzP4Q1HpGjORMRegdMTUpwHmspI+ap3tDvl0mEDTPwOA +BoJA6LHip1GnHYMma6ve+heRK9jGrB6xnhkB1Zem6g23xFUfJ3zSCNV2HykVh0A5 +3ThFEXXQmqc04L/NyFIduUd+Dbi7xgz2c1cWWn5DkR9VOsZtRASqnKmcp0yJF4Ou +owReUoCLHhIlERnXDH19MURB6tuvsBzvgdAsxZohmz3tQjtQJvLsznFhBmIhVE5/ +wZ0+fyCMgMsq2JdiyIMzkX2woloPV+g7zPIlstR8L+xNxqE6FXrntl019fZISjZF +ZtS6mFjBAgMBAAGjYzBhMB0GA1UdDgQWBBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAf +BgNVHSMEGDAWgBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAPBgNVHRMBAf8EBTADAQH/ +MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEABT41XBVwm8nHc2Fv +civUwo/yQ10CzsSUuZQRg2dd4mdsdXa/uwyqNsatR5Nj3B5+1t4u/ukZMjgDfxT2 +AHMsWbEhBuH7rBiVDKP/mZb3Kyeb1STMHd3BOuCYRLDE5D53sXOpZCz2HAF8P11F +hcCF5yWPldwX8zyfGm6wyuMdKulMY/okYWLW2n62HGz1Ah3UKt1VkOsqEUc8Ll50 +soIipX1TH0XsJ5F95yIW6MBoNtjG8U+ARDL54dHRHareqKucBK+tIA5kmE2la8BI +WJZpTdwHjFGTot+fDz2LYLSCjaoITmJF4PkL0uDgPFveXHEnJcLmA4GLEFPjx1Wi +tJ/X5g== +-----END CERTIFICATE----- + +# Issuer: CN=SSL.com Root Certification Authority RSA O=SSL Corporation +# Subject: CN=SSL.com Root Certification Authority RSA O=SSL Corporation +# Label: "SSL.com Root Certification Authority RSA" +# Serial: 8875640296558310041 +# MD5 Fingerprint: 86:69:12:c0:70:f1:ec:ac:ac:c2:d5:bc:a5:5b:a1:29 +# SHA1 Fingerprint: b7:ab:33:08:d1:ea:44:77:ba:14:80:12:5a:6f:bd:a9:36:49:0c:bb +# SHA256 Fingerprint: 85:66:6a:56:2e:e0:be:5c:e9:25:c1:d8:89:0a:6f:76:a8:7e:c1:6d:4d:7d:5f:29:ea:74:19:cf:20:12:3b:69 +-----BEGIN CERTIFICATE----- +MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE +BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK +DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTczOTM5WhcNNDEwMjEyMTcz +OTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv +dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv +bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2R +xFdHaxh3a3by/ZPkPQ/CFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aX +qhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcC +C52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/geoeOy3ZExqysdBP+lSgQ3 +6YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkpk8zruFvh +/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrF +YD3ZfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93E +JNyAKoFBbZQ+yODJgUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVc +US4cK38acijnALXRdMbX5J+tB5O2UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8 +ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi81xtZPCvM8hnIk2snYxnP/Okm ++Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4sbE6x/c+cCbqi +M+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4G +A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGV +cpNxJK1ok1iOMq8bs3AD/CUrdIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBc +Hadm47GUBwwyOabqG7B52B2ccETjit3E+ZUfijhDPwGFpUenPUayvOUiaPd7nNgs +PgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAslu1OJD7OAUN5F7kR/ +q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjqerQ0 +cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jr +a6x+3uxjMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90I +H37hVZkLId6Tngr75qNJvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/Y +K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu +nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf +oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY +Ic2wBlX7Jz9TkHCpBB5XJ7k= +-----END CERTIFICATE----- + +# Issuer: CN=SSL.com Root Certification Authority ECC O=SSL Corporation +# Subject: CN=SSL.com Root Certification Authority ECC O=SSL Corporation +# Label: "SSL.com Root Certification Authority ECC" +# Serial: 8495723813297216424 +# MD5 Fingerprint: 2e:da:e4:39:7f:9c:8f:37:d1:70:9f:26:17:51:3a:8e +# SHA1 Fingerprint: c3:19:7c:39:24:e6:54:af:1b:c4:ab:20:95:7a:e2:c3:0e:13:02:6a +# SHA256 Fingerprint: 34:17:bb:06:cc:60:07:da:1b:96:1c:92:0b:8a:b4:ce:3f:ad:82:0e:4a:a3:0b:9a:cb:c4:a7:4e:bd:ce:bc:65 +-----BEGIN CERTIFICATE----- +MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC +VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T +U0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNDAzWhcNNDEwMjEyMTgxNDAz +WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0 +b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBS +b290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB +BAAiA2IABEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI +7Z4INcgn64mMU1jrYor+8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPg +CemB+vNH06NjMGEwHQYDVR0OBBYEFILRhXMw5zUE044CkvvlpNHEIejNMA8GA1Ud +EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTTjgKS++Wk0cQh6M0wDgYD +VR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCWe+0F+S8T +kdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+ +gA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl +-----END CERTIFICATE----- + +# Issuer: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation +# Subject: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation +# Label: "SSL.com EV Root Certification Authority RSA R2" +# Serial: 6248227494352943350 +# MD5 Fingerprint: e1:1e:31:58:1a:ae:54:53:02:f6:17:6a:11:7b:4d:95 +# SHA1 Fingerprint: 74:3a:f0:52:9b:d0:32:a0:f4:4a:83:cd:d4:ba:a9:7b:7c:2e:c4:9a +# SHA256 Fingerprint: 2e:7b:f1:6c:c2:24:85:a7:bb:e2:aa:86:96:75:07:61:b0:ae:39:be:3b:2f:e9:d0:cc:6d:4e:f7:34:91:42:5c +-----BEGIN CERTIFICATE----- +MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV +BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE +CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMB4XDTE3MDUzMTE4MTQzN1oXDTQy +MDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G +A1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQD +DC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvq +M0fNTPl9fb69LT3w23jhhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssuf +OePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7wcXHswxzpY6IXFJ3vG2fThVUCAtZJycxa +4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTOZw+oz12WGQvE43LrrdF9 +HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+B6KjBSYR +aZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcA +b9ZhCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQ +Gp8hLH94t2S42Oim9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQV +PWKchjgGAGYS5Fl2WlPAApiiECtoRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMO +pgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+SlmJuwgUHfbSguPvuUCYHBBXtSu +UDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48+qvWBkofZ6aY +MBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV +HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa4 +9QaAJadz20ZpqJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBW +s47LCp1Jjr+kxJG7ZhcFUZh1++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5 +Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nxY/hoLVUE0fKNsKTPvDxeH3jnpaAg +cLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2GguDKBAdRUNf/ktUM +79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDzOFSz +/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXt +ll9ldDz7CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEm +Kf7GUmG6sXP/wwyc5WxqlD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKK +QbNmC1r7fSOl8hqw/96bg5Qu0T/fkreRrwU7ZcegbLHNYhLDkBvjJc40vG93drEQ +w/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1hlMYegouCRw2n5H9gooi +S9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX9hwJ1C07 +mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== +-----END CERTIFICATE----- + +# Issuer: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation +# Subject: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation +# Label: "SSL.com EV Root Certification Authority ECC" +# Serial: 3182246526754555285 +# MD5 Fingerprint: 59:53:22:65:83:42:01:54:c0:ce:42:b9:5a:7c:f2:90 +# SHA1 Fingerprint: 4c:dd:51:a3:d1:f5:20:32:14:b0:c6:c5:32:23:03:91:c7:46:42:6d +# SHA256 Fingerprint: 22:a2:c1:f7:bd:ed:70:4c:c1:e7:01:b5:f4:08:c3:10:88:0f:e9:56:b5:de:2a:4a:44:f9:9c:87:3a:25:a7:c8 +-----BEGIN CERTIFICATE----- +MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMC +VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T +U0wgQ29ycG9yYXRpb24xNDAyBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNTIzWhcNNDEwMjEyMTgx +NTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv +dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NMLmNv +bSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMA +VIbc/R/fALhBYlzccBYy3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1Kthku +WnBaBu2+8KGwytAJKaNjMGEwHQYDVR0OBBYEFFvKXuXe0oGqzagtZFG22XKbl+ZP +MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe5d7SgarNqC1kUbbZcpuX +5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJN+vp1RPZ +ytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZg +h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6 +# Label: "GlobalSign Root CA - R6" +# Serial: 1417766617973444989252670301619537 +# MD5 Fingerprint: 4f:dd:07:e4:d4:22:64:39:1e:0c:37:42:ea:d1:c6:ae +# SHA1 Fingerprint: 80:94:64:0e:b5:a7:a1:ca:11:9c:1f:dd:d5:9f:81:02:63:a7:fb:d1 +# SHA256 Fingerprint: 2c:ab:ea:fe:37:d0:6c:a2:2a:ba:73:91:c0:03:3d:25:98:29:52:c4:53:64:73:49:76:3a:3a:b5:ad:6c:cf:69 +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg +MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh +bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx +MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET +MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI +xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k +ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD +aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw +LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw +1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX +k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2 +SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h +bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n +WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY +rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce +MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu +bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN +nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt +Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61 +55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj +vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf +cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz +oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp +nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs +pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v +JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R +8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4 +5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= +-----END CERTIFICATE----- + +# Issuer: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed +# Subject: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed +# Label: "OISTE WISeKey Global Root GC CA" +# Serial: 44084345621038548146064804565436152554 +# MD5 Fingerprint: a9:d6:b9:2d:2f:93:64:f8:a5:69:ca:91:e9:68:07:23 +# SHA1 Fingerprint: e0:11:84:5e:34:de:be:88:81:b9:9c:f6:16:26:d1:96:1f:c3:b9:31 +# SHA256 Fingerprint: 85:60:f9:1c:36:24:da:ba:95:70:b5:fe:a0:db:e3:6f:f1:1a:83:23:be:94:86:85:4f:b3:f3:4a:55:71:19:8d +-----BEGIN CERTIFICATE----- +MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQsw +CQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91 +bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwg +Um9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRaFw00MjA1MDkwOTU4MzNaMG0xCzAJ +BgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBGb3Vu +ZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2JhbCBS +b290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4ni +eUqjFqdrVCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4W +p2OQ0jnUsYd4XxiWD1AbNTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7T +rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV +57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg +Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 +-----END CERTIFICATE----- + +# Issuer: CN=GTS Root R1 O=Google Trust Services LLC +# Subject: CN=GTS Root R1 O=Google Trust Services LLC +# Label: "GTS Root R1" +# Serial: 146587175971765017618439757810265552097 +# MD5 Fingerprint: 82:1a:ef:d4:d2:4a:f2:9f:e2:3d:97:06:14:70:72:85 +# SHA1 Fingerprint: e1:c9:50:e6:ef:22:f8:4c:56:45:72:8b:92:20:60:d7:d5:a7:a3:e8 +# SHA256 Fingerprint: 2a:57:54:71:e3:13:40:bc:21:58:1c:bd:2c:f1:3e:15:84:63:20:3e:ce:94:bc:f9:d3:cc:19:6b:f0:9a:54:72 +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBH +MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM +QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy +MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl +cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM +f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vX +mX7wCl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7 +zUjwTcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0P +fyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtc +vfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4 +Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUsp +zBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOO +Rc92wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYW +k70paDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+ +DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgF +lQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBADiW +Cu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1 +d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6Z +XPYfcX3v73svfuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZR +gyFmxhE+885H7pwoHyXa/6xmld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3 +d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9bgsiG1eGZbYwE8na6SfZu6W0eX6Dv +J4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq4BjFbkerQUIpm/Zg +DdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWErtXvM ++SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyy +F62ARPBopY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9 +SQ98POyDGCBDTtWTurQ0sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdws +E3PYJ/HQcu51OyLemGhmW/HGY0dVHLqlCFF1pkgl +-----END CERTIFICATE----- + +# Issuer: CN=GTS Root R2 O=Google Trust Services LLC +# Subject: CN=GTS Root R2 O=Google Trust Services LLC +# Label: "GTS Root R2" +# Serial: 146587176055767053814479386953112547951 +# MD5 Fingerprint: 44:ed:9a:0e:a4:09:3b:00:f2:ae:4c:a3:c6:61:b0:8b +# SHA1 Fingerprint: d2:73:96:2a:2a:5e:39:9f:73:3f:e1:c7:1e:64:3f:03:38:34:fc:4d +# SHA256 Fingerprint: c4:5d:7b:b0:8e:6d:67:e6:2e:42:35:11:0b:56:4e:5f:78:fd:92:ef:05:8c:84:0a:ea:4e:64:55:d7:58:5c:60 +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBH +MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM +QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy +MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl +cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv +CvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3Kg +GjSY6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9Bu +XvAuMC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOd +re7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXu +PuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1 +mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K +8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqj +x5RWIr9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsR +nTKaG73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0 +kzCqgc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9Ok +twIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBALZp +8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT +vhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiT +z9D2PGcDFWEJ+YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiA +pJiS4wGWAqoC7o87xdFtCjMwc3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvb +pxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3DaWsYDQvTtN6LwG1BUSw7YhN4ZKJmB +R64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5rn/WkhLx3+WuXrD5R +RaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56GtmwfuNmsk +0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC +5AwiWVIQ7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiF +izoHCBy69Y9Vmhh1fuXsgWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLn +yOd/xCxgXS/Dr55FBcOEArf9LAhST4Ldo/DUhgkC +-----END CERTIFICATE----- + +# Issuer: CN=GTS Root R3 O=Google Trust Services LLC +# Subject: CN=GTS Root R3 O=Google Trust Services LLC +# Label: "GTS Root R3" +# Serial: 146587176140553309517047991083707763997 +# MD5 Fingerprint: 1a:79:5b:6b:04:52:9c:5d:c7:74:33:1b:25:9a:f9:25 +# SHA1 Fingerprint: 30:d4:24:6f:07:ff:db:91:89:8a:0b:e9:49:66:11:eb:8c:5e:46:e5 +# SHA256 Fingerprint: 15:d5:b8:77:46:19:ea:7d:54:ce:1c:a6:d0:b0:c4:03:e0:37:a9:17:f1:31:e8:a0:4e:1e:6b:7a:71:ba:bc:e5 +-----BEGIN CERTIFICATE----- +MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout +736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2A +DDL24CejQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFuk +fCPAlaUs3L6JbyO5o91lAFJekazInXJ0glMLfalAvWhgxeG4VDvBNhcl2MG9AjEA +njWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOaKaqW04MjyaR7YbPMAuhd +-----END CERTIFICATE----- + +# Issuer: CN=GTS Root R4 O=Google Trust Services LLC +# Subject: CN=GTS Root R4 O=Google Trust Services LLC +# Label: "GTS Root R4" +# Serial: 146587176229350439916519468929765261721 +# MD5 Fingerprint: 5d:b6:6a:c4:60:17:24:6a:1a:99:a8:4b:ee:5e:b4:26 +# SHA1 Fingerprint: 2a:1d:60:27:d9:4a:b1:0a:1c:4d:91:5c:cd:33:a0:cb:3e:2d:54:cb +# SHA256 Fingerprint: 71:cc:a5:39:1f:9e:79:4b:04:80:25:30:b3:63:e1:21:da:8a:30:43:bb:26:66:2f:ea:4d:ca:7f:c9:51:a4:bd +-----BEGIN CERTIFICATE----- +MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu +hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/l +xKvRHYqjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0 +CMRw3J5QdCHojXohw0+WbhXRIjVhLfoIN+4Zba3bssx9BzT1YBkstTTZbyACMANx +sbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11xzPKwTdb+mciUqXWi4w== +-----END CERTIFICATE----- + +# Issuer: CN=UCA Global G2 Root O=UniTrust +# Subject: CN=UCA Global G2 Root O=UniTrust +# Label: "UCA Global G2 Root" +# Serial: 124779693093741543919145257850076631279 +# MD5 Fingerprint: 80:fe:f0:c4:4a:f0:5c:62:32:9f:1c:ba:78:a9:50:f8 +# SHA1 Fingerprint: 28:f9:78:16:19:7a:ff:18:25:18:aa:44:fe:c1:a0:ce:5c:b6:4c:8a +# SHA256 Fingerprint: 9b:ea:11:c9:76:fe:01:47:64:c1:be:56:a6:f9:14:b5:a5:60:31:7a:bd:99:88:39:33:82:e5:16:1a:a0:49:3c +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9 +MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBH +bG9iYWwgRzIgUm9vdDAeFw0xNjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0x +CzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlUcnVzdDEbMBkGA1UEAwwSVUNBIEds +b2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxeYr +b3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmToni9 +kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzm +VHqUwCoV8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/R +VogvGjqNO7uCEeBHANBSh6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDc +C/Vkw85DvG1xudLeJ1uK6NjGruFZfc8oLTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIj +tm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/R+zvWr9LesGtOxdQXGLY +D0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBeKW4bHAyv +j5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6Dl +NaBa4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6 +iIis7nCs+dwp4wwcOxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznP +O6Q0ibd5Ei9Hxeepl2n8pndntd978XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/ +BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIHEjMz15DD/pQwIX4wV +ZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo5sOASD0Ee/oj +L3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5 +1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl +1qnN3e92mI0ADs0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oU +b3n09tDh05S60FdRvScFDcH9yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LV +PtateJLbXDzz2K36uGt/xDYotgIVilQsnLAXc47QN6MUPJiVAAwpBVueSUmxX8fj +y88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHojhJi6IjMtX9Gl8Cb +EGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZkbxqg +DMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI ++Vg7RE+xygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGy +YiGqhkCyLmTTX8jjfhFnRR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bX +UB+K+wb1whnw0A== +-----END CERTIFICATE----- + +# Issuer: CN=UCA Extended Validation Root O=UniTrust +# Subject: CN=UCA Extended Validation Root O=UniTrust +# Label: "UCA Extended Validation Root" +# Serial: 106100277556486529736699587978573607008 +# MD5 Fingerprint: a1:f3:5f:43:c6:34:9b:da:bf:8c:7e:05:53:ad:96:e2 +# SHA1 Fingerprint: a3:a1:b0:6f:24:61:23:4a:e3:36:a5:c2:37:fc:a6:ff:dd:f0:d7:3a +# SHA256 Fingerprint: d4:3a:f9:b3:54:73:75:5c:96:84:fc:06:d7:d8:cb:70:ee:5c:28:e7:73:fb:29:4e:b4:1e:e7:17:22:92:4d:24 +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBH +MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBF +eHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMx +MDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNV +BAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrsiWog +D4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvS +sPGP2KxFRv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aop +O2z6+I9tTcg1367r3CTueUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dk +sHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR59mzLC52LqGj3n5qiAno8geK+LLNEOfi +c0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH0mK1lTnj8/FtDw5lhIpj +VMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KRel7sFsLz +KuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/ +TuDvB0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41G +sx2VYVdWf6/wFlthWG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs +1+lvK9JKBZP8nm9rZ/+I8U6laUpSNwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQD +fwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS3H5aBZ8eNJr34RQwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBADaN +l8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR +ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQ +VBcZEhrxH9cMaVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5 +c6sq1WnIeJEmMX3ixzDx/BR4dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp +4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb+7lsq+KePRXBOy5nAliRn+/4Qh8s +t2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOWF3sGPjLtx7dCvHaj +2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwiGpWO +vpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2C +xR9GUeOcGMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmx +cmtpzyKEC2IPrNkZAJSidjzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbM +fjKaiJUINlK73nZfdklJrX+9ZSCyycErdhh2n1ax +-----END CERTIFICATE----- + +# Issuer: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036 +# Subject: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036 +# Label: "Certigna Root CA" +# Serial: 269714418870597844693661054334862075617 +# MD5 Fingerprint: 0e:5c:30:62:27:eb:5b:bc:d7:ae:62:ba:e9:d5:df:77 +# SHA1 Fingerprint: 2d:0d:52:14:ff:9e:ad:99:24:01:74:20:47:6e:6c:85:27:27:f5:43 +# SHA256 Fingerprint: d4:8d:3d:23:ee:db:50:a4:59:e5:51:97:60:1c:27:77:4b:9d:7b:18:c9:4d:5a:05:95:11:a1:02:50:b9:31:68 +-----BEGIN CERTIFICATE----- +MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw +WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw +MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x +MzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjdaMFoxCzAJBgNVBAYTAkZSMRIwEAYD +VQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxGTAX +BgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sO +ty3tRQgXstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9M +CiBtnyN6tMbaLOQdLNyzKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPu +I9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8JXrJhFwLrN1CTivngqIkicuQstDuI7pm +TLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16XdG+RCYyKfHx9WzMfgIh +C59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq4NYKpkDf +ePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3Yz +IoejwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWT +Co/1VTp2lc5ZmIoJlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1k +JWumIWmbat10TWuXekG9qxf5kBdIjzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5 +hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp//TBt2dzhauH8XwIDAQABo4IB +GjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of +1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczov +L3d3d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilo +dHRwOi8vY3JsLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYr +aHR0cDovL2NybC5kaGlteW90aXMuY29tL2NlcnRpZ25hcm9vdGNhLmNybDANBgkq +hkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOItOoldaDgvUSILSo3L +6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxPTGRG +HVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH6 +0BGM+RFq7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncB +lA2c5uk5jR+mUYyZDDl34bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdi +o2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1 +gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS6Cvu5zHbugRqh5jnxV/v +faci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaYtlu3zM63 +Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh +jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw +3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= +-----END CERTIFICATE----- + +# Issuer: CN=emSign Root CA - G1 O=eMudhra Technologies Limited OU=emSign PKI +# Subject: CN=emSign Root CA - G1 O=eMudhra Technologies Limited OU=emSign PKI +# Label: "emSign Root CA - G1" +# Serial: 235931866688319308814040 +# MD5 Fingerprint: 9c:42:84:57:dd:cb:0b:a7:2e:95:ad:b6:f3:da:bc:ac +# SHA1 Fingerprint: 8a:c7:ad:8f:73:ac:4e:c1:b5:75:4d:a5:40:f4:fc:cf:7c:b5:8e:8c +# SHA256 Fingerprint: 40:f6:af:03:46:a9:9a:a1:cd:1d:55:5a:4e:9c:ce:62:c7:f9:63:46:03:ee:40:66:15:83:3d:c8:c8:d0:03:67 +-----BEGIN CERTIFICATE----- +MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD +VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU +ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH +MTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgxODMwMDBaMGcxCzAJBgNVBAYTAklO +MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv +Z2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQz +f2N4aLTNLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO +8oG0x5ZOrRkVUkr+PHB1cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aq +d7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHWDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhM +tTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ6DqS0hdW5TUaQBw+jSzt +Od9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrHhQIDAQAB +o0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQD +AgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31x +PaOfG1vR2vjTnGs2vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjM +wiI/aTvFthUvozXGaCocV685743QNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6d +GNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q+Mri/Tm3R7nrft8EI6/6nAYH +6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeihU80Bv2noWgby +RQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx +iN66zB+Afko= +-----END CERTIFICATE----- + +# Issuer: CN=emSign ECC Root CA - G3 O=eMudhra Technologies Limited OU=emSign PKI +# Subject: CN=emSign ECC Root CA - G3 O=eMudhra Technologies Limited OU=emSign PKI +# Label: "emSign ECC Root CA - G3" +# Serial: 287880440101571086945156 +# MD5 Fingerprint: ce:0b:72:d1:9f:88:8e:d0:50:03:e8:e3:b8:8b:67:40 +# SHA1 Fingerprint: 30:43:fa:4f:f2:57:dc:a0:c3:80:ee:2e:58:ea:78:b2:3f:e6:bb:c1 +# SHA256 Fingerprint: 86:a1:ec:ba:08:9c:4a:8d:3b:be:27:34:c6:12:ba:34:1d:81:3e:04:3c:f9:e8:a8:62:cd:5c:57:a3:6b:be:6b +-----BEGIN CERTIFICATE----- +MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG +EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo +bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g +RzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBrMQswCQYDVQQGEwJJ +TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s +b2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMw +djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0 +WXTsuwYc58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xyS +fvalY8L1X44uT6EYGQIrMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuB +zhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq +hkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB +CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD ++JbNR6iC8hZVdyR+EhCVBCyj +-----END CERTIFICATE----- + +# Issuer: CN=emSign Root CA - C1 O=eMudhra Inc OU=emSign PKI +# Subject: CN=emSign Root CA - C1 O=eMudhra Inc OU=emSign PKI +# Label: "emSign Root CA - C1" +# Serial: 825510296613316004955058 +# MD5 Fingerprint: d8:e3:5d:01:21:fa:78:5a:b0:df:ba:d2:ee:2a:5f:68 +# SHA1 Fingerprint: e7:2e:f1:df:fc:b2:09:28:cf:5d:d4:d5:67:37:b1:51:cb:86:4f:01 +# SHA256 Fingerprint: 12:56:09:aa:30:1d:a0:a2:49:b9:7a:82:39:cb:6a:34:21:6f:44:dc:ac:9f:39:54:b1:42:92:f2:e8:c8:60:8f +-----BEGIN CERTIFICATE----- +MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkG +A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg +SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw +MFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln +biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNpZ24gUm9v +dCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+upufGZ +BczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZ +HdPIWoU/Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH +3DspVpNqs8FqOp099cGXOFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvH +GPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4VI5b2P/AgNBbeCsbEBEV5f6f9vtKppa+c +xSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleoomslMuoaJuvimUnzYnu3Yy1 +aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+XJGFehiq +TbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87 +/kOXSTKZEhVb3xEp/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4 +kqNPEjE2NuLe/gDEo2APJ62gsIq1NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrG +YQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9wC68AivTxEDkigcxHpvOJpkT ++xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQBmIMMMAVSKeo +WXzhriKi4gp6D/piq1JM4fHfyr6DDUI= +-----END CERTIFICATE----- + +# Issuer: CN=emSign ECC Root CA - C3 O=eMudhra Inc OU=emSign PKI +# Subject: CN=emSign ECC Root CA - C3 O=eMudhra Inc OU=emSign PKI +# Label: "emSign ECC Root CA - C3" +# Serial: 582948710642506000014504 +# MD5 Fingerprint: 3e:53:b3:a3:81:ee:d7:10:f8:d3:b0:1d:17:92:f5:d5 +# SHA1 Fingerprint: b6:af:43:c2:9b:81:53:7d:f6:ef:6b:c3:1f:1f:60:15:0c:ee:48:66 +# SHA256 Fingerprint: bc:4d:80:9b:15:18:9d:78:db:3e:1d:8c:f4:f9:72:6a:79:5d:a1:64:3c:a5:f1:35:8e:1d:db:0e:dc:0d:7e:b3 +-----BEGIN CERTIFICATE----- +MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQG +EwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMx +IDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAw +MFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln +biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQDExdlbVNpZ24gRUND +IFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd6bci +MK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4Ojavti +sIGJAnB9SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0O +BBYEFPtaSNCAIEDyqOkAB2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB +Af8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQC02C8Cif22TGK6Q04ThHK1rt0c +3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwUZOR8loMRnLDRWmFLpg9J +0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== +-----END CERTIFICATE----- + +# Issuer: CN=Hongkong Post Root CA 3 O=Hongkong Post +# Subject: CN=Hongkong Post Root CA 3 O=Hongkong Post +# Label: "Hongkong Post Root CA 3" +# Serial: 46170865288971385588281144162979347873371282084 +# MD5 Fingerprint: 11:fc:9f:bd:73:30:02:8a:fd:3f:f3:58:b9:cb:20:f0 +# SHA1 Fingerprint: 58:a2:d0:ec:20:52:81:5b:c1:f3:f8:64:02:24:4e:c2:8e:02:4b:02 +# SHA256 Fingerprint: 5a:2f:c0:3f:0c:83:b0:90:bb:fa:40:60:4b:09:88:44:6c:76:36:18:3d:f9:84:6e:17:10:1a:44:7f:b8:ef:d6 +-----BEGIN CERTIFICATE----- +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 +mpv0 +-----END CERTIFICATE----- + +# Issuer: CN=Entrust Root Certification Authority - G4 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2015 Entrust, Inc. - for authorized use only +# Subject: CN=Entrust Root Certification Authority - G4 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2015 Entrust, Inc. - for authorized use only +# Label: "Entrust Root Certification Authority - G4" +# Serial: 289383649854506086828220374796556676440 +# MD5 Fingerprint: 89:53:f1:83:23:b7:7c:8e:05:f1:8c:71:38:4e:1f:88 +# SHA1 Fingerprint: 14:88:4e:86:26:37:b0:26:af:59:62:5c:40:77:ec:35:29:ba:96:01 +# SHA256 Fingerprint: db:35:17:d1:f6:73:2a:2d:5a:b9:7c:53:3e:c7:07:79:ee:32:70:a6:2f:b4:ac:42:38:37:24:60:e6:f0:1e:88 +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAw +gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL +Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg +MjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw +BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0 +MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1 +c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJ +bmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3Qg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3DumSXbcr3DbVZwbPLqGgZ +2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV3imz/f3E +T+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j +5pds8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAM +C1rlLAHGVK/XqsEQe9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73T +DtTUXm6Hnmo9RR3RXRv06QqsYJn7ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNX +wbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5XxNMhIWNlUpEbsZmOeX7m640A +2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV7rtNOzK+mndm +nqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8 +dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwl +N4y6mACXi0mWHv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNj +c0kCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9nMA0GCSqGSIb3DQEBCwUAA4ICAQAS +5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4QjbRaZIxowLByQzTS +Gwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht7LGr +hFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/ +B7NTeLUKYvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uI +AeV8KEsD+UmDfLJ/fOPtjqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbw +H5Lk6rWS02FREAutp9lfx1/cH6NcjKF+m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+ +b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKWRGhXxNUzzxkvFMSUHHuk +2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjAJOgc47Ol +IQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk +5F6G+TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuY +n/PIjhs4ViFqUZPTkcpG2om3PVODLAgfi49T3f+sHw== +-----END CERTIFICATE----- + +# Issuer: CN=Microsoft ECC Root Certificate Authority 2017 O=Microsoft Corporation +# Subject: CN=Microsoft ECC Root Certificate Authority 2017 O=Microsoft Corporation +# Label: "Microsoft ECC Root Certificate Authority 2017" +# Serial: 136839042543790627607696632466672567020 +# MD5 Fingerprint: dd:a1:03:e6:4a:93:10:d1:bf:f0:19:42:cb:fe:ed:67 +# SHA1 Fingerprint: 99:9a:64:c3:7f:f4:7d:9f:ab:95:f1:47:69:89:14:60:ee:c4:c3:c5 +# SHA256 Fingerprint: 35:8d:f3:9d:76:4a:f9:e1:b7:66:e9:c9:72:df:35:2e:e1:5c:fa:c2:27:af:6a:d1:d7:0e:8e:4a:6e:dc:ba:02 +-----BEGIN CERTIFICATE----- +MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYD +VQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw +MTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4MjMxNjA0WjBlMQswCQYDVQQGEwJV +UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNy +b3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZR +ogPZnZH6thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYb +hGBKia/teQ87zvH2RPUBeMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBTIy5lycFIM+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3 +FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlfXu5gKcs68tvWMoQZP3zV +L8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaReNtUjGUB +iudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M= +-----END CERTIFICATE----- + +# Issuer: CN=Microsoft RSA Root Certificate Authority 2017 O=Microsoft Corporation +# Subject: CN=Microsoft RSA Root Certificate Authority 2017 O=Microsoft Corporation +# Label: "Microsoft RSA Root Certificate Authority 2017" +# Serial: 40975477897264996090493496164228220339 +# MD5 Fingerprint: 10:ff:00:ff:cf:c9:f8:c7:7a:c0:ee:35:8e:c9:0f:47 +# SHA1 Fingerprint: 73:a5:e6:4a:3b:ff:83:16:ff:0e:dc:cc:61:8a:90:6e:4e:ae:4d:74 +# SHA256 Fingerprint: c7:41:f7:0f:4b:2a:8d:88:bf:2e:71:c1:41:22:ef:53:ef:10:eb:a0:cf:a5:e6:4c:fa:20:f4:18:85:30:73:e0 +-----BEGIN CERTIFICATE----- +MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBl +MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw +NAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 +IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIwNzE4MjMwMDIzWjBlMQswCQYDVQQG +EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1N +aWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZ +Nt9GkMml7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0 +ZdDMbRnMlfl7rEqUrQ7eS0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1 +HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw71VdyvD/IybLeS2v4I2wDwAW9lcfNcztm +gGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+dkC0zVJhUXAoP8XFWvLJ +jEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49FyGcohJUc +aDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaG +YaRSMLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6 +W6IYZVcSn2i51BVrlMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4K +UGsTuqwPN1q3ErWQgR5WrlcihtnJ0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH ++FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJClTUFLkqqNfs+avNJVgyeY+Q +W5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZC +LgLNFgVZJ8og6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OC +gMNPOsduET/m4xaRhPtthH80dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6 +tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk+ONVFT24bcMKpBLBaYVu32TxU5nh +SnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex/2kskZGT4d9Mozd2 +TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDyAmH3 +pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGR +xpl/j8nWZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiApp +GWSZI1b7rCoucL5mxAyE7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9 +dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKTc0QWbej09+CVgI+WXTik9KveCjCHk9hN +AHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D5KbvtwEwXlGjefVwaaZB +RA+GsCyRxj3qrg+E +-----END CERTIFICATE----- + +# Issuer: CN=e-Szigno Root CA 2017 O=Microsec Ltd. +# Subject: CN=e-Szigno Root CA 2017 O=Microsec Ltd. +# Label: "e-Szigno Root CA 2017" +# Serial: 411379200276854331539784714 +# MD5 Fingerprint: de:1f:f6:9e:84:ae:a7:b4:21:ce:1e:58:7d:d1:84:98 +# SHA1 Fingerprint: 89:d4:83:03:4f:9e:9a:48:80:5f:72:37:d4:a9:a6:ef:cb:7c:1f:d1 +# SHA256 Fingerprint: be:b0:0b:30:83:9b:9b:c3:2c:32:e4:44:79:05:95:06:41:f2:64:21:b1:5e:d0:89:19:8b:51:8a:e2:ea:1b:99 +-----BEGIN CERTIFICATE----- +MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNV +BAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRk +LjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJv +b3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZaFw00MjA4MjIxMjA3MDZaMHExCzAJ +BgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMg +THRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25v +IFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtv +xie+RJCxs1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+H +Wyx7xf58etqjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBSHERUI0arBeAyxr87GyZDvvzAEwDAfBgNVHSMEGDAWgBSHERUI0arB +eAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEAtVfd14pVCzbhhkT61Nlo +jbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxOsvxyqltZ ++efcMQ== +-----END CERTIFICATE----- + +# Issuer: O=CERTSIGN SA OU=certSIGN ROOT CA G2 +# Subject: O=CERTSIGN SA OU=certSIGN ROOT CA G2 +# Label: "certSIGN Root CA G2" +# Serial: 313609486401300475190 +# MD5 Fingerprint: 8c:f1:75:8a:c6:19:cf:94:b7:f7:65:20:87:c3:97:c7 +# SHA1 Fingerprint: 26:f9:93:b4:ed:3d:28:27:b0:b9:4b:a7:e9:15:1d:a3:8d:92:e5:32 +# SHA256 Fingerprint: 65:7c:fe:2f:a7:3f:aa:38:46:25:71:f3:32:a2:36:3a:46:fc:e7:02:09:51:71:07:02:cd:fb:b6:ee:da:33:05 +-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNV +BAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04g +Uk9PVCBDQSBHMjAeFw0xNzAyMDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJ +BgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJ +R04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDF +dRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05N0Iw +vlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZ +uIt4ImfkabBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhp +n+Sc8CnTXPnGFiWeI8MgwT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKs +cpc/I1mbySKEwQdPzH/iV8oScLumZfNpdWO9lfsbl83kqK/20U6o2YpxJM02PbyW +xPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91QqhngLjYl/rNUssuHLoPj1P +rCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732jcZZroiF +DsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fx +DTvf95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgy +LcsUDFDYg2WD7rlcz8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6C +eWRgKRM+o/1Pcmqr4tTluCRVLERLiohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSCIS1mxteg4BXrzkwJ +d8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOBywaK8SJJ6ejq +kX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC +b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQl +qiCA2ClV9+BB/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0 +OJD7uNGzcgbJceaBxXntC6Z58hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+c +NywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5BiKDUyUM/FHE5r7iOZULJK2v0ZXk +ltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklWatKcsWMy5WHgUyIO +pwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tUSxfj +03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZk +PuXaTH4MNMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE +1LlSVHJ7liXMvGnjSG4N0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MX +QRBdJ3NghVdJIgc= +-----END CERTIFICATE----- + +# Issuer: CN=Trustwave Global Certification Authority O=Trustwave Holdings, Inc. +# Subject: CN=Trustwave Global Certification Authority O=Trustwave Holdings, Inc. +# Label: "Trustwave Global Certification Authority" +# Serial: 1846098327275375458322922162 +# MD5 Fingerprint: f8:1c:18:2d:2f:ba:5f:6d:a1:6c:bc:c7:ab:91:c7:0e +# SHA1 Fingerprint: 2f:8f:36:4f:e1:58:97:44:21:59:87:a5:2a:9a:d0:69:95:26:7f:b5 +# SHA256 Fingerprint: 97:55:20:15:f5:dd:fc:3c:87:88:c0:06:94:45:55:40:88:94:45:00:84:f1:00:86:70:86:bc:1a:2b:b5:8d:c8 +-----BEGIN CERTIFICATE----- +MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQsw +CQYDVQQGEwJVUzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28x +ITAfBgNVBAoMGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1 +c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMx +OTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJVUzERMA8GA1UECAwI +SWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2ZSBI +b2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +ALldUShLPDeS0YLOvR29zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0Xzn +swuvCAAJWX/NKSqIk4cXGIDtiLK0thAfLdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu +7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4BqstTnoApTAbqOl5F2brz8 +1Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9oWN0EACyW +80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotP +JqX+OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1l +RtzuzWniTY+HKE40Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfw +hI0Vcnyh78zyiGG69Gm7DIwLdVcEuE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10 +coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm+9jaJXLE9gCxInm943xZYkqc +BW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqjifLJS3tBEW1n +twiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1Ud +DwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W +0OhUKDtkLSGm+J1WE2pIPU/HPinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfe +uyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0HZJDmHvUqoai7PF35owgLEQzxPy0Q +lG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla4gt5kNdXElE1GYhB +aCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5RvbbE +sLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPT +MaCm/zjdzyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qe +qu5AvzSxnI9O4fKSTx+O856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxh +VicGaeVyQYHTtgGJoC86cnn+OjC/QezHYj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8 +h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu3R3y4G5OBVixwJAWKqQ9 +EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP29FpHOTK +yeC2nOnOcXHebD8WpHk= +-----END CERTIFICATE----- + +# Issuer: CN=Trustwave Global ECC P256 Certification Authority O=Trustwave Holdings, Inc. +# Subject: CN=Trustwave Global ECC P256 Certification Authority O=Trustwave Holdings, Inc. +# Label: "Trustwave Global ECC P256 Certification Authority" +# Serial: 4151900041497450638097112925 +# MD5 Fingerprint: 5b:44:e3:8d:5d:36:86:26:e8:0d:05:d2:59:a7:83:54 +# SHA1 Fingerprint: b4:90:82:dd:45:0c:be:8b:5b:b1:66:d3:e2:a4:08:26:cd:ed:42:cf +# SHA256 Fingerprint: 94:5b:bc:82:5e:a5:54:f4:89:d1:fd:51:a7:3d:df:2e:a6:24:ac:70:19:a0:52:05:22:5c:22:a7:8c:cf:a8:b4 +-----BEGIN CERTIFICATE----- +MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf +BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 +YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x +NzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYDVQQGEwJVUzERMA8G +A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 +d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF +Q0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqG +SM49AwEHA0IABH77bOYj43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoN +FWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqmP62jQzBBMA8GA1UdEwEB/wQFMAMBAf8w +DwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt0UrrdaVKEJmzsaGLSvcw +CgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjzRM4q3wgh +DDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7 +-----END CERTIFICATE----- + +# Issuer: CN=Trustwave Global ECC P384 Certification Authority O=Trustwave Holdings, Inc. +# Subject: CN=Trustwave Global ECC P384 Certification Authority O=Trustwave Holdings, Inc. +# Label: "Trustwave Global ECC P384 Certification Authority" +# Serial: 2704997926503831671788816187 +# MD5 Fingerprint: ea:cf:60:c4:3b:b9:15:29:40:a1:97:ed:78:27:93:d6 +# SHA1 Fingerprint: e7:f3:a3:c8:cf:6f:c3:04:2e:6d:0e:67:32:c5:9e:68:95:0d:5e:d2 +# SHA256 Fingerprint: 55:90:38:59:c8:c0:c3:eb:b8:75:9e:ce:4e:25:57:22:5f:f5:75:8b:bd:38:eb:d4:82:76:60:1e:1b:d5:80:97 +-----BEGIN CERTIFICATE----- +MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf +BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 +YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x +NzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYDVQQGEwJVUzERMA8G +A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 +d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF +Q0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuB +BAAiA2IABGvaDXU1CDFHBa5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJ +j9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr/TklZvFe/oyujUF5nQlgziip04pt89ZF +1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNVHQ8BAf8EBQMDBwYAMB0G +A1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNnADBkAjA3 +AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsC +MGclCrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVu +Sw== +-----END CERTIFICATE----- diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi/core.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi/core.py new file mode 100644 index 0000000..5d2b8cd --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/certifi/core.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- + +""" +certifi.py +~~~~~~~~~~ + +This module returns the installation location of cacert.pem or its contents. +""" +import os + +try: + from importlib.resources import path as get_path, read_text + + _CACERT_CTX = None + _CACERT_PATH = None + + def where(): + # This is slightly terrible, but we want to delay extracting the file + # in cases where we're inside of a zipimport situation until someone + # actually calls where(), but we don't want to re-extract the file + # on every call of where(), so we'll do it once then store it in a + # global variable. + global _CACERT_CTX + global _CACERT_PATH + if _CACERT_PATH is None: + # This is slightly janky, the importlib.resources API wants you to + # manage the cleanup of this file, so it doesn't actually return a + # path, it returns a context manager that will give you the path + # when you enter it and will do any cleanup when you leave it. In + # the common case of not needing a temporary file, it will just + # return the file system location and the __exit__() is a no-op. + # + # We also have to hold onto the actual context manager, because + # it will do the cleanup whenever it gets garbage collected, so + # we will also store that at the global level as well. + _CACERT_CTX = get_path("certifi", "cacert.pem") + _CACERT_PATH = str(_CACERT_CTX.__enter__()) + + return _CACERT_PATH + + +except ImportError: + # This fallback will work for Python versions prior to 3.7 that lack the + # importlib.resources module but relies on the existing `where` function + # so won't address issues with environments like PyOxidizer that don't set + # __file__ on modules. + def read_text(_module, _path, encoding="ascii"): + with open(where(), "r", encoding=encoding) as data: + return data.read() + + # If we don't have importlib.resources, then we will just do the old logic + # of assuming we're on the filesystem and munge the path directly. + def where(): + f = os.path.dirname(__file__) + + return os.path.join(f, "cacert.pem") + + +def contents(): + return read_text("certifi", "cacert.pem", encoding="ascii") diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/INSTALLER b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/LICENSE b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/LICENSE new file mode 100644 index 0000000..29225ee --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/LICENSE @@ -0,0 +1,26 @@ + +Except when otherwise stated (look for LICENSE files in directories or +information at the beginning of each file) all software and +documentation is licensed as follows: + + The MIT License + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, + copy, modify, merge, publish, distribute, sublicense, and/or + sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/METADATA b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/METADATA new file mode 100644 index 0000000..d3c31da --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/METADATA @@ -0,0 +1,37 @@ +Metadata-Version: 2.1 +Name: cffi +Version: 1.14.3 +Summary: Foreign Function Interface for Python calling C code. +Home-page: http://cffi.readthedocs.org +Author: Armin Rigo, Maciej Fijalkowski +Author-email: python-cffi@googlegroups.com +License: MIT +Platform: UNKNOWN +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.2 +Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: License :: OSI Approved :: MIT License +Requires-Dist: pycparser + + +CFFI +==== + +Foreign Function Interface for Python calling C code. +Please see the `Documentation `_. + +Contact +------- + +`Mailing list `_ + + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/RECORD b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/RECORD new file mode 100644 index 0000000..ac83787 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/RECORD @@ -0,0 +1,45 @@ +_cffi_backend.cpython-38-x86_64-linux-gnu.so,sha256=e8IQkWtUGYoThLZMIj9VcOoXikFuKBroZg6h67FiyJM,886648 +cffi-1.14.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +cffi-1.14.3.dist-info/LICENSE,sha256=BLgPWwd7vtaICM_rreteNSPyqMmpZJXFh72W3x6sKjM,1294 +cffi-1.14.3.dist-info/METADATA,sha256=SOxoTo-W2jbz8qj7XHL2Ry3Shfpbeg6IHx7crTt4NRs,1191 +cffi-1.14.3.dist-info/RECORD,, +cffi-1.14.3.dist-info/WHEEL,sha256=0wGQBSV-BlYX9ESMZyEiLMpXIYwrZGj6McPYyDp_RjA,108 +cffi-1.14.3.dist-info/entry_points.txt,sha256=Q9f5C9IpjYxo0d2PK9eUcnkgxHc9pHWwjEMaANPKNCI,76 +cffi-1.14.3.dist-info/top_level.txt,sha256=rE7WR3rZfNKxWI9-jn6hsHCAl7MDkB-FmuQbxWjFehQ,19 +cffi.libs/libffi-806b1a9d.so.6.0.4,sha256=xgERNdZXaam4q4jB4p5DTqbAIUIhQmoxdgvKHaKyA8Y,46632 +cffi/__init__.py,sha256=HTFBhEn6DYP-4HAgRGBKCWPT-auDgugi4hSXlWO5Faw,513 +cffi/__pycache__/__init__.cpython-38.pyc,, +cffi/__pycache__/api.cpython-38.pyc,, +cffi/__pycache__/backend_ctypes.cpython-38.pyc,, +cffi/__pycache__/cffi_opcode.cpython-38.pyc,, +cffi/__pycache__/commontypes.cpython-38.pyc,, +cffi/__pycache__/cparser.cpython-38.pyc,, +cffi/__pycache__/error.cpython-38.pyc,, +cffi/__pycache__/ffiplatform.cpython-38.pyc,, +cffi/__pycache__/lock.cpython-38.pyc,, +cffi/__pycache__/model.cpython-38.pyc,, +cffi/__pycache__/pkgconfig.cpython-38.pyc,, +cffi/__pycache__/recompiler.cpython-38.pyc,, +cffi/__pycache__/setuptools_ext.cpython-38.pyc,, +cffi/__pycache__/vengine_cpy.cpython-38.pyc,, +cffi/__pycache__/vengine_gen.cpython-38.pyc,, +cffi/__pycache__/verifier.cpython-38.pyc,, +cffi/_cffi_errors.h,sha256=6nFQ-4dRQI1bXRoSeqdvyKU33TmutQJB_2fAhWSzdl8,3856 +cffi/_cffi_include.h,sha256=tKnA1rdSoPHp23FnDL1mDGwFo-Uj6fXfA6vA6kcoEUc,14800 +cffi/_embedding.h,sha256=Y62WZc3LFNsw37OKZj3Zs6FdJIngZt8UmTnM5x_7JKw,17581 +cffi/api.py,sha256=yxJalIePbr1mz_WxAHokSwyP5CVYde44m-nolHnbJNo,42064 +cffi/backend_ctypes.py,sha256=h5ZIzLc6BFVXnGyc9xPqZWUS7qGy7yFSDqXe68Sa8z4,42454 +cffi/cffi_opcode.py,sha256=v9RdD_ovA8rCtqsC95Ivki5V667rAOhGgs3fb2q9xpM,5724 +cffi/commontypes.py,sha256=QS4uxCDI7JhtTyjh1hlnCA-gynmaszWxJaRRLGkJa1A,2689 +cffi/cparser.py,sha256=rO_1pELRw1gI1DE1m4gi2ik5JMfpxouAACLXpRPlVEA,44231 +cffi/error.py,sha256=v6xTiS4U0kvDcy4h_BDRo5v39ZQuj-IMRYLv5ETddZs,877 +cffi/ffiplatform.py,sha256=HMXqR8ks2wtdsNxGaWpQ_PyqIvtiuos_vf1qKCy-cwg,4046 +cffi/lock.py,sha256=l9TTdwMIMpi6jDkJGnQgE9cvTIR7CAntIJr8EGHt3pY,747 +cffi/model.py,sha256=_GH_UF1Rn9vC4AvmgJm6qj7RUXXG3eqKPc8bPxxyBKE,21768 +cffi/parse_c_type.h,sha256=OdwQfwM9ktq6vlCB43exFQmxDBtj2MBNdK8LYl15tjw,5976 +cffi/pkgconfig.py,sha256=LP1w7vmWvmKwyqLaU1Z243FOWGNQMrgMUZrvgFuOlco,4374 +cffi/recompiler.py,sha256=XtQNxkxXz5Ze5Lz-j9yHZj_JIZqbuZz4_STIOBv4sCU,64061 +cffi/setuptools_ext.py,sha256=RUR17N5f8gpiQBBlXL34P9FtOu1mhHIaAf3WJlg5S4I,8931 +cffi/vengine_cpy.py,sha256=YglN8YS-UaHEv2k2cxgotNWE87dHX20-68EyKoiKUYA,43320 +cffi/vengine_gen.py,sha256=5dX7s1DU6pTBOMI6oTVn_8Bnmru_lj932B6b4v29Hlg,26684 +cffi/verifier.py,sha256=J9Enz2rbJb9CHPqWlWQ5uQESoyr0uc7MNWugchjXBv4,11207 diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/WHEEL b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/WHEEL new file mode 100644 index 0000000..0796649 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.34.2) +Root-Is-Purelib: false +Tag: cp38-cp38-manylinux1_x86_64 + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/entry_points.txt b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/entry_points.txt new file mode 100644 index 0000000..eee7e0f --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[distutils.setup_keywords] +cffi_modules = cffi.setuptools_ext:cffi_modules + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/top_level.txt b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/top_level.txt new file mode 100644 index 0000000..f645779 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi-1.14.3.dist-info/top_level.txt @@ -0,0 +1,2 @@ +_cffi_backend +cffi diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi.libs/libffi-806b1a9d.so.6.0.4 b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi.libs/libffi-806b1a9d.so.6.0.4 new file mode 100755 index 0000000000000000000000000000000000000000..13bc481195e17946b05ce0ed920d656815083e93 GIT binary patch literal 46632 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 3 + bi = PyImport_ImportModule("builtins"); +#else + bi = PyImport_ImportModule("__builtin__"); +#endif + if (bi == NULL) + goto error; + PyDict_SetItemString(result, "__builtins__", bi); + Py_DECREF(bi); + + x = PyRun_String( + "import sys\n" + "class FileLike:\n" + " def write(self, x):\n" + " try:\n" + " of.write(x)\n" + " except: pass\n" + " self.buf += x\n" + "fl = FileLike()\n" + "fl.buf = ''\n" + "of = sys.stderr\n" + "sys.stderr = fl\n" + "def done():\n" + " sys.stderr = of\n" + " return fl.buf\n", /* make sure the returned value stays alive */ + Py_file_input, + result, result); + Py_XDECREF(x); + + error: + if (PyErr_Occurred()) + { + PyErr_WriteUnraisable(Py_None); + PyErr_Clear(); + } + return result; +} + +#pragma comment(lib, "user32.lib") + +static DWORD WINAPI _cffi_bootstrap_dialog(LPVOID ignored) +{ + Sleep(666); /* may be interrupted if the whole process is closing */ +#if PY_MAJOR_VERSION >= 3 + MessageBoxW(NULL, (wchar_t *)_cffi_bootstrap_text, + L"Python-CFFI error", + MB_OK | MB_ICONERROR); +#else + MessageBoxA(NULL, (char *)_cffi_bootstrap_text, + "Python-CFFI error", + MB_OK | MB_ICONERROR); +#endif + _cffi_bootstrap_text = NULL; + return 0; +} + +static void _cffi_stop_error_capture(PyObject *ecap) +{ + PyObject *s; + void *text; + + if (ecap == (PyObject *)1) + return; + + if (ecap == NULL) + goto error; + + s = PyRun_String("done()", Py_eval_input, ecap, ecap); + if (s == NULL) + goto error; + + /* Show a dialog box, but in a background thread, and + never show multiple dialog boxes at once. */ +#if PY_MAJOR_VERSION >= 3 + text = PyUnicode_AsWideCharString(s, NULL); +#else + text = PyString_AsString(s); +#endif + + _cffi_bootstrap_text = text; + + if (text != NULL) + { + HANDLE h; + h = CreateThread(NULL, 0, _cffi_bootstrap_dialog, + NULL, 0, NULL); + if (h != NULL) + CloseHandle(h); + } + /* decref the string, but it should stay alive as 'fl.buf' + in the small module above. It will really be freed only if + we later get another similar error. So it's a leak of at + most one copy of the small module. That's fine for this + situation which is usually a "fatal error" anyway. */ + Py_DECREF(s); + PyErr_Clear(); + return; + + error: + _cffi_bootstrap_text = NULL; + PyErr_Clear(); +} + +#else + +static PyObject *_cffi_start_error_capture(void) { return NULL; } +static void _cffi_stop_error_capture(PyObject *ecap) { } + +#endif diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/_cffi_include.h b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/_cffi_include.h new file mode 100644 index 0000000..e4c0a67 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/_cffi_include.h @@ -0,0 +1,385 @@ +#define _CFFI_ + +/* We try to define Py_LIMITED_API before including Python.h. + + Mess: we can only define it if Py_DEBUG, Py_TRACE_REFS and + Py_REF_DEBUG are not defined. This is a best-effort approximation: + we can learn about Py_DEBUG from pyconfig.h, but it is unclear if + the same works for the other two macros. Py_DEBUG implies them, + but not the other way around. + + The implementation is messy (issue #350): on Windows, with _MSC_VER, + we have to define Py_LIMITED_API even before including pyconfig.h. + In that case, we guess what pyconfig.h will do to the macros above, + and check our guess after the #include. + + Note that on Windows, with CPython 3.x, you need >= 3.5 and virtualenv + version >= 16.0.0. With older versions of either, you don't get a + copy of PYTHON3.DLL in the virtualenv. We can't check the version of + CPython *before* we even include pyconfig.h. ffi.set_source() puts + a ``#define _CFFI_NO_LIMITED_API'' at the start of this file if it is + running on Windows < 3.5, as an attempt at fixing it, but that's + arguably wrong because it may not be the target version of Python. + Still better than nothing I guess. As another workaround, you can + remove the definition of Py_LIMITED_API here. + + See also 'py_limited_api' in cffi/setuptools_ext.py. +*/ +#if !defined(_CFFI_USE_EMBEDDING) && !defined(Py_LIMITED_API) +# ifdef _MSC_VER +# if !defined(_DEBUG) && !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) && !defined(_CFFI_NO_LIMITED_API) +# define Py_LIMITED_API +# endif +# include + /* sanity-check: Py_LIMITED_API will cause crashes if any of these + are also defined. Normally, the Python file PC/pyconfig.h does not + cause any of these to be defined, with the exception that _DEBUG + causes Py_DEBUG. Double-check that. */ +# ifdef Py_LIMITED_API +# if defined(Py_DEBUG) +# error "pyconfig.h unexpectedly defines Py_DEBUG, but Py_LIMITED_API is set" +# endif +# if defined(Py_TRACE_REFS) +# error "pyconfig.h unexpectedly defines Py_TRACE_REFS, but Py_LIMITED_API is set" +# endif +# if defined(Py_REF_DEBUG) +# error "pyconfig.h unexpectedly defines Py_REF_DEBUG, but Py_LIMITED_API is set" +# endif +# endif +# else +# include +# if !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) && !defined(_CFFI_NO_LIMITED_API) +# define Py_LIMITED_API +# endif +# endif +#endif + +#include +#ifdef __cplusplus +extern "C" { +#endif +#include +#include "parse_c_type.h" + +/* this block of #ifs should be kept exactly identical between + c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py + and cffi/_cffi_include.h */ +#if defined(_MSC_VER) +# include /* for alloca() */ +# if _MSC_VER < 1600 /* MSVC < 2010 */ + typedef __int8 int8_t; + typedef __int16 int16_t; + typedef __int32 int32_t; + typedef __int64 int64_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + typedef unsigned __int64 uint64_t; + typedef __int8 int_least8_t; + typedef __int16 int_least16_t; + typedef __int32 int_least32_t; + typedef __int64 int_least64_t; + typedef unsigned __int8 uint_least8_t; + typedef unsigned __int16 uint_least16_t; + typedef unsigned __int32 uint_least32_t; + typedef unsigned __int64 uint_least64_t; + typedef __int8 int_fast8_t; + typedef __int16 int_fast16_t; + typedef __int32 int_fast32_t; + typedef __int64 int_fast64_t; + typedef unsigned __int8 uint_fast8_t; + typedef unsigned __int16 uint_fast16_t; + typedef unsigned __int32 uint_fast32_t; + typedef unsigned __int64 uint_fast64_t; + typedef __int64 intmax_t; + typedef unsigned __int64 uintmax_t; +# else +# include +# endif +# if _MSC_VER < 1800 /* MSVC < 2013 */ +# ifndef __cplusplus + typedef unsigned char _Bool; +# endif +# endif +#else +# include +# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) +# include +# endif +#endif + +#ifdef __GNUC__ +# define _CFFI_UNUSED_FN __attribute__((unused)) +#else +# define _CFFI_UNUSED_FN /* nothing */ +#endif + +#ifdef __cplusplus +# ifndef _Bool + typedef bool _Bool; /* semi-hackish: C++ has no _Bool; bool is builtin */ +# endif +#endif + +/********** CPython-specific section **********/ +#ifndef PYPY_VERSION + + +#if PY_MAJOR_VERSION >= 3 +# define PyInt_FromLong PyLong_FromLong +#endif + +#define _cffi_from_c_double PyFloat_FromDouble +#define _cffi_from_c_float PyFloat_FromDouble +#define _cffi_from_c_long PyInt_FromLong +#define _cffi_from_c_ulong PyLong_FromUnsignedLong +#define _cffi_from_c_longlong PyLong_FromLongLong +#define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong +#define _cffi_from_c__Bool PyBool_FromLong + +#define _cffi_to_c_double PyFloat_AsDouble +#define _cffi_to_c_float PyFloat_AsDouble + +#define _cffi_from_c_int(x, type) \ + (((type)-1) > 0 ? /* unsigned */ \ + (sizeof(type) < sizeof(long) ? \ + PyInt_FromLong((long)x) : \ + sizeof(type) == sizeof(long) ? \ + PyLong_FromUnsignedLong((unsigned long)x) : \ + PyLong_FromUnsignedLongLong((unsigned long long)x)) : \ + (sizeof(type) <= sizeof(long) ? \ + PyInt_FromLong((long)x) : \ + PyLong_FromLongLong((long long)x))) + +#define _cffi_to_c_int(o, type) \ + ((type)( \ + sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \ + : (type)_cffi_to_c_i8(o)) : \ + sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o) \ + : (type)_cffi_to_c_i16(o)) : \ + sizeof(type) == 4 ? (((type)-1) > 0 ? (type)_cffi_to_c_u32(o) \ + : (type)_cffi_to_c_i32(o)) : \ + sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o) \ + : (type)_cffi_to_c_i64(o)) : \ + (Py_FatalError("unsupported size for type " #type), (type)0))) + +#define _cffi_to_c_i8 \ + ((int(*)(PyObject *))_cffi_exports[1]) +#define _cffi_to_c_u8 \ + ((int(*)(PyObject *))_cffi_exports[2]) +#define _cffi_to_c_i16 \ + ((int(*)(PyObject *))_cffi_exports[3]) +#define _cffi_to_c_u16 \ + ((int(*)(PyObject *))_cffi_exports[4]) +#define _cffi_to_c_i32 \ + ((int(*)(PyObject *))_cffi_exports[5]) +#define _cffi_to_c_u32 \ + ((unsigned int(*)(PyObject *))_cffi_exports[6]) +#define _cffi_to_c_i64 \ + ((long long(*)(PyObject *))_cffi_exports[7]) +#define _cffi_to_c_u64 \ + ((unsigned long long(*)(PyObject *))_cffi_exports[8]) +#define _cffi_to_c_char \ + ((int(*)(PyObject *))_cffi_exports[9]) +#define _cffi_from_c_pointer \ + ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[10]) +#define _cffi_to_c_pointer \ + ((char *(*)(PyObject *, struct _cffi_ctypedescr *))_cffi_exports[11]) +#define _cffi_get_struct_layout \ + not used any more +#define _cffi_restore_errno \ + ((void(*)(void))_cffi_exports[13]) +#define _cffi_save_errno \ + ((void(*)(void))_cffi_exports[14]) +#define _cffi_from_c_char \ + ((PyObject *(*)(char))_cffi_exports[15]) +#define _cffi_from_c_deref \ + ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[16]) +#define _cffi_to_c \ + ((int(*)(char *, struct _cffi_ctypedescr *, PyObject *))_cffi_exports[17]) +#define _cffi_from_c_struct \ + ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[18]) +#define _cffi_to_c_wchar_t \ + ((_cffi_wchar_t(*)(PyObject *))_cffi_exports[19]) +#define _cffi_from_c_wchar_t \ + ((PyObject *(*)(_cffi_wchar_t))_cffi_exports[20]) +#define _cffi_to_c_long_double \ + ((long double(*)(PyObject *))_cffi_exports[21]) +#define _cffi_to_c__Bool \ + ((_Bool(*)(PyObject *))_cffi_exports[22]) +#define _cffi_prepare_pointer_call_argument \ + ((Py_ssize_t(*)(struct _cffi_ctypedescr *, \ + PyObject *, char **))_cffi_exports[23]) +#define _cffi_convert_array_from_object \ + ((int(*)(char *, struct _cffi_ctypedescr *, PyObject *))_cffi_exports[24]) +#define _CFFI_CPIDX 25 +#define _cffi_call_python \ + ((void(*)(struct _cffi_externpy_s *, char *))_cffi_exports[_CFFI_CPIDX]) +#define _cffi_to_c_wchar3216_t \ + ((int(*)(PyObject *))_cffi_exports[26]) +#define _cffi_from_c_wchar3216_t \ + ((PyObject *(*)(int))_cffi_exports[27]) +#define _CFFI_NUM_EXPORTS 28 + +struct _cffi_ctypedescr; + +static void *_cffi_exports[_CFFI_NUM_EXPORTS]; + +#define _cffi_type(index) ( \ + assert((((uintptr_t)_cffi_types[index]) & 1) == 0), \ + (struct _cffi_ctypedescr *)_cffi_types[index]) + +static PyObject *_cffi_init(const char *module_name, Py_ssize_t version, + const struct _cffi_type_context_s *ctx) +{ + PyObject *module, *o_arg, *new_module; + void *raw[] = { + (void *)module_name, + (void *)version, + (void *)_cffi_exports, + (void *)ctx, + }; + + module = PyImport_ImportModule("_cffi_backend"); + if (module == NULL) + goto failure; + + o_arg = PyLong_FromVoidPtr((void *)raw); + if (o_arg == NULL) + goto failure; + + new_module = PyObject_CallMethod( + module, (char *)"_init_cffi_1_0_external_module", (char *)"O", o_arg); + + Py_DECREF(o_arg); + Py_DECREF(module); + return new_module; + + failure: + Py_XDECREF(module); + return NULL; +} + + +#ifdef HAVE_WCHAR_H +typedef wchar_t _cffi_wchar_t; +#else +typedef uint16_t _cffi_wchar_t; /* same random pick as _cffi_backend.c */ +#endif + +_CFFI_UNUSED_FN static uint16_t _cffi_to_c_char16_t(PyObject *o) +{ + if (sizeof(_cffi_wchar_t) == 2) + return (uint16_t)_cffi_to_c_wchar_t(o); + else + return (uint16_t)_cffi_to_c_wchar3216_t(o); +} + +_CFFI_UNUSED_FN static PyObject *_cffi_from_c_char16_t(uint16_t x) +{ + if (sizeof(_cffi_wchar_t) == 2) + return _cffi_from_c_wchar_t((_cffi_wchar_t)x); + else + return _cffi_from_c_wchar3216_t((int)x); +} + +_CFFI_UNUSED_FN static int _cffi_to_c_char32_t(PyObject *o) +{ + if (sizeof(_cffi_wchar_t) == 4) + return (int)_cffi_to_c_wchar_t(o); + else + return (int)_cffi_to_c_wchar3216_t(o); +} + +_CFFI_UNUSED_FN static PyObject *_cffi_from_c_char32_t(unsigned int x) +{ + if (sizeof(_cffi_wchar_t) == 4) + return _cffi_from_c_wchar_t((_cffi_wchar_t)x); + else + return _cffi_from_c_wchar3216_t((int)x); +} + +union _cffi_union_alignment_u { + unsigned char m_char; + unsigned short m_short; + unsigned int m_int; + unsigned long m_long; + unsigned long long m_longlong; + float m_float; + double m_double; + long double m_longdouble; +}; + +struct _cffi_freeme_s { + struct _cffi_freeme_s *next; + union _cffi_union_alignment_u alignment; +}; + +_CFFI_UNUSED_FN static int +_cffi_convert_array_argument(struct _cffi_ctypedescr *ctptr, PyObject *arg, + char **output_data, Py_ssize_t datasize, + struct _cffi_freeme_s **freeme) +{ + char *p; + if (datasize < 0) + return -1; + + p = *output_data; + if (p == NULL) { + struct _cffi_freeme_s *fp = (struct _cffi_freeme_s *)PyObject_Malloc( + offsetof(struct _cffi_freeme_s, alignment) + (size_t)datasize); + if (fp == NULL) + return -1; + fp->next = *freeme; + *freeme = fp; + p = *output_data = (char *)&fp->alignment; + } + memset((void *)p, 0, (size_t)datasize); + return _cffi_convert_array_from_object(p, ctptr, arg); +} + +_CFFI_UNUSED_FN static void +_cffi_free_array_arguments(struct _cffi_freeme_s *freeme) +{ + do { + void *p = (void *)freeme; + freeme = freeme->next; + PyObject_Free(p); + } while (freeme != NULL); +} + +/********** end CPython-specific section **********/ +#else +_CFFI_UNUSED_FN +static void (*_cffi_call_python_org)(struct _cffi_externpy_s *, char *); +# define _cffi_call_python _cffi_call_python_org +#endif + + +#define _cffi_array_len(array) (sizeof(array) / sizeof((array)[0])) + +#define _cffi_prim_int(size, sign) \ + ((size) == 1 ? ((sign) ? _CFFI_PRIM_INT8 : _CFFI_PRIM_UINT8) : \ + (size) == 2 ? ((sign) ? _CFFI_PRIM_INT16 : _CFFI_PRIM_UINT16) : \ + (size) == 4 ? ((sign) ? _CFFI_PRIM_INT32 : _CFFI_PRIM_UINT32) : \ + (size) == 8 ? ((sign) ? _CFFI_PRIM_INT64 : _CFFI_PRIM_UINT64) : \ + _CFFI__UNKNOWN_PRIM) + +#define _cffi_prim_float(size) \ + ((size) == sizeof(float) ? _CFFI_PRIM_FLOAT : \ + (size) == sizeof(double) ? _CFFI_PRIM_DOUBLE : \ + (size) == sizeof(long double) ? _CFFI__UNKNOWN_LONG_DOUBLE : \ + _CFFI__UNKNOWN_FLOAT_PRIM) + +#define _cffi_check_int(got, got_nonpos, expected) \ + ((got_nonpos) == (expected <= 0) && \ + (got) == (unsigned long long)expected) + +#ifdef MS_WIN32 +# define _cffi_stdcall __stdcall +#else +# define _cffi_stdcall /* nothing */ +#endif + +#ifdef __cplusplus +} +#endif diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/_embedding.h b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/_embedding.h new file mode 100644 index 0000000..fdce222 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/_embedding.h @@ -0,0 +1,527 @@ + +/***** Support code for embedding *****/ + +#ifdef __cplusplus +extern "C" { +#endif + + +#if defined(_WIN32) +# define CFFI_DLLEXPORT __declspec(dllexport) +#elif defined(__GNUC__) +# define CFFI_DLLEXPORT __attribute__((visibility("default"))) +#else +# define CFFI_DLLEXPORT /* nothing */ +#endif + + +/* There are two global variables of type _cffi_call_python_fnptr: + + * _cffi_call_python, which we declare just below, is the one called + by ``extern "Python"`` implementations. + + * _cffi_call_python_org, which on CPython is actually part of the + _cffi_exports[] array, is the function pointer copied from + _cffi_backend. + + After initialization is complete, both are equal. However, the + first one remains equal to &_cffi_start_and_call_python until the + very end of initialization, when we are (or should be) sure that + concurrent threads also see a completely initialized world, and + only then is it changed. +*/ +#undef _cffi_call_python +typedef void (*_cffi_call_python_fnptr)(struct _cffi_externpy_s *, char *); +static void _cffi_start_and_call_python(struct _cffi_externpy_s *, char *); +static _cffi_call_python_fnptr _cffi_call_python = &_cffi_start_and_call_python; + + +#ifndef _MSC_VER + /* --- Assuming a GCC not infinitely old --- */ +# define cffi_compare_and_swap(l,o,n) __sync_bool_compare_and_swap(l,o,n) +# define cffi_write_barrier() __sync_synchronize() +# if !defined(__amd64__) && !defined(__x86_64__) && \ + !defined(__i386__) && !defined(__i386) +# define cffi_read_barrier() __sync_synchronize() +# else +# define cffi_read_barrier() (void)0 +# endif +#else + /* --- Windows threads version --- */ +# include +# define cffi_compare_and_swap(l,o,n) \ + (InterlockedCompareExchangePointer(l,n,o) == (o)) +# define cffi_write_barrier() InterlockedCompareExchange(&_cffi_dummy,0,0) +# define cffi_read_barrier() (void)0 +static volatile LONG _cffi_dummy; +#endif + +#ifdef WITH_THREAD +# ifndef _MSC_VER +# include + static pthread_mutex_t _cffi_embed_startup_lock; +# else + static CRITICAL_SECTION _cffi_embed_startup_lock; +# endif + static char _cffi_embed_startup_lock_ready = 0; +#endif + +static void _cffi_acquire_reentrant_mutex(void) +{ + static void *volatile lock = NULL; + + while (!cffi_compare_and_swap(&lock, NULL, (void *)1)) { + /* should ideally do a spin loop instruction here, but + hard to do it portably and doesn't really matter I + think: pthread_mutex_init() should be very fast, and + this is only run at start-up anyway. */ + } + +#ifdef WITH_THREAD + if (!_cffi_embed_startup_lock_ready) { +# ifndef _MSC_VER + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&_cffi_embed_startup_lock, &attr); +# else + InitializeCriticalSection(&_cffi_embed_startup_lock); +# endif + _cffi_embed_startup_lock_ready = 1; + } +#endif + + while (!cffi_compare_and_swap(&lock, (void *)1, NULL)) + ; + +#ifndef _MSC_VER + pthread_mutex_lock(&_cffi_embed_startup_lock); +#else + EnterCriticalSection(&_cffi_embed_startup_lock); +#endif +} + +static void _cffi_release_reentrant_mutex(void) +{ +#ifndef _MSC_VER + pthread_mutex_unlock(&_cffi_embed_startup_lock); +#else + LeaveCriticalSection(&_cffi_embed_startup_lock); +#endif +} + + +/********** CPython-specific section **********/ +#ifndef PYPY_VERSION + +#include "_cffi_errors.h" + + +#define _cffi_call_python_org _cffi_exports[_CFFI_CPIDX] + +PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(void); /* forward */ + +static void _cffi_py_initialize(void) +{ + /* XXX use initsigs=0, which "skips initialization registration of + signal handlers, which might be useful when Python is + embedded" according to the Python docs. But review and think + if it should be a user-controllable setting. + + XXX we should also give a way to write errors to a buffer + instead of to stderr. + + XXX if importing 'site' fails, CPython (any version) calls + exit(). Should we try to work around this behavior here? + */ + Py_InitializeEx(0); +} + +static int _cffi_initialize_python(void) +{ + /* This initializes Python, imports _cffi_backend, and then the + present .dll/.so is set up as a CPython C extension module. + */ + int result; + PyGILState_STATE state; + PyObject *pycode=NULL, *global_dict=NULL, *x; + PyObject *builtins; + + state = PyGILState_Ensure(); + + /* Call the initxxx() function from the present module. It will + create and initialize us as a CPython extension module, instead + of letting the startup Python code do it---it might reimport + the same .dll/.so and get maybe confused on some platforms. + It might also have troubles locating the .dll/.so again for all + I know. + */ + (void)_CFFI_PYTHON_STARTUP_FUNC(); + if (PyErr_Occurred()) + goto error; + + /* Now run the Python code provided to ffi.embedding_init_code(). + */ + pycode = Py_CompileString(_CFFI_PYTHON_STARTUP_CODE, + "", + Py_file_input); + if (pycode == NULL) + goto error; + global_dict = PyDict_New(); + if (global_dict == NULL) + goto error; + builtins = PyEval_GetBuiltins(); + if (builtins == NULL) + goto error; + if (PyDict_SetItemString(global_dict, "__builtins__", builtins) < 0) + goto error; + x = PyEval_EvalCode( +#if PY_MAJOR_VERSION < 3 + (PyCodeObject *) +#endif + pycode, global_dict, global_dict); + if (x == NULL) + goto error; + Py_DECREF(x); + + /* Done! Now if we've been called from + _cffi_start_and_call_python() in an ``extern "Python"``, we can + only hope that the Python code did correctly set up the + corresponding @ffi.def_extern() function. Otherwise, the + general logic of ``extern "Python"`` functions (inside the + _cffi_backend module) will find that the reference is still + missing and print an error. + */ + result = 0; + done: + Py_XDECREF(pycode); + Py_XDECREF(global_dict); + PyGILState_Release(state); + return result; + + error:; + { + /* Print as much information as potentially useful. + Debugging load-time failures with embedding is not fun + */ + PyObject *ecap; + PyObject *exception, *v, *tb, *f, *modules, *mod; + PyErr_Fetch(&exception, &v, &tb); + ecap = _cffi_start_error_capture(); + f = PySys_GetObject((char *)"stderr"); + if (f != NULL && f != Py_None) { + PyFile_WriteString( + "Failed to initialize the Python-CFFI embedding logic:\n\n", f); + } + + if (exception != NULL) { + PyErr_NormalizeException(&exception, &v, &tb); + PyErr_Display(exception, v, tb); + } + Py_XDECREF(exception); + Py_XDECREF(v); + Py_XDECREF(tb); + + if (f != NULL && f != Py_None) { + PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME + "\ncompiled with cffi version: 1.14.3" + "\n_cffi_backend module: ", f); + modules = PyImport_GetModuleDict(); + mod = PyDict_GetItemString(modules, "_cffi_backend"); + if (mod == NULL) { + PyFile_WriteString("not loaded", f); + } + else { + v = PyObject_GetAttrString(mod, "__file__"); + PyFile_WriteObject(v, f, 0); + Py_XDECREF(v); + } + PyFile_WriteString("\nsys.path: ", f); + PyFile_WriteObject(PySys_GetObject((char *)"path"), f, 0); + PyFile_WriteString("\n\n", f); + } + _cffi_stop_error_capture(ecap); + } + result = -1; + goto done; +} + +#if PY_VERSION_HEX < 0x03080000 +PyAPI_DATA(char *) _PyParser_TokenNames[]; /* from CPython */ +#endif + +static int _cffi_carefully_make_gil(void) +{ + /* This does the basic initialization of Python. It can be called + completely concurrently from unrelated threads. It assumes + that we don't hold the GIL before (if it exists), and we don't + hold it afterwards. + + (What it really does used to be completely different in Python 2 + and Python 3, with the Python 2 solution avoiding the spin-lock + around the Py_InitializeEx() call. However, after recent changes + to CPython 2.7 (issue #358) it no longer works. So we use the + Python 3 solution everywhere.) + + This initializes Python by calling Py_InitializeEx(). + Important: this must not be called concurrently at all. + So we use a global variable as a simple spin lock. This global + variable must be from 'libpythonX.Y.so', not from this + cffi-based extension module, because it must be shared from + different cffi-based extension modules. + + In Python < 3.8, we choose + _PyParser_TokenNames[0] as a completely arbitrary pointer value + that is never written to. The default is to point to the + string "ENDMARKER". We change it temporarily to point to the + next character in that string. (Yes, I know it's REALLY + obscure.) + + In Python >= 3.8, this string array is no longer writable, so + instead we pick PyCapsuleType.tp_version_tag. We can't change + Python < 3.8 because someone might use a mixture of cffi + embedded modules, some of which were compiled before this file + changed. + */ + +#ifdef WITH_THREAD +# if PY_VERSION_HEX < 0x03080000 + char *volatile *lock = (char *volatile *)_PyParser_TokenNames; + char *old_value, *locked_value; + + while (1) { /* spin loop */ + old_value = *lock; + locked_value = old_value + 1; + if (old_value[0] == 'E') { + assert(old_value[1] == 'N'); + if (cffi_compare_and_swap(lock, old_value, locked_value)) + break; + } + else { + assert(old_value[0] == 'N'); + /* should ideally do a spin loop instruction here, but + hard to do it portably and doesn't really matter I + think: PyEval_InitThreads() should be very fast, and + this is only run at start-up anyway. */ + } + } +# else + int volatile *lock = (int volatile *)&PyCapsule_Type.tp_version_tag; + int old_value, locked_value; + assert(!(PyCapsule_Type.tp_flags & Py_TPFLAGS_HAVE_VERSION_TAG)); + + while (1) { /* spin loop */ + old_value = *lock; + locked_value = -42; + if (old_value == 0) { + if (cffi_compare_and_swap(lock, old_value, locked_value)) + break; + } + else { + assert(old_value == locked_value); + /* should ideally do a spin loop instruction here, but + hard to do it portably and doesn't really matter I + think: PyEval_InitThreads() should be very fast, and + this is only run at start-up anyway. */ + } + } +# endif +#endif + + /* call Py_InitializeEx() */ + if (!Py_IsInitialized()) { + _cffi_py_initialize(); +#if PY_VERSION_HEX < 0x03070000 + PyEval_InitThreads(); +#endif + PyEval_SaveThread(); /* release the GIL */ + /* the returned tstate must be the one that has been stored into the + autoTLSkey by _PyGILState_Init() called from Py_Initialize(). */ + } + else { +#if PY_VERSION_HEX < 0x03070000 + /* PyEval_InitThreads() is always a no-op from CPython 3.7 */ + PyGILState_STATE state = PyGILState_Ensure(); + PyEval_InitThreads(); + PyGILState_Release(state); +#endif + } + +#ifdef WITH_THREAD + /* release the lock */ + while (!cffi_compare_and_swap(lock, locked_value, old_value)) + ; +#endif + + return 0; +} + +/********** end CPython-specific section **********/ + + +#else + + +/********** PyPy-specific section **********/ + +PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(const void *[]); /* forward */ + +static struct _cffi_pypy_init_s { + const char *name; + void *func; /* function pointer */ + const char *code; +} _cffi_pypy_init = { + _CFFI_MODULE_NAME, + _CFFI_PYTHON_STARTUP_FUNC, + _CFFI_PYTHON_STARTUP_CODE, +}; + +extern int pypy_carefully_make_gil(const char *); +extern int pypy_init_embedded_cffi_module(int, struct _cffi_pypy_init_s *); + +static int _cffi_carefully_make_gil(void) +{ + return pypy_carefully_make_gil(_CFFI_MODULE_NAME); +} + +static int _cffi_initialize_python(void) +{ + return pypy_init_embedded_cffi_module(0xB011, &_cffi_pypy_init); +} + +/********** end PyPy-specific section **********/ + + +#endif + + +#ifdef __GNUC__ +__attribute__((noinline)) +#endif +static _cffi_call_python_fnptr _cffi_start_python(void) +{ + /* Delicate logic to initialize Python. This function can be + called multiple times concurrently, e.g. when the process calls + its first ``extern "Python"`` functions in multiple threads at + once. It can also be called recursively, in which case we must + ignore it. We also have to consider what occurs if several + different cffi-based extensions reach this code in parallel + threads---it is a different copy of the code, then, and we + can't have any shared global variable unless it comes from + 'libpythonX.Y.so'. + + Idea: + + * _cffi_carefully_make_gil(): "carefully" call + PyEval_InitThreads() (possibly with Py_InitializeEx() first). + + * then we use a (local) custom lock to make sure that a call to this + cffi-based extension will wait if another call to the *same* + extension is running the initialization in another thread. + It is reentrant, so that a recursive call will not block, but + only one from a different thread. + + * then we grab the GIL and (Python 2) we call Py_InitializeEx(). + At this point, concurrent calls to Py_InitializeEx() are not + possible: we have the GIL. + + * do the rest of the specific initialization, which may + temporarily release the GIL but not the custom lock. + Only release the custom lock when we are done. + */ + static char called = 0; + + if (_cffi_carefully_make_gil() != 0) + return NULL; + + _cffi_acquire_reentrant_mutex(); + + /* Here the GIL exists, but we don't have it. We're only protected + from concurrency by the reentrant mutex. */ + + /* This file only initializes the embedded module once, the first + time this is called, even if there are subinterpreters. */ + if (!called) { + called = 1; /* invoke _cffi_initialize_python() only once, + but don't set '_cffi_call_python' right now, + otherwise concurrent threads won't call + this function at all (we need them to wait) */ + if (_cffi_initialize_python() == 0) { + /* now initialization is finished. Switch to the fast-path. */ + + /* We would like nobody to see the new value of + '_cffi_call_python' without also seeing the rest of the + data initialized. However, this is not possible. But + the new value of '_cffi_call_python' is the function + 'cffi_call_python()' from _cffi_backend. So: */ + cffi_write_barrier(); + /* ^^^ we put a write barrier here, and a corresponding + read barrier at the start of cffi_call_python(). This + ensures that after that read barrier, we see everything + done here before the write barrier. + */ + + assert(_cffi_call_python_org != NULL); + _cffi_call_python = (_cffi_call_python_fnptr)_cffi_call_python_org; + } + else { + /* initialization failed. Reset this to NULL, even if it was + already set to some other value. Future calls to + _cffi_start_python() are still forced to occur, and will + always return NULL from now on. */ + _cffi_call_python_org = NULL; + } + } + + _cffi_release_reentrant_mutex(); + + return (_cffi_call_python_fnptr)_cffi_call_python_org; +} + +static +void _cffi_start_and_call_python(struct _cffi_externpy_s *externpy, char *args) +{ + _cffi_call_python_fnptr fnptr; + int current_err = errno; +#ifdef _MSC_VER + int current_lasterr = GetLastError(); +#endif + fnptr = _cffi_start_python(); + if (fnptr == NULL) { + fprintf(stderr, "function %s() called, but initialization code " + "failed. Returning 0.\n", externpy->name); + memset(args, 0, externpy->size_of_result); + } +#ifdef _MSC_VER + SetLastError(current_lasterr); +#endif + errno = current_err; + + if (fnptr != NULL) + fnptr(externpy, args); +} + + +/* The cffi_start_python() function makes sure Python is initialized + and our cffi module is set up. It can be called manually from the + user C code. The same effect is obtained automatically from any + dll-exported ``extern "Python"`` function. This function returns + -1 if initialization failed, 0 if all is OK. */ +_CFFI_UNUSED_FN +static int cffi_start_python(void) +{ + if (_cffi_call_python == &_cffi_start_and_call_python) { + if (_cffi_start_python() == NULL) + return -1; + } + cffi_read_barrier(); + return 0; +} + +#undef cffi_compare_and_swap +#undef cffi_write_barrier +#undef cffi_read_barrier + +#ifdef __cplusplus +} +#endif diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/api.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/api.py new file mode 100644 index 0000000..999a8ae --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/api.py @@ -0,0 +1,965 @@ +import sys, types +from .lock import allocate_lock +from .error import CDefError +from . import model + +try: + callable +except NameError: + # Python 3.1 + from collections import Callable + callable = lambda x: isinstance(x, Callable) + +try: + basestring +except NameError: + # Python 3.x + basestring = str + +_unspecified = object() + + + +class FFI(object): + r''' + The main top-level class that you instantiate once, or once per module. + + Example usage: + + ffi = FFI() + ffi.cdef(""" + int printf(const char *, ...); + """) + + C = ffi.dlopen(None) # standard library + -or- + C = ffi.verify() # use a C compiler: verify the decl above is right + + C.printf("hello, %s!\n", ffi.new("char[]", "world")) + ''' + + def __init__(self, backend=None): + """Create an FFI instance. The 'backend' argument is used to + select a non-default backend, mostly for tests. + """ + if backend is None: + # You need PyPy (>= 2.0 beta), or a CPython (>= 2.6) with + # _cffi_backend.so compiled. + import _cffi_backend as backend + from . import __version__ + if backend.__version__ != __version__: + # bad version! Try to be as explicit as possible. + if hasattr(backend, '__file__'): + # CPython + raise Exception("Version mismatch: this is the 'cffi' package version %s, located in %r. When we import the top-level '_cffi_backend' extension module, we get version %s, located in %r. The two versions should be equal; check your installation." % ( + __version__, __file__, + backend.__version__, backend.__file__)) + else: + # PyPy + raise Exception("Version mismatch: this is the 'cffi' package version %s, located in %r. This interpreter comes with a built-in '_cffi_backend' module, which is version %s. The two versions should be equal; check your installation." % ( + __version__, __file__, backend.__version__)) + # (If you insist you can also try to pass the option + # 'backend=backend_ctypes.CTypesBackend()', but don't + # rely on it! It's probably not going to work well.) + + from . import cparser + self._backend = backend + self._lock = allocate_lock() + self._parser = cparser.Parser() + self._cached_btypes = {} + self._parsed_types = types.ModuleType('parsed_types').__dict__ + self._new_types = types.ModuleType('new_types').__dict__ + self._function_caches = [] + self._libraries = [] + self._cdefsources = [] + self._included_ffis = [] + self._windows_unicode = None + self._init_once_cache = {} + self._cdef_version = None + self._embedding = None + self._typecache = model.get_typecache(backend) + if hasattr(backend, 'set_ffi'): + backend.set_ffi(self) + for name in list(backend.__dict__): + if name.startswith('RTLD_'): + setattr(self, name, getattr(backend, name)) + # + with self._lock: + self.BVoidP = self._get_cached_btype(model.voidp_type) + self.BCharA = self._get_cached_btype(model.char_array_type) + if isinstance(backend, types.ModuleType): + # _cffi_backend: attach these constants to the class + if not hasattr(FFI, 'NULL'): + FFI.NULL = self.cast(self.BVoidP, 0) + FFI.CData, FFI.CType = backend._get_types() + else: + # ctypes backend: attach these constants to the instance + self.NULL = self.cast(self.BVoidP, 0) + self.CData, self.CType = backend._get_types() + self.buffer = backend.buffer + + def cdef(self, csource, override=False, packed=False, pack=None): + """Parse the given C source. This registers all declared functions, + types, and global variables. The functions and global variables can + then be accessed via either 'ffi.dlopen()' or 'ffi.verify()'. + The types can be used in 'ffi.new()' and other functions. + If 'packed' is specified as True, all structs declared inside this + cdef are packed, i.e. laid out without any field alignment at all. + Alternatively, 'pack' can be a small integer, and requests for + alignment greater than that are ignored (pack=1 is equivalent to + packed=True). + """ + self._cdef(csource, override=override, packed=packed, pack=pack) + + def embedding_api(self, csource, packed=False, pack=None): + self._cdef(csource, packed=packed, pack=pack, dllexport=True) + if self._embedding is None: + self._embedding = '' + + def _cdef(self, csource, override=False, **options): + if not isinstance(csource, str): # unicode, on Python 2 + if not isinstance(csource, basestring): + raise TypeError("cdef() argument must be a string") + csource = csource.encode('ascii') + with self._lock: + self._cdef_version = object() + self._parser.parse(csource, override=override, **options) + self._cdefsources.append(csource) + if override: + for cache in self._function_caches: + cache.clear() + finishlist = self._parser._recomplete + if finishlist: + self._parser._recomplete = [] + for tp in finishlist: + tp.finish_backend_type(self, finishlist) + + def dlopen(self, name, flags=0): + """Load and return a dynamic library identified by 'name'. + The standard C library can be loaded by passing None. + Note that functions and types declared by 'ffi.cdef()' are not + linked to a particular library, just like C headers; in the + library we only look for the actual (untyped) symbols. + """ + if not (isinstance(name, basestring) or + name is None or + isinstance(name, self.CData)): + raise TypeError("dlopen(name): name must be a file name, None, " + "or an already-opened 'void *' handle") + with self._lock: + lib, function_cache = _make_ffi_library(self, name, flags) + self._function_caches.append(function_cache) + self._libraries.append(lib) + return lib + + def dlclose(self, lib): + """Close a library obtained with ffi.dlopen(). After this call, + access to functions or variables from the library will fail + (possibly with a segmentation fault). + """ + type(lib).__cffi_close__(lib) + + def _typeof_locked(self, cdecl): + # call me with the lock! + key = cdecl + if key in self._parsed_types: + return self._parsed_types[key] + # + if not isinstance(cdecl, str): # unicode, on Python 2 + cdecl = cdecl.encode('ascii') + # + type = self._parser.parse_type(cdecl) + really_a_function_type = type.is_raw_function + if really_a_function_type: + type = type.as_function_pointer() + btype = self._get_cached_btype(type) + result = btype, really_a_function_type + self._parsed_types[key] = result + return result + + def _typeof(self, cdecl, consider_function_as_funcptr=False): + # string -> ctype object + try: + result = self._parsed_types[cdecl] + except KeyError: + with self._lock: + result = self._typeof_locked(cdecl) + # + btype, really_a_function_type = result + if really_a_function_type and not consider_function_as_funcptr: + raise CDefError("the type %r is a function type, not a " + "pointer-to-function type" % (cdecl,)) + return btype + + def typeof(self, cdecl): + """Parse the C type given as a string and return the + corresponding object. + It can also be used on 'cdata' instance to get its C type. + """ + if isinstance(cdecl, basestring): + return self._typeof(cdecl) + if isinstance(cdecl, self.CData): + return self._backend.typeof(cdecl) + if isinstance(cdecl, types.BuiltinFunctionType): + res = _builtin_function_type(cdecl) + if res is not None: + return res + if (isinstance(cdecl, types.FunctionType) + and hasattr(cdecl, '_cffi_base_type')): + with self._lock: + return self._get_cached_btype(cdecl._cffi_base_type) + raise TypeError(type(cdecl)) + + def sizeof(self, cdecl): + """Return the size in bytes of the argument. It can be a + string naming a C type, or a 'cdata' instance. + """ + if isinstance(cdecl, basestring): + BType = self._typeof(cdecl) + return self._backend.sizeof(BType) + else: + return self._backend.sizeof(cdecl) + + def alignof(self, cdecl): + """Return the natural alignment size in bytes of the C type + given as a string. + """ + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return self._backend.alignof(cdecl) + + def offsetof(self, cdecl, *fields_or_indexes): + """Return the offset of the named field inside the given + structure or array, which must be given as a C type name. + You can give several field names in case of nested structures. + You can also give numeric values which correspond to array + items, in case of an array type. + """ + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return self._typeoffsetof(cdecl, *fields_or_indexes)[1] + + def new(self, cdecl, init=None): + """Allocate an instance according to the specified C type and + return a pointer to it. The specified C type must be either a + pointer or an array: ``new('X *')`` allocates an X and returns + a pointer to it, whereas ``new('X[n]')`` allocates an array of + n X'es and returns an array referencing it (which works + mostly like a pointer, like in C). You can also use + ``new('X[]', n)`` to allocate an array of a non-constant + length n. + + The memory is initialized following the rules of declaring a + global variable in C: by default it is zero-initialized, but + an explicit initializer can be given which can be used to + fill all or part of the memory. + + When the returned object goes out of scope, the memory + is freed. In other words the returned object has + ownership of the value of type 'cdecl' that it points to. This + means that the raw data can be used as long as this object is + kept alive, but must not be used for a longer time. Be careful + about that when copying the pointer to the memory somewhere + else, e.g. into another structure. + """ + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return self._backend.newp(cdecl, init) + + def new_allocator(self, alloc=None, free=None, + should_clear_after_alloc=True): + """Return a new allocator, i.e. a function that behaves like ffi.new() + but uses the provided low-level 'alloc' and 'free' functions. + + 'alloc' is called with the size as argument. If it returns NULL, a + MemoryError is raised. 'free' is called with the result of 'alloc' + as argument. Both can be either Python function or directly C + functions. If 'free' is None, then no free function is called. + If both 'alloc' and 'free' are None, the default is used. + + If 'should_clear_after_alloc' is set to False, then the memory + returned by 'alloc' is assumed to be already cleared (or you are + fine with garbage); otherwise CFFI will clear it. + """ + compiled_ffi = self._backend.FFI() + allocator = compiled_ffi.new_allocator(alloc, free, + should_clear_after_alloc) + def allocate(cdecl, init=None): + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return allocator(cdecl, init) + return allocate + + def cast(self, cdecl, source): + """Similar to a C cast: returns an instance of the named C + type initialized with the given 'source'. The source is + casted between integers or pointers of any type. + """ + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return self._backend.cast(cdecl, source) + + def string(self, cdata, maxlen=-1): + """Return a Python string (or unicode string) from the 'cdata'. + If 'cdata' is a pointer or array of characters or bytes, returns + the null-terminated string. The returned string extends until + the first null character, or at most 'maxlen' characters. If + 'cdata' is an array then 'maxlen' defaults to its length. + + If 'cdata' is a pointer or array of wchar_t, returns a unicode + string following the same rules. + + If 'cdata' is a single character or byte or a wchar_t, returns + it as a string or unicode string. + + If 'cdata' is an enum, returns the value of the enumerator as a + string, or 'NUMBER' if the value is out of range. + """ + return self._backend.string(cdata, maxlen) + + def unpack(self, cdata, length): + """Unpack an array of C data of the given length, + returning a Python string/unicode/list. + + If 'cdata' is a pointer to 'char', returns a byte string. + It does not stop at the first null. This is equivalent to: + ffi.buffer(cdata, length)[:] + + If 'cdata' is a pointer to 'wchar_t', returns a unicode string. + 'length' is measured in wchar_t's; it is not the size in bytes. + + If 'cdata' is a pointer to anything else, returns a list of + 'length' items. This is a faster equivalent to: + [cdata[i] for i in range(length)] + """ + return self._backend.unpack(cdata, length) + + #def buffer(self, cdata, size=-1): + # """Return a read-write buffer object that references the raw C data + # pointed to by the given 'cdata'. The 'cdata' must be a pointer or + # an array. Can be passed to functions expecting a buffer, or directly + # manipulated with: + # + # buf[:] get a copy of it in a regular string, or + # buf[idx] as a single character + # buf[:] = ... + # buf[idx] = ... change the content + # """ + # note that 'buffer' is a type, set on this instance by __init__ + + def from_buffer(self, cdecl, python_buffer=_unspecified, + require_writable=False): + """Return a cdata of the given type pointing to the data of the + given Python object, which must support the buffer interface. + Note that this is not meant to be used on the built-in types + str or unicode (you can build 'char[]' arrays explicitly) + but only on objects containing large quantities of raw data + in some other format, like 'array.array' or numpy arrays. + + The first argument is optional and default to 'char[]'. + """ + if python_buffer is _unspecified: + cdecl, python_buffer = self.BCharA, cdecl + elif isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return self._backend.from_buffer(cdecl, python_buffer, + require_writable) + + def memmove(self, dest, src, n): + """ffi.memmove(dest, src, n) copies n bytes of memory from src to dest. + + Like the C function memmove(), the memory areas may overlap; + apart from that it behaves like the C function memcpy(). + + 'src' can be any cdata ptr or array, or any Python buffer object. + 'dest' can be any cdata ptr or array, or a writable Python buffer + object. The size to copy, 'n', is always measured in bytes. + + Unlike other methods, this one supports all Python buffer including + byte strings and bytearrays---but it still does not support + non-contiguous buffers. + """ + return self._backend.memmove(dest, src, n) + + def callback(self, cdecl, python_callable=None, error=None, onerror=None): + """Return a callback object or a decorator making such a + callback object. 'cdecl' must name a C function pointer type. + The callback invokes the specified 'python_callable' (which may + be provided either directly or via a decorator). Important: the + callback object must be manually kept alive for as long as the + callback may be invoked from the C level. + """ + def callback_decorator_wrap(python_callable): + if not callable(python_callable): + raise TypeError("the 'python_callable' argument " + "is not callable") + return self._backend.callback(cdecl, python_callable, + error, onerror) + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl, consider_function_as_funcptr=True) + if python_callable is None: + return callback_decorator_wrap # decorator mode + else: + return callback_decorator_wrap(python_callable) # direct mode + + def getctype(self, cdecl, replace_with=''): + """Return a string giving the C type 'cdecl', which may be itself + a string or a object. If 'replace_with' is given, it gives + extra text to append (or insert for more complicated C types), like + a variable name, or '*' to get actually the C type 'pointer-to-cdecl'. + """ + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + replace_with = replace_with.strip() + if (replace_with.startswith('*') + and '&[' in self._backend.getcname(cdecl, '&')): + replace_with = '(%s)' % replace_with + elif replace_with and not replace_with[0] in '[(': + replace_with = ' ' + replace_with + return self._backend.getcname(cdecl, replace_with) + + def gc(self, cdata, destructor, size=0): + """Return a new cdata object that points to the same + data. Later, when this new cdata object is garbage-collected, + 'destructor(old_cdata_object)' will be called. + + The optional 'size' gives an estimate of the size, used to + trigger the garbage collection more eagerly. So far only used + on PyPy. It tells the GC that the returned object keeps alive + roughly 'size' bytes of external memory. + """ + return self._backend.gcp(cdata, destructor, size) + + def _get_cached_btype(self, type): + assert self._lock.acquire(False) is False + # call me with the lock! + try: + BType = self._cached_btypes[type] + except KeyError: + finishlist = [] + BType = type.get_cached_btype(self, finishlist) + for type in finishlist: + type.finish_backend_type(self, finishlist) + return BType + + def verify(self, source='', tmpdir=None, **kwargs): + """Verify that the current ffi signatures compile on this + machine, and return a dynamic library object. The dynamic + library can be used to call functions and access global + variables declared in this 'ffi'. The library is compiled + by the C compiler: it gives you C-level API compatibility + (including calling macros). This is unlike 'ffi.dlopen()', + which requires binary compatibility in the signatures. + """ + from .verifier import Verifier, _caller_dir_pycache + # + # If set_unicode(True) was called, insert the UNICODE and + # _UNICODE macro declarations + if self._windows_unicode: + self._apply_windows_unicode(kwargs) + # + # Set the tmpdir here, and not in Verifier.__init__: it picks + # up the caller's directory, which we want to be the caller of + # ffi.verify(), as opposed to the caller of Veritier(). + tmpdir = tmpdir or _caller_dir_pycache() + # + # Make a Verifier() and use it to load the library. + self.verifier = Verifier(self, source, tmpdir, **kwargs) + lib = self.verifier.load_library() + # + # Save the loaded library for keep-alive purposes, even + # if the caller doesn't keep it alive itself (it should). + self._libraries.append(lib) + return lib + + def _get_errno(self): + return self._backend.get_errno() + def _set_errno(self, errno): + self._backend.set_errno(errno) + errno = property(_get_errno, _set_errno, None, + "the value of 'errno' from/to the C calls") + + def getwinerror(self, code=-1): + return self._backend.getwinerror(code) + + def _pointer_to(self, ctype): + with self._lock: + return model.pointer_cache(self, ctype) + + def addressof(self, cdata, *fields_or_indexes): + """Return the address of a . + If 'fields_or_indexes' are given, returns the address of that + field or array item in the structure or array, recursively in + case of nested structures. + """ + try: + ctype = self._backend.typeof(cdata) + except TypeError: + if '__addressof__' in type(cdata).__dict__: + return type(cdata).__addressof__(cdata, *fields_or_indexes) + raise + if fields_or_indexes: + ctype, offset = self._typeoffsetof(ctype, *fields_or_indexes) + else: + if ctype.kind == "pointer": + raise TypeError("addressof(pointer)") + offset = 0 + ctypeptr = self._pointer_to(ctype) + return self._backend.rawaddressof(ctypeptr, cdata, offset) + + def _typeoffsetof(self, ctype, field_or_index, *fields_or_indexes): + ctype, offset = self._backend.typeoffsetof(ctype, field_or_index) + for field1 in fields_or_indexes: + ctype, offset1 = self._backend.typeoffsetof(ctype, field1, 1) + offset += offset1 + return ctype, offset + + def include(self, ffi_to_include): + """Includes the typedefs, structs, unions and enums defined + in another FFI instance. Usage is similar to a #include in C, + where a part of the program might include types defined in + another part for its own usage. Note that the include() + method has no effect on functions, constants and global + variables, which must anyway be accessed directly from the + lib object returned by the original FFI instance. + """ + if not isinstance(ffi_to_include, FFI): + raise TypeError("ffi.include() expects an argument that is also of" + " type cffi.FFI, not %r" % ( + type(ffi_to_include).__name__,)) + if ffi_to_include is self: + raise ValueError("self.include(self)") + with ffi_to_include._lock: + with self._lock: + self._parser.include(ffi_to_include._parser) + self._cdefsources.append('[') + self._cdefsources.extend(ffi_to_include._cdefsources) + self._cdefsources.append(']') + self._included_ffis.append(ffi_to_include) + + def new_handle(self, x): + return self._backend.newp_handle(self.BVoidP, x) + + def from_handle(self, x): + return self._backend.from_handle(x) + + def release(self, x): + self._backend.release(x) + + def set_unicode(self, enabled_flag): + """Windows: if 'enabled_flag' is True, enable the UNICODE and + _UNICODE defines in C, and declare the types like TCHAR and LPTCSTR + to be (pointers to) wchar_t. If 'enabled_flag' is False, + declare these types to be (pointers to) plain 8-bit characters. + This is mostly for backward compatibility; you usually want True. + """ + if self._windows_unicode is not None: + raise ValueError("set_unicode() can only be called once") + enabled_flag = bool(enabled_flag) + if enabled_flag: + self.cdef("typedef wchar_t TBYTE;" + "typedef wchar_t TCHAR;" + "typedef const wchar_t *LPCTSTR;" + "typedef const wchar_t *PCTSTR;" + "typedef wchar_t *LPTSTR;" + "typedef wchar_t *PTSTR;" + "typedef TBYTE *PTBYTE;" + "typedef TCHAR *PTCHAR;") + else: + self.cdef("typedef char TBYTE;" + "typedef char TCHAR;" + "typedef const char *LPCTSTR;" + "typedef const char *PCTSTR;" + "typedef char *LPTSTR;" + "typedef char *PTSTR;" + "typedef TBYTE *PTBYTE;" + "typedef TCHAR *PTCHAR;") + self._windows_unicode = enabled_flag + + def _apply_windows_unicode(self, kwds): + defmacros = kwds.get('define_macros', ()) + if not isinstance(defmacros, (list, tuple)): + raise TypeError("'define_macros' must be a list or tuple") + defmacros = list(defmacros) + [('UNICODE', '1'), + ('_UNICODE', '1')] + kwds['define_macros'] = defmacros + + def _apply_embedding_fix(self, kwds): + # must include an argument like "-lpython2.7" for the compiler + def ensure(key, value): + lst = kwds.setdefault(key, []) + if value not in lst: + lst.append(value) + # + if '__pypy__' in sys.builtin_module_names: + import os + if sys.platform == "win32": + # we need 'libpypy-c.lib'. Current distributions of + # pypy (>= 4.1) contain it as 'libs/python27.lib'. + pythonlib = "python{0[0]}{0[1]}".format(sys.version_info) + if hasattr(sys, 'prefix'): + ensure('library_dirs', os.path.join(sys.prefix, 'libs')) + else: + # we need 'libpypy-c.{so,dylib}', which should be by + # default located in 'sys.prefix/bin' for installed + # systems. + if sys.version_info < (3,): + pythonlib = "pypy-c" + else: + pythonlib = "pypy3-c" + if hasattr(sys, 'prefix'): + ensure('library_dirs', os.path.join(sys.prefix, 'bin')) + # On uninstalled pypy's, the libpypy-c is typically found in + # .../pypy/goal/. + if hasattr(sys, 'prefix'): + ensure('library_dirs', os.path.join(sys.prefix, 'pypy', 'goal')) + else: + if sys.platform == "win32": + template = "python%d%d" + if hasattr(sys, 'gettotalrefcount'): + template += '_d' + else: + try: + import sysconfig + except ImportError: # 2.6 + from distutils import sysconfig + template = "python%d.%d" + if sysconfig.get_config_var('DEBUG_EXT'): + template += sysconfig.get_config_var('DEBUG_EXT') + pythonlib = (template % + (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff)) + if hasattr(sys, 'abiflags'): + pythonlib += sys.abiflags + ensure('libraries', pythonlib) + if sys.platform == "win32": + ensure('extra_link_args', '/MANIFEST') + + def set_source(self, module_name, source, source_extension='.c', **kwds): + import os + if hasattr(self, '_assigned_source'): + raise ValueError("set_source() cannot be called several times " + "per ffi object") + if not isinstance(module_name, basestring): + raise TypeError("'module_name' must be a string") + if os.sep in module_name or (os.altsep and os.altsep in module_name): + raise ValueError("'module_name' must not contain '/': use a dotted " + "name to make a 'package.module' location") + self._assigned_source = (str(module_name), source, + source_extension, kwds) + + def set_source_pkgconfig(self, module_name, pkgconfig_libs, source, + source_extension='.c', **kwds): + from . import pkgconfig + if not isinstance(pkgconfig_libs, list): + raise TypeError("the pkgconfig_libs argument must be a list " + "of package names") + kwds2 = pkgconfig.flags_from_pkgconfig(pkgconfig_libs) + pkgconfig.merge_flags(kwds, kwds2) + self.set_source(module_name, source, source_extension, **kwds) + + def distutils_extension(self, tmpdir='build', verbose=True): + from distutils.dir_util import mkpath + from .recompiler import recompile + # + if not hasattr(self, '_assigned_source'): + if hasattr(self, 'verifier'): # fallback, 'tmpdir' ignored + return self.verifier.get_extension() + raise ValueError("set_source() must be called before" + " distutils_extension()") + module_name, source, source_extension, kwds = self._assigned_source + if source is None: + raise TypeError("distutils_extension() is only for C extension " + "modules, not for dlopen()-style pure Python " + "modules") + mkpath(tmpdir) + ext, updated = recompile(self, module_name, + source, tmpdir=tmpdir, extradir=tmpdir, + source_extension=source_extension, + call_c_compiler=False, **kwds) + if verbose: + if updated: + sys.stderr.write("regenerated: %r\n" % (ext.sources[0],)) + else: + sys.stderr.write("not modified: %r\n" % (ext.sources[0],)) + return ext + + def emit_c_code(self, filename): + from .recompiler import recompile + # + if not hasattr(self, '_assigned_source'): + raise ValueError("set_source() must be called before emit_c_code()") + module_name, source, source_extension, kwds = self._assigned_source + if source is None: + raise TypeError("emit_c_code() is only for C extension modules, " + "not for dlopen()-style pure Python modules") + recompile(self, module_name, source, + c_file=filename, call_c_compiler=False, **kwds) + + def emit_python_code(self, filename): + from .recompiler import recompile + # + if not hasattr(self, '_assigned_source'): + raise ValueError("set_source() must be called before emit_c_code()") + module_name, source, source_extension, kwds = self._assigned_source + if source is not None: + raise TypeError("emit_python_code() is only for dlopen()-style " + "pure Python modules, not for C extension modules") + recompile(self, module_name, source, + c_file=filename, call_c_compiler=False, **kwds) + + def compile(self, tmpdir='.', verbose=0, target=None, debug=None): + """The 'target' argument gives the final file name of the + compiled DLL. Use '*' to force distutils' choice, suitable for + regular CPython C API modules. Use a file name ending in '.*' + to ask for the system's default extension for dynamic libraries + (.so/.dll/.dylib). + + The default is '*' when building a non-embedded C API extension, + and (module_name + '.*') when building an embedded library. + """ + from .recompiler import recompile + # + if not hasattr(self, '_assigned_source'): + raise ValueError("set_source() must be called before compile()") + module_name, source, source_extension, kwds = self._assigned_source + return recompile(self, module_name, source, tmpdir=tmpdir, + target=target, source_extension=source_extension, + compiler_verbose=verbose, debug=debug, **kwds) + + def init_once(self, func, tag): + # Read _init_once_cache[tag], which is either (False, lock) if + # we're calling the function now in some thread, or (True, result). + # Don't call setdefault() in most cases, to avoid allocating and + # immediately freeing a lock; but still use setdefaut() to avoid + # races. + try: + x = self._init_once_cache[tag] + except KeyError: + x = self._init_once_cache.setdefault(tag, (False, allocate_lock())) + # Common case: we got (True, result), so we return the result. + if x[0]: + return x[1] + # Else, it's a lock. Acquire it to serialize the following tests. + with x[1]: + # Read again from _init_once_cache the current status. + x = self._init_once_cache[tag] + if x[0]: + return x[1] + # Call the function and store the result back. + result = func() + self._init_once_cache[tag] = (True, result) + return result + + def embedding_init_code(self, pysource): + if self._embedding: + raise ValueError("embedding_init_code() can only be called once") + # fix 'pysource' before it gets dumped into the C file: + # - remove empty lines at the beginning, so it starts at "line 1" + # - dedent, if all non-empty lines are indented + # - check for SyntaxErrors + import re + match = re.match(r'\s*\n', pysource) + if match: + pysource = pysource[match.end():] + lines = pysource.splitlines() or [''] + prefix = re.match(r'\s*', lines[0]).group() + for i in range(1, len(lines)): + line = lines[i] + if line.rstrip(): + while not line.startswith(prefix): + prefix = prefix[:-1] + i = len(prefix) + lines = [line[i:]+'\n' for line in lines] + pysource = ''.join(lines) + # + compile(pysource, "cffi_init", "exec") + # + self._embedding = pysource + + def def_extern(self, *args, **kwds): + raise ValueError("ffi.def_extern() is only available on API-mode FFI " + "objects") + + def list_types(self): + """Returns the user type names known to this FFI instance. + This returns a tuple containing three lists of names: + (typedef_names, names_of_structs, names_of_unions) + """ + typedefs = [] + structs = [] + unions = [] + for key in self._parser._declarations: + if key.startswith('typedef '): + typedefs.append(key[8:]) + elif key.startswith('struct '): + structs.append(key[7:]) + elif key.startswith('union '): + unions.append(key[6:]) + typedefs.sort() + structs.sort() + unions.sort() + return (typedefs, structs, unions) + + +def _load_backend_lib(backend, name, flags): + import os + if not isinstance(name, basestring): + if sys.platform != "win32" or name is not None: + return backend.load_library(name, flags) + name = "c" # Windows: load_library(None) fails, but this works + # on Python 2 (backward compatibility hack only) + first_error = None + if '.' in name or '/' in name or os.sep in name: + try: + return backend.load_library(name, flags) + except OSError as e: + first_error = e + import ctypes.util + path = ctypes.util.find_library(name) + if path is None: + if name == "c" and sys.platform == "win32" and sys.version_info >= (3,): + raise OSError("dlopen(None) cannot work on Windows for Python 3 " + "(see http://bugs.python.org/issue23606)") + msg = ("ctypes.util.find_library() did not manage " + "to locate a library called %r" % (name,)) + if first_error is not None: + msg = "%s. Additionally, %s" % (first_error, msg) + raise OSError(msg) + return backend.load_library(path, flags) + +def _make_ffi_library(ffi, libname, flags): + backend = ffi._backend + backendlib = _load_backend_lib(backend, libname, flags) + # + def accessor_function(name): + key = 'function ' + name + tp, _ = ffi._parser._declarations[key] + BType = ffi._get_cached_btype(tp) + value = backendlib.load_function(BType, name) + library.__dict__[name] = value + # + def accessor_variable(name): + key = 'variable ' + name + tp, _ = ffi._parser._declarations[key] + BType = ffi._get_cached_btype(tp) + read_variable = backendlib.read_variable + write_variable = backendlib.write_variable + setattr(FFILibrary, name, property( + lambda self: read_variable(BType, name), + lambda self, value: write_variable(BType, name, value))) + # + def addressof_var(name): + try: + return addr_variables[name] + except KeyError: + with ffi._lock: + if name not in addr_variables: + key = 'variable ' + name + tp, _ = ffi._parser._declarations[key] + BType = ffi._get_cached_btype(tp) + if BType.kind != 'array': + BType = model.pointer_cache(ffi, BType) + p = backendlib.load_function(BType, name) + addr_variables[name] = p + return addr_variables[name] + # + def accessor_constant(name): + raise NotImplementedError("non-integer constant '%s' cannot be " + "accessed from a dlopen() library" % (name,)) + # + def accessor_int_constant(name): + library.__dict__[name] = ffi._parser._int_constants[name] + # + accessors = {} + accessors_version = [False] + addr_variables = {} + # + def update_accessors(): + if accessors_version[0] is ffi._cdef_version: + return + # + for key, (tp, _) in ffi._parser._declarations.items(): + if not isinstance(tp, model.EnumType): + tag, name = key.split(' ', 1) + if tag == 'function': + accessors[name] = accessor_function + elif tag == 'variable': + accessors[name] = accessor_variable + elif tag == 'constant': + accessors[name] = accessor_constant + else: + for i, enumname in enumerate(tp.enumerators): + def accessor_enum(name, tp=tp, i=i): + tp.check_not_partial() + library.__dict__[name] = tp.enumvalues[i] + accessors[enumname] = accessor_enum + for name in ffi._parser._int_constants: + accessors.setdefault(name, accessor_int_constant) + accessors_version[0] = ffi._cdef_version + # + def make_accessor(name): + with ffi._lock: + if name in library.__dict__ or name in FFILibrary.__dict__: + return # added by another thread while waiting for the lock + if name not in accessors: + update_accessors() + if name not in accessors: + raise AttributeError(name) + accessors[name](name) + # + class FFILibrary(object): + def __getattr__(self, name): + make_accessor(name) + return getattr(self, name) + def __setattr__(self, name, value): + try: + property = getattr(self.__class__, name) + except AttributeError: + make_accessor(name) + setattr(self, name, value) + else: + property.__set__(self, value) + def __dir__(self): + with ffi._lock: + update_accessors() + return accessors.keys() + def __addressof__(self, name): + if name in library.__dict__: + return library.__dict__[name] + if name in FFILibrary.__dict__: + return addressof_var(name) + make_accessor(name) + if name in library.__dict__: + return library.__dict__[name] + if name in FFILibrary.__dict__: + return addressof_var(name) + raise AttributeError("cffi library has no function or " + "global variable named '%s'" % (name,)) + def __cffi_close__(self): + backendlib.close_lib() + self.__dict__.clear() + # + if isinstance(libname, basestring): + try: + if not isinstance(libname, str): # unicode, on Python 2 + libname = libname.encode('utf-8') + FFILibrary.__name__ = 'FFILibrary_%s' % libname + except UnicodeError: + pass + library = FFILibrary() + return library, library.__dict__ + +def _builtin_function_type(func): + # a hack to make at least ffi.typeof(builtin_function) work, + # if the builtin function was obtained by 'vengine_cpy'. + import sys + try: + module = sys.modules[func.__module__] + ffi = module._cffi_original_ffi + types_of_builtin_funcs = module._cffi_types_of_builtin_funcs + tp = types_of_builtin_funcs[func] + except (KeyError, AttributeError, TypeError): + return None + else: + with ffi._lock: + return ffi._get_cached_btype(tp) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/backend_ctypes.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/backend_ctypes.py new file mode 100644 index 0000000..e7956a7 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/backend_ctypes.py @@ -0,0 +1,1121 @@ +import ctypes, ctypes.util, operator, sys +from . import model + +if sys.version_info < (3,): + bytechr = chr +else: + unicode = str + long = int + xrange = range + bytechr = lambda num: bytes([num]) + +class CTypesType(type): + pass + +class CTypesData(object): + __metaclass__ = CTypesType + __slots__ = ['__weakref__'] + __name__ = '' + + def __init__(self, *args): + raise TypeError("cannot instantiate %r" % (self.__class__,)) + + @classmethod + def _newp(cls, init): + raise TypeError("expected a pointer or array ctype, got '%s'" + % (cls._get_c_name(),)) + + @staticmethod + def _to_ctypes(value): + raise TypeError + + @classmethod + def _arg_to_ctypes(cls, *value): + try: + ctype = cls._ctype + except AttributeError: + raise TypeError("cannot create an instance of %r" % (cls,)) + if value: + res = cls._to_ctypes(*value) + if not isinstance(res, ctype): + res = cls._ctype(res) + else: + res = cls._ctype() + return res + + @classmethod + def _create_ctype_obj(cls, init): + if init is None: + return cls._arg_to_ctypes() + else: + return cls._arg_to_ctypes(init) + + @staticmethod + def _from_ctypes(ctypes_value): + raise TypeError + + @classmethod + def _get_c_name(cls, replace_with=''): + return cls._reftypename.replace(' &', replace_with) + + @classmethod + def _fix_class(cls): + cls.__name__ = 'CData<%s>' % (cls._get_c_name(),) + cls.__qualname__ = 'CData<%s>' % (cls._get_c_name(),) + cls.__module__ = 'ffi' + + def _get_own_repr(self): + raise NotImplementedError + + def _addr_repr(self, address): + if address == 0: + return 'NULL' + else: + if address < 0: + address += 1 << (8*ctypes.sizeof(ctypes.c_void_p)) + return '0x%x' % address + + def __repr__(self, c_name=None): + own = self._get_own_repr() + return '' % (c_name or self._get_c_name(), own) + + def _convert_to_address(self, BClass): + if BClass is None: + raise TypeError("cannot convert %r to an address" % ( + self._get_c_name(),)) + else: + raise TypeError("cannot convert %r to %r" % ( + self._get_c_name(), BClass._get_c_name())) + + @classmethod + def _get_size(cls): + return ctypes.sizeof(cls._ctype) + + def _get_size_of_instance(self): + return ctypes.sizeof(self._ctype) + + @classmethod + def _cast_from(cls, source): + raise TypeError("cannot cast to %r" % (cls._get_c_name(),)) + + def _cast_to_integer(self): + return self._convert_to_address(None) + + @classmethod + def _alignment(cls): + return ctypes.alignment(cls._ctype) + + def __iter__(self): + raise TypeError("cdata %r does not support iteration" % ( + self._get_c_name()),) + + def _make_cmp(name): + cmpfunc = getattr(operator, name) + def cmp(self, other): + v_is_ptr = not isinstance(self, CTypesGenericPrimitive) + w_is_ptr = (isinstance(other, CTypesData) and + not isinstance(other, CTypesGenericPrimitive)) + if v_is_ptr and w_is_ptr: + return cmpfunc(self._convert_to_address(None), + other._convert_to_address(None)) + elif v_is_ptr or w_is_ptr: + return NotImplemented + else: + if isinstance(self, CTypesGenericPrimitive): + self = self._value + if isinstance(other, CTypesGenericPrimitive): + other = other._value + return cmpfunc(self, other) + cmp.func_name = name + return cmp + + __eq__ = _make_cmp('__eq__') + __ne__ = _make_cmp('__ne__') + __lt__ = _make_cmp('__lt__') + __le__ = _make_cmp('__le__') + __gt__ = _make_cmp('__gt__') + __ge__ = _make_cmp('__ge__') + + def __hash__(self): + return hash(self._convert_to_address(None)) + + def _to_string(self, maxlen): + raise TypeError("string(): %r" % (self,)) + + +class CTypesGenericPrimitive(CTypesData): + __slots__ = [] + + def __hash__(self): + return hash(self._value) + + def _get_own_repr(self): + return repr(self._from_ctypes(self._value)) + + +class CTypesGenericArray(CTypesData): + __slots__ = [] + + @classmethod + def _newp(cls, init): + return cls(init) + + def __iter__(self): + for i in xrange(len(self)): + yield self[i] + + def _get_own_repr(self): + return self._addr_repr(ctypes.addressof(self._blob)) + + +class CTypesGenericPtr(CTypesData): + __slots__ = ['_address', '_as_ctype_ptr'] + _automatic_casts = False + kind = "pointer" + + @classmethod + def _newp(cls, init): + return cls(init) + + @classmethod + def _cast_from(cls, source): + if source is None: + address = 0 + elif isinstance(source, CTypesData): + address = source._cast_to_integer() + elif isinstance(source, (int, long)): + address = source + else: + raise TypeError("bad type for cast to %r: %r" % + (cls, type(source).__name__)) + return cls._new_pointer_at(address) + + @classmethod + def _new_pointer_at(cls, address): + self = cls.__new__(cls) + self._address = address + self._as_ctype_ptr = ctypes.cast(address, cls._ctype) + return self + + def _get_own_repr(self): + try: + return self._addr_repr(self._address) + except AttributeError: + return '???' + + def _cast_to_integer(self): + return self._address + + def __nonzero__(self): + return bool(self._address) + __bool__ = __nonzero__ + + @classmethod + def _to_ctypes(cls, value): + if not isinstance(value, CTypesData): + raise TypeError("unexpected %s object" % type(value).__name__) + address = value._convert_to_address(cls) + return ctypes.cast(address, cls._ctype) + + @classmethod + def _from_ctypes(cls, ctypes_ptr): + address = ctypes.cast(ctypes_ptr, ctypes.c_void_p).value or 0 + return cls._new_pointer_at(address) + + @classmethod + def _initialize(cls, ctypes_ptr, value): + if value: + ctypes_ptr.contents = cls._to_ctypes(value).contents + + def _convert_to_address(self, BClass): + if (BClass in (self.__class__, None) or BClass._automatic_casts + or self._automatic_casts): + return self._address + else: + return CTypesData._convert_to_address(self, BClass) + + +class CTypesBaseStructOrUnion(CTypesData): + __slots__ = ['_blob'] + + @classmethod + def _create_ctype_obj(cls, init): + # may be overridden + raise TypeError("cannot instantiate opaque type %s" % (cls,)) + + def _get_own_repr(self): + return self._addr_repr(ctypes.addressof(self._blob)) + + @classmethod + def _offsetof(cls, fieldname): + return getattr(cls._ctype, fieldname).offset + + def _convert_to_address(self, BClass): + if getattr(BClass, '_BItem', None) is self.__class__: + return ctypes.addressof(self._blob) + else: + return CTypesData._convert_to_address(self, BClass) + + @classmethod + def _from_ctypes(cls, ctypes_struct_or_union): + self = cls.__new__(cls) + self._blob = ctypes_struct_or_union + return self + + @classmethod + def _to_ctypes(cls, value): + return value._blob + + def __repr__(self, c_name=None): + return CTypesData.__repr__(self, c_name or self._get_c_name(' &')) + + +class CTypesBackend(object): + + PRIMITIVE_TYPES = { + 'char': ctypes.c_char, + 'short': ctypes.c_short, + 'int': ctypes.c_int, + 'long': ctypes.c_long, + 'long long': ctypes.c_longlong, + 'signed char': ctypes.c_byte, + 'unsigned char': ctypes.c_ubyte, + 'unsigned short': ctypes.c_ushort, + 'unsigned int': ctypes.c_uint, + 'unsigned long': ctypes.c_ulong, + 'unsigned long long': ctypes.c_ulonglong, + 'float': ctypes.c_float, + 'double': ctypes.c_double, + '_Bool': ctypes.c_bool, + } + + for _name in ['unsigned long long', 'unsigned long', + 'unsigned int', 'unsigned short', 'unsigned char']: + _size = ctypes.sizeof(PRIMITIVE_TYPES[_name]) + PRIMITIVE_TYPES['uint%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name] + if _size == ctypes.sizeof(ctypes.c_void_p): + PRIMITIVE_TYPES['uintptr_t'] = PRIMITIVE_TYPES[_name] + if _size == ctypes.sizeof(ctypes.c_size_t): + PRIMITIVE_TYPES['size_t'] = PRIMITIVE_TYPES[_name] + + for _name in ['long long', 'long', 'int', 'short', 'signed char']: + _size = ctypes.sizeof(PRIMITIVE_TYPES[_name]) + PRIMITIVE_TYPES['int%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name] + if _size == ctypes.sizeof(ctypes.c_void_p): + PRIMITIVE_TYPES['intptr_t'] = PRIMITIVE_TYPES[_name] + PRIMITIVE_TYPES['ptrdiff_t'] = PRIMITIVE_TYPES[_name] + if _size == ctypes.sizeof(ctypes.c_size_t): + PRIMITIVE_TYPES['ssize_t'] = PRIMITIVE_TYPES[_name] + + + def __init__(self): + self.RTLD_LAZY = 0 # not supported anyway by ctypes + self.RTLD_NOW = 0 + self.RTLD_GLOBAL = ctypes.RTLD_GLOBAL + self.RTLD_LOCAL = ctypes.RTLD_LOCAL + + def set_ffi(self, ffi): + self.ffi = ffi + + def _get_types(self): + return CTypesData, CTypesType + + def load_library(self, path, flags=0): + cdll = ctypes.CDLL(path, flags) + return CTypesLibrary(self, cdll) + + def new_void_type(self): + class CTypesVoid(CTypesData): + __slots__ = [] + _reftypename = 'void &' + @staticmethod + def _from_ctypes(novalue): + return None + @staticmethod + def _to_ctypes(novalue): + if novalue is not None: + raise TypeError("None expected, got %s object" % + (type(novalue).__name__,)) + return None + CTypesVoid._fix_class() + return CTypesVoid + + def new_primitive_type(self, name): + if name == 'wchar_t': + raise NotImplementedError(name) + ctype = self.PRIMITIVE_TYPES[name] + if name == 'char': + kind = 'char' + elif name in ('float', 'double'): + kind = 'float' + else: + if name in ('signed char', 'unsigned char'): + kind = 'byte' + elif name == '_Bool': + kind = 'bool' + else: + kind = 'int' + is_signed = (ctype(-1).value == -1) + # + def _cast_source_to_int(source): + if isinstance(source, (int, long, float)): + source = int(source) + elif isinstance(source, CTypesData): + source = source._cast_to_integer() + elif isinstance(source, bytes): + source = ord(source) + elif source is None: + source = 0 + else: + raise TypeError("bad type for cast to %r: %r" % + (CTypesPrimitive, type(source).__name__)) + return source + # + kind1 = kind + class CTypesPrimitive(CTypesGenericPrimitive): + __slots__ = ['_value'] + _ctype = ctype + _reftypename = '%s &' % name + kind = kind1 + + def __init__(self, value): + self._value = value + + @staticmethod + def _create_ctype_obj(init): + if init is None: + return ctype() + return ctype(CTypesPrimitive._to_ctypes(init)) + + if kind == 'int' or kind == 'byte': + @classmethod + def _cast_from(cls, source): + source = _cast_source_to_int(source) + source = ctype(source).value # cast within range + return cls(source) + def __int__(self): + return self._value + + if kind == 'bool': + @classmethod + def _cast_from(cls, source): + if not isinstance(source, (int, long, float)): + source = _cast_source_to_int(source) + return cls(bool(source)) + def __int__(self): + return int(self._value) + + if kind == 'char': + @classmethod + def _cast_from(cls, source): + source = _cast_source_to_int(source) + source = bytechr(source & 0xFF) + return cls(source) + def __int__(self): + return ord(self._value) + + if kind == 'float': + @classmethod + def _cast_from(cls, source): + if isinstance(source, float): + pass + elif isinstance(source, CTypesGenericPrimitive): + if hasattr(source, '__float__'): + source = float(source) + else: + source = int(source) + else: + source = _cast_source_to_int(source) + source = ctype(source).value # fix precision + return cls(source) + def __int__(self): + return int(self._value) + def __float__(self): + return self._value + + _cast_to_integer = __int__ + + if kind == 'int' or kind == 'byte' or kind == 'bool': + @staticmethod + def _to_ctypes(x): + if not isinstance(x, (int, long)): + if isinstance(x, CTypesData): + x = int(x) + else: + raise TypeError("integer expected, got %s" % + type(x).__name__) + if ctype(x).value != x: + if not is_signed and x < 0: + raise OverflowError("%s: negative integer" % name) + else: + raise OverflowError("%s: integer out of bounds" + % name) + return x + + if kind == 'char': + @staticmethod + def _to_ctypes(x): + if isinstance(x, bytes) and len(x) == 1: + return x + if isinstance(x, CTypesPrimitive): # > + return x._value + raise TypeError("character expected, got %s" % + type(x).__name__) + def __nonzero__(self): + return ord(self._value) != 0 + else: + def __nonzero__(self): + return self._value != 0 + __bool__ = __nonzero__ + + if kind == 'float': + @staticmethod + def _to_ctypes(x): + if not isinstance(x, (int, long, float, CTypesData)): + raise TypeError("float expected, got %s" % + type(x).__name__) + return ctype(x).value + + @staticmethod + def _from_ctypes(value): + return getattr(value, 'value', value) + + @staticmethod + def _initialize(blob, init): + blob.value = CTypesPrimitive._to_ctypes(init) + + if kind == 'char': + def _to_string(self, maxlen): + return self._value + if kind == 'byte': + def _to_string(self, maxlen): + return chr(self._value & 0xff) + # + CTypesPrimitive._fix_class() + return CTypesPrimitive + + def new_pointer_type(self, BItem): + getbtype = self.ffi._get_cached_btype + if BItem is getbtype(model.PrimitiveType('char')): + kind = 'charp' + elif BItem in (getbtype(model.PrimitiveType('signed char')), + getbtype(model.PrimitiveType('unsigned char'))): + kind = 'bytep' + elif BItem is getbtype(model.void_type): + kind = 'voidp' + else: + kind = 'generic' + # + class CTypesPtr(CTypesGenericPtr): + __slots__ = ['_own'] + if kind == 'charp': + __slots__ += ['__as_strbuf'] + _BItem = BItem + if hasattr(BItem, '_ctype'): + _ctype = ctypes.POINTER(BItem._ctype) + _bitem_size = ctypes.sizeof(BItem._ctype) + else: + _ctype = ctypes.c_void_p + if issubclass(BItem, CTypesGenericArray): + _reftypename = BItem._get_c_name('(* &)') + else: + _reftypename = BItem._get_c_name(' * &') + + def __init__(self, init): + ctypeobj = BItem._create_ctype_obj(init) + if kind == 'charp': + self.__as_strbuf = ctypes.create_string_buffer( + ctypeobj.value + b'\x00') + self._as_ctype_ptr = ctypes.cast( + self.__as_strbuf, self._ctype) + else: + self._as_ctype_ptr = ctypes.pointer(ctypeobj) + self._address = ctypes.cast(self._as_ctype_ptr, + ctypes.c_void_p).value + self._own = True + + def __add__(self, other): + if isinstance(other, (int, long)): + return self._new_pointer_at(self._address + + other * self._bitem_size) + else: + return NotImplemented + + def __sub__(self, other): + if isinstance(other, (int, long)): + return self._new_pointer_at(self._address - + other * self._bitem_size) + elif type(self) is type(other): + return (self._address - other._address) // self._bitem_size + else: + return NotImplemented + + def __getitem__(self, index): + if getattr(self, '_own', False) and index != 0: + raise IndexError + return BItem._from_ctypes(self._as_ctype_ptr[index]) + + def __setitem__(self, index, value): + self._as_ctype_ptr[index] = BItem._to_ctypes(value) + + if kind == 'charp' or kind == 'voidp': + @classmethod + def _arg_to_ctypes(cls, *value): + if value and isinstance(value[0], bytes): + return ctypes.c_char_p(value[0]) + else: + return super(CTypesPtr, cls)._arg_to_ctypes(*value) + + if kind == 'charp' or kind == 'bytep': + def _to_string(self, maxlen): + if maxlen < 0: + maxlen = sys.maxsize + p = ctypes.cast(self._as_ctype_ptr, + ctypes.POINTER(ctypes.c_char)) + n = 0 + while n < maxlen and p[n] != b'\x00': + n += 1 + return b''.join([p[i] for i in range(n)]) + + def _get_own_repr(self): + if getattr(self, '_own', False): + return 'owning %d bytes' % ( + ctypes.sizeof(self._as_ctype_ptr.contents),) + return super(CTypesPtr, self)._get_own_repr() + # + if (BItem is self.ffi._get_cached_btype(model.void_type) or + BItem is self.ffi._get_cached_btype(model.PrimitiveType('char'))): + CTypesPtr._automatic_casts = True + # + CTypesPtr._fix_class() + return CTypesPtr + + def new_array_type(self, CTypesPtr, length): + if length is None: + brackets = ' &[]' + else: + brackets = ' &[%d]' % length + BItem = CTypesPtr._BItem + getbtype = self.ffi._get_cached_btype + if BItem is getbtype(model.PrimitiveType('char')): + kind = 'char' + elif BItem in (getbtype(model.PrimitiveType('signed char')), + getbtype(model.PrimitiveType('unsigned char'))): + kind = 'byte' + else: + kind = 'generic' + # + class CTypesArray(CTypesGenericArray): + __slots__ = ['_blob', '_own'] + if length is not None: + _ctype = BItem._ctype * length + else: + __slots__.append('_ctype') + _reftypename = BItem._get_c_name(brackets) + _declared_length = length + _CTPtr = CTypesPtr + + def __init__(self, init): + if length is None: + if isinstance(init, (int, long)): + len1 = init + init = None + elif kind == 'char' and isinstance(init, bytes): + len1 = len(init) + 1 # extra null + else: + init = tuple(init) + len1 = len(init) + self._ctype = BItem._ctype * len1 + self._blob = self._ctype() + self._own = True + if init is not None: + self._initialize(self._blob, init) + + @staticmethod + def _initialize(blob, init): + if isinstance(init, bytes): + init = [init[i:i+1] for i in range(len(init))] + else: + if isinstance(init, CTypesGenericArray): + if (len(init) != len(blob) or + not isinstance(init, CTypesArray)): + raise TypeError("length/type mismatch: %s" % (init,)) + init = tuple(init) + if len(init) > len(blob): + raise IndexError("too many initializers") + addr = ctypes.cast(blob, ctypes.c_void_p).value + PTR = ctypes.POINTER(BItem._ctype) + itemsize = ctypes.sizeof(BItem._ctype) + for i, value in enumerate(init): + p = ctypes.cast(addr + i * itemsize, PTR) + BItem._initialize(p.contents, value) + + def __len__(self): + return len(self._blob) + + def __getitem__(self, index): + if not (0 <= index < len(self._blob)): + raise IndexError + return BItem._from_ctypes(self._blob[index]) + + def __setitem__(self, index, value): + if not (0 <= index < len(self._blob)): + raise IndexError + self._blob[index] = BItem._to_ctypes(value) + + if kind == 'char' or kind == 'byte': + def _to_string(self, maxlen): + if maxlen < 0: + maxlen = len(self._blob) + p = ctypes.cast(self._blob, + ctypes.POINTER(ctypes.c_char)) + n = 0 + while n < maxlen and p[n] != b'\x00': + n += 1 + return b''.join([p[i] for i in range(n)]) + + def _get_own_repr(self): + if getattr(self, '_own', False): + return 'owning %d bytes' % (ctypes.sizeof(self._blob),) + return super(CTypesArray, self)._get_own_repr() + + def _convert_to_address(self, BClass): + if BClass in (CTypesPtr, None) or BClass._automatic_casts: + return ctypes.addressof(self._blob) + else: + return CTypesData._convert_to_address(self, BClass) + + @staticmethod + def _from_ctypes(ctypes_array): + self = CTypesArray.__new__(CTypesArray) + self._blob = ctypes_array + return self + + @staticmethod + def _arg_to_ctypes(value): + return CTypesPtr._arg_to_ctypes(value) + + def __add__(self, other): + if isinstance(other, (int, long)): + return CTypesPtr._new_pointer_at( + ctypes.addressof(self._blob) + + other * ctypes.sizeof(BItem._ctype)) + else: + return NotImplemented + + @classmethod + def _cast_from(cls, source): + raise NotImplementedError("casting to %r" % ( + cls._get_c_name(),)) + # + CTypesArray._fix_class() + return CTypesArray + + def _new_struct_or_union(self, kind, name, base_ctypes_class): + # + class struct_or_union(base_ctypes_class): + pass + struct_or_union.__name__ = '%s_%s' % (kind, name) + kind1 = kind + # + class CTypesStructOrUnion(CTypesBaseStructOrUnion): + __slots__ = ['_blob'] + _ctype = struct_or_union + _reftypename = '%s &' % (name,) + _kind = kind = kind1 + # + CTypesStructOrUnion._fix_class() + return CTypesStructOrUnion + + def new_struct_type(self, name): + return self._new_struct_or_union('struct', name, ctypes.Structure) + + def new_union_type(self, name): + return self._new_struct_or_union('union', name, ctypes.Union) + + def complete_struct_or_union(self, CTypesStructOrUnion, fields, tp, + totalsize=-1, totalalignment=-1, sflags=0, + pack=0): + if totalsize >= 0 or totalalignment >= 0: + raise NotImplementedError("the ctypes backend of CFFI does not support " + "structures completed by verify(); please " + "compile and install the _cffi_backend module.") + struct_or_union = CTypesStructOrUnion._ctype + fnames = [fname for (fname, BField, bitsize) in fields] + btypes = [BField for (fname, BField, bitsize) in fields] + bitfields = [bitsize for (fname, BField, bitsize) in fields] + # + bfield_types = {} + cfields = [] + for (fname, BField, bitsize) in fields: + if bitsize < 0: + cfields.append((fname, BField._ctype)) + bfield_types[fname] = BField + else: + cfields.append((fname, BField._ctype, bitsize)) + bfield_types[fname] = Ellipsis + if sflags & 8: + struct_or_union._pack_ = 1 + elif pack: + struct_or_union._pack_ = pack + struct_or_union._fields_ = cfields + CTypesStructOrUnion._bfield_types = bfield_types + # + @staticmethod + def _create_ctype_obj(init): + result = struct_or_union() + if init is not None: + initialize(result, init) + return result + CTypesStructOrUnion._create_ctype_obj = _create_ctype_obj + # + def initialize(blob, init): + if is_union: + if len(init) > 1: + raise ValueError("union initializer: %d items given, but " + "only one supported (use a dict if needed)" + % (len(init),)) + if not isinstance(init, dict): + if isinstance(init, (bytes, unicode)): + raise TypeError("union initializer: got a str") + init = tuple(init) + if len(init) > len(fnames): + raise ValueError("too many values for %s initializer" % + CTypesStructOrUnion._get_c_name()) + init = dict(zip(fnames, init)) + addr = ctypes.addressof(blob) + for fname, value in init.items(): + BField, bitsize = name2fieldtype[fname] + assert bitsize < 0, \ + "not implemented: initializer with bit fields" + offset = CTypesStructOrUnion._offsetof(fname) + PTR = ctypes.POINTER(BField._ctype) + p = ctypes.cast(addr + offset, PTR) + BField._initialize(p.contents, value) + is_union = CTypesStructOrUnion._kind == 'union' + name2fieldtype = dict(zip(fnames, zip(btypes, bitfields))) + # + for fname, BField, bitsize in fields: + if fname == '': + raise NotImplementedError("nested anonymous structs/unions") + if hasattr(CTypesStructOrUnion, fname): + raise ValueError("the field name %r conflicts in " + "the ctypes backend" % fname) + if bitsize < 0: + def getter(self, fname=fname, BField=BField, + offset=CTypesStructOrUnion._offsetof(fname), + PTR=ctypes.POINTER(BField._ctype)): + addr = ctypes.addressof(self._blob) + p = ctypes.cast(addr + offset, PTR) + return BField._from_ctypes(p.contents) + def setter(self, value, fname=fname, BField=BField): + setattr(self._blob, fname, BField._to_ctypes(value)) + # + if issubclass(BField, CTypesGenericArray): + setter = None + if BField._declared_length == 0: + def getter(self, fname=fname, BFieldPtr=BField._CTPtr, + offset=CTypesStructOrUnion._offsetof(fname), + PTR=ctypes.POINTER(BField._ctype)): + addr = ctypes.addressof(self._blob) + p = ctypes.cast(addr + offset, PTR) + return BFieldPtr._from_ctypes(p) + # + else: + def getter(self, fname=fname, BField=BField): + return BField._from_ctypes(getattr(self._blob, fname)) + def setter(self, value, fname=fname, BField=BField): + # xxx obscure workaround + value = BField._to_ctypes(value) + oldvalue = getattr(self._blob, fname) + setattr(self._blob, fname, value) + if value != getattr(self._blob, fname): + setattr(self._blob, fname, oldvalue) + raise OverflowError("value too large for bitfield") + setattr(CTypesStructOrUnion, fname, property(getter, setter)) + # + CTypesPtr = self.ffi._get_cached_btype(model.PointerType(tp)) + for fname in fnames: + if hasattr(CTypesPtr, fname): + raise ValueError("the field name %r conflicts in " + "the ctypes backend" % fname) + def getter(self, fname=fname): + return getattr(self[0], fname) + def setter(self, value, fname=fname): + setattr(self[0], fname, value) + setattr(CTypesPtr, fname, property(getter, setter)) + + def new_function_type(self, BArgs, BResult, has_varargs): + nameargs = [BArg._get_c_name() for BArg in BArgs] + if has_varargs: + nameargs.append('...') + nameargs = ', '.join(nameargs) + # + class CTypesFunctionPtr(CTypesGenericPtr): + __slots__ = ['_own_callback', '_name'] + _ctype = ctypes.CFUNCTYPE(getattr(BResult, '_ctype', None), + *[BArg._ctype for BArg in BArgs], + use_errno=True) + _reftypename = BResult._get_c_name('(* &)(%s)' % (nameargs,)) + + def __init__(self, init, error=None): + # create a callback to the Python callable init() + import traceback + assert not has_varargs, "varargs not supported for callbacks" + if getattr(BResult, '_ctype', None) is not None: + error = BResult._from_ctypes( + BResult._create_ctype_obj(error)) + else: + error = None + def callback(*args): + args2 = [] + for arg, BArg in zip(args, BArgs): + args2.append(BArg._from_ctypes(arg)) + try: + res2 = init(*args2) + res2 = BResult._to_ctypes(res2) + except: + traceback.print_exc() + res2 = error + if issubclass(BResult, CTypesGenericPtr): + if res2: + res2 = ctypes.cast(res2, ctypes.c_void_p).value + # .value: http://bugs.python.org/issue1574593 + else: + res2 = None + #print repr(res2) + return res2 + if issubclass(BResult, CTypesGenericPtr): + # The only pointers callbacks can return are void*s: + # http://bugs.python.org/issue5710 + callback_ctype = ctypes.CFUNCTYPE( + ctypes.c_void_p, + *[BArg._ctype for BArg in BArgs], + use_errno=True) + else: + callback_ctype = CTypesFunctionPtr._ctype + self._as_ctype_ptr = callback_ctype(callback) + self._address = ctypes.cast(self._as_ctype_ptr, + ctypes.c_void_p).value + self._own_callback = init + + @staticmethod + def _initialize(ctypes_ptr, value): + if value: + raise NotImplementedError("ctypes backend: not supported: " + "initializers for function pointers") + + def __repr__(self): + c_name = getattr(self, '_name', None) + if c_name: + i = self._reftypename.index('(* &)') + if self._reftypename[i-1] not in ' )*': + c_name = ' ' + c_name + c_name = self._reftypename.replace('(* &)', c_name) + return CTypesData.__repr__(self, c_name) + + def _get_own_repr(self): + if getattr(self, '_own_callback', None) is not None: + return 'calling %r' % (self._own_callback,) + return super(CTypesFunctionPtr, self)._get_own_repr() + + def __call__(self, *args): + if has_varargs: + assert len(args) >= len(BArgs) + extraargs = args[len(BArgs):] + args = args[:len(BArgs)] + else: + assert len(args) == len(BArgs) + ctypes_args = [] + for arg, BArg in zip(args, BArgs): + ctypes_args.append(BArg._arg_to_ctypes(arg)) + if has_varargs: + for i, arg in enumerate(extraargs): + if arg is None: + ctypes_args.append(ctypes.c_void_p(0)) # NULL + continue + if not isinstance(arg, CTypesData): + raise TypeError( + "argument %d passed in the variadic part " + "needs to be a cdata object (got %s)" % + (1 + len(BArgs) + i, type(arg).__name__)) + ctypes_args.append(arg._arg_to_ctypes(arg)) + result = self._as_ctype_ptr(*ctypes_args) + return BResult._from_ctypes(result) + # + CTypesFunctionPtr._fix_class() + return CTypesFunctionPtr + + def new_enum_type(self, name, enumerators, enumvalues, CTypesInt): + assert isinstance(name, str) + reverse_mapping = dict(zip(reversed(enumvalues), + reversed(enumerators))) + # + class CTypesEnum(CTypesInt): + __slots__ = [] + _reftypename = '%s &' % name + + def _get_own_repr(self): + value = self._value + try: + return '%d: %s' % (value, reverse_mapping[value]) + except KeyError: + return str(value) + + def _to_string(self, maxlen): + value = self._value + try: + return reverse_mapping[value] + except KeyError: + return str(value) + # + CTypesEnum._fix_class() + return CTypesEnum + + def get_errno(self): + return ctypes.get_errno() + + def set_errno(self, value): + ctypes.set_errno(value) + + def string(self, b, maxlen=-1): + return b._to_string(maxlen) + + def buffer(self, bptr, size=-1): + raise NotImplementedError("buffer() with ctypes backend") + + def sizeof(self, cdata_or_BType): + if isinstance(cdata_or_BType, CTypesData): + return cdata_or_BType._get_size_of_instance() + else: + assert issubclass(cdata_or_BType, CTypesData) + return cdata_or_BType._get_size() + + def alignof(self, BType): + assert issubclass(BType, CTypesData) + return BType._alignment() + + def newp(self, BType, source): + if not issubclass(BType, CTypesData): + raise TypeError + return BType._newp(source) + + def cast(self, BType, source): + return BType._cast_from(source) + + def callback(self, BType, source, error, onerror): + assert onerror is None # XXX not implemented + return BType(source, error) + + _weakref_cache_ref = None + + def gcp(self, cdata, destructor, size=0): + if self._weakref_cache_ref is None: + import weakref + class MyRef(weakref.ref): + def __eq__(self, other): + myref = self() + return self is other or ( + myref is not None and myref is other()) + def __ne__(self, other): + return not (self == other) + def __hash__(self): + try: + return self._hash + except AttributeError: + self._hash = hash(self()) + return self._hash + self._weakref_cache_ref = {}, MyRef + weak_cache, MyRef = self._weakref_cache_ref + + if destructor is None: + try: + del weak_cache[MyRef(cdata)] + except KeyError: + raise TypeError("Can remove destructor only on a object " + "previously returned by ffi.gc()") + return None + + def remove(k): + cdata, destructor = weak_cache.pop(k, (None, None)) + if destructor is not None: + destructor(cdata) + + new_cdata = self.cast(self.typeof(cdata), cdata) + assert new_cdata is not cdata + weak_cache[MyRef(new_cdata, remove)] = (cdata, destructor) + return new_cdata + + typeof = type + + def getcname(self, BType, replace_with): + return BType._get_c_name(replace_with) + + def typeoffsetof(self, BType, fieldname, num=0): + if isinstance(fieldname, str): + if num == 0 and issubclass(BType, CTypesGenericPtr): + BType = BType._BItem + if not issubclass(BType, CTypesBaseStructOrUnion): + raise TypeError("expected a struct or union ctype") + BField = BType._bfield_types[fieldname] + if BField is Ellipsis: + raise TypeError("not supported for bitfields") + return (BField, BType._offsetof(fieldname)) + elif isinstance(fieldname, (int, long)): + if issubclass(BType, CTypesGenericArray): + BType = BType._CTPtr + if not issubclass(BType, CTypesGenericPtr): + raise TypeError("expected an array or ptr ctype") + BItem = BType._BItem + offset = BItem._get_size() * fieldname + if offset > sys.maxsize: + raise OverflowError + return (BItem, offset) + else: + raise TypeError(type(fieldname)) + + def rawaddressof(self, BTypePtr, cdata, offset=None): + if isinstance(cdata, CTypesBaseStructOrUnion): + ptr = ctypes.pointer(type(cdata)._to_ctypes(cdata)) + elif isinstance(cdata, CTypesGenericPtr): + if offset is None or not issubclass(type(cdata)._BItem, + CTypesBaseStructOrUnion): + raise TypeError("unexpected cdata type") + ptr = type(cdata)._to_ctypes(cdata) + elif isinstance(cdata, CTypesGenericArray): + ptr = type(cdata)._to_ctypes(cdata) + else: + raise TypeError("expected a ") + if offset: + ptr = ctypes.cast( + ctypes.c_void_p( + ctypes.cast(ptr, ctypes.c_void_p).value + offset), + type(ptr)) + return BTypePtr._from_ctypes(ptr) + + +class CTypesLibrary(object): + + def __init__(self, backend, cdll): + self.backend = backend + self.cdll = cdll + + def load_function(self, BType, name): + c_func = getattr(self.cdll, name) + funcobj = BType._from_ctypes(c_func) + funcobj._name = name + return funcobj + + def read_variable(self, BType, name): + try: + ctypes_obj = BType._ctype.in_dll(self.cdll, name) + except AttributeError as e: + raise NotImplementedError(e) + return BType._from_ctypes(ctypes_obj) + + def write_variable(self, BType, name, value): + new_ctypes_obj = BType._to_ctypes(value) + ctypes_obj = BType._ctype.in_dll(self.cdll, name) + ctypes.memmove(ctypes.addressof(ctypes_obj), + ctypes.addressof(new_ctypes_obj), + ctypes.sizeof(BType._ctype)) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/cffi_opcode.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/cffi_opcode.py new file mode 100644 index 0000000..a0df98d --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/cffi_opcode.py @@ -0,0 +1,187 @@ +from .error import VerificationError + +class CffiOp(object): + def __init__(self, op, arg): + self.op = op + self.arg = arg + + def as_c_expr(self): + if self.op is None: + assert isinstance(self.arg, str) + return '(_cffi_opcode_t)(%s)' % (self.arg,) + classname = CLASS_NAME[self.op] + return '_CFFI_OP(_CFFI_OP_%s, %s)' % (classname, self.arg) + + def as_python_bytes(self): + if self.op is None and self.arg.isdigit(): + value = int(self.arg) # non-negative: '-' not in self.arg + if value >= 2**31: + raise OverflowError("cannot emit %r: limited to 2**31-1" + % (self.arg,)) + return format_four_bytes(value) + if isinstance(self.arg, str): + raise VerificationError("cannot emit to Python: %r" % (self.arg,)) + return format_four_bytes((self.arg << 8) | self.op) + + def __str__(self): + classname = CLASS_NAME.get(self.op, self.op) + return '(%s %s)' % (classname, self.arg) + +def format_four_bytes(num): + return '\\x%02X\\x%02X\\x%02X\\x%02X' % ( + (num >> 24) & 0xFF, + (num >> 16) & 0xFF, + (num >> 8) & 0xFF, + (num ) & 0xFF) + +OP_PRIMITIVE = 1 +OP_POINTER = 3 +OP_ARRAY = 5 +OP_OPEN_ARRAY = 7 +OP_STRUCT_UNION = 9 +OP_ENUM = 11 +OP_FUNCTION = 13 +OP_FUNCTION_END = 15 +OP_NOOP = 17 +OP_BITFIELD = 19 +OP_TYPENAME = 21 +OP_CPYTHON_BLTN_V = 23 # varargs +OP_CPYTHON_BLTN_N = 25 # noargs +OP_CPYTHON_BLTN_O = 27 # O (i.e. a single arg) +OP_CONSTANT = 29 +OP_CONSTANT_INT = 31 +OP_GLOBAL_VAR = 33 +OP_DLOPEN_FUNC = 35 +OP_DLOPEN_CONST = 37 +OP_GLOBAL_VAR_F = 39 +OP_EXTERN_PYTHON = 41 + +PRIM_VOID = 0 +PRIM_BOOL = 1 +PRIM_CHAR = 2 +PRIM_SCHAR = 3 +PRIM_UCHAR = 4 +PRIM_SHORT = 5 +PRIM_USHORT = 6 +PRIM_INT = 7 +PRIM_UINT = 8 +PRIM_LONG = 9 +PRIM_ULONG = 10 +PRIM_LONGLONG = 11 +PRIM_ULONGLONG = 12 +PRIM_FLOAT = 13 +PRIM_DOUBLE = 14 +PRIM_LONGDOUBLE = 15 + +PRIM_WCHAR = 16 +PRIM_INT8 = 17 +PRIM_UINT8 = 18 +PRIM_INT16 = 19 +PRIM_UINT16 = 20 +PRIM_INT32 = 21 +PRIM_UINT32 = 22 +PRIM_INT64 = 23 +PRIM_UINT64 = 24 +PRIM_INTPTR = 25 +PRIM_UINTPTR = 26 +PRIM_PTRDIFF = 27 +PRIM_SIZE = 28 +PRIM_SSIZE = 29 +PRIM_INT_LEAST8 = 30 +PRIM_UINT_LEAST8 = 31 +PRIM_INT_LEAST16 = 32 +PRIM_UINT_LEAST16 = 33 +PRIM_INT_LEAST32 = 34 +PRIM_UINT_LEAST32 = 35 +PRIM_INT_LEAST64 = 36 +PRIM_UINT_LEAST64 = 37 +PRIM_INT_FAST8 = 38 +PRIM_UINT_FAST8 = 39 +PRIM_INT_FAST16 = 40 +PRIM_UINT_FAST16 = 41 +PRIM_INT_FAST32 = 42 +PRIM_UINT_FAST32 = 43 +PRIM_INT_FAST64 = 44 +PRIM_UINT_FAST64 = 45 +PRIM_INTMAX = 46 +PRIM_UINTMAX = 47 +PRIM_FLOATCOMPLEX = 48 +PRIM_DOUBLECOMPLEX = 49 +PRIM_CHAR16 = 50 +PRIM_CHAR32 = 51 + +_NUM_PRIM = 52 +_UNKNOWN_PRIM = -1 +_UNKNOWN_FLOAT_PRIM = -2 +_UNKNOWN_LONG_DOUBLE = -3 + +_IO_FILE_STRUCT = -1 + +PRIMITIVE_TO_INDEX = { + 'char': PRIM_CHAR, + 'short': PRIM_SHORT, + 'int': PRIM_INT, + 'long': PRIM_LONG, + 'long long': PRIM_LONGLONG, + 'signed char': PRIM_SCHAR, + 'unsigned char': PRIM_UCHAR, + 'unsigned short': PRIM_USHORT, + 'unsigned int': PRIM_UINT, + 'unsigned long': PRIM_ULONG, + 'unsigned long long': PRIM_ULONGLONG, + 'float': PRIM_FLOAT, + 'double': PRIM_DOUBLE, + 'long double': PRIM_LONGDOUBLE, + 'float _Complex': PRIM_FLOATCOMPLEX, + 'double _Complex': PRIM_DOUBLECOMPLEX, + '_Bool': PRIM_BOOL, + 'wchar_t': PRIM_WCHAR, + 'char16_t': PRIM_CHAR16, + 'char32_t': PRIM_CHAR32, + 'int8_t': PRIM_INT8, + 'uint8_t': PRIM_UINT8, + 'int16_t': PRIM_INT16, + 'uint16_t': PRIM_UINT16, + 'int32_t': PRIM_INT32, + 'uint32_t': PRIM_UINT32, + 'int64_t': PRIM_INT64, + 'uint64_t': PRIM_UINT64, + 'intptr_t': PRIM_INTPTR, + 'uintptr_t': PRIM_UINTPTR, + 'ptrdiff_t': PRIM_PTRDIFF, + 'size_t': PRIM_SIZE, + 'ssize_t': PRIM_SSIZE, + 'int_least8_t': PRIM_INT_LEAST8, + 'uint_least8_t': PRIM_UINT_LEAST8, + 'int_least16_t': PRIM_INT_LEAST16, + 'uint_least16_t': PRIM_UINT_LEAST16, + 'int_least32_t': PRIM_INT_LEAST32, + 'uint_least32_t': PRIM_UINT_LEAST32, + 'int_least64_t': PRIM_INT_LEAST64, + 'uint_least64_t': PRIM_UINT_LEAST64, + 'int_fast8_t': PRIM_INT_FAST8, + 'uint_fast8_t': PRIM_UINT_FAST8, + 'int_fast16_t': PRIM_INT_FAST16, + 'uint_fast16_t': PRIM_UINT_FAST16, + 'int_fast32_t': PRIM_INT_FAST32, + 'uint_fast32_t': PRIM_UINT_FAST32, + 'int_fast64_t': PRIM_INT_FAST64, + 'uint_fast64_t': PRIM_UINT_FAST64, + 'intmax_t': PRIM_INTMAX, + 'uintmax_t': PRIM_UINTMAX, + } + +F_UNION = 0x01 +F_CHECK_FIELDS = 0x02 +F_PACKED = 0x04 +F_EXTERNAL = 0x08 +F_OPAQUE = 0x10 + +G_FLAGS = dict([('_CFFI_' + _key, globals()[_key]) + for _key in ['F_UNION', 'F_CHECK_FIELDS', 'F_PACKED', + 'F_EXTERNAL', 'F_OPAQUE']]) + +CLASS_NAME = {} +for _name, _value in list(globals().items()): + if _name.startswith('OP_') and isinstance(_value, int): + CLASS_NAME[_value] = _name[3:] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/commontypes.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/commontypes.py new file mode 100644 index 0000000..8ec97c7 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/commontypes.py @@ -0,0 +1,80 @@ +import sys +from . import model +from .error import FFIError + + +COMMON_TYPES = {} + +try: + # fetch "bool" and all simple Windows types + from _cffi_backend import _get_common_types + _get_common_types(COMMON_TYPES) +except ImportError: + pass + +COMMON_TYPES['FILE'] = model.unknown_type('FILE', '_IO_FILE') +COMMON_TYPES['bool'] = '_Bool' # in case we got ImportError above + +for _type in model.PrimitiveType.ALL_PRIMITIVE_TYPES: + if _type.endswith('_t'): + COMMON_TYPES[_type] = _type +del _type + +_CACHE = {} + +def resolve_common_type(parser, commontype): + try: + return _CACHE[commontype] + except KeyError: + cdecl = COMMON_TYPES.get(commontype, commontype) + if not isinstance(cdecl, str): + result, quals = cdecl, 0 # cdecl is already a BaseType + elif cdecl in model.PrimitiveType.ALL_PRIMITIVE_TYPES: + result, quals = model.PrimitiveType(cdecl), 0 + elif cdecl == 'set-unicode-needed': + raise FFIError("The Windows type %r is only available after " + "you call ffi.set_unicode()" % (commontype,)) + else: + if commontype == cdecl: + raise FFIError( + "Unsupported type: %r. Please look at " + "http://cffi.readthedocs.io/en/latest/cdef.html#ffi-cdef-limitations " + "and file an issue if you think this type should really " + "be supported." % (commontype,)) + result, quals = parser.parse_type_and_quals(cdecl) # recursive + + assert isinstance(result, model.BaseTypeByIdentity) + _CACHE[commontype] = result, quals + return result, quals + + +# ____________________________________________________________ +# extra types for Windows (most of them are in commontypes.c) + + +def win_common_types(): + return { + "UNICODE_STRING": model.StructType( + "_UNICODE_STRING", + ["Length", + "MaximumLength", + "Buffer"], + [model.PrimitiveType("unsigned short"), + model.PrimitiveType("unsigned short"), + model.PointerType(model.PrimitiveType("wchar_t"))], + [-1, -1, -1]), + "PUNICODE_STRING": "UNICODE_STRING *", + "PCUNICODE_STRING": "const UNICODE_STRING *", + + "TBYTE": "set-unicode-needed", + "TCHAR": "set-unicode-needed", + "LPCTSTR": "set-unicode-needed", + "PCTSTR": "set-unicode-needed", + "LPTSTR": "set-unicode-needed", + "PTSTR": "set-unicode-needed", + "PTBYTE": "set-unicode-needed", + "PTCHAR": "set-unicode-needed", + } + +if sys.platform == 'win32': + COMMON_TYPES.update(win_common_types()) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/cparser.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/cparser.py new file mode 100644 index 0000000..74830e9 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/cparser.py @@ -0,0 +1,1006 @@ +from . import model +from .commontypes import COMMON_TYPES, resolve_common_type +from .error import FFIError, CDefError +try: + from . import _pycparser as pycparser +except ImportError: + import pycparser +import weakref, re, sys + +try: + if sys.version_info < (3,): + import thread as _thread + else: + import _thread + lock = _thread.allocate_lock() +except ImportError: + lock = None + +def _workaround_for_static_import_finders(): + # Issue #392: packaging tools like cx_Freeze can not find these + # because pycparser uses exec dynamic import. This is an obscure + # workaround. This function is never called. + import pycparser.yacctab + import pycparser.lextab + +CDEF_SOURCE_STRING = "" +_r_comment = re.compile(r"/\*.*?\*/|//([^\n\\]|\\.)*?$", + re.DOTALL | re.MULTILINE) +_r_define = re.compile(r"^\s*#\s*define\s+([A-Za-z_][A-Za-z_0-9]*)" + r"\b((?:[^\n\\]|\\.)*?)$", + re.DOTALL | re.MULTILINE) +_r_line_directive = re.compile(r"^[ \t]*#[ \t]*(?:line|\d+)\b.*$", re.MULTILINE) +_r_partial_enum = re.compile(r"=\s*\.\.\.\s*[,}]|\.\.\.\s*\}") +_r_enum_dotdotdot = re.compile(r"__dotdotdot\d+__$") +_r_partial_array = re.compile(r"\[\s*\.\.\.\s*\]") +_r_words = re.compile(r"\w+|\S") +_parser_cache = None +_r_int_literal = re.compile(r"-?0?x?[0-9a-f]+[lu]*$", re.IGNORECASE) +_r_stdcall1 = re.compile(r"\b(__stdcall|WINAPI)\b") +_r_stdcall2 = re.compile(r"[(]\s*(__stdcall|WINAPI)\b") +_r_cdecl = re.compile(r"\b__cdecl\b") +_r_extern_python = re.compile(r'\bextern\s*"' + r'(Python|Python\s*\+\s*C|C\s*\+\s*Python)"\s*.') +_r_star_const_space = re.compile( # matches "* const " + r"[*]\s*((const|volatile|restrict)\b\s*)+") +_r_int_dotdotdot = re.compile(r"(\b(int|long|short|signed|unsigned|char)\s*)+" + r"\.\.\.") +_r_float_dotdotdot = re.compile(r"\b(double|float)\s*\.\.\.") + +def _get_parser(): + global _parser_cache + if _parser_cache is None: + _parser_cache = pycparser.CParser() + return _parser_cache + +def _workaround_for_old_pycparser(csource): + # Workaround for a pycparser issue (fixed between pycparser 2.10 and + # 2.14): "char*const***" gives us a wrong syntax tree, the same as + # for "char***(*const)". This means we can't tell the difference + # afterwards. But "char(*const(***))" gives us the right syntax + # tree. The issue only occurs if there are several stars in + # sequence with no parenthesis inbetween, just possibly qualifiers. + # Attempt to fix it by adding some parentheses in the source: each + # time we see "* const" or "* const *", we add an opening + # parenthesis before each star---the hard part is figuring out where + # to close them. + parts = [] + while True: + match = _r_star_const_space.search(csource) + if not match: + break + #print repr(''.join(parts)+csource), '=>', + parts.append(csource[:match.start()]) + parts.append('('); closing = ')' + parts.append(match.group()) # e.g. "* const " + endpos = match.end() + if csource.startswith('*', endpos): + parts.append('('); closing += ')' + level = 0 + i = endpos + while i < len(csource): + c = csource[i] + if c == '(': + level += 1 + elif c == ')': + if level == 0: + break + level -= 1 + elif c in ',;=': + if level == 0: + break + i += 1 + csource = csource[endpos:i] + closing + csource[i:] + #print repr(''.join(parts)+csource) + parts.append(csource) + return ''.join(parts) + +def _preprocess_extern_python(csource): + # input: `extern "Python" int foo(int);` or + # `extern "Python" { int foo(int); }` + # output: + # void __cffi_extern_python_start; + # int foo(int); + # void __cffi_extern_python_stop; + # + # input: `extern "Python+C" int foo(int);` + # output: + # void __cffi_extern_python_plus_c_start; + # int foo(int); + # void __cffi_extern_python_stop; + parts = [] + while True: + match = _r_extern_python.search(csource) + if not match: + break + endpos = match.end() - 1 + #print + #print ''.join(parts)+csource + #print '=>' + parts.append(csource[:match.start()]) + if 'C' in match.group(1): + parts.append('void __cffi_extern_python_plus_c_start; ') + else: + parts.append('void __cffi_extern_python_start; ') + if csource[endpos] == '{': + # grouping variant + closing = csource.find('}', endpos) + if closing < 0: + raise CDefError("'extern \"Python\" {': no '}' found") + if csource.find('{', endpos + 1, closing) >= 0: + raise NotImplementedError("cannot use { } inside a block " + "'extern \"Python\" { ... }'") + parts.append(csource[endpos+1:closing]) + csource = csource[closing+1:] + else: + # non-grouping variant + semicolon = csource.find(';', endpos) + if semicolon < 0: + raise CDefError("'extern \"Python\": no ';' found") + parts.append(csource[endpos:semicolon+1]) + csource = csource[semicolon+1:] + parts.append(' void __cffi_extern_python_stop;') + #print ''.join(parts)+csource + #print + parts.append(csource) + return ''.join(parts) + +def _warn_for_string_literal(csource): + if '"' not in csource: + return + for line in csource.splitlines(): + if '"' in line and not line.lstrip().startswith('#'): + import warnings + warnings.warn("String literal found in cdef() or type source. " + "String literals are ignored here, but you should " + "remove them anyway because some character sequences " + "confuse pre-parsing.") + break + +def _warn_for_non_extern_non_static_global_variable(decl): + if not decl.storage: + import warnings + warnings.warn("Global variable '%s' in cdef(): for consistency " + "with C it should have a storage class specifier " + "(usually 'extern')" % (decl.name,)) + +def _remove_line_directives(csource): + # _r_line_directive matches whole lines, without the final \n, if they + # start with '#line' with some spacing allowed, or '#NUMBER'. This + # function stores them away and replaces them with exactly the string + # '#line@N', where N is the index in the list 'line_directives'. + line_directives = [] + def replace(m): + i = len(line_directives) + line_directives.append(m.group()) + return '#line@%d' % i + csource = _r_line_directive.sub(replace, csource) + return csource, line_directives + +def _put_back_line_directives(csource, line_directives): + def replace(m): + s = m.group() + if not s.startswith('#line@'): + raise AssertionError("unexpected #line directive " + "(should have been processed and removed") + return line_directives[int(s[6:])] + return _r_line_directive.sub(replace, csource) + +def _preprocess(csource): + # First, remove the lines of the form '#line N "filename"' because + # the "filename" part could confuse the rest + csource, line_directives = _remove_line_directives(csource) + # Remove comments. NOTE: this only work because the cdef() section + # should not contain any string literals (except in line directives)! + def replace_keeping_newlines(m): + return ' ' + m.group().count('\n') * '\n' + csource = _r_comment.sub(replace_keeping_newlines, csource) + # Remove the "#define FOO x" lines + macros = {} + for match in _r_define.finditer(csource): + macroname, macrovalue = match.groups() + macrovalue = macrovalue.replace('\\\n', '').strip() + macros[macroname] = macrovalue + csource = _r_define.sub('', csource) + # + if pycparser.__version__ < '2.14': + csource = _workaround_for_old_pycparser(csource) + # + # BIG HACK: replace WINAPI or __stdcall with "volatile const". + # It doesn't make sense for the return type of a function to be + # "volatile volatile const", so we abuse it to detect __stdcall... + # Hack number 2 is that "int(volatile *fptr)();" is not valid C + # syntax, so we place the "volatile" before the opening parenthesis. + csource = _r_stdcall2.sub(' volatile volatile const(', csource) + csource = _r_stdcall1.sub(' volatile volatile const ', csource) + csource = _r_cdecl.sub(' ', csource) + # + # Replace `extern "Python"` with start/end markers + csource = _preprocess_extern_python(csource) + # + # Now there should not be any string literal left; warn if we get one + _warn_for_string_literal(csource) + # + # Replace "[...]" with "[__dotdotdotarray__]" + csource = _r_partial_array.sub('[__dotdotdotarray__]', csource) + # + # Replace "...}" with "__dotdotdotNUM__}". This construction should + # occur only at the end of enums; at the end of structs we have "...;}" + # and at the end of vararg functions "...);". Also replace "=...[,}]" + # with ",__dotdotdotNUM__[,}]": this occurs in the enums too, when + # giving an unknown value. + matches = list(_r_partial_enum.finditer(csource)) + for number, match in enumerate(reversed(matches)): + p = match.start() + if csource[p] == '=': + p2 = csource.find('...', p, match.end()) + assert p2 > p + csource = '%s,__dotdotdot%d__ %s' % (csource[:p], number, + csource[p2+3:]) + else: + assert csource[p:p+3] == '...' + csource = '%s __dotdotdot%d__ %s' % (csource[:p], number, + csource[p+3:]) + # Replace "int ..." or "unsigned long int..." with "__dotdotdotint__" + csource = _r_int_dotdotdot.sub(' __dotdotdotint__ ', csource) + # Replace "float ..." or "double..." with "__dotdotdotfloat__" + csource = _r_float_dotdotdot.sub(' __dotdotdotfloat__ ', csource) + # Replace all remaining "..." with the same name, "__dotdotdot__", + # which is declared with a typedef for the purpose of C parsing. + csource = csource.replace('...', ' __dotdotdot__ ') + # Finally, put back the line directives + csource = _put_back_line_directives(csource, line_directives) + return csource, macros + +def _common_type_names(csource): + # Look in the source for what looks like usages of types from the + # list of common types. A "usage" is approximated here as the + # appearance of the word, minus a "definition" of the type, which + # is the last word in a "typedef" statement. Approximative only + # but should be fine for all the common types. + look_for_words = set(COMMON_TYPES) + look_for_words.add(';') + look_for_words.add(',') + look_for_words.add('(') + look_for_words.add(')') + look_for_words.add('typedef') + words_used = set() + is_typedef = False + paren = 0 + previous_word = '' + for word in _r_words.findall(csource): + if word in look_for_words: + if word == ';': + if is_typedef: + words_used.discard(previous_word) + look_for_words.discard(previous_word) + is_typedef = False + elif word == 'typedef': + is_typedef = True + paren = 0 + elif word == '(': + paren += 1 + elif word == ')': + paren -= 1 + elif word == ',': + if is_typedef and paren == 0: + words_used.discard(previous_word) + look_for_words.discard(previous_word) + else: # word in COMMON_TYPES + words_used.add(word) + previous_word = word + return words_used + + +class Parser(object): + + def __init__(self): + self._declarations = {} + self._included_declarations = set() + self._anonymous_counter = 0 + self._structnode2type = weakref.WeakKeyDictionary() + self._options = {} + self._int_constants = {} + self._recomplete = [] + self._uses_new_feature = None + + def _parse(self, csource): + csource, macros = _preprocess(csource) + # XXX: for more efficiency we would need to poke into the + # internals of CParser... the following registers the + # typedefs, because their presence or absence influences the + # parsing itself (but what they are typedef'ed to plays no role) + ctn = _common_type_names(csource) + typenames = [] + for name in sorted(self._declarations): + if name.startswith('typedef '): + name = name[8:] + typenames.append(name) + ctn.discard(name) + typenames += sorted(ctn) + # + csourcelines = [] + csourcelines.append('# 1 ""') + for typename in typenames: + csourcelines.append('typedef int %s;' % typename) + csourcelines.append('typedef int __dotdotdotint__, __dotdotdotfloat__,' + ' __dotdotdot__;') + # this forces pycparser to consider the following in the file + # called from line 1 + csourcelines.append('# 1 "%s"' % (CDEF_SOURCE_STRING,)) + csourcelines.append(csource) + fullcsource = '\n'.join(csourcelines) + if lock is not None: + lock.acquire() # pycparser is not thread-safe... + try: + ast = _get_parser().parse(fullcsource) + except pycparser.c_parser.ParseError as e: + self.convert_pycparser_error(e, csource) + finally: + if lock is not None: + lock.release() + # csource will be used to find buggy source text + return ast, macros, csource + + def _convert_pycparser_error(self, e, csource): + # xxx look for ":NUM:" at the start of str(e) + # and interpret that as a line number. This will not work if + # the user gives explicit ``# NUM "FILE"`` directives. + line = None + msg = str(e) + match = re.match(r"%s:(\d+):" % (CDEF_SOURCE_STRING,), msg) + if match: + linenum = int(match.group(1), 10) + csourcelines = csource.splitlines() + if 1 <= linenum <= len(csourcelines): + line = csourcelines[linenum-1] + return line + + def convert_pycparser_error(self, e, csource): + line = self._convert_pycparser_error(e, csource) + + msg = str(e) + if line: + msg = 'cannot parse "%s"\n%s' % (line.strip(), msg) + else: + msg = 'parse error\n%s' % (msg,) + raise CDefError(msg) + + def parse(self, csource, override=False, packed=False, pack=None, + dllexport=False): + if packed: + if packed != True: + raise ValueError("'packed' should be False or True; use " + "'pack' to give another value") + if pack: + raise ValueError("cannot give both 'pack' and 'packed'") + pack = 1 + elif pack: + if pack & (pack - 1): + raise ValueError("'pack' must be a power of two, not %r" % + (pack,)) + else: + pack = 0 + prev_options = self._options + try: + self._options = {'override': override, + 'packed': pack, + 'dllexport': dllexport} + self._internal_parse(csource) + finally: + self._options = prev_options + + def _internal_parse(self, csource): + ast, macros, csource = self._parse(csource) + # add the macros + self._process_macros(macros) + # find the first "__dotdotdot__" and use that as a separator + # between the repeated typedefs and the real csource + iterator = iter(ast.ext) + for decl in iterator: + if decl.name == '__dotdotdot__': + break + else: + assert 0 + current_decl = None + # + try: + self._inside_extern_python = '__cffi_extern_python_stop' + for decl in iterator: + current_decl = decl + if isinstance(decl, pycparser.c_ast.Decl): + self._parse_decl(decl) + elif isinstance(decl, pycparser.c_ast.Typedef): + if not decl.name: + raise CDefError("typedef does not declare any name", + decl) + quals = 0 + if (isinstance(decl.type.type, pycparser.c_ast.IdentifierType) and + decl.type.type.names[-1].startswith('__dotdotdot')): + realtype = self._get_unknown_type(decl) + elif (isinstance(decl.type, pycparser.c_ast.PtrDecl) and + isinstance(decl.type.type, pycparser.c_ast.TypeDecl) and + isinstance(decl.type.type.type, + pycparser.c_ast.IdentifierType) and + decl.type.type.type.names[-1].startswith('__dotdotdot')): + realtype = self._get_unknown_ptr_type(decl) + else: + realtype, quals = self._get_type_and_quals( + decl.type, name=decl.name, partial_length_ok=True, + typedef_example="*(%s *)0" % (decl.name,)) + self._declare('typedef ' + decl.name, realtype, quals=quals) + elif decl.__class__.__name__ == 'Pragma': + pass # skip pragma, only in pycparser 2.15 + else: + raise CDefError("unexpected <%s>: this construct is valid " + "C but not valid in cdef()" % + decl.__class__.__name__, decl) + except CDefError as e: + if len(e.args) == 1: + e.args = e.args + (current_decl,) + raise + except FFIError as e: + msg = self._convert_pycparser_error(e, csource) + if msg: + e.args = (e.args[0] + "\n *** Err: %s" % msg,) + raise + + def _add_constants(self, key, val): + if key in self._int_constants: + if self._int_constants[key] == val: + return # ignore identical double declarations + raise FFIError( + "multiple declarations of constant: %s" % (key,)) + self._int_constants[key] = val + + def _add_integer_constant(self, name, int_str): + int_str = int_str.lower().rstrip("ul") + neg = int_str.startswith('-') + if neg: + int_str = int_str[1:] + # "010" is not valid oct in py3 + if (int_str.startswith("0") and int_str != '0' + and not int_str.startswith("0x")): + int_str = "0o" + int_str[1:] + pyvalue = int(int_str, 0) + if neg: + pyvalue = -pyvalue + self._add_constants(name, pyvalue) + self._declare('macro ' + name, pyvalue) + + def _process_macros(self, macros): + for key, value in macros.items(): + value = value.strip() + if _r_int_literal.match(value): + self._add_integer_constant(key, value) + elif value == '...': + self._declare('macro ' + key, value) + else: + raise CDefError( + 'only supports one of the following syntax:\n' + ' #define %s ... (literally dot-dot-dot)\n' + ' #define %s NUMBER (with NUMBER an integer' + ' constant, decimal/hex/octal)\n' + 'got:\n' + ' #define %s %s' + % (key, key, key, value)) + + def _declare_function(self, tp, quals, decl): + tp = self._get_type_pointer(tp, quals) + if self._options.get('dllexport'): + tag = 'dllexport_python ' + elif self._inside_extern_python == '__cffi_extern_python_start': + tag = 'extern_python ' + elif self._inside_extern_python == '__cffi_extern_python_plus_c_start': + tag = 'extern_python_plus_c ' + else: + tag = 'function ' + self._declare(tag + decl.name, tp) + + def _parse_decl(self, decl): + node = decl.type + if isinstance(node, pycparser.c_ast.FuncDecl): + tp, quals = self._get_type_and_quals(node, name=decl.name) + assert isinstance(tp, model.RawFunctionType) + self._declare_function(tp, quals, decl) + else: + if isinstance(node, pycparser.c_ast.Struct): + self._get_struct_union_enum_type('struct', node) + elif isinstance(node, pycparser.c_ast.Union): + self._get_struct_union_enum_type('union', node) + elif isinstance(node, pycparser.c_ast.Enum): + self._get_struct_union_enum_type('enum', node) + elif not decl.name: + raise CDefError("construct does not declare any variable", + decl) + # + if decl.name: + tp, quals = self._get_type_and_quals(node, + partial_length_ok=True) + if tp.is_raw_function: + self._declare_function(tp, quals, decl) + elif (tp.is_integer_type() and + hasattr(decl, 'init') and + hasattr(decl.init, 'value') and + _r_int_literal.match(decl.init.value)): + self._add_integer_constant(decl.name, decl.init.value) + elif (tp.is_integer_type() and + isinstance(decl.init, pycparser.c_ast.UnaryOp) and + decl.init.op == '-' and + hasattr(decl.init.expr, 'value') and + _r_int_literal.match(decl.init.expr.value)): + self._add_integer_constant(decl.name, + '-' + decl.init.expr.value) + elif (tp is model.void_type and + decl.name.startswith('__cffi_extern_python_')): + # hack: `extern "Python"` in the C source is replaced + # with "void __cffi_extern_python_start;" and + # "void __cffi_extern_python_stop;" + self._inside_extern_python = decl.name + else: + if self._inside_extern_python !='__cffi_extern_python_stop': + raise CDefError( + "cannot declare constants or " + "variables with 'extern \"Python\"'") + if (quals & model.Q_CONST) and not tp.is_array_type: + self._declare('constant ' + decl.name, tp, quals=quals) + else: + _warn_for_non_extern_non_static_global_variable(decl) + self._declare('variable ' + decl.name, tp, quals=quals) + + def parse_type(self, cdecl): + return self.parse_type_and_quals(cdecl)[0] + + def parse_type_and_quals(self, cdecl): + ast, macros = self._parse('void __dummy(\n%s\n);' % cdecl)[:2] + assert not macros + exprnode = ast.ext[-1].type.args.params[0] + if isinstance(exprnode, pycparser.c_ast.ID): + raise CDefError("unknown identifier '%s'" % (exprnode.name,)) + return self._get_type_and_quals(exprnode.type) + + def _declare(self, name, obj, included=False, quals=0): + if name in self._declarations: + prevobj, prevquals = self._declarations[name] + if prevobj is obj and prevquals == quals: + return + if not self._options.get('override'): + raise FFIError( + "multiple declarations of %s (for interactive usage, " + "try cdef(xx, override=True))" % (name,)) + assert '__dotdotdot__' not in name.split() + self._declarations[name] = (obj, quals) + if included: + self._included_declarations.add(obj) + + def _extract_quals(self, type): + quals = 0 + if isinstance(type, (pycparser.c_ast.TypeDecl, + pycparser.c_ast.PtrDecl)): + if 'const' in type.quals: + quals |= model.Q_CONST + if 'volatile' in type.quals: + quals |= model.Q_VOLATILE + if 'restrict' in type.quals: + quals |= model.Q_RESTRICT + return quals + + def _get_type_pointer(self, type, quals, declname=None): + if isinstance(type, model.RawFunctionType): + return type.as_function_pointer() + if (isinstance(type, model.StructOrUnionOrEnum) and + type.name.startswith('$') and type.name[1:].isdigit() and + type.forcename is None and declname is not None): + return model.NamedPointerType(type, declname, quals) + return model.PointerType(type, quals) + + def _get_type_and_quals(self, typenode, name=None, partial_length_ok=False, + typedef_example=None): + # first, dereference typedefs, if we have it already parsed, we're good + if (isinstance(typenode, pycparser.c_ast.TypeDecl) and + isinstance(typenode.type, pycparser.c_ast.IdentifierType) and + len(typenode.type.names) == 1 and + ('typedef ' + typenode.type.names[0]) in self._declarations): + tp, quals = self._declarations['typedef ' + typenode.type.names[0]] + quals |= self._extract_quals(typenode) + return tp, quals + # + if isinstance(typenode, pycparser.c_ast.ArrayDecl): + # array type + if typenode.dim is None: + length = None + else: + length = self._parse_constant( + typenode.dim, partial_length_ok=partial_length_ok) + # a hack: in 'typedef int foo_t[...][...];', don't use '...' as + # the length but use directly the C expression that would be + # generated by recompiler.py. This lets the typedef be used in + # many more places within recompiler.py + if typedef_example is not None: + if length == '...': + length = '_cffi_array_len(%s)' % (typedef_example,) + typedef_example = "*" + typedef_example + # + tp, quals = self._get_type_and_quals(typenode.type, + partial_length_ok=partial_length_ok, + typedef_example=typedef_example) + return model.ArrayType(tp, length), quals + # + if isinstance(typenode, pycparser.c_ast.PtrDecl): + # pointer type + itemtype, itemquals = self._get_type_and_quals(typenode.type) + tp = self._get_type_pointer(itemtype, itemquals, declname=name) + quals = self._extract_quals(typenode) + return tp, quals + # + if isinstance(typenode, pycparser.c_ast.TypeDecl): + quals = self._extract_quals(typenode) + type = typenode.type + if isinstance(type, pycparser.c_ast.IdentifierType): + # assume a primitive type. get it from .names, but reduce + # synonyms to a single chosen combination + names = list(type.names) + if names != ['signed', 'char']: # keep this unmodified + prefixes = {} + while names: + name = names[0] + if name in ('short', 'long', 'signed', 'unsigned'): + prefixes[name] = prefixes.get(name, 0) + 1 + del names[0] + else: + break + # ignore the 'signed' prefix below, and reorder the others + newnames = [] + for prefix in ('unsigned', 'short', 'long'): + for i in range(prefixes.get(prefix, 0)): + newnames.append(prefix) + if not names: + names = ['int'] # implicitly + if names == ['int']: # but kill it if 'short' or 'long' + if 'short' in prefixes or 'long' in prefixes: + names = [] + names = newnames + names + ident = ' '.join(names) + if ident == 'void': + return model.void_type, quals + if ident == '__dotdotdot__': + raise FFIError(':%d: bad usage of "..."' % + typenode.coord.line) + tp0, quals0 = resolve_common_type(self, ident) + return tp0, (quals | quals0) + # + if isinstance(type, pycparser.c_ast.Struct): + # 'struct foobar' + tp = self._get_struct_union_enum_type('struct', type, name) + return tp, quals + # + if isinstance(type, pycparser.c_ast.Union): + # 'union foobar' + tp = self._get_struct_union_enum_type('union', type, name) + return tp, quals + # + if isinstance(type, pycparser.c_ast.Enum): + # 'enum foobar' + tp = self._get_struct_union_enum_type('enum', type, name) + return tp, quals + # + if isinstance(typenode, pycparser.c_ast.FuncDecl): + # a function type + return self._parse_function_type(typenode, name), 0 + # + # nested anonymous structs or unions end up here + if isinstance(typenode, pycparser.c_ast.Struct): + return self._get_struct_union_enum_type('struct', typenode, name, + nested=True), 0 + if isinstance(typenode, pycparser.c_ast.Union): + return self._get_struct_union_enum_type('union', typenode, name, + nested=True), 0 + # + raise FFIError(":%d: bad or unsupported type declaration" % + typenode.coord.line) + + def _parse_function_type(self, typenode, funcname=None): + params = list(getattr(typenode.args, 'params', [])) + for i, arg in enumerate(params): + if not hasattr(arg, 'type'): + raise CDefError("%s arg %d: unknown type '%s'" + " (if you meant to use the old C syntax of giving" + " untyped arguments, it is not supported)" + % (funcname or 'in expression', i + 1, + getattr(arg, 'name', '?'))) + ellipsis = ( + len(params) > 0 and + isinstance(params[-1].type, pycparser.c_ast.TypeDecl) and + isinstance(params[-1].type.type, + pycparser.c_ast.IdentifierType) and + params[-1].type.type.names == ['__dotdotdot__']) + if ellipsis: + params.pop() + if not params: + raise CDefError( + "%s: a function with only '(...)' as argument" + " is not correct C" % (funcname or 'in expression')) + args = [self._as_func_arg(*self._get_type_and_quals(argdeclnode.type)) + for argdeclnode in params] + if not ellipsis and args == [model.void_type]: + args = [] + result, quals = self._get_type_and_quals(typenode.type) + # the 'quals' on the result type are ignored. HACK: we absure them + # to detect __stdcall functions: we textually replace "__stdcall" + # with "volatile volatile const" above. + abi = None + if hasattr(typenode.type, 'quals'): # else, probable syntax error anyway + if typenode.type.quals[-3:] == ['volatile', 'volatile', 'const']: + abi = '__stdcall' + return model.RawFunctionType(tuple(args), result, ellipsis, abi) + + def _as_func_arg(self, type, quals): + if isinstance(type, model.ArrayType): + return model.PointerType(type.item, quals) + elif isinstance(type, model.RawFunctionType): + return type.as_function_pointer() + else: + return type + + def _get_struct_union_enum_type(self, kind, type, name=None, nested=False): + # First, a level of caching on the exact 'type' node of the AST. + # This is obscure, but needed because pycparser "unrolls" declarations + # such as "typedef struct { } foo_t, *foo_p" and we end up with + # an AST that is not a tree, but a DAG, with the "type" node of the + # two branches foo_t and foo_p of the trees being the same node. + # It's a bit silly but detecting "DAG-ness" in the AST tree seems + # to be the only way to distinguish this case from two independent + # structs. See test_struct_with_two_usages. + try: + return self._structnode2type[type] + except KeyError: + pass + # + # Note that this must handle parsing "struct foo" any number of + # times and always return the same StructType object. Additionally, + # one of these times (not necessarily the first), the fields of + # the struct can be specified with "struct foo { ...fields... }". + # If no name is given, then we have to create a new anonymous struct + # with no caching; in this case, the fields are either specified + # right now or never. + # + force_name = name + name = type.name + # + # get the type or create it if needed + if name is None: + # 'force_name' is used to guess a more readable name for + # anonymous structs, for the common case "typedef struct { } foo". + if force_name is not None: + explicit_name = '$%s' % force_name + else: + self._anonymous_counter += 1 + explicit_name = '$%d' % self._anonymous_counter + tp = None + else: + explicit_name = name + key = '%s %s' % (kind, name) + tp, _ = self._declarations.get(key, (None, None)) + # + if tp is None: + if kind == 'struct': + tp = model.StructType(explicit_name, None, None, None) + elif kind == 'union': + tp = model.UnionType(explicit_name, None, None, None) + elif kind == 'enum': + if explicit_name == '__dotdotdot__': + raise CDefError("Enums cannot be declared with ...") + tp = self._build_enum_type(explicit_name, type.values) + else: + raise AssertionError("kind = %r" % (kind,)) + if name is not None: + self._declare(key, tp) + else: + if kind == 'enum' and type.values is not None: + raise NotImplementedError( + "enum %s: the '{}' declaration should appear on the first " + "time the enum is mentioned, not later" % explicit_name) + if not tp.forcename: + tp.force_the_name(force_name) + if tp.forcename and '$' in tp.name: + self._declare('anonymous %s' % tp.forcename, tp) + # + self._structnode2type[type] = tp + # + # enums: done here + if kind == 'enum': + return tp + # + # is there a 'type.decls'? If yes, then this is the place in the + # C sources that declare the fields. If no, then just return the + # existing type, possibly still incomplete. + if type.decls is None: + return tp + # + if tp.fldnames is not None: + raise CDefError("duplicate declaration of struct %s" % name) + fldnames = [] + fldtypes = [] + fldbitsize = [] + fldquals = [] + for decl in type.decls: + if (isinstance(decl.type, pycparser.c_ast.IdentifierType) and + ''.join(decl.type.names) == '__dotdotdot__'): + # XXX pycparser is inconsistent: 'names' should be a list + # of strings, but is sometimes just one string. Use + # str.join() as a way to cope with both. + self._make_partial(tp, nested) + continue + if decl.bitsize is None: + bitsize = -1 + else: + bitsize = self._parse_constant(decl.bitsize) + self._partial_length = False + type, fqual = self._get_type_and_quals(decl.type, + partial_length_ok=True) + if self._partial_length: + self._make_partial(tp, nested) + if isinstance(type, model.StructType) and type.partial: + self._make_partial(tp, nested) + fldnames.append(decl.name or '') + fldtypes.append(type) + fldbitsize.append(bitsize) + fldquals.append(fqual) + tp.fldnames = tuple(fldnames) + tp.fldtypes = tuple(fldtypes) + tp.fldbitsize = tuple(fldbitsize) + tp.fldquals = tuple(fldquals) + if fldbitsize != [-1] * len(fldbitsize): + if isinstance(tp, model.StructType) and tp.partial: + raise NotImplementedError("%s: using both bitfields and '...;'" + % (tp,)) + tp.packed = self._options.get('packed') + if tp.completed: # must be re-completed: it is not opaque any more + tp.completed = 0 + self._recomplete.append(tp) + return tp + + def _make_partial(self, tp, nested): + if not isinstance(tp, model.StructOrUnion): + raise CDefError("%s cannot be partial" % (tp,)) + if not tp.has_c_name() and not nested: + raise NotImplementedError("%s is partial but has no C name" %(tp,)) + tp.partial = True + + def _parse_constant(self, exprnode, partial_length_ok=False): + # for now, limited to expressions that are an immediate number + # or positive/negative number + if isinstance(exprnode, pycparser.c_ast.Constant): + s = exprnode.value + if '0' <= s[0] <= '9': + s = s.rstrip('uUlL') + try: + if s.startswith('0'): + return int(s, 8) + else: + return int(s, 10) + except ValueError: + if len(s) > 1: + if s.lower()[0:2] == '0x': + return int(s, 16) + elif s.lower()[0:2] == '0b': + return int(s, 2) + raise CDefError("invalid constant %r" % (s,)) + elif s[0] == "'" and s[-1] == "'" and ( + len(s) == 3 or (len(s) == 4 and s[1] == "\\")): + return ord(s[-2]) + else: + raise CDefError("invalid constant %r" % (s,)) + # + if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and + exprnode.op == '+'): + return self._parse_constant(exprnode.expr) + # + if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and + exprnode.op == '-'): + return -self._parse_constant(exprnode.expr) + # load previously defined int constant + if (isinstance(exprnode, pycparser.c_ast.ID) and + exprnode.name in self._int_constants): + return self._int_constants[exprnode.name] + # + if (isinstance(exprnode, pycparser.c_ast.ID) and + exprnode.name == '__dotdotdotarray__'): + if partial_length_ok: + self._partial_length = True + return '...' + raise FFIError(":%d: unsupported '[...]' here, cannot derive " + "the actual array length in this context" + % exprnode.coord.line) + # + if isinstance(exprnode, pycparser.c_ast.BinaryOp): + left = self._parse_constant(exprnode.left) + right = self._parse_constant(exprnode.right) + if exprnode.op == '+': + return left + right + elif exprnode.op == '-': + return left - right + elif exprnode.op == '*': + return left * right + elif exprnode.op == '/': + return self._c_div(left, right) + elif exprnode.op == '%': + return left - self._c_div(left, right) * right + elif exprnode.op == '<<': + return left << right + elif exprnode.op == '>>': + return left >> right + elif exprnode.op == '&': + return left & right + elif exprnode.op == '|': + return left | right + elif exprnode.op == '^': + return left ^ right + # + raise FFIError(":%d: unsupported expression: expected a " + "simple numeric constant" % exprnode.coord.line) + + def _c_div(self, a, b): + result = a // b + if ((a < 0) ^ (b < 0)) and (a % b) != 0: + result += 1 + return result + + def _build_enum_type(self, explicit_name, decls): + if decls is not None: + partial = False + enumerators = [] + enumvalues = [] + nextenumvalue = 0 + for enum in decls.enumerators: + if _r_enum_dotdotdot.match(enum.name): + partial = True + continue + if enum.value is not None: + nextenumvalue = self._parse_constant(enum.value) + enumerators.append(enum.name) + enumvalues.append(nextenumvalue) + self._add_constants(enum.name, nextenumvalue) + nextenumvalue += 1 + enumerators = tuple(enumerators) + enumvalues = tuple(enumvalues) + tp = model.EnumType(explicit_name, enumerators, enumvalues) + tp.partial = partial + else: # opaque enum + tp = model.EnumType(explicit_name, (), ()) + return tp + + def include(self, other): + for name, (tp, quals) in other._declarations.items(): + if name.startswith('anonymous $enum_$'): + continue # fix for test_anonymous_enum_include + kind = name.split(' ', 1)[0] + if kind in ('struct', 'union', 'enum', 'anonymous', 'typedef'): + self._declare(name, tp, included=True, quals=quals) + for k, v in other._int_constants.items(): + self._add_constants(k, v) + + def _get_unknown_type(self, decl): + typenames = decl.type.type.names + if typenames == ['__dotdotdot__']: + return model.unknown_type(decl.name) + + if typenames == ['__dotdotdotint__']: + if self._uses_new_feature is None: + self._uses_new_feature = "'typedef int... %s'" % decl.name + return model.UnknownIntegerType(decl.name) + + if typenames == ['__dotdotdotfloat__']: + # note: not for 'long double' so far + if self._uses_new_feature is None: + self._uses_new_feature = "'typedef float... %s'" % decl.name + return model.UnknownFloatType(decl.name) + + raise FFIError(':%d: unsupported usage of "..." in typedef' + % decl.coord.line) + + def _get_unknown_ptr_type(self, decl): + if decl.type.type.type.names == ['__dotdotdot__']: + return model.unknown_ptr_type(decl.name) + raise FFIError(':%d: unsupported usage of "..." in typedef' + % decl.coord.line) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/error.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/error.py new file mode 100644 index 0000000..0a27247 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/error.py @@ -0,0 +1,31 @@ + +class FFIError(Exception): + __module__ = 'cffi' + +class CDefError(Exception): + __module__ = 'cffi' + def __str__(self): + try: + current_decl = self.args[1] + filename = current_decl.coord.file + linenum = current_decl.coord.line + prefix = '%s:%d: ' % (filename, linenum) + except (AttributeError, TypeError, IndexError): + prefix = '' + return '%s%s' % (prefix, self.args[0]) + +class VerificationError(Exception): + """ An error raised when verification fails + """ + __module__ = 'cffi' + +class VerificationMissing(Exception): + """ An error raised when incomplete structures are passed into + cdef, but no verification has been done + """ + __module__ = 'cffi' + +class PkgConfigError(Exception): + """ An error raised for missing modules in pkg-config + """ + __module__ = 'cffi' diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/ffiplatform.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/ffiplatform.py new file mode 100644 index 0000000..8531346 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/ffiplatform.py @@ -0,0 +1,127 @@ +import sys, os +from .error import VerificationError + + +LIST_OF_FILE_NAMES = ['sources', 'include_dirs', 'library_dirs', + 'extra_objects', 'depends'] + +def get_extension(srcfilename, modname, sources=(), **kwds): + _hack_at_distutils() + from distutils.core import Extension + allsources = [srcfilename] + for src in sources: + allsources.append(os.path.normpath(src)) + return Extension(name=modname, sources=allsources, **kwds) + +def compile(tmpdir, ext, compiler_verbose=0, debug=None): + """Compile a C extension module using distutils.""" + + _hack_at_distutils() + saved_environ = os.environ.copy() + try: + outputfilename = _build(tmpdir, ext, compiler_verbose, debug) + outputfilename = os.path.abspath(outputfilename) + finally: + # workaround for a distutils bugs where some env vars can + # become longer and longer every time it is used + for key, value in saved_environ.items(): + if os.environ.get(key) != value: + os.environ[key] = value + return outputfilename + +def _build(tmpdir, ext, compiler_verbose=0, debug=None): + # XXX compact but horrible :-( + from distutils.core import Distribution + import distutils.errors, distutils.log + # + dist = Distribution({'ext_modules': [ext]}) + dist.parse_config_files() + options = dist.get_option_dict('build_ext') + if debug is None: + debug = sys.flags.debug + options['debug'] = ('ffiplatform', debug) + options['force'] = ('ffiplatform', True) + options['build_lib'] = ('ffiplatform', tmpdir) + options['build_temp'] = ('ffiplatform', tmpdir) + # + try: + old_level = distutils.log.set_threshold(0) or 0 + try: + distutils.log.set_verbosity(compiler_verbose) + dist.run_command('build_ext') + cmd_obj = dist.get_command_obj('build_ext') + [soname] = cmd_obj.get_outputs() + finally: + distutils.log.set_threshold(old_level) + except (distutils.errors.CompileError, + distutils.errors.LinkError) as e: + raise VerificationError('%s: %s' % (e.__class__.__name__, e)) + # + return soname + +try: + from os.path import samefile +except ImportError: + def samefile(f1, f2): + return os.path.abspath(f1) == os.path.abspath(f2) + +def maybe_relative_path(path): + if not os.path.isabs(path): + return path # already relative + dir = path + names = [] + while True: + prevdir = dir + dir, name = os.path.split(prevdir) + if dir == prevdir or not dir: + return path # failed to make it relative + names.append(name) + try: + if samefile(dir, os.curdir): + names.reverse() + return os.path.join(*names) + except OSError: + pass + +# ____________________________________________________________ + +try: + int_or_long = (int, long) + import cStringIO +except NameError: + int_or_long = int # Python 3 + import io as cStringIO + +def _flatten(x, f): + if isinstance(x, str): + f.write('%ds%s' % (len(x), x)) + elif isinstance(x, dict): + keys = sorted(x.keys()) + f.write('%dd' % len(keys)) + for key in keys: + _flatten(key, f) + _flatten(x[key], f) + elif isinstance(x, (list, tuple)): + f.write('%dl' % len(x)) + for value in x: + _flatten(value, f) + elif isinstance(x, int_or_long): + f.write('%di' % (x,)) + else: + raise TypeError( + "the keywords to verify() contains unsupported object %r" % (x,)) + +def flatten(x): + f = cStringIO.StringIO() + _flatten(x, f) + return f.getvalue() + +def _hack_at_distutils(): + # Windows-only workaround for some configurations: see + # https://bugs.python.org/issue23246 (Python 2.7 with + # a specific MS compiler suite download) + if sys.platform == "win32": + try: + import setuptools # for side-effects, patches distutils + except ImportError: + pass diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/lock.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/lock.py new file mode 100644 index 0000000..db91b71 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/lock.py @@ -0,0 +1,30 @@ +import sys + +if sys.version_info < (3,): + try: + from thread import allocate_lock + except ImportError: + from dummy_thread import allocate_lock +else: + try: + from _thread import allocate_lock + except ImportError: + from _dummy_thread import allocate_lock + + +##import sys +##l1 = allocate_lock + +##class allocate_lock(object): +## def __init__(self): +## self._real = l1() +## def __enter__(self): +## for i in range(4, 0, -1): +## print sys._getframe(i).f_code +## print +## return self._real.__enter__() +## def __exit__(self, *args): +## return self._real.__exit__(*args) +## def acquire(self, f): +## assert f is False +## return self._real.acquire(f) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/model.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/model.py new file mode 100644 index 0000000..ad1c176 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/model.py @@ -0,0 +1,617 @@ +import types +import weakref + +from .lock import allocate_lock +from .error import CDefError, VerificationError, VerificationMissing + +# type qualifiers +Q_CONST = 0x01 +Q_RESTRICT = 0x02 +Q_VOLATILE = 0x04 + +def qualify(quals, replace_with): + if quals & Q_CONST: + replace_with = ' const ' + replace_with.lstrip() + if quals & Q_VOLATILE: + replace_with = ' volatile ' + replace_with.lstrip() + if quals & Q_RESTRICT: + # It seems that __restrict is supported by gcc and msvc. + # If you hit some different compiler, add a #define in + # _cffi_include.h for it (and in its copies, documented there) + replace_with = ' __restrict ' + replace_with.lstrip() + return replace_with + + +class BaseTypeByIdentity(object): + is_array_type = False + is_raw_function = False + + def get_c_name(self, replace_with='', context='a C file', quals=0): + result = self.c_name_with_marker + assert result.count('&') == 1 + # some logic duplication with ffi.getctype()... :-( + replace_with = replace_with.strip() + if replace_with: + if replace_with.startswith('*') and '&[' in result: + replace_with = '(%s)' % replace_with + elif not replace_with[0] in '[(': + replace_with = ' ' + replace_with + replace_with = qualify(quals, replace_with) + result = result.replace('&', replace_with) + if '$' in result: + raise VerificationError( + "cannot generate '%s' in %s: unknown type name" + % (self._get_c_name(), context)) + return result + + def _get_c_name(self): + return self.c_name_with_marker.replace('&', '') + + def has_c_name(self): + return '$' not in self._get_c_name() + + def is_integer_type(self): + return False + + def get_cached_btype(self, ffi, finishlist, can_delay=False): + try: + BType = ffi._cached_btypes[self] + except KeyError: + BType = self.build_backend_type(ffi, finishlist) + BType2 = ffi._cached_btypes.setdefault(self, BType) + assert BType2 is BType + return BType + + def __repr__(self): + return '<%s>' % (self._get_c_name(),) + + def _get_items(self): + return [(name, getattr(self, name)) for name in self._attrs_] + + +class BaseType(BaseTypeByIdentity): + + def __eq__(self, other): + return (self.__class__ == other.__class__ and + self._get_items() == other._get_items()) + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash((self.__class__, tuple(self._get_items()))) + + +class VoidType(BaseType): + _attrs_ = () + + def __init__(self): + self.c_name_with_marker = 'void&' + + def build_backend_type(self, ffi, finishlist): + return global_cache(self, ffi, 'new_void_type') + +void_type = VoidType() + + +class BasePrimitiveType(BaseType): + def is_complex_type(self): + return False + + +class PrimitiveType(BasePrimitiveType): + _attrs_ = ('name',) + + ALL_PRIMITIVE_TYPES = { + 'char': 'c', + 'short': 'i', + 'int': 'i', + 'long': 'i', + 'long long': 'i', + 'signed char': 'i', + 'unsigned char': 'i', + 'unsigned short': 'i', + 'unsigned int': 'i', + 'unsigned long': 'i', + 'unsigned long long': 'i', + 'float': 'f', + 'double': 'f', + 'long double': 'f', + 'float _Complex': 'j', + 'double _Complex': 'j', + '_Bool': 'i', + # the following types are not primitive in the C sense + 'wchar_t': 'c', + 'char16_t': 'c', + 'char32_t': 'c', + 'int8_t': 'i', + 'uint8_t': 'i', + 'int16_t': 'i', + 'uint16_t': 'i', + 'int32_t': 'i', + 'uint32_t': 'i', + 'int64_t': 'i', + 'uint64_t': 'i', + 'int_least8_t': 'i', + 'uint_least8_t': 'i', + 'int_least16_t': 'i', + 'uint_least16_t': 'i', + 'int_least32_t': 'i', + 'uint_least32_t': 'i', + 'int_least64_t': 'i', + 'uint_least64_t': 'i', + 'int_fast8_t': 'i', + 'uint_fast8_t': 'i', + 'int_fast16_t': 'i', + 'uint_fast16_t': 'i', + 'int_fast32_t': 'i', + 'uint_fast32_t': 'i', + 'int_fast64_t': 'i', + 'uint_fast64_t': 'i', + 'intptr_t': 'i', + 'uintptr_t': 'i', + 'intmax_t': 'i', + 'uintmax_t': 'i', + 'ptrdiff_t': 'i', + 'size_t': 'i', + 'ssize_t': 'i', + } + + def __init__(self, name): + assert name in self.ALL_PRIMITIVE_TYPES + self.name = name + self.c_name_with_marker = name + '&' + + def is_char_type(self): + return self.ALL_PRIMITIVE_TYPES[self.name] == 'c' + def is_integer_type(self): + return self.ALL_PRIMITIVE_TYPES[self.name] == 'i' + def is_float_type(self): + return self.ALL_PRIMITIVE_TYPES[self.name] == 'f' + def is_complex_type(self): + return self.ALL_PRIMITIVE_TYPES[self.name] == 'j' + + def build_backend_type(self, ffi, finishlist): + return global_cache(self, ffi, 'new_primitive_type', self.name) + + +class UnknownIntegerType(BasePrimitiveType): + _attrs_ = ('name',) + + def __init__(self, name): + self.name = name + self.c_name_with_marker = name + '&' + + def is_integer_type(self): + return True + + def build_backend_type(self, ffi, finishlist): + raise NotImplementedError("integer type '%s' can only be used after " + "compilation" % self.name) + +class UnknownFloatType(BasePrimitiveType): + _attrs_ = ('name', ) + + def __init__(self, name): + self.name = name + self.c_name_with_marker = name + '&' + + def build_backend_type(self, ffi, finishlist): + raise NotImplementedError("float type '%s' can only be used after " + "compilation" % self.name) + + +class BaseFunctionType(BaseType): + _attrs_ = ('args', 'result', 'ellipsis', 'abi') + + def __init__(self, args, result, ellipsis, abi=None): + self.args = args + self.result = result + self.ellipsis = ellipsis + self.abi = abi + # + reprargs = [arg._get_c_name() for arg in self.args] + if self.ellipsis: + reprargs.append('...') + reprargs = reprargs or ['void'] + replace_with = self._base_pattern % (', '.join(reprargs),) + if abi is not None: + replace_with = replace_with[:1] + abi + ' ' + replace_with[1:] + self.c_name_with_marker = ( + self.result.c_name_with_marker.replace('&', replace_with)) + + +class RawFunctionType(BaseFunctionType): + # Corresponds to a C type like 'int(int)', which is the C type of + # a function, but not a pointer-to-function. The backend has no + # notion of such a type; it's used temporarily by parsing. + _base_pattern = '(&)(%s)' + is_raw_function = True + + def build_backend_type(self, ffi, finishlist): + raise CDefError("cannot render the type %r: it is a function " + "type, not a pointer-to-function type" % (self,)) + + def as_function_pointer(self): + return FunctionPtrType(self.args, self.result, self.ellipsis, self.abi) + + +class FunctionPtrType(BaseFunctionType): + _base_pattern = '(*&)(%s)' + + def build_backend_type(self, ffi, finishlist): + result = self.result.get_cached_btype(ffi, finishlist) + args = [] + for tp in self.args: + args.append(tp.get_cached_btype(ffi, finishlist)) + abi_args = () + if self.abi == "__stdcall": + if not self.ellipsis: # __stdcall ignored for variadic funcs + try: + abi_args = (ffi._backend.FFI_STDCALL,) + except AttributeError: + pass + return global_cache(self, ffi, 'new_function_type', + tuple(args), result, self.ellipsis, *abi_args) + + def as_raw_function(self): + return RawFunctionType(self.args, self.result, self.ellipsis, self.abi) + + +class PointerType(BaseType): + _attrs_ = ('totype', 'quals') + + def __init__(self, totype, quals=0): + self.totype = totype + self.quals = quals + extra = qualify(quals, " *&") + if totype.is_array_type: + extra = "(%s)" % (extra.lstrip(),) + self.c_name_with_marker = totype.c_name_with_marker.replace('&', extra) + + def build_backend_type(self, ffi, finishlist): + BItem = self.totype.get_cached_btype(ffi, finishlist, can_delay=True) + return global_cache(self, ffi, 'new_pointer_type', BItem) + +voidp_type = PointerType(void_type) + +def ConstPointerType(totype): + return PointerType(totype, Q_CONST) + +const_voidp_type = ConstPointerType(void_type) + + +class NamedPointerType(PointerType): + _attrs_ = ('totype', 'name') + + def __init__(self, totype, name, quals=0): + PointerType.__init__(self, totype, quals) + self.name = name + self.c_name_with_marker = name + '&' + + +class ArrayType(BaseType): + _attrs_ = ('item', 'length') + is_array_type = True + + def __init__(self, item, length): + self.item = item + self.length = length + # + if length is None: + brackets = '&[]' + elif length == '...': + brackets = '&[/*...*/]' + else: + brackets = '&[%s]' % length + self.c_name_with_marker = ( + self.item.c_name_with_marker.replace('&', brackets)) + + def length_is_unknown(self): + return isinstance(self.length, str) + + def resolve_length(self, newlength): + return ArrayType(self.item, newlength) + + def build_backend_type(self, ffi, finishlist): + if self.length_is_unknown(): + raise CDefError("cannot render the type %r: unknown length" % + (self,)) + self.item.get_cached_btype(ffi, finishlist) # force the item BType + BPtrItem = PointerType(self.item).get_cached_btype(ffi, finishlist) + return global_cache(self, ffi, 'new_array_type', BPtrItem, self.length) + +char_array_type = ArrayType(PrimitiveType('char'), None) + + +class StructOrUnionOrEnum(BaseTypeByIdentity): + _attrs_ = ('name',) + forcename = None + + def build_c_name_with_marker(self): + name = self.forcename or '%s %s' % (self.kind, self.name) + self.c_name_with_marker = name + '&' + + def force_the_name(self, forcename): + self.forcename = forcename + self.build_c_name_with_marker() + + def get_official_name(self): + assert self.c_name_with_marker.endswith('&') + return self.c_name_with_marker[:-1] + + +class StructOrUnion(StructOrUnionOrEnum): + fixedlayout = None + completed = 0 + partial = False + packed = 0 + + def __init__(self, name, fldnames, fldtypes, fldbitsize, fldquals=None): + self.name = name + self.fldnames = fldnames + self.fldtypes = fldtypes + self.fldbitsize = fldbitsize + self.fldquals = fldquals + self.build_c_name_with_marker() + + def anonymous_struct_fields(self): + if self.fldtypes is not None: + for name, type in zip(self.fldnames, self.fldtypes): + if name == '' and isinstance(type, StructOrUnion): + yield type + + def enumfields(self, expand_anonymous_struct_union=True): + fldquals = self.fldquals + if fldquals is None: + fldquals = (0,) * len(self.fldnames) + for name, type, bitsize, quals in zip(self.fldnames, self.fldtypes, + self.fldbitsize, fldquals): + if (name == '' and isinstance(type, StructOrUnion) + and expand_anonymous_struct_union): + # nested anonymous struct/union + for result in type.enumfields(): + yield result + else: + yield (name, type, bitsize, quals) + + def force_flatten(self): + # force the struct or union to have a declaration that lists + # directly all fields returned by enumfields(), flattening + # nested anonymous structs/unions. + names = [] + types = [] + bitsizes = [] + fldquals = [] + for name, type, bitsize, quals in self.enumfields(): + names.append(name) + types.append(type) + bitsizes.append(bitsize) + fldquals.append(quals) + self.fldnames = tuple(names) + self.fldtypes = tuple(types) + self.fldbitsize = tuple(bitsizes) + self.fldquals = tuple(fldquals) + + def get_cached_btype(self, ffi, finishlist, can_delay=False): + BType = StructOrUnionOrEnum.get_cached_btype(self, ffi, finishlist, + can_delay) + if not can_delay: + self.finish_backend_type(ffi, finishlist) + return BType + + def finish_backend_type(self, ffi, finishlist): + if self.completed: + if self.completed != 2: + raise NotImplementedError("recursive structure declaration " + "for '%s'" % (self.name,)) + return + BType = ffi._cached_btypes[self] + # + self.completed = 1 + # + if self.fldtypes is None: + pass # not completing it: it's an opaque struct + # + elif self.fixedlayout is None: + fldtypes = [tp.get_cached_btype(ffi, finishlist) + for tp in self.fldtypes] + lst = list(zip(self.fldnames, fldtypes, self.fldbitsize)) + extra_flags = () + if self.packed: + if self.packed == 1: + extra_flags = (8,) # SF_PACKED + else: + extra_flags = (0, self.packed) + ffi._backend.complete_struct_or_union(BType, lst, self, + -1, -1, *extra_flags) + # + else: + fldtypes = [] + fieldofs, fieldsize, totalsize, totalalignment = self.fixedlayout + for i in range(len(self.fldnames)): + fsize = fieldsize[i] + ftype = self.fldtypes[i] + # + if isinstance(ftype, ArrayType) and ftype.length_is_unknown(): + # fix the length to match the total size + BItemType = ftype.item.get_cached_btype(ffi, finishlist) + nlen, nrest = divmod(fsize, ffi.sizeof(BItemType)) + if nrest != 0: + self._verification_error( + "field '%s.%s' has a bogus size?" % ( + self.name, self.fldnames[i] or '{}')) + ftype = ftype.resolve_length(nlen) + self.fldtypes = (self.fldtypes[:i] + (ftype,) + + self.fldtypes[i+1:]) + # + BFieldType = ftype.get_cached_btype(ffi, finishlist) + if isinstance(ftype, ArrayType) and ftype.length is None: + assert fsize == 0 + else: + bitemsize = ffi.sizeof(BFieldType) + if bitemsize != fsize: + self._verification_error( + "field '%s.%s' is declared as %d bytes, but is " + "really %d bytes" % (self.name, + self.fldnames[i] or '{}', + bitemsize, fsize)) + fldtypes.append(BFieldType) + # + lst = list(zip(self.fldnames, fldtypes, self.fldbitsize, fieldofs)) + ffi._backend.complete_struct_or_union(BType, lst, self, + totalsize, totalalignment) + self.completed = 2 + + def _verification_error(self, msg): + raise VerificationError(msg) + + def check_not_partial(self): + if self.partial and self.fixedlayout is None: + raise VerificationMissing(self._get_c_name()) + + def build_backend_type(self, ffi, finishlist): + self.check_not_partial() + finishlist.append(self) + # + return global_cache(self, ffi, 'new_%s_type' % self.kind, + self.get_official_name(), key=self) + + +class StructType(StructOrUnion): + kind = 'struct' + + +class UnionType(StructOrUnion): + kind = 'union' + + +class EnumType(StructOrUnionOrEnum): + kind = 'enum' + partial = False + partial_resolved = False + + def __init__(self, name, enumerators, enumvalues, baseinttype=None): + self.name = name + self.enumerators = enumerators + self.enumvalues = enumvalues + self.baseinttype = baseinttype + self.build_c_name_with_marker() + + def force_the_name(self, forcename): + StructOrUnionOrEnum.force_the_name(self, forcename) + if self.forcename is None: + name = self.get_official_name() + self.forcename = '$' + name.replace(' ', '_') + + def check_not_partial(self): + if self.partial and not self.partial_resolved: + raise VerificationMissing(self._get_c_name()) + + def build_backend_type(self, ffi, finishlist): + self.check_not_partial() + base_btype = self.build_baseinttype(ffi, finishlist) + return global_cache(self, ffi, 'new_enum_type', + self.get_official_name(), + self.enumerators, self.enumvalues, + base_btype, key=self) + + def build_baseinttype(self, ffi, finishlist): + if self.baseinttype is not None: + return self.baseinttype.get_cached_btype(ffi, finishlist) + # + if self.enumvalues: + smallest_value = min(self.enumvalues) + largest_value = max(self.enumvalues) + else: + import warnings + try: + # XXX! The goal is to ensure that the warnings.warn() + # will not suppress the warning. We want to get it + # several times if we reach this point several times. + __warningregistry__.clear() + except NameError: + pass + warnings.warn("%r has no values explicitly defined; " + "guessing that it is equivalent to 'unsigned int'" + % self._get_c_name()) + smallest_value = largest_value = 0 + if smallest_value < 0: # needs a signed type + sign = 1 + candidate1 = PrimitiveType("int") + candidate2 = PrimitiveType("long") + else: + sign = 0 + candidate1 = PrimitiveType("unsigned int") + candidate2 = PrimitiveType("unsigned long") + btype1 = candidate1.get_cached_btype(ffi, finishlist) + btype2 = candidate2.get_cached_btype(ffi, finishlist) + size1 = ffi.sizeof(btype1) + size2 = ffi.sizeof(btype2) + if (smallest_value >= ((-1) << (8*size1-1)) and + largest_value < (1 << (8*size1-sign))): + return btype1 + if (smallest_value >= ((-1) << (8*size2-1)) and + largest_value < (1 << (8*size2-sign))): + return btype2 + raise CDefError("%s values don't all fit into either 'long' " + "or 'unsigned long'" % self._get_c_name()) + +def unknown_type(name, structname=None): + if structname is None: + structname = '$%s' % name + tp = StructType(structname, None, None, None) + tp.force_the_name(name) + tp.origin = "unknown_type" + return tp + +def unknown_ptr_type(name, structname=None): + if structname is None: + structname = '$$%s' % name + tp = StructType(structname, None, None, None) + return NamedPointerType(tp, name) + + +global_lock = allocate_lock() +_typecache_cffi_backend = weakref.WeakValueDictionary() + +def get_typecache(backend): + # returns _typecache_cffi_backend if backend is the _cffi_backend + # module, or type(backend).__typecache if backend is an instance of + # CTypesBackend (or some FakeBackend class during tests) + if isinstance(backend, types.ModuleType): + return _typecache_cffi_backend + with global_lock: + if not hasattr(type(backend), '__typecache'): + type(backend).__typecache = weakref.WeakValueDictionary() + return type(backend).__typecache + +def global_cache(srctype, ffi, funcname, *args, **kwds): + key = kwds.pop('key', (funcname, args)) + assert not kwds + try: + return ffi._typecache[key] + except KeyError: + pass + try: + res = getattr(ffi._backend, funcname)(*args) + except NotImplementedError as e: + raise NotImplementedError("%s: %r: %s" % (funcname, srctype, e)) + # note that setdefault() on WeakValueDictionary is not atomic + # and contains a rare bug (http://bugs.python.org/issue19542); + # we have to use a lock and do it ourselves + cache = ffi._typecache + with global_lock: + res1 = cache.get(key) + if res1 is None: + cache[key] = res + return res + else: + return res1 + +def pointer_cache(ffi, BType): + return global_cache('?', ffi, 'new_pointer_type', BType) + +def attach_exception_info(e, name): + if e.args and type(e.args[0]) is str: + e.args = ('%s: %s' % (name, e.args[0]),) + e.args[1:] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/parse_c_type.h b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/parse_c_type.h new file mode 100644 index 0000000..84e4ef8 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/parse_c_type.h @@ -0,0 +1,181 @@ + +/* This part is from file 'cffi/parse_c_type.h'. It is copied at the + beginning of C sources generated by CFFI's ffi.set_source(). */ + +typedef void *_cffi_opcode_t; + +#define _CFFI_OP(opcode, arg) (_cffi_opcode_t)(opcode | (((uintptr_t)(arg)) << 8)) +#define _CFFI_GETOP(cffi_opcode) ((unsigned char)(uintptr_t)cffi_opcode) +#define _CFFI_GETARG(cffi_opcode) (((intptr_t)cffi_opcode) >> 8) + +#define _CFFI_OP_PRIMITIVE 1 +#define _CFFI_OP_POINTER 3 +#define _CFFI_OP_ARRAY 5 +#define _CFFI_OP_OPEN_ARRAY 7 +#define _CFFI_OP_STRUCT_UNION 9 +#define _CFFI_OP_ENUM 11 +#define _CFFI_OP_FUNCTION 13 +#define _CFFI_OP_FUNCTION_END 15 +#define _CFFI_OP_NOOP 17 +#define _CFFI_OP_BITFIELD 19 +#define _CFFI_OP_TYPENAME 21 +#define _CFFI_OP_CPYTHON_BLTN_V 23 // varargs +#define _CFFI_OP_CPYTHON_BLTN_N 25 // noargs +#define _CFFI_OP_CPYTHON_BLTN_O 27 // O (i.e. a single arg) +#define _CFFI_OP_CONSTANT 29 +#define _CFFI_OP_CONSTANT_INT 31 +#define _CFFI_OP_GLOBAL_VAR 33 +#define _CFFI_OP_DLOPEN_FUNC 35 +#define _CFFI_OP_DLOPEN_CONST 37 +#define _CFFI_OP_GLOBAL_VAR_F 39 +#define _CFFI_OP_EXTERN_PYTHON 41 + +#define _CFFI_PRIM_VOID 0 +#define _CFFI_PRIM_BOOL 1 +#define _CFFI_PRIM_CHAR 2 +#define _CFFI_PRIM_SCHAR 3 +#define _CFFI_PRIM_UCHAR 4 +#define _CFFI_PRIM_SHORT 5 +#define _CFFI_PRIM_USHORT 6 +#define _CFFI_PRIM_INT 7 +#define _CFFI_PRIM_UINT 8 +#define _CFFI_PRIM_LONG 9 +#define _CFFI_PRIM_ULONG 10 +#define _CFFI_PRIM_LONGLONG 11 +#define _CFFI_PRIM_ULONGLONG 12 +#define _CFFI_PRIM_FLOAT 13 +#define _CFFI_PRIM_DOUBLE 14 +#define _CFFI_PRIM_LONGDOUBLE 15 + +#define _CFFI_PRIM_WCHAR 16 +#define _CFFI_PRIM_INT8 17 +#define _CFFI_PRIM_UINT8 18 +#define _CFFI_PRIM_INT16 19 +#define _CFFI_PRIM_UINT16 20 +#define _CFFI_PRIM_INT32 21 +#define _CFFI_PRIM_UINT32 22 +#define _CFFI_PRIM_INT64 23 +#define _CFFI_PRIM_UINT64 24 +#define _CFFI_PRIM_INTPTR 25 +#define _CFFI_PRIM_UINTPTR 26 +#define _CFFI_PRIM_PTRDIFF 27 +#define _CFFI_PRIM_SIZE 28 +#define _CFFI_PRIM_SSIZE 29 +#define _CFFI_PRIM_INT_LEAST8 30 +#define _CFFI_PRIM_UINT_LEAST8 31 +#define _CFFI_PRIM_INT_LEAST16 32 +#define _CFFI_PRIM_UINT_LEAST16 33 +#define _CFFI_PRIM_INT_LEAST32 34 +#define _CFFI_PRIM_UINT_LEAST32 35 +#define _CFFI_PRIM_INT_LEAST64 36 +#define _CFFI_PRIM_UINT_LEAST64 37 +#define _CFFI_PRIM_INT_FAST8 38 +#define _CFFI_PRIM_UINT_FAST8 39 +#define _CFFI_PRIM_INT_FAST16 40 +#define _CFFI_PRIM_UINT_FAST16 41 +#define _CFFI_PRIM_INT_FAST32 42 +#define _CFFI_PRIM_UINT_FAST32 43 +#define _CFFI_PRIM_INT_FAST64 44 +#define _CFFI_PRIM_UINT_FAST64 45 +#define _CFFI_PRIM_INTMAX 46 +#define _CFFI_PRIM_UINTMAX 47 +#define _CFFI_PRIM_FLOATCOMPLEX 48 +#define _CFFI_PRIM_DOUBLECOMPLEX 49 +#define _CFFI_PRIM_CHAR16 50 +#define _CFFI_PRIM_CHAR32 51 + +#define _CFFI__NUM_PRIM 52 +#define _CFFI__UNKNOWN_PRIM (-1) +#define _CFFI__UNKNOWN_FLOAT_PRIM (-2) +#define _CFFI__UNKNOWN_LONG_DOUBLE (-3) + +#define _CFFI__IO_FILE_STRUCT (-1) + + +struct _cffi_global_s { + const char *name; + void *address; + _cffi_opcode_t type_op; + void *size_or_direct_fn; // OP_GLOBAL_VAR: size, or 0 if unknown + // OP_CPYTHON_BLTN_*: addr of direct function +}; + +struct _cffi_getconst_s { + unsigned long long value; + const struct _cffi_type_context_s *ctx; + int gindex; +}; + +struct _cffi_struct_union_s { + const char *name; + int type_index; // -> _cffi_types, on a OP_STRUCT_UNION + int flags; // _CFFI_F_* flags below + size_t size; + int alignment; + int first_field_index; // -> _cffi_fields array + int num_fields; +}; +#define _CFFI_F_UNION 0x01 // is a union, not a struct +#define _CFFI_F_CHECK_FIELDS 0x02 // complain if fields are not in the + // "standard layout" or if some are missing +#define _CFFI_F_PACKED 0x04 // for CHECK_FIELDS, assume a packed struct +#define _CFFI_F_EXTERNAL 0x08 // in some other ffi.include() +#define _CFFI_F_OPAQUE 0x10 // opaque + +struct _cffi_field_s { + const char *name; + size_t field_offset; + size_t field_size; + _cffi_opcode_t field_type_op; +}; + +struct _cffi_enum_s { + const char *name; + int type_index; // -> _cffi_types, on a OP_ENUM + int type_prim; // _CFFI_PRIM_xxx + const char *enumerators; // comma-delimited string +}; + +struct _cffi_typename_s { + const char *name; + int type_index; /* if opaque, points to a possibly artificial + OP_STRUCT which is itself opaque */ +}; + +struct _cffi_type_context_s { + _cffi_opcode_t *types; + const struct _cffi_global_s *globals; + const struct _cffi_field_s *fields; + const struct _cffi_struct_union_s *struct_unions; + const struct _cffi_enum_s *enums; + const struct _cffi_typename_s *typenames; + int num_globals; + int num_struct_unions; + int num_enums; + int num_typenames; + const char *const *includes; + int num_types; + int flags; /* future extension */ +}; + +struct _cffi_parse_info_s { + const struct _cffi_type_context_s *ctx; + _cffi_opcode_t *output; + unsigned int output_size; + size_t error_location; + const char *error_message; +}; + +struct _cffi_externpy_s { + const char *name; + size_t size_of_result; + void *reserved1, *reserved2; +}; + +#ifdef _CFFI_INTERNAL +static int parse_c_type(struct _cffi_parse_info_s *info, const char *input); +static int search_in_globals(const struct _cffi_type_context_s *ctx, + const char *search, size_t search_len); +static int search_in_struct_unions(const struct _cffi_type_context_s *ctx, + const char *search, size_t search_len); +#endif diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/pkgconfig.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/pkgconfig.py new file mode 100644 index 0000000..5c93f15 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/pkgconfig.py @@ -0,0 +1,121 @@ +# pkg-config, https://www.freedesktop.org/wiki/Software/pkg-config/ integration for cffi +import sys, os, subprocess + +from .error import PkgConfigError + + +def merge_flags(cfg1, cfg2): + """Merge values from cffi config flags cfg2 to cf1 + + Example: + merge_flags({"libraries": ["one"]}, {"libraries": ["two"]}) + {"libraries": ["one", "two"]} + """ + for key, value in cfg2.items(): + if key not in cfg1: + cfg1[key] = value + else: + if not isinstance(cfg1[key], list): + raise TypeError("cfg1[%r] should be a list of strings" % (key,)) + if not isinstance(value, list): + raise TypeError("cfg2[%r] should be a list of strings" % (key,)) + cfg1[key].extend(value) + return cfg1 + + +def call(libname, flag, encoding=sys.getfilesystemencoding()): + """Calls pkg-config and returns the output if found + """ + a = ["pkg-config", "--print-errors"] + a.append(flag) + a.append(libname) + try: + pc = subprocess.Popen(a, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + except EnvironmentError as e: + raise PkgConfigError("cannot run pkg-config: %s" % (str(e).strip(),)) + + bout, berr = pc.communicate() + if pc.returncode != 0: + try: + berr = berr.decode(encoding) + except Exception: + pass + raise PkgConfigError(berr.strip()) + + if sys.version_info >= (3,) and not isinstance(bout, str): # Python 3.x + try: + bout = bout.decode(encoding) + except UnicodeDecodeError: + raise PkgConfigError("pkg-config %s %s returned bytes that cannot " + "be decoded with encoding %r:\n%r" % + (flag, libname, encoding, bout)) + + if os.altsep != '\\' and '\\' in bout: + raise PkgConfigError("pkg-config %s %s returned an unsupported " + "backslash-escaped output:\n%r" % + (flag, libname, bout)) + return bout + + +def flags_from_pkgconfig(libs): + r"""Return compiler line flags for FFI.set_source based on pkg-config output + + Usage + ... + ffibuilder.set_source("_foo", pkgconfig = ["libfoo", "libbar >= 1.8.3"]) + + If pkg-config is installed on build machine, then arguments include_dirs, + library_dirs, libraries, define_macros, extra_compile_args and + extra_link_args are extended with an output of pkg-config for libfoo and + libbar. + + Raises PkgConfigError in case the pkg-config call fails. + """ + + def get_include_dirs(string): + return [x[2:] for x in string.split() if x.startswith("-I")] + + def get_library_dirs(string): + return [x[2:] for x in string.split() if x.startswith("-L")] + + def get_libraries(string): + return [x[2:] for x in string.split() if x.startswith("-l")] + + # convert -Dfoo=bar to list of tuples [("foo", "bar")] expected by distutils + def get_macros(string): + def _macro(x): + x = x[2:] # drop "-D" + if '=' in x: + return tuple(x.split("=", 1)) # "-Dfoo=bar" => ("foo", "bar") + else: + return (x, None) # "-Dfoo" => ("foo", None) + return [_macro(x) for x in string.split() if x.startswith("-D")] + + def get_other_cflags(string): + return [x for x in string.split() if not x.startswith("-I") and + not x.startswith("-D")] + + def get_other_libs(string): + return [x for x in string.split() if not x.startswith("-L") and + not x.startswith("-l")] + + # return kwargs for given libname + def kwargs(libname): + fse = sys.getfilesystemencoding() + all_cflags = call(libname, "--cflags") + all_libs = call(libname, "--libs") + return { + "include_dirs": get_include_dirs(all_cflags), + "library_dirs": get_library_dirs(all_libs), + "libraries": get_libraries(all_libs), + "define_macros": get_macros(all_cflags), + "extra_compile_args": get_other_cflags(all_cflags), + "extra_link_args": get_other_libs(all_libs), + } + + # merge all arguments together + ret = {} + for libname in libs: + lib_flags = kwargs(libname) + merge_flags(ret, lib_flags) + return ret diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/recompiler.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/recompiler.py new file mode 100644 index 0000000..1aeae5b --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/recompiler.py @@ -0,0 +1,1571 @@ +import os, sys, io +from . import ffiplatform, model +from .error import VerificationError +from .cffi_opcode import * + +VERSION_BASE = 0x2601 +VERSION_EMBEDDED = 0x2701 +VERSION_CHAR16CHAR32 = 0x2801 + +USE_LIMITED_API = (sys.platform != 'win32' or sys.version_info < (3, 0) or + sys.version_info >= (3, 5)) + + +class GlobalExpr: + def __init__(self, name, address, type_op, size=0, check_value=0): + self.name = name + self.address = address + self.type_op = type_op + self.size = size + self.check_value = check_value + + def as_c_expr(self): + return ' { "%s", (void *)%s, %s, (void *)%s },' % ( + self.name, self.address, self.type_op.as_c_expr(), self.size) + + def as_python_expr(self): + return "b'%s%s',%d" % (self.type_op.as_python_bytes(), self.name, + self.check_value) + +class FieldExpr: + def __init__(self, name, field_offset, field_size, fbitsize, field_type_op): + self.name = name + self.field_offset = field_offset + self.field_size = field_size + self.fbitsize = fbitsize + self.field_type_op = field_type_op + + def as_c_expr(self): + spaces = " " * len(self.name) + return (' { "%s", %s,\n' % (self.name, self.field_offset) + + ' %s %s,\n' % (spaces, self.field_size) + + ' %s %s },' % (spaces, self.field_type_op.as_c_expr())) + + def as_python_expr(self): + raise NotImplementedError + + def as_field_python_expr(self): + if self.field_type_op.op == OP_NOOP: + size_expr = '' + elif self.field_type_op.op == OP_BITFIELD: + size_expr = format_four_bytes(self.fbitsize) + else: + raise NotImplementedError + return "b'%s%s%s'" % (self.field_type_op.as_python_bytes(), + size_expr, + self.name) + +class StructUnionExpr: + def __init__(self, name, type_index, flags, size, alignment, comment, + first_field_index, c_fields): + self.name = name + self.type_index = type_index + self.flags = flags + self.size = size + self.alignment = alignment + self.comment = comment + self.first_field_index = first_field_index + self.c_fields = c_fields + + def as_c_expr(self): + return (' { "%s", %d, %s,' % (self.name, self.type_index, self.flags) + + '\n %s, %s, ' % (self.size, self.alignment) + + '%d, %d ' % (self.first_field_index, len(self.c_fields)) + + ('/* %s */ ' % self.comment if self.comment else '') + + '},') + + def as_python_expr(self): + flags = eval(self.flags, G_FLAGS) + fields_expr = [c_field.as_field_python_expr() + for c_field in self.c_fields] + return "(b'%s%s%s',%s)" % ( + format_four_bytes(self.type_index), + format_four_bytes(flags), + self.name, + ','.join(fields_expr)) + +class EnumExpr: + def __init__(self, name, type_index, size, signed, allenums): + self.name = name + self.type_index = type_index + self.size = size + self.signed = signed + self.allenums = allenums + + def as_c_expr(self): + return (' { "%s", %d, _cffi_prim_int(%s, %s),\n' + ' "%s" },' % (self.name, self.type_index, + self.size, self.signed, self.allenums)) + + def as_python_expr(self): + prim_index = { + (1, 0): PRIM_UINT8, (1, 1): PRIM_INT8, + (2, 0): PRIM_UINT16, (2, 1): PRIM_INT16, + (4, 0): PRIM_UINT32, (4, 1): PRIM_INT32, + (8, 0): PRIM_UINT64, (8, 1): PRIM_INT64, + }[self.size, self.signed] + return "b'%s%s%s\\x00%s'" % (format_four_bytes(self.type_index), + format_four_bytes(prim_index), + self.name, self.allenums) + +class TypenameExpr: + def __init__(self, name, type_index): + self.name = name + self.type_index = type_index + + def as_c_expr(self): + return ' { "%s", %d },' % (self.name, self.type_index) + + def as_python_expr(self): + return "b'%s%s'" % (format_four_bytes(self.type_index), self.name) + + +# ____________________________________________________________ + + +class Recompiler: + _num_externpy = 0 + + def __init__(self, ffi, module_name, target_is_python=False): + self.ffi = ffi + self.module_name = module_name + self.target_is_python = target_is_python + self._version = VERSION_BASE + + def needs_version(self, ver): + self._version = max(self._version, ver) + + def collect_type_table(self): + self._typesdict = {} + self._generate("collecttype") + # + all_decls = sorted(self._typesdict, key=str) + # + # prepare all FUNCTION bytecode sequences first + self.cffi_types = [] + for tp in all_decls: + if tp.is_raw_function: + assert self._typesdict[tp] is None + self._typesdict[tp] = len(self.cffi_types) + self.cffi_types.append(tp) # placeholder + for tp1 in tp.args: + assert isinstance(tp1, (model.VoidType, + model.BasePrimitiveType, + model.PointerType, + model.StructOrUnionOrEnum, + model.FunctionPtrType)) + if self._typesdict[tp1] is None: + self._typesdict[tp1] = len(self.cffi_types) + self.cffi_types.append(tp1) # placeholder + self.cffi_types.append('END') # placeholder + # + # prepare all OTHER bytecode sequences + for tp in all_decls: + if not tp.is_raw_function and self._typesdict[tp] is None: + self._typesdict[tp] = len(self.cffi_types) + self.cffi_types.append(tp) # placeholder + if tp.is_array_type and tp.length is not None: + self.cffi_types.append('LEN') # placeholder + assert None not in self._typesdict.values() + # + # collect all structs and unions and enums + self._struct_unions = {} + self._enums = {} + for tp in all_decls: + if isinstance(tp, model.StructOrUnion): + self._struct_unions[tp] = None + elif isinstance(tp, model.EnumType): + self._enums[tp] = None + for i, tp in enumerate(sorted(self._struct_unions, + key=lambda tp: tp.name)): + self._struct_unions[tp] = i + for i, tp in enumerate(sorted(self._enums, + key=lambda tp: tp.name)): + self._enums[tp] = i + # + # emit all bytecode sequences now + for tp in all_decls: + method = getattr(self, '_emit_bytecode_' + tp.__class__.__name__) + method(tp, self._typesdict[tp]) + # + # consistency check + for op in self.cffi_types: + assert isinstance(op, CffiOp) + self.cffi_types = tuple(self.cffi_types) # don't change any more + + def _do_collect_type(self, tp): + if not isinstance(tp, model.BaseTypeByIdentity): + if isinstance(tp, tuple): + for x in tp: + self._do_collect_type(x) + return + if tp not in self._typesdict: + self._typesdict[tp] = None + if isinstance(tp, model.FunctionPtrType): + self._do_collect_type(tp.as_raw_function()) + elif isinstance(tp, model.StructOrUnion): + if tp.fldtypes is not None and ( + tp not in self.ffi._parser._included_declarations): + for name1, tp1, _, _ in tp.enumfields(): + self._do_collect_type(self._field_type(tp, name1, tp1)) + else: + for _, x in tp._get_items(): + self._do_collect_type(x) + + def _generate(self, step_name): + lst = self.ffi._parser._declarations.items() + for name, (tp, quals) in sorted(lst): + kind, realname = name.split(' ', 1) + try: + method = getattr(self, '_generate_cpy_%s_%s' % (kind, + step_name)) + except AttributeError: + raise VerificationError( + "not implemented in recompile(): %r" % name) + try: + self._current_quals = quals + method(tp, realname) + except Exception as e: + model.attach_exception_info(e, name) + raise + + # ---------- + + ALL_STEPS = ["global", "field", "struct_union", "enum", "typename"] + + def collect_step_tables(self): + # collect the declarations for '_cffi_globals', '_cffi_typenames', etc. + self._lsts = {} + for step_name in self.ALL_STEPS: + self._lsts[step_name] = [] + self._seen_struct_unions = set() + self._generate("ctx") + self._add_missing_struct_unions() + # + for step_name in self.ALL_STEPS: + lst = self._lsts[step_name] + if step_name != "field": + lst.sort(key=lambda entry: entry.name) + self._lsts[step_name] = tuple(lst) # don't change any more + # + # check for a possible internal inconsistency: _cffi_struct_unions + # should have been generated with exactly self._struct_unions + lst = self._lsts["struct_union"] + for tp, i in self._struct_unions.items(): + assert i < len(lst) + assert lst[i].name == tp.name + assert len(lst) == len(self._struct_unions) + # same with enums + lst = self._lsts["enum"] + for tp, i in self._enums.items(): + assert i < len(lst) + assert lst[i].name == tp.name + assert len(lst) == len(self._enums) + + # ---------- + + def _prnt(self, what=''): + self._f.write(what + '\n') + + def write_source_to_f(self, f, preamble): + if self.target_is_python: + assert preamble is None + self.write_py_source_to_f(f) + else: + assert preamble is not None + self.write_c_source_to_f(f, preamble) + + def _rel_readlines(self, filename): + g = open(os.path.join(os.path.dirname(__file__), filename), 'r') + lines = g.readlines() + g.close() + return lines + + def write_c_source_to_f(self, f, preamble): + self._f = f + prnt = self._prnt + if self.ffi._embedding is not None: + prnt('#define _CFFI_USE_EMBEDDING') + if not USE_LIMITED_API: + prnt('#define _CFFI_NO_LIMITED_API') + # + # first the '#include' (actually done by inlining the file's content) + lines = self._rel_readlines('_cffi_include.h') + i = lines.index('#include "parse_c_type.h"\n') + lines[i:i+1] = self._rel_readlines('parse_c_type.h') + prnt(''.join(lines)) + # + # if we have ffi._embedding != None, we give it here as a macro + # and include an extra file + base_module_name = self.module_name.split('.')[-1] + if self.ffi._embedding is not None: + prnt('#define _CFFI_MODULE_NAME "%s"' % (self.module_name,)) + prnt('static const char _CFFI_PYTHON_STARTUP_CODE[] = {') + self._print_string_literal_in_array(self.ffi._embedding) + prnt('0 };') + prnt('#ifdef PYPY_VERSION') + prnt('# define _CFFI_PYTHON_STARTUP_FUNC _cffi_pypyinit_%s' % ( + base_module_name,)) + prnt('#elif PY_MAJOR_VERSION >= 3') + prnt('# define _CFFI_PYTHON_STARTUP_FUNC PyInit_%s' % ( + base_module_name,)) + prnt('#else') + prnt('# define _CFFI_PYTHON_STARTUP_FUNC init%s' % ( + base_module_name,)) + prnt('#endif') + lines = self._rel_readlines('_embedding.h') + i = lines.index('#include "_cffi_errors.h"\n') + lines[i:i+1] = self._rel_readlines('_cffi_errors.h') + prnt(''.join(lines)) + self.needs_version(VERSION_EMBEDDED) + # + # then paste the C source given by the user, verbatim. + prnt('/************************************************************/') + prnt() + prnt(preamble) + prnt() + prnt('/************************************************************/') + prnt() + # + # the declaration of '_cffi_types' + prnt('static void *_cffi_types[] = {') + typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()]) + for i, op in enumerate(self.cffi_types): + comment = '' + if i in typeindex2type: + comment = ' // ' + typeindex2type[i]._get_c_name() + prnt('/* %2d */ %s,%s' % (i, op.as_c_expr(), comment)) + if not self.cffi_types: + prnt(' 0') + prnt('};') + prnt() + # + # call generate_cpy_xxx_decl(), for every xxx found from + # ffi._parser._declarations. This generates all the functions. + self._seen_constants = set() + self._generate("decl") + # + # the declaration of '_cffi_globals' and '_cffi_typenames' + nums = {} + for step_name in self.ALL_STEPS: + lst = self._lsts[step_name] + nums[step_name] = len(lst) + if nums[step_name] > 0: + prnt('static const struct _cffi_%s_s _cffi_%ss[] = {' % ( + step_name, step_name)) + for entry in lst: + prnt(entry.as_c_expr()) + prnt('};') + prnt() + # + # the declaration of '_cffi_includes' + if self.ffi._included_ffis: + prnt('static const char * const _cffi_includes[] = {') + for ffi_to_include in self.ffi._included_ffis: + try: + included_module_name, included_source = ( + ffi_to_include._assigned_source[:2]) + except AttributeError: + raise VerificationError( + "ffi object %r includes %r, but the latter has not " + "been prepared with set_source()" % ( + self.ffi, ffi_to_include,)) + if included_source is None: + raise VerificationError( + "not implemented yet: ffi.include() of a Python-based " + "ffi inside a C-based ffi") + prnt(' "%s",' % (included_module_name,)) + prnt(' NULL') + prnt('};') + prnt() + # + # the declaration of '_cffi_type_context' + prnt('static const struct _cffi_type_context_s _cffi_type_context = {') + prnt(' _cffi_types,') + for step_name in self.ALL_STEPS: + if nums[step_name] > 0: + prnt(' _cffi_%ss,' % step_name) + else: + prnt(' NULL, /* no %ss */' % step_name) + for step_name in self.ALL_STEPS: + if step_name != "field": + prnt(' %d, /* num_%ss */' % (nums[step_name], step_name)) + if self.ffi._included_ffis: + prnt(' _cffi_includes,') + else: + prnt(' NULL, /* no includes */') + prnt(' %d, /* num_types */' % (len(self.cffi_types),)) + flags = 0 + if self._num_externpy: + flags |= 1 # set to mean that we use extern "Python" + prnt(' %d, /* flags */' % flags) + prnt('};') + prnt() + # + # the init function + prnt('#ifdef __GNUC__') + prnt('# pragma GCC visibility push(default) /* for -fvisibility= */') + prnt('#endif') + prnt() + prnt('#ifdef PYPY_VERSION') + prnt('PyMODINIT_FUNC') + prnt('_cffi_pypyinit_%s(const void *p[])' % (base_module_name,)) + prnt('{') + if self._num_externpy: + prnt(' if (((intptr_t)p[0]) >= 0x0A03) {') + prnt(' _cffi_call_python_org = ' + '(void(*)(struct _cffi_externpy_s *, char *))p[1];') + prnt(' }') + prnt(' p[0] = (const void *)0x%x;' % self._version) + prnt(' p[1] = &_cffi_type_context;') + prnt('#if PY_MAJOR_VERSION >= 3') + prnt(' return NULL;') + prnt('#endif') + prnt('}') + # on Windows, distutils insists on putting init_cffi_xyz in + # 'export_symbols', so instead of fighting it, just give up and + # give it one + prnt('# ifdef _MSC_VER') + prnt(' PyMODINIT_FUNC') + prnt('# if PY_MAJOR_VERSION >= 3') + prnt(' PyInit_%s(void) { return NULL; }' % (base_module_name,)) + prnt('# else') + prnt(' init%s(void) { }' % (base_module_name,)) + prnt('# endif') + prnt('# endif') + prnt('#elif PY_MAJOR_VERSION >= 3') + prnt('PyMODINIT_FUNC') + prnt('PyInit_%s(void)' % (base_module_name,)) + prnt('{') + prnt(' return _cffi_init("%s", 0x%x, &_cffi_type_context);' % ( + self.module_name, self._version)) + prnt('}') + prnt('#else') + prnt('PyMODINIT_FUNC') + prnt('init%s(void)' % (base_module_name,)) + prnt('{') + prnt(' _cffi_init("%s", 0x%x, &_cffi_type_context);' % ( + self.module_name, self._version)) + prnt('}') + prnt('#endif') + prnt() + prnt('#ifdef __GNUC__') + prnt('# pragma GCC visibility pop') + prnt('#endif') + self._version = None + + def _to_py(self, x): + if isinstance(x, str): + return "b'%s'" % (x,) + if isinstance(x, (list, tuple)): + rep = [self._to_py(item) for item in x] + if len(rep) == 1: + rep.append('') + return "(%s)" % (','.join(rep),) + return x.as_python_expr() # Py2: unicode unexpected; Py3: bytes unexp. + + def write_py_source_to_f(self, f): + self._f = f + prnt = self._prnt + # + # header + prnt("# auto-generated file") + prnt("import _cffi_backend") + # + # the 'import' of the included ffis + num_includes = len(self.ffi._included_ffis or ()) + for i in range(num_includes): + ffi_to_include = self.ffi._included_ffis[i] + try: + included_module_name, included_source = ( + ffi_to_include._assigned_source[:2]) + except AttributeError: + raise VerificationError( + "ffi object %r includes %r, but the latter has not " + "been prepared with set_source()" % ( + self.ffi, ffi_to_include,)) + if included_source is not None: + raise VerificationError( + "not implemented yet: ffi.include() of a C-based " + "ffi inside a Python-based ffi") + prnt('from %s import ffi as _ffi%d' % (included_module_name, i)) + prnt() + prnt("ffi = _cffi_backend.FFI('%s'," % (self.module_name,)) + prnt(" _version = 0x%x," % (self._version,)) + self._version = None + # + # the '_types' keyword argument + self.cffi_types = tuple(self.cffi_types) # don't change any more + types_lst = [op.as_python_bytes() for op in self.cffi_types] + prnt(' _types = %s,' % (self._to_py(''.join(types_lst)),)) + typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()]) + # + # the keyword arguments from ALL_STEPS + for step_name in self.ALL_STEPS: + lst = self._lsts[step_name] + if len(lst) > 0 and step_name != "field": + prnt(' _%ss = %s,' % (step_name, self._to_py(lst))) + # + # the '_includes' keyword argument + if num_includes > 0: + prnt(' _includes = (%s,),' % ( + ', '.join(['_ffi%d' % i for i in range(num_includes)]),)) + # + # the footer + prnt(')') + + # ---------- + + def _gettypenum(self, type): + # a KeyError here is a bug. please report it! :-) + return self._typesdict[type] + + def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode): + extraarg = '' + if isinstance(tp, model.BasePrimitiveType) and not tp.is_complex_type(): + if tp.is_integer_type() and tp.name != '_Bool': + converter = '_cffi_to_c_int' + extraarg = ', %s' % tp.name + elif isinstance(tp, model.UnknownFloatType): + # don't check with is_float_type(): it may be a 'long + # double' here, and _cffi_to_c_double would loose precision + converter = '(%s)_cffi_to_c_double' % (tp.get_c_name(''),) + else: + cname = tp.get_c_name('') + converter = '(%s)_cffi_to_c_%s' % (cname, + tp.name.replace(' ', '_')) + if cname in ('char16_t', 'char32_t'): + self.needs_version(VERSION_CHAR16CHAR32) + errvalue = '-1' + # + elif isinstance(tp, model.PointerType): + self._convert_funcarg_to_c_ptr_or_array(tp, fromvar, + tovar, errcode) + return + # + elif (isinstance(tp, model.StructOrUnionOrEnum) or + isinstance(tp, model.BasePrimitiveType)): + # a struct (not a struct pointer) as a function argument; + # or, a complex (the same code works) + self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)' + % (tovar, self._gettypenum(tp), fromvar)) + self._prnt(' %s;' % errcode) + return + # + elif isinstance(tp, model.FunctionPtrType): + converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('') + extraarg = ', _cffi_type(%d)' % self._gettypenum(tp) + errvalue = 'NULL' + # + else: + raise NotImplementedError(tp) + # + self._prnt(' %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg)) + self._prnt(' if (%s == (%s)%s && PyErr_Occurred())' % ( + tovar, tp.get_c_name(''), errvalue)) + self._prnt(' %s;' % errcode) + + def _extra_local_variables(self, tp, localvars, freelines): + if isinstance(tp, model.PointerType): + localvars.add('Py_ssize_t datasize') + localvars.add('struct _cffi_freeme_s *large_args_free = NULL') + freelines.add('if (large_args_free != NULL)' + ' _cffi_free_array_arguments(large_args_free);') + + def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode): + self._prnt(' datasize = _cffi_prepare_pointer_call_argument(') + self._prnt(' _cffi_type(%d), %s, (char **)&%s);' % ( + self._gettypenum(tp), fromvar, tovar)) + self._prnt(' if (datasize != 0) {') + self._prnt(' %s = ((size_t)datasize) <= 640 ? ' + '(%s)alloca((size_t)datasize) : NULL;' % ( + tovar, tp.get_c_name(''))) + self._prnt(' if (_cffi_convert_array_argument(_cffi_type(%d), %s, ' + '(char **)&%s,' % (self._gettypenum(tp), fromvar, tovar)) + self._prnt(' datasize, &large_args_free) < 0)') + self._prnt(' %s;' % errcode) + self._prnt(' }') + + def _convert_expr_from_c(self, tp, var, context): + if isinstance(tp, model.BasePrimitiveType): + if tp.is_integer_type() and tp.name != '_Bool': + return '_cffi_from_c_int(%s, %s)' % (var, tp.name) + elif isinstance(tp, model.UnknownFloatType): + return '_cffi_from_c_double(%s)' % (var,) + elif tp.name != 'long double' and not tp.is_complex_type(): + cname = tp.name.replace(' ', '_') + if cname in ('char16_t', 'char32_t'): + self.needs_version(VERSION_CHAR16CHAR32) + return '_cffi_from_c_%s(%s)' % (cname, var) + else: + return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, (model.PointerType, model.FunctionPtrType)): + return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, model.ArrayType): + return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( + var, self._gettypenum(model.PointerType(tp.item))) + elif isinstance(tp, model.StructOrUnion): + if tp.fldnames is None: + raise TypeError("'%s' is used as %s, but is opaque" % ( + tp._get_c_name(), context)) + return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, model.EnumType): + return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + else: + raise NotImplementedError(tp) + + # ---------- + # typedefs + + def _typedef_type(self, tp, name): + return self._global_type(tp, "(*(%s *)0)" % (name,)) + + def _generate_cpy_typedef_collecttype(self, tp, name): + self._do_collect_type(self._typedef_type(tp, name)) + + def _generate_cpy_typedef_decl(self, tp, name): + pass + + def _typedef_ctx(self, tp, name): + type_index = self._typesdict[tp] + self._lsts["typename"].append(TypenameExpr(name, type_index)) + + def _generate_cpy_typedef_ctx(self, tp, name): + tp = self._typedef_type(tp, name) + self._typedef_ctx(tp, name) + if getattr(tp, "origin", None) == "unknown_type": + self._struct_ctx(tp, tp.name, approxname=None) + elif isinstance(tp, model.NamedPointerType): + self._struct_ctx(tp.totype, tp.totype.name, approxname=tp.name, + named_ptr=tp) + + # ---------- + # function declarations + + def _generate_cpy_function_collecttype(self, tp, name): + self._do_collect_type(tp.as_raw_function()) + if tp.ellipsis and not self.target_is_python: + self._do_collect_type(tp) + + def _generate_cpy_function_decl(self, tp, name): + assert not self.target_is_python + assert isinstance(tp, model.FunctionPtrType) + if tp.ellipsis: + # cannot support vararg functions better than this: check for its + # exact type (including the fixed arguments), and build it as a + # constant function pointer (no CPython wrapper) + self._generate_cpy_constant_decl(tp, name) + return + prnt = self._prnt + numargs = len(tp.args) + if numargs == 0: + argname = 'noarg' + elif numargs == 1: + argname = 'arg0' + else: + argname = 'args' + # + # ------------------------------ + # the 'd' version of the function, only for addressof(lib, 'func') + arguments = [] + call_arguments = [] + context = 'argument of %s' % name + for i, type in enumerate(tp.args): + arguments.append(type.get_c_name(' x%d' % i, context)) + call_arguments.append('x%d' % i) + repr_arguments = ', '.join(arguments) + repr_arguments = repr_arguments or 'void' + if tp.abi: + abi = tp.abi + ' ' + else: + abi = '' + name_and_arguments = '%s_cffi_d_%s(%s)' % (abi, name, repr_arguments) + prnt('static %s' % (tp.result.get_c_name(name_and_arguments),)) + prnt('{') + call_arguments = ', '.join(call_arguments) + result_code = 'return ' + if isinstance(tp.result, model.VoidType): + result_code = '' + prnt(' %s%s(%s);' % (result_code, name, call_arguments)) + prnt('}') + # + prnt('#ifndef PYPY_VERSION') # ------------------------------ + # + prnt('static PyObject *') + prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname)) + prnt('{') + # + context = 'argument of %s' % name + for i, type in enumerate(tp.args): + arg = type.get_c_name(' x%d' % i, context) + prnt(' %s;' % arg) + # + localvars = set() + freelines = set() + for type in tp.args: + self._extra_local_variables(type, localvars, freelines) + for decl in sorted(localvars): + prnt(' %s;' % (decl,)) + # + if not isinstance(tp.result, model.VoidType): + result_code = 'result = ' + context = 'result of %s' % name + result_decl = ' %s;' % tp.result.get_c_name(' result', context) + prnt(result_decl) + prnt(' PyObject *pyresult;') + else: + result_decl = None + result_code = '' + # + if len(tp.args) > 1: + rng = range(len(tp.args)) + for i in rng: + prnt(' PyObject *arg%d;' % i) + prnt() + prnt(' if (!PyArg_UnpackTuple(args, "%s", %d, %d, %s))' % ( + name, len(rng), len(rng), + ', '.join(['&arg%d' % i for i in rng]))) + prnt(' return NULL;') + prnt() + # + for i, type in enumerate(tp.args): + self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i, + 'return NULL') + prnt() + # + prnt(' Py_BEGIN_ALLOW_THREADS') + prnt(' _cffi_restore_errno();') + call_arguments = ['x%d' % i for i in range(len(tp.args))] + call_arguments = ', '.join(call_arguments) + prnt(' { %s%s(%s); }' % (result_code, name, call_arguments)) + prnt(' _cffi_save_errno();') + prnt(' Py_END_ALLOW_THREADS') + prnt() + # + prnt(' (void)self; /* unused */') + if numargs == 0: + prnt(' (void)noarg; /* unused */') + if result_code: + prnt(' pyresult = %s;' % + self._convert_expr_from_c(tp.result, 'result', 'result type')) + for freeline in freelines: + prnt(' ' + freeline) + prnt(' return pyresult;') + else: + for freeline in freelines: + prnt(' ' + freeline) + prnt(' Py_INCREF(Py_None);') + prnt(' return Py_None;') + prnt('}') + # + prnt('#else') # ------------------------------ + # + # the PyPy version: need to replace struct/union arguments with + # pointers, and if the result is a struct/union, insert a first + # arg that is a pointer to the result. We also do that for + # complex args and return type. + def need_indirection(type): + return (isinstance(type, model.StructOrUnion) or + (isinstance(type, model.PrimitiveType) and + type.is_complex_type())) + difference = False + arguments = [] + call_arguments = [] + context = 'argument of %s' % name + for i, type in enumerate(tp.args): + indirection = '' + if need_indirection(type): + indirection = '*' + difference = True + arg = type.get_c_name(' %sx%d' % (indirection, i), context) + arguments.append(arg) + call_arguments.append('%sx%d' % (indirection, i)) + tp_result = tp.result + if need_indirection(tp_result): + context = 'result of %s' % name + arg = tp_result.get_c_name(' *result', context) + arguments.insert(0, arg) + tp_result = model.void_type + result_decl = None + result_code = '*result = ' + difference = True + if difference: + repr_arguments = ', '.join(arguments) + repr_arguments = repr_arguments or 'void' + name_and_arguments = '%s_cffi_f_%s(%s)' % (abi, name, + repr_arguments) + prnt('static %s' % (tp_result.get_c_name(name_and_arguments),)) + prnt('{') + if result_decl: + prnt(result_decl) + call_arguments = ', '.join(call_arguments) + prnt(' { %s%s(%s); }' % (result_code, name, call_arguments)) + if result_decl: + prnt(' return result;') + prnt('}') + else: + prnt('# define _cffi_f_%s _cffi_d_%s' % (name, name)) + # + prnt('#endif') # ------------------------------ + prnt() + + def _generate_cpy_function_ctx(self, tp, name): + if tp.ellipsis and not self.target_is_python: + self._generate_cpy_constant_ctx(tp, name) + return + type_index = self._typesdict[tp.as_raw_function()] + numargs = len(tp.args) + if self.target_is_python: + meth_kind = OP_DLOPEN_FUNC + elif numargs == 0: + meth_kind = OP_CPYTHON_BLTN_N # 'METH_NOARGS' + elif numargs == 1: + meth_kind = OP_CPYTHON_BLTN_O # 'METH_O' + else: + meth_kind = OP_CPYTHON_BLTN_V # 'METH_VARARGS' + self._lsts["global"].append( + GlobalExpr(name, '_cffi_f_%s' % name, + CffiOp(meth_kind, type_index), + size='_cffi_d_%s' % name)) + + # ---------- + # named structs or unions + + def _field_type(self, tp_struct, field_name, tp_field): + if isinstance(tp_field, model.ArrayType): + actual_length = tp_field.length + if actual_length == '...': + ptr_struct_name = tp_struct.get_c_name('*') + actual_length = '_cffi_array_len(((%s)0)->%s)' % ( + ptr_struct_name, field_name) + tp_item = self._field_type(tp_struct, '%s[0]' % field_name, + tp_field.item) + tp_field = model.ArrayType(tp_item, actual_length) + return tp_field + + def _struct_collecttype(self, tp): + self._do_collect_type(tp) + if self.target_is_python: + # also requires nested anon struct/unions in ABI mode, recursively + for fldtype in tp.anonymous_struct_fields(): + self._struct_collecttype(fldtype) + + def _struct_decl(self, tp, cname, approxname): + if tp.fldtypes is None: + return + prnt = self._prnt + checkfuncname = '_cffi_checkfld_%s' % (approxname,) + prnt('_CFFI_UNUSED_FN') + prnt('static void %s(%s *p)' % (checkfuncname, cname)) + prnt('{') + prnt(' /* only to generate compile-time warnings or errors */') + prnt(' (void)p;') + for fname, ftype, fbitsize, fqual in tp.enumfields(): + try: + if ftype.is_integer_type() or fbitsize >= 0: + # accept all integers, but complain on float or double + if fname != '': + prnt(" (void)((p->%s) | 0); /* check that '%s.%s' is " + "an integer */" % (fname, cname, fname)) + continue + # only accept exactly the type declared, except that '[]' + # is interpreted as a '*' and so will match any array length. + # (It would also match '*', but that's harder to detect...) + while (isinstance(ftype, model.ArrayType) + and (ftype.length is None or ftype.length == '...')): + ftype = ftype.item + fname = fname + '[0]' + prnt(' { %s = &p->%s; (void)tmp; }' % ( + ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), + fname)) + except VerificationError as e: + prnt(' /* %s */' % str(e)) # cannot verify it, ignore + prnt('}') + prnt('struct _cffi_align_%s { char x; %s y; };' % (approxname, cname)) + prnt() + + def _struct_ctx(self, tp, cname, approxname, named_ptr=None): + type_index = self._typesdict[tp] + reason_for_not_expanding = None + flags = [] + if isinstance(tp, model.UnionType): + flags.append("_CFFI_F_UNION") + if tp.fldtypes is None: + flags.append("_CFFI_F_OPAQUE") + reason_for_not_expanding = "opaque" + if (tp not in self.ffi._parser._included_declarations and + (named_ptr is None or + named_ptr not in self.ffi._parser._included_declarations)): + if tp.fldtypes is None: + pass # opaque + elif tp.partial or any(tp.anonymous_struct_fields()): + pass # field layout obtained silently from the C compiler + else: + flags.append("_CFFI_F_CHECK_FIELDS") + if tp.packed: + if tp.packed > 1: + raise NotImplementedError( + "%r is declared with 'pack=%r'; only 0 or 1 are " + "supported in API mode (try to use \"...;\", which " + "does not require a 'pack' declaration)" % + (tp, tp.packed)) + flags.append("_CFFI_F_PACKED") + else: + flags.append("_CFFI_F_EXTERNAL") + reason_for_not_expanding = "external" + flags = '|'.join(flags) or '0' + c_fields = [] + if reason_for_not_expanding is None: + expand_anonymous_struct_union = not self.target_is_python + enumfields = list(tp.enumfields(expand_anonymous_struct_union)) + for fldname, fldtype, fbitsize, fqual in enumfields: + fldtype = self._field_type(tp, fldname, fldtype) + self._check_not_opaque(fldtype, + "field '%s.%s'" % (tp.name, fldname)) + # cname is None for _add_missing_struct_unions() only + op = OP_NOOP + if fbitsize >= 0: + op = OP_BITFIELD + size = '%d /* bits */' % fbitsize + elif cname is None or ( + isinstance(fldtype, model.ArrayType) and + fldtype.length is None): + size = '(size_t)-1' + else: + size = 'sizeof(((%s)0)->%s)' % ( + tp.get_c_name('*') if named_ptr is None + else named_ptr.name, + fldname) + if cname is None or fbitsize >= 0: + offset = '(size_t)-1' + elif named_ptr is not None: + offset = '((char *)&((%s)0)->%s) - (char *)0' % ( + named_ptr.name, fldname) + else: + offset = 'offsetof(%s, %s)' % (tp.get_c_name(''), fldname) + c_fields.append( + FieldExpr(fldname, offset, size, fbitsize, + CffiOp(op, self._typesdict[fldtype]))) + first_field_index = len(self._lsts["field"]) + self._lsts["field"].extend(c_fields) + # + if cname is None: # unknown name, for _add_missing_struct_unions + size = '(size_t)-2' + align = -2 + comment = "unnamed" + else: + if named_ptr is not None: + size = 'sizeof(*(%s)0)' % (named_ptr.name,) + align = '-1 /* unknown alignment */' + else: + size = 'sizeof(%s)' % (cname,) + align = 'offsetof(struct _cffi_align_%s, y)' % (approxname,) + comment = None + else: + size = '(size_t)-1' + align = -1 + first_field_index = -1 + comment = reason_for_not_expanding + self._lsts["struct_union"].append( + StructUnionExpr(tp.name, type_index, flags, size, align, comment, + first_field_index, c_fields)) + self._seen_struct_unions.add(tp) + + def _check_not_opaque(self, tp, location): + while isinstance(tp, model.ArrayType): + tp = tp.item + if isinstance(tp, model.StructOrUnion) and tp.fldtypes is None: + raise TypeError( + "%s is of an opaque type (not declared in cdef())" % location) + + def _add_missing_struct_unions(self): + # not very nice, but some struct declarations might be missing + # because they don't have any known C name. Check that they are + # not partial (we can't complete or verify them!) and emit them + # anonymously. + lst = list(self._struct_unions.items()) + lst.sort(key=lambda tp_order: tp_order[1]) + for tp, order in lst: + if tp not in self._seen_struct_unions: + if tp.partial: + raise NotImplementedError("internal inconsistency: %r is " + "partial but was not seen at " + "this point" % (tp,)) + if tp.name.startswith('$') and tp.name[1:].isdigit(): + approxname = tp.name[1:] + elif tp.name == '_IO_FILE' and tp.forcename == 'FILE': + approxname = 'FILE' + self._typedef_ctx(tp, 'FILE') + else: + raise NotImplementedError("internal inconsistency: %r" % + (tp,)) + self._struct_ctx(tp, None, approxname) + + def _generate_cpy_struct_collecttype(self, tp, name): + self._struct_collecttype(tp) + _generate_cpy_union_collecttype = _generate_cpy_struct_collecttype + + def _struct_names(self, tp): + cname = tp.get_c_name('') + if ' ' in cname: + return cname, cname.replace(' ', '_') + else: + return cname, '_' + cname + + def _generate_cpy_struct_decl(self, tp, name): + self._struct_decl(tp, *self._struct_names(tp)) + _generate_cpy_union_decl = _generate_cpy_struct_decl + + def _generate_cpy_struct_ctx(self, tp, name): + self._struct_ctx(tp, *self._struct_names(tp)) + _generate_cpy_union_ctx = _generate_cpy_struct_ctx + + # ---------- + # 'anonymous' declarations. These are produced for anonymous structs + # or unions; the 'name' is obtained by a typedef. + + def _generate_cpy_anonymous_collecttype(self, tp, name): + if isinstance(tp, model.EnumType): + self._generate_cpy_enum_collecttype(tp, name) + else: + self._struct_collecttype(tp) + + def _generate_cpy_anonymous_decl(self, tp, name): + if isinstance(tp, model.EnumType): + self._generate_cpy_enum_decl(tp) + else: + self._struct_decl(tp, name, 'typedef_' + name) + + def _generate_cpy_anonymous_ctx(self, tp, name): + if isinstance(tp, model.EnumType): + self._enum_ctx(tp, name) + else: + self._struct_ctx(tp, name, 'typedef_' + name) + + # ---------- + # constants, declared with "static const ..." + + def _generate_cpy_const(self, is_int, name, tp=None, category='const', + check_value=None): + if (category, name) in self._seen_constants: + raise VerificationError( + "duplicate declaration of %s '%s'" % (category, name)) + self._seen_constants.add((category, name)) + # + prnt = self._prnt + funcname = '_cffi_%s_%s' % (category, name) + if is_int: + prnt('static int %s(unsigned long long *o)' % funcname) + prnt('{') + prnt(' int n = (%s) <= 0;' % (name,)) + prnt(' *o = (unsigned long long)((%s) | 0);' + ' /* check that %s is an integer */' % (name, name)) + if check_value is not None: + if check_value > 0: + check_value = '%dU' % (check_value,) + prnt(' if (!_cffi_check_int(*o, n, %s))' % (check_value,)) + prnt(' n |= 2;') + prnt(' return n;') + prnt('}') + else: + assert check_value is None + prnt('static void %s(char *o)' % funcname) + prnt('{') + prnt(' *(%s)o = %s;' % (tp.get_c_name('*'), name)) + prnt('}') + prnt() + + def _generate_cpy_constant_collecttype(self, tp, name): + is_int = tp.is_integer_type() + if not is_int or self.target_is_python: + self._do_collect_type(tp) + + def _generate_cpy_constant_decl(self, tp, name): + is_int = tp.is_integer_type() + self._generate_cpy_const(is_int, name, tp) + + def _generate_cpy_constant_ctx(self, tp, name): + if not self.target_is_python and tp.is_integer_type(): + type_op = CffiOp(OP_CONSTANT_INT, -1) + else: + if self.target_is_python: + const_kind = OP_DLOPEN_CONST + else: + const_kind = OP_CONSTANT + type_index = self._typesdict[tp] + type_op = CffiOp(const_kind, type_index) + self._lsts["global"].append( + GlobalExpr(name, '_cffi_const_%s' % name, type_op)) + + # ---------- + # enums + + def _generate_cpy_enum_collecttype(self, tp, name): + self._do_collect_type(tp) + + def _generate_cpy_enum_decl(self, tp, name=None): + for enumerator in tp.enumerators: + self._generate_cpy_const(True, enumerator) + + def _enum_ctx(self, tp, cname): + type_index = self._typesdict[tp] + type_op = CffiOp(OP_ENUM, -1) + if self.target_is_python: + tp.check_not_partial() + for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): + self._lsts["global"].append( + GlobalExpr(enumerator, '_cffi_const_%s' % enumerator, type_op, + check_value=enumvalue)) + # + if cname is not None and '$' not in cname and not self.target_is_python: + size = "sizeof(%s)" % cname + signed = "((%s)-1) <= 0" % cname + else: + basetp = tp.build_baseinttype(self.ffi, []) + size = self.ffi.sizeof(basetp) + signed = int(int(self.ffi.cast(basetp, -1)) < 0) + allenums = ",".join(tp.enumerators) + self._lsts["enum"].append( + EnumExpr(tp.name, type_index, size, signed, allenums)) + + def _generate_cpy_enum_ctx(self, tp, name): + self._enum_ctx(tp, tp._get_c_name()) + + # ---------- + # macros: for now only for integers + + def _generate_cpy_macro_collecttype(self, tp, name): + pass + + def _generate_cpy_macro_decl(self, tp, name): + if tp == '...': + check_value = None + else: + check_value = tp # an integer + self._generate_cpy_const(True, name, check_value=check_value) + + def _generate_cpy_macro_ctx(self, tp, name): + if tp == '...': + if self.target_is_python: + raise VerificationError( + "cannot use the syntax '...' in '#define %s ...' when " + "using the ABI mode" % (name,)) + check_value = None + else: + check_value = tp # an integer + type_op = CffiOp(OP_CONSTANT_INT, -1) + self._lsts["global"].append( + GlobalExpr(name, '_cffi_const_%s' % name, type_op, + check_value=check_value)) + + # ---------- + # global variables + + def _global_type(self, tp, global_name): + if isinstance(tp, model.ArrayType): + actual_length = tp.length + if actual_length == '...': + actual_length = '_cffi_array_len(%s)' % (global_name,) + tp_item = self._global_type(tp.item, '%s[0]' % global_name) + tp = model.ArrayType(tp_item, actual_length) + return tp + + def _generate_cpy_variable_collecttype(self, tp, name): + self._do_collect_type(self._global_type(tp, name)) + + def _generate_cpy_variable_decl(self, tp, name): + prnt = self._prnt + tp = self._global_type(tp, name) + if isinstance(tp, model.ArrayType) and tp.length is None: + tp = tp.item + ampersand = '' + else: + ampersand = '&' + # This code assumes that casts from "tp *" to "void *" is a + # no-op, i.e. a function that returns a "tp *" can be called + # as if it returned a "void *". This should be generally true + # on any modern machine. The only exception to that rule (on + # uncommon architectures, and as far as I can tell) might be + # if 'tp' were a function type, but that is not possible here. + # (If 'tp' is a function _pointer_ type, then casts from "fn_t + # **" to "void *" are again no-ops, as far as I can tell.) + decl = '*_cffi_var_%s(void)' % (name,) + prnt('static ' + tp.get_c_name(decl, quals=self._current_quals)) + prnt('{') + prnt(' return %s(%s);' % (ampersand, name)) + prnt('}') + prnt() + + def _generate_cpy_variable_ctx(self, tp, name): + tp = self._global_type(tp, name) + type_index = self._typesdict[tp] + if self.target_is_python: + op = OP_GLOBAL_VAR + else: + op = OP_GLOBAL_VAR_F + self._lsts["global"].append( + GlobalExpr(name, '_cffi_var_%s' % name, CffiOp(op, type_index))) + + # ---------- + # extern "Python" + + def _generate_cpy_extern_python_collecttype(self, tp, name): + assert isinstance(tp, model.FunctionPtrType) + self._do_collect_type(tp) + _generate_cpy_dllexport_python_collecttype = \ + _generate_cpy_extern_python_plus_c_collecttype = \ + _generate_cpy_extern_python_collecttype + + def _extern_python_decl(self, tp, name, tag_and_space): + prnt = self._prnt + if isinstance(tp.result, model.VoidType): + size_of_result = '0' + else: + context = 'result of %s' % name + size_of_result = '(int)sizeof(%s)' % ( + tp.result.get_c_name('', context),) + prnt('static struct _cffi_externpy_s _cffi_externpy__%s =' % name) + prnt(' { "%s.%s", %s, 0, 0 };' % ( + self.module_name, name, size_of_result)) + prnt() + # + arguments = [] + context = 'argument of %s' % name + for i, type in enumerate(tp.args): + arg = type.get_c_name(' a%d' % i, context) + arguments.append(arg) + # + repr_arguments = ', '.join(arguments) + repr_arguments = repr_arguments or 'void' + name_and_arguments = '%s(%s)' % (name, repr_arguments) + if tp.abi == "__stdcall": + name_and_arguments = '_cffi_stdcall ' + name_and_arguments + # + def may_need_128_bits(tp): + return (isinstance(tp, model.PrimitiveType) and + tp.name == 'long double') + # + size_of_a = max(len(tp.args)*8, 8) + if may_need_128_bits(tp.result): + size_of_a = max(size_of_a, 16) + if isinstance(tp.result, model.StructOrUnion): + size_of_a = 'sizeof(%s) > %d ? sizeof(%s) : %d' % ( + tp.result.get_c_name(''), size_of_a, + tp.result.get_c_name(''), size_of_a) + prnt('%s%s' % (tag_and_space, tp.result.get_c_name(name_and_arguments))) + prnt('{') + prnt(' char a[%s];' % size_of_a) + prnt(' char *p = a;') + for i, type in enumerate(tp.args): + arg = 'a%d' % i + if (isinstance(type, model.StructOrUnion) or + may_need_128_bits(type)): + arg = '&' + arg + type = model.PointerType(type) + prnt(' *(%s)(p + %d) = %s;' % (type.get_c_name('*'), i*8, arg)) + prnt(' _cffi_call_python(&_cffi_externpy__%s, p);' % name) + if not isinstance(tp.result, model.VoidType): + prnt(' return *(%s)p;' % (tp.result.get_c_name('*'),)) + prnt('}') + prnt() + self._num_externpy += 1 + + def _generate_cpy_extern_python_decl(self, tp, name): + self._extern_python_decl(tp, name, 'static ') + + def _generate_cpy_dllexport_python_decl(self, tp, name): + self._extern_python_decl(tp, name, 'CFFI_DLLEXPORT ') + + def _generate_cpy_extern_python_plus_c_decl(self, tp, name): + self._extern_python_decl(tp, name, '') + + def _generate_cpy_extern_python_ctx(self, tp, name): + if self.target_is_python: + raise VerificationError( + "cannot use 'extern \"Python\"' in the ABI mode") + if tp.ellipsis: + raise NotImplementedError("a vararg function is extern \"Python\"") + type_index = self._typesdict[tp] + type_op = CffiOp(OP_EXTERN_PYTHON, type_index) + self._lsts["global"].append( + GlobalExpr(name, '&_cffi_externpy__%s' % name, type_op, name)) + + _generate_cpy_dllexport_python_ctx = \ + _generate_cpy_extern_python_plus_c_ctx = \ + _generate_cpy_extern_python_ctx + + def _print_string_literal_in_array(self, s): + prnt = self._prnt + prnt('// # NB. this is not a string because of a size limit in MSVC') + if not isinstance(s, bytes): # unicode + s = s.encode('utf-8') # -> bytes + else: + s.decode('utf-8') # got bytes, check for valid utf-8 + try: + s.decode('ascii') + except UnicodeDecodeError: + s = b'# -*- encoding: utf8 -*-\n' + s + for line in s.splitlines(True): + comment = line + if type('//') is bytes: # python2 + line = map(ord, line) # make a list of integers + else: # python3 + # type(line) is bytes, which enumerates like a list of integers + comment = ascii(comment)[1:-1] + prnt(('// ' + comment).rstrip()) + printed_line = '' + for c in line: + if len(printed_line) >= 76: + prnt(printed_line) + printed_line = '' + printed_line += '%d,' % (c,) + prnt(printed_line) + + # ---------- + # emitting the opcodes for individual types + + def _emit_bytecode_VoidType(self, tp, index): + self.cffi_types[index] = CffiOp(OP_PRIMITIVE, PRIM_VOID) + + def _emit_bytecode_PrimitiveType(self, tp, index): + prim_index = PRIMITIVE_TO_INDEX[tp.name] + self.cffi_types[index] = CffiOp(OP_PRIMITIVE, prim_index) + + def _emit_bytecode_UnknownIntegerType(self, tp, index): + s = ('_cffi_prim_int(sizeof(%s), (\n' + ' ((%s)-1) | 0 /* check that %s is an integer type */\n' + ' ) <= 0)' % (tp.name, tp.name, tp.name)) + self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) + + def _emit_bytecode_UnknownFloatType(self, tp, index): + s = ('_cffi_prim_float(sizeof(%s) *\n' + ' (((%s)1) / 2) * 2 /* integer => 0, float => 1 */\n' + ' )' % (tp.name, tp.name)) + self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) + + def _emit_bytecode_RawFunctionType(self, tp, index): + self.cffi_types[index] = CffiOp(OP_FUNCTION, self._typesdict[tp.result]) + index += 1 + for tp1 in tp.args: + realindex = self._typesdict[tp1] + if index != realindex: + if isinstance(tp1, model.PrimitiveType): + self._emit_bytecode_PrimitiveType(tp1, index) + else: + self.cffi_types[index] = CffiOp(OP_NOOP, realindex) + index += 1 + flags = int(tp.ellipsis) + if tp.abi is not None: + if tp.abi == '__stdcall': + flags |= 2 + else: + raise NotImplementedError("abi=%r" % (tp.abi,)) + self.cffi_types[index] = CffiOp(OP_FUNCTION_END, flags) + + def _emit_bytecode_PointerType(self, tp, index): + self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[tp.totype]) + + _emit_bytecode_ConstPointerType = _emit_bytecode_PointerType + _emit_bytecode_NamedPointerType = _emit_bytecode_PointerType + + def _emit_bytecode_FunctionPtrType(self, tp, index): + raw = tp.as_raw_function() + self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[raw]) + + def _emit_bytecode_ArrayType(self, tp, index): + item_index = self._typesdict[tp.item] + if tp.length is None: + self.cffi_types[index] = CffiOp(OP_OPEN_ARRAY, item_index) + elif tp.length == '...': + raise VerificationError( + "type %s badly placed: the '...' array length can only be " + "used on global arrays or on fields of structures" % ( + str(tp).replace('/*...*/', '...'),)) + else: + assert self.cffi_types[index + 1] == 'LEN' + self.cffi_types[index] = CffiOp(OP_ARRAY, item_index) + self.cffi_types[index + 1] = CffiOp(None, str(tp.length)) + + def _emit_bytecode_StructType(self, tp, index): + struct_index = self._struct_unions[tp] + self.cffi_types[index] = CffiOp(OP_STRUCT_UNION, struct_index) + _emit_bytecode_UnionType = _emit_bytecode_StructType + + def _emit_bytecode_EnumType(self, tp, index): + enum_index = self._enums[tp] + self.cffi_types[index] = CffiOp(OP_ENUM, enum_index) + + +if sys.version_info >= (3,): + NativeIO = io.StringIO +else: + class NativeIO(io.BytesIO): + def write(self, s): + if isinstance(s, unicode): + s = s.encode('ascii') + super(NativeIO, self).write(s) + +def _make_c_or_py_source(ffi, module_name, preamble, target_file, verbose): + if verbose: + print("generating %s" % (target_file,)) + recompiler = Recompiler(ffi, module_name, + target_is_python=(preamble is None)) + recompiler.collect_type_table() + recompiler.collect_step_tables() + f = NativeIO() + recompiler.write_source_to_f(f, preamble) + output = f.getvalue() + try: + with open(target_file, 'r') as f1: + if f1.read(len(output) + 1) != output: + raise IOError + if verbose: + print("(already up-to-date)") + return False # already up-to-date + except IOError: + tmp_file = '%s.~%d' % (target_file, os.getpid()) + with open(tmp_file, 'w') as f1: + f1.write(output) + try: + os.rename(tmp_file, target_file) + except OSError: + os.unlink(target_file) + os.rename(tmp_file, target_file) + return True + +def make_c_source(ffi, module_name, preamble, target_c_file, verbose=False): + assert preamble is not None + return _make_c_or_py_source(ffi, module_name, preamble, target_c_file, + verbose) + +def make_py_source(ffi, module_name, target_py_file, verbose=False): + return _make_c_or_py_source(ffi, module_name, None, target_py_file, + verbose) + +def _modname_to_file(outputdir, modname, extension): + parts = modname.split('.') + try: + os.makedirs(os.path.join(outputdir, *parts[:-1])) + except OSError: + pass + parts[-1] += extension + return os.path.join(outputdir, *parts), parts + + +# Aaargh. Distutils is not tested at all for the purpose of compiling +# DLLs that are not extension modules. Here are some hacks to work +# around that, in the _patch_for_*() functions... + +def _patch_meth(patchlist, cls, name, new_meth): + old = getattr(cls, name) + patchlist.append((cls, name, old)) + setattr(cls, name, new_meth) + return old + +def _unpatch_meths(patchlist): + for cls, name, old_meth in reversed(patchlist): + setattr(cls, name, old_meth) + +def _patch_for_embedding(patchlist): + if sys.platform == 'win32': + # we must not remove the manifest when building for embedding! + from distutils.msvc9compiler import MSVCCompiler + _patch_meth(patchlist, MSVCCompiler, '_remove_visual_c_ref', + lambda self, manifest_file: manifest_file) + + if sys.platform == 'darwin': + # we must not make a '-bundle', but a '-dynamiclib' instead + from distutils.ccompiler import CCompiler + def my_link_shared_object(self, *args, **kwds): + if '-bundle' in self.linker_so: + self.linker_so = list(self.linker_so) + i = self.linker_so.index('-bundle') + self.linker_so[i] = '-dynamiclib' + return old_link_shared_object(self, *args, **kwds) + old_link_shared_object = _patch_meth(patchlist, CCompiler, + 'link_shared_object', + my_link_shared_object) + +def _patch_for_target(patchlist, target): + from distutils.command.build_ext import build_ext + # if 'target' is different from '*', we need to patch some internal + # method to just return this 'target' value, instead of having it + # built from module_name + if target.endswith('.*'): + target = target[:-2] + if sys.platform == 'win32': + target += '.dll' + elif sys.platform == 'darwin': + target += '.dylib' + else: + target += '.so' + _patch_meth(patchlist, build_ext, 'get_ext_filename', + lambda self, ext_name: target) + + +def recompile(ffi, module_name, preamble, tmpdir='.', call_c_compiler=True, + c_file=None, source_extension='.c', extradir=None, + compiler_verbose=1, target=None, debug=None, **kwds): + if not isinstance(module_name, str): + module_name = module_name.encode('ascii') + if ffi._windows_unicode: + ffi._apply_windows_unicode(kwds) + if preamble is not None: + embedding = (ffi._embedding is not None) + if embedding: + ffi._apply_embedding_fix(kwds) + if c_file is None: + c_file, parts = _modname_to_file(tmpdir, module_name, + source_extension) + if extradir: + parts = [extradir] + parts + ext_c_file = os.path.join(*parts) + else: + ext_c_file = c_file + # + if target is None: + if embedding: + target = '%s.*' % module_name + else: + target = '*' + # + ext = ffiplatform.get_extension(ext_c_file, module_name, **kwds) + updated = make_c_source(ffi, module_name, preamble, c_file, + verbose=compiler_verbose) + if call_c_compiler: + patchlist = [] + cwd = os.getcwd() + try: + if embedding: + _patch_for_embedding(patchlist) + if target != '*': + _patch_for_target(patchlist, target) + if compiler_verbose: + if tmpdir == '.': + msg = 'the current directory is' + else: + msg = 'setting the current directory to' + print('%s %r' % (msg, os.path.abspath(tmpdir))) + os.chdir(tmpdir) + outputfilename = ffiplatform.compile('.', ext, + compiler_verbose, debug) + finally: + os.chdir(cwd) + _unpatch_meths(patchlist) + return outputfilename + else: + return ext, updated + else: + if c_file is None: + c_file, _ = _modname_to_file(tmpdir, module_name, '.py') + updated = make_py_source(ffi, module_name, c_file, + verbose=compiler_verbose) + if call_c_compiler: + return c_file + else: + return None, updated + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/setuptools_ext.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/setuptools_ext.py new file mode 100644 index 0000000..8fe3614 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/setuptools_ext.py @@ -0,0 +1,219 @@ +import os +import sys + +try: + basestring +except NameError: + # Python 3.x + basestring = str + +def error(msg): + from distutils.errors import DistutilsSetupError + raise DistutilsSetupError(msg) + + +def execfile(filename, glob): + # We use execfile() (here rewritten for Python 3) instead of + # __import__() to load the build script. The problem with + # a normal import is that in some packages, the intermediate + # __init__.py files may already try to import the file that + # we are generating. + with open(filename) as f: + src = f.read() + src += '\n' # Python 2.6 compatibility + code = compile(src, filename, 'exec') + exec(code, glob, glob) + + +def add_cffi_module(dist, mod_spec): + from cffi.api import FFI + + if not isinstance(mod_spec, basestring): + error("argument to 'cffi_modules=...' must be a str or a list of str," + " not %r" % (type(mod_spec).__name__,)) + mod_spec = str(mod_spec) + try: + build_file_name, ffi_var_name = mod_spec.split(':') + except ValueError: + error("%r must be of the form 'path/build.py:ffi_variable'" % + (mod_spec,)) + if not os.path.exists(build_file_name): + ext = '' + rewritten = build_file_name.replace('.', '/') + '.py' + if os.path.exists(rewritten): + ext = ' (rewrite cffi_modules to [%r])' % ( + rewritten + ':' + ffi_var_name,) + error("%r does not name an existing file%s" % (build_file_name, ext)) + + mod_vars = {'__name__': '__cffi__', '__file__': build_file_name} + execfile(build_file_name, mod_vars) + + try: + ffi = mod_vars[ffi_var_name] + except KeyError: + error("%r: object %r not found in module" % (mod_spec, + ffi_var_name)) + if not isinstance(ffi, FFI): + ffi = ffi() # maybe it's a function instead of directly an ffi + if not isinstance(ffi, FFI): + error("%r is not an FFI instance (got %r)" % (mod_spec, + type(ffi).__name__)) + if not hasattr(ffi, '_assigned_source'): + error("%r: the set_source() method was not called" % (mod_spec,)) + module_name, source, source_extension, kwds = ffi._assigned_source + if ffi._windows_unicode: + kwds = kwds.copy() + ffi._apply_windows_unicode(kwds) + + if source is None: + _add_py_module(dist, ffi, module_name) + else: + _add_c_module(dist, ffi, module_name, source, source_extension, kwds) + +def _set_py_limited_api(Extension, kwds): + """ + Add py_limited_api to kwds if setuptools >= 26 is in use. + Do not alter the setting if it already exists. + Setuptools takes care of ignoring the flag on Python 2 and PyPy. + + CPython itself should ignore the flag in a debugging version + (by not listing .abi3.so in the extensions it supports), but + it doesn't so far, creating troubles. That's why we check + for "not hasattr(sys, 'gettotalrefcount')" (the 2.7 compatible equivalent + of 'd' not in sys.abiflags). (http://bugs.python.org/issue28401) + + On Windows, with CPython <= 3.4, it's better not to use py_limited_api + because virtualenv *still* doesn't copy PYTHON3.DLL on these versions. + Recently (2020) we started shipping only >= 3.5 wheels, though. So + we'll give it another try and set py_limited_api on Windows >= 3.5. + """ + from cffi import recompiler + + if ('py_limited_api' not in kwds and not hasattr(sys, 'gettotalrefcount') + and recompiler.USE_LIMITED_API): + import setuptools + try: + setuptools_major_version = int(setuptools.__version__.partition('.')[0]) + if setuptools_major_version >= 26: + kwds['py_limited_api'] = True + except ValueError: # certain development versions of setuptools + # If we don't know the version number of setuptools, we + # try to set 'py_limited_api' anyway. At worst, we get a + # warning. + kwds['py_limited_api'] = True + return kwds + +def _add_c_module(dist, ffi, module_name, source, source_extension, kwds): + from distutils.core import Extension + # We are a setuptools extension. Need this build_ext for py_limited_api. + from setuptools.command.build_ext import build_ext + from distutils.dir_util import mkpath + from distutils import log + from cffi import recompiler + + allsources = ['$PLACEHOLDER'] + allsources.extend(kwds.pop('sources', [])) + kwds = _set_py_limited_api(Extension, kwds) + ext = Extension(name=module_name, sources=allsources, **kwds) + + def make_mod(tmpdir, pre_run=None): + c_file = os.path.join(tmpdir, module_name + source_extension) + log.info("generating cffi module %r" % c_file) + mkpath(tmpdir) + # a setuptools-only, API-only hook: called with the "ext" and "ffi" + # arguments just before we turn the ffi into C code. To use it, + # subclass the 'distutils.command.build_ext.build_ext' class and + # add a method 'def pre_run(self, ext, ffi)'. + if pre_run is not None: + pre_run(ext, ffi) + updated = recompiler.make_c_source(ffi, module_name, source, c_file) + if not updated: + log.info("already up-to-date") + return c_file + + if dist.ext_modules is None: + dist.ext_modules = [] + dist.ext_modules.append(ext) + + base_class = dist.cmdclass.get('build_ext', build_ext) + class build_ext_make_mod(base_class): + def run(self): + if ext.sources[0] == '$PLACEHOLDER': + pre_run = getattr(self, 'pre_run', None) + ext.sources[0] = make_mod(self.build_temp, pre_run) + base_class.run(self) + dist.cmdclass['build_ext'] = build_ext_make_mod + # NB. multiple runs here will create multiple 'build_ext_make_mod' + # classes. Even in this case the 'build_ext' command should be + # run once; but just in case, the logic above does nothing if + # called again. + + +def _add_py_module(dist, ffi, module_name): + from distutils.dir_util import mkpath + from setuptools.command.build_py import build_py + from setuptools.command.build_ext import build_ext + from distutils import log + from cffi import recompiler + + def generate_mod(py_file): + log.info("generating cffi module %r" % py_file) + mkpath(os.path.dirname(py_file)) + updated = recompiler.make_py_source(ffi, module_name, py_file) + if not updated: + log.info("already up-to-date") + + base_class = dist.cmdclass.get('build_py', build_py) + class build_py_make_mod(base_class): + def run(self): + base_class.run(self) + module_path = module_name.split('.') + module_path[-1] += '.py' + generate_mod(os.path.join(self.build_lib, *module_path)) + def get_source_files(self): + # This is called from 'setup.py sdist' only. Exclude + # the generate .py module in this case. + saved_py_modules = self.py_modules + try: + if saved_py_modules: + self.py_modules = [m for m in saved_py_modules + if m != module_name] + return base_class.get_source_files(self) + finally: + self.py_modules = saved_py_modules + dist.cmdclass['build_py'] = build_py_make_mod + + # distutils and setuptools have no notion I could find of a + # generated python module. If we don't add module_name to + # dist.py_modules, then things mostly work but there are some + # combination of options (--root and --record) that will miss + # the module. So we add it here, which gives a few apparently + # harmless warnings about not finding the file outside the + # build directory. + # Then we need to hack more in get_source_files(); see above. + if dist.py_modules is None: + dist.py_modules = [] + dist.py_modules.append(module_name) + + # the following is only for "build_ext -i" + base_class_2 = dist.cmdclass.get('build_ext', build_ext) + class build_ext_make_mod(base_class_2): + def run(self): + base_class_2.run(self) + if self.inplace: + # from get_ext_fullpath() in distutils/command/build_ext.py + module_path = module_name.split('.') + package = '.'.join(module_path[:-1]) + build_py = self.get_finalized_command('build_py') + package_dir = build_py.get_package_dir(package) + file_name = module_path[-1] + '.py' + generate_mod(os.path.join(package_dir, file_name)) + dist.cmdclass['build_ext'] = build_ext_make_mod + +def cffi_modules(dist, attr, value): + assert attr == 'cffi_modules' + if isinstance(value, basestring): + value = [value] + + for cffi_module in value: + add_cffi_module(dist, cffi_module) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/vengine_cpy.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/vengine_cpy.py new file mode 100644 index 0000000..6de0df0 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/vengine_cpy.py @@ -0,0 +1,1076 @@ +# +# DEPRECATED: implementation for ffi.verify() +# +import sys, imp +from . import model +from .error import VerificationError + + +class VCPythonEngine(object): + _class_key = 'x' + _gen_python_module = True + + def __init__(self, verifier): + self.verifier = verifier + self.ffi = verifier.ffi + self._struct_pending_verification = {} + self._types_of_builtin_functions = {} + + def patch_extension_kwds(self, kwds): + pass + + def find_module(self, module_name, path, so_suffixes): + try: + f, filename, descr = imp.find_module(module_name, path) + except ImportError: + return None + if f is not None: + f.close() + # Note that after a setuptools installation, there are both .py + # and .so files with the same basename. The code here relies on + # imp.find_module() locating the .so in priority. + if descr[0] not in so_suffixes: + return None + return filename + + def collect_types(self): + self._typesdict = {} + self._generate("collecttype") + + def _prnt(self, what=''): + self._f.write(what + '\n') + + def _gettypenum(self, type): + # a KeyError here is a bug. please report it! :-) + return self._typesdict[type] + + def _do_collect_type(self, tp): + if ((not isinstance(tp, model.PrimitiveType) + or tp.name == 'long double') + and tp not in self._typesdict): + num = len(self._typesdict) + self._typesdict[tp] = num + + def write_source_to_f(self): + self.collect_types() + # + # The new module will have a _cffi_setup() function that receives + # objects from the ffi world, and that calls some setup code in + # the module. This setup code is split in several independent + # functions, e.g. one per constant. The functions are "chained" + # by ending in a tail call to each other. + # + # This is further split in two chained lists, depending on if we + # can do it at import-time or if we must wait for _cffi_setup() to + # provide us with the objects. This is needed because we + # need the values of the enum constants in order to build the + # that we may have to pass to _cffi_setup(). + # + # The following two 'chained_list_constants' items contains + # the head of these two chained lists, as a string that gives the + # call to do, if any. + self._chained_list_constants = ['((void)lib,0)', '((void)lib,0)'] + # + prnt = self._prnt + # first paste some standard set of lines that are mostly '#define' + prnt(cffimod_header) + prnt() + # then paste the C source given by the user, verbatim. + prnt(self.verifier.preamble) + prnt() + # + # call generate_cpy_xxx_decl(), for every xxx found from + # ffi._parser._declarations. This generates all the functions. + self._generate("decl") + # + # implement the function _cffi_setup_custom() as calling the + # head of the chained list. + self._generate_setup_custom() + prnt() + # + # produce the method table, including the entries for the + # generated Python->C function wrappers, which are done + # by generate_cpy_function_method(). + prnt('static PyMethodDef _cffi_methods[] = {') + self._generate("method") + prnt(' {"_cffi_setup", _cffi_setup, METH_VARARGS, NULL},') + prnt(' {NULL, NULL, 0, NULL} /* Sentinel */') + prnt('};') + prnt() + # + # standard init. + modname = self.verifier.get_module_name() + constants = self._chained_list_constants[False] + prnt('#if PY_MAJOR_VERSION >= 3') + prnt() + prnt('static struct PyModuleDef _cffi_module_def = {') + prnt(' PyModuleDef_HEAD_INIT,') + prnt(' "%s",' % modname) + prnt(' NULL,') + prnt(' -1,') + prnt(' _cffi_methods,') + prnt(' NULL, NULL, NULL, NULL') + prnt('};') + prnt() + prnt('PyMODINIT_FUNC') + prnt('PyInit_%s(void)' % modname) + prnt('{') + prnt(' PyObject *lib;') + prnt(' lib = PyModule_Create(&_cffi_module_def);') + prnt(' if (lib == NULL)') + prnt(' return NULL;') + prnt(' if (%s < 0 || _cffi_init() < 0) {' % (constants,)) + prnt(' Py_DECREF(lib);') + prnt(' return NULL;') + prnt(' }') + prnt(' return lib;') + prnt('}') + prnt() + prnt('#else') + prnt() + prnt('PyMODINIT_FUNC') + prnt('init%s(void)' % modname) + prnt('{') + prnt(' PyObject *lib;') + prnt(' lib = Py_InitModule("%s", _cffi_methods);' % modname) + prnt(' if (lib == NULL)') + prnt(' return;') + prnt(' if (%s < 0 || _cffi_init() < 0)' % (constants,)) + prnt(' return;') + prnt(' return;') + prnt('}') + prnt() + prnt('#endif') + + def load_library(self, flags=None): + # XXX review all usages of 'self' here! + # import it as a new extension module + imp.acquire_lock() + try: + if hasattr(sys, "getdlopenflags"): + previous_flags = sys.getdlopenflags() + try: + if hasattr(sys, "setdlopenflags") and flags is not None: + sys.setdlopenflags(flags) + module = imp.load_dynamic(self.verifier.get_module_name(), + self.verifier.modulefilename) + except ImportError as e: + error = "importing %r: %s" % (self.verifier.modulefilename, e) + raise VerificationError(error) + finally: + if hasattr(sys, "setdlopenflags"): + sys.setdlopenflags(previous_flags) + finally: + imp.release_lock() + # + # call loading_cpy_struct() to get the struct layout inferred by + # the C compiler + self._load(module, 'loading') + # + # the C code will need the objects. Collect them in + # order in a list. + revmapping = dict([(value, key) + for (key, value) in self._typesdict.items()]) + lst = [revmapping[i] for i in range(len(revmapping))] + lst = list(map(self.ffi._get_cached_btype, lst)) + # + # build the FFILibrary class and instance and call _cffi_setup(). + # this will set up some fields like '_cffi_types', and only then + # it will invoke the chained list of functions that will really + # build (notably) the constant objects, as if they are + # pointers, and store them as attributes on the 'library' object. + class FFILibrary(object): + _cffi_python_module = module + _cffi_ffi = self.ffi + _cffi_dir = [] + def __dir__(self): + return FFILibrary._cffi_dir + list(self.__dict__) + library = FFILibrary() + if module._cffi_setup(lst, VerificationError, library): + import warnings + warnings.warn("reimporting %r might overwrite older definitions" + % (self.verifier.get_module_name())) + # + # finally, call the loaded_cpy_xxx() functions. This will perform + # the final adjustments, like copying the Python->C wrapper + # functions from the module to the 'library' object, and setting + # up the FFILibrary class with properties for the global C variables. + self._load(module, 'loaded', library=library) + module._cffi_original_ffi = self.ffi + module._cffi_types_of_builtin_funcs = self._types_of_builtin_functions + return library + + def _get_declarations(self): + lst = [(key, tp) for (key, (tp, qual)) in + self.ffi._parser._declarations.items()] + lst.sort() + return lst + + def _generate(self, step_name): + for name, tp in self._get_declarations(): + kind, realname = name.split(' ', 1) + try: + method = getattr(self, '_generate_cpy_%s_%s' % (kind, + step_name)) + except AttributeError: + raise VerificationError( + "not implemented in verify(): %r" % name) + try: + method(tp, realname) + except Exception as e: + model.attach_exception_info(e, name) + raise + + def _load(self, module, step_name, **kwds): + for name, tp in self._get_declarations(): + kind, realname = name.split(' ', 1) + method = getattr(self, '_%s_cpy_%s' % (step_name, kind)) + try: + method(tp, realname, module, **kwds) + except Exception as e: + model.attach_exception_info(e, name) + raise + + def _generate_nothing(self, tp, name): + pass + + def _loaded_noop(self, tp, name, module, **kwds): + pass + + # ---------- + + def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode): + extraarg = '' + if isinstance(tp, model.PrimitiveType): + if tp.is_integer_type() and tp.name != '_Bool': + converter = '_cffi_to_c_int' + extraarg = ', %s' % tp.name + else: + converter = '(%s)_cffi_to_c_%s' % (tp.get_c_name(''), + tp.name.replace(' ', '_')) + errvalue = '-1' + # + elif isinstance(tp, model.PointerType): + self._convert_funcarg_to_c_ptr_or_array(tp, fromvar, + tovar, errcode) + return + # + elif isinstance(tp, (model.StructOrUnion, model.EnumType)): + # a struct (not a struct pointer) as a function argument + self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)' + % (tovar, self._gettypenum(tp), fromvar)) + self._prnt(' %s;' % errcode) + return + # + elif isinstance(tp, model.FunctionPtrType): + converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('') + extraarg = ', _cffi_type(%d)' % self._gettypenum(tp) + errvalue = 'NULL' + # + else: + raise NotImplementedError(tp) + # + self._prnt(' %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg)) + self._prnt(' if (%s == (%s)%s && PyErr_Occurred())' % ( + tovar, tp.get_c_name(''), errvalue)) + self._prnt(' %s;' % errcode) + + def _extra_local_variables(self, tp, localvars, freelines): + if isinstance(tp, model.PointerType): + localvars.add('Py_ssize_t datasize') + localvars.add('struct _cffi_freeme_s *large_args_free = NULL') + freelines.add('if (large_args_free != NULL)' + ' _cffi_free_array_arguments(large_args_free);') + + def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode): + self._prnt(' datasize = _cffi_prepare_pointer_call_argument(') + self._prnt(' _cffi_type(%d), %s, (char **)&%s);' % ( + self._gettypenum(tp), fromvar, tovar)) + self._prnt(' if (datasize != 0) {') + self._prnt(' %s = ((size_t)datasize) <= 640 ? ' + 'alloca((size_t)datasize) : NULL;' % (tovar,)) + self._prnt(' if (_cffi_convert_array_argument(_cffi_type(%d), %s, ' + '(char **)&%s,' % (self._gettypenum(tp), fromvar, tovar)) + self._prnt(' datasize, &large_args_free) < 0)') + self._prnt(' %s;' % errcode) + self._prnt(' }') + + def _convert_expr_from_c(self, tp, var, context): + if isinstance(tp, model.PrimitiveType): + if tp.is_integer_type() and tp.name != '_Bool': + return '_cffi_from_c_int(%s, %s)' % (var, tp.name) + elif tp.name != 'long double': + return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var) + else: + return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, (model.PointerType, model.FunctionPtrType)): + return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, model.ArrayType): + return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( + var, self._gettypenum(model.PointerType(tp.item))) + elif isinstance(tp, model.StructOrUnion): + if tp.fldnames is None: + raise TypeError("'%s' is used as %s, but is opaque" % ( + tp._get_c_name(), context)) + return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, model.EnumType): + return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + else: + raise NotImplementedError(tp) + + # ---------- + # typedefs: generates no code so far + + _generate_cpy_typedef_collecttype = _generate_nothing + _generate_cpy_typedef_decl = _generate_nothing + _generate_cpy_typedef_method = _generate_nothing + _loading_cpy_typedef = _loaded_noop + _loaded_cpy_typedef = _loaded_noop + + # ---------- + # function declarations + + def _generate_cpy_function_collecttype(self, tp, name): + assert isinstance(tp, model.FunctionPtrType) + if tp.ellipsis: + self._do_collect_type(tp) + else: + # don't call _do_collect_type(tp) in this common case, + # otherwise test_autofilled_struct_as_argument fails + for type in tp.args: + self._do_collect_type(type) + self._do_collect_type(tp.result) + + def _generate_cpy_function_decl(self, tp, name): + assert isinstance(tp, model.FunctionPtrType) + if tp.ellipsis: + # cannot support vararg functions better than this: check for its + # exact type (including the fixed arguments), and build it as a + # constant function pointer (no CPython wrapper) + self._generate_cpy_const(False, name, tp) + return + prnt = self._prnt + numargs = len(tp.args) + if numargs == 0: + argname = 'noarg' + elif numargs == 1: + argname = 'arg0' + else: + argname = 'args' + prnt('static PyObject *') + prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname)) + prnt('{') + # + context = 'argument of %s' % name + for i, type in enumerate(tp.args): + prnt(' %s;' % type.get_c_name(' x%d' % i, context)) + # + localvars = set() + freelines = set() + for type in tp.args: + self._extra_local_variables(type, localvars, freelines) + for decl in sorted(localvars): + prnt(' %s;' % (decl,)) + # + if not isinstance(tp.result, model.VoidType): + result_code = 'result = ' + context = 'result of %s' % name + prnt(' %s;' % tp.result.get_c_name(' result', context)) + prnt(' PyObject *pyresult;') + else: + result_code = '' + # + if len(tp.args) > 1: + rng = range(len(tp.args)) + for i in rng: + prnt(' PyObject *arg%d;' % i) + prnt() + prnt(' if (!PyArg_ParseTuple(args, "%s:%s", %s))' % ( + 'O' * numargs, name, ', '.join(['&arg%d' % i for i in rng]))) + prnt(' return NULL;') + prnt() + # + for i, type in enumerate(tp.args): + self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i, + 'return NULL') + prnt() + # + prnt(' Py_BEGIN_ALLOW_THREADS') + prnt(' _cffi_restore_errno();') + prnt(' { %s%s(%s); }' % ( + result_code, name, + ', '.join(['x%d' % i for i in range(len(tp.args))]))) + prnt(' _cffi_save_errno();') + prnt(' Py_END_ALLOW_THREADS') + prnt() + # + prnt(' (void)self; /* unused */') + if numargs == 0: + prnt(' (void)noarg; /* unused */') + if result_code: + prnt(' pyresult = %s;' % + self._convert_expr_from_c(tp.result, 'result', 'result type')) + for freeline in freelines: + prnt(' ' + freeline) + prnt(' return pyresult;') + else: + for freeline in freelines: + prnt(' ' + freeline) + prnt(' Py_INCREF(Py_None);') + prnt(' return Py_None;') + prnt('}') + prnt() + + def _generate_cpy_function_method(self, tp, name): + if tp.ellipsis: + return + numargs = len(tp.args) + if numargs == 0: + meth = 'METH_NOARGS' + elif numargs == 1: + meth = 'METH_O' + else: + meth = 'METH_VARARGS' + self._prnt(' {"%s", _cffi_f_%s, %s, NULL},' % (name, name, meth)) + + _loading_cpy_function = _loaded_noop + + def _loaded_cpy_function(self, tp, name, module, library): + if tp.ellipsis: + return + func = getattr(module, name) + setattr(library, name, func) + self._types_of_builtin_functions[func] = tp + + # ---------- + # named structs + + _generate_cpy_struct_collecttype = _generate_nothing + def _generate_cpy_struct_decl(self, tp, name): + assert name == tp.name + self._generate_struct_or_union_decl(tp, 'struct', name) + def _generate_cpy_struct_method(self, tp, name): + self._generate_struct_or_union_method(tp, 'struct', name) + def _loading_cpy_struct(self, tp, name, module): + self._loading_struct_or_union(tp, 'struct', name, module) + def _loaded_cpy_struct(self, tp, name, module, **kwds): + self._loaded_struct_or_union(tp) + + _generate_cpy_union_collecttype = _generate_nothing + def _generate_cpy_union_decl(self, tp, name): + assert name == tp.name + self._generate_struct_or_union_decl(tp, 'union', name) + def _generate_cpy_union_method(self, tp, name): + self._generate_struct_or_union_method(tp, 'union', name) + def _loading_cpy_union(self, tp, name, module): + self._loading_struct_or_union(tp, 'union', name, module) + def _loaded_cpy_union(self, tp, name, module, **kwds): + self._loaded_struct_or_union(tp) + + def _generate_struct_or_union_decl(self, tp, prefix, name): + if tp.fldnames is None: + return # nothing to do with opaque structs + checkfuncname = '_cffi_check_%s_%s' % (prefix, name) + layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) + cname = ('%s %s' % (prefix, name)).strip() + # + prnt = self._prnt + prnt('static void %s(%s *p)' % (checkfuncname, cname)) + prnt('{') + prnt(' /* only to generate compile-time warnings or errors */') + prnt(' (void)p;') + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if (isinstance(ftype, model.PrimitiveType) + and ftype.is_integer_type()) or fbitsize >= 0: + # accept all integers, but complain on float or double + prnt(' (void)((p->%s) << 1);' % fname) + else: + # only accept exactly the type declared. + try: + prnt(' { %s = &p->%s; (void)tmp; }' % ( + ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), + fname)) + except VerificationError as e: + prnt(' /* %s */' % str(e)) # cannot verify it, ignore + prnt('}') + prnt('static PyObject *') + prnt('%s(PyObject *self, PyObject *noarg)' % (layoutfuncname,)) + prnt('{') + prnt(' struct _cffi_aligncheck { char x; %s y; };' % cname) + prnt(' static Py_ssize_t nums[] = {') + prnt(' sizeof(%s),' % cname) + prnt(' offsetof(struct _cffi_aligncheck, y),') + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if fbitsize >= 0: + continue # xxx ignore fbitsize for now + prnt(' offsetof(%s, %s),' % (cname, fname)) + if isinstance(ftype, model.ArrayType) and ftype.length is None: + prnt(' 0, /* %s */' % ftype._get_c_name()) + else: + prnt(' sizeof(((%s *)0)->%s),' % (cname, fname)) + prnt(' -1') + prnt(' };') + prnt(' (void)self; /* unused */') + prnt(' (void)noarg; /* unused */') + prnt(' return _cffi_get_struct_layout(nums);') + prnt(' /* the next line is not executed, but compiled */') + prnt(' %s(0);' % (checkfuncname,)) + prnt('}') + prnt() + + def _generate_struct_or_union_method(self, tp, prefix, name): + if tp.fldnames is None: + return # nothing to do with opaque structs + layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) + self._prnt(' {"%s", %s, METH_NOARGS, NULL},' % (layoutfuncname, + layoutfuncname)) + + def _loading_struct_or_union(self, tp, prefix, name, module): + if tp.fldnames is None: + return # nothing to do with opaque structs + layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) + # + function = getattr(module, layoutfuncname) + layout = function() + if isinstance(tp, model.StructOrUnion) and tp.partial: + # use the function()'s sizes and offsets to guide the + # layout of the struct + totalsize = layout[0] + totalalignment = layout[1] + fieldofs = layout[2::2] + fieldsize = layout[3::2] + tp.force_flatten() + assert len(fieldofs) == len(fieldsize) == len(tp.fldnames) + tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment + else: + cname = ('%s %s' % (prefix, name)).strip() + self._struct_pending_verification[tp] = layout, cname + + def _loaded_struct_or_union(self, tp): + if tp.fldnames is None: + return # nothing to do with opaque structs + self.ffi._get_cached_btype(tp) # force 'fixedlayout' to be considered + + if tp in self._struct_pending_verification: + # check that the layout sizes and offsets match the real ones + def check(realvalue, expectedvalue, msg): + if realvalue != expectedvalue: + raise VerificationError( + "%s (we have %d, but C compiler says %d)" + % (msg, expectedvalue, realvalue)) + ffi = self.ffi + BStruct = ffi._get_cached_btype(tp) + layout, cname = self._struct_pending_verification.pop(tp) + check(layout[0], ffi.sizeof(BStruct), "wrong total size") + check(layout[1], ffi.alignof(BStruct), "wrong total alignment") + i = 2 + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if fbitsize >= 0: + continue # xxx ignore fbitsize for now + check(layout[i], ffi.offsetof(BStruct, fname), + "wrong offset for field %r" % (fname,)) + if layout[i+1] != 0: + BField = ffi._get_cached_btype(ftype) + check(layout[i+1], ffi.sizeof(BField), + "wrong size for field %r" % (fname,)) + i += 2 + assert i == len(layout) + + # ---------- + # 'anonymous' declarations. These are produced for anonymous structs + # or unions; the 'name' is obtained by a typedef. + + _generate_cpy_anonymous_collecttype = _generate_nothing + + def _generate_cpy_anonymous_decl(self, tp, name): + if isinstance(tp, model.EnumType): + self._generate_cpy_enum_decl(tp, name, '') + else: + self._generate_struct_or_union_decl(tp, '', name) + + def _generate_cpy_anonymous_method(self, tp, name): + if not isinstance(tp, model.EnumType): + self._generate_struct_or_union_method(tp, '', name) + + def _loading_cpy_anonymous(self, tp, name, module): + if isinstance(tp, model.EnumType): + self._loading_cpy_enum(tp, name, module) + else: + self._loading_struct_or_union(tp, '', name, module) + + def _loaded_cpy_anonymous(self, tp, name, module, **kwds): + if isinstance(tp, model.EnumType): + self._loaded_cpy_enum(tp, name, module, **kwds) + else: + self._loaded_struct_or_union(tp) + + # ---------- + # constants, likely declared with '#define' + + def _generate_cpy_const(self, is_int, name, tp=None, category='const', + vartp=None, delayed=True, size_too=False, + check_value=None): + prnt = self._prnt + funcname = '_cffi_%s_%s' % (category, name) + prnt('static int %s(PyObject *lib)' % funcname) + prnt('{') + prnt(' PyObject *o;') + prnt(' int res;') + if not is_int: + prnt(' %s;' % (vartp or tp).get_c_name(' i', name)) + else: + assert category == 'const' + # + if check_value is not None: + self._check_int_constant_value(name, check_value) + # + if not is_int: + if category == 'var': + realexpr = '&' + name + else: + realexpr = name + prnt(' i = (%s);' % (realexpr,)) + prnt(' o = %s;' % (self._convert_expr_from_c(tp, 'i', + 'variable type'),)) + assert delayed + else: + prnt(' o = _cffi_from_c_int_const(%s);' % name) + prnt(' if (o == NULL)') + prnt(' return -1;') + if size_too: + prnt(' {') + prnt(' PyObject *o1 = o;') + prnt(' o = Py_BuildValue("On", o1, (Py_ssize_t)sizeof(%s));' + % (name,)) + prnt(' Py_DECREF(o1);') + prnt(' if (o == NULL)') + prnt(' return -1;') + prnt(' }') + prnt(' res = PyObject_SetAttrString(lib, "%s", o);' % name) + prnt(' Py_DECREF(o);') + prnt(' if (res < 0)') + prnt(' return -1;') + prnt(' return %s;' % self._chained_list_constants[delayed]) + self._chained_list_constants[delayed] = funcname + '(lib)' + prnt('}') + prnt() + + def _generate_cpy_constant_collecttype(self, tp, name): + is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() + if not is_int: + self._do_collect_type(tp) + + def _generate_cpy_constant_decl(self, tp, name): + is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() + self._generate_cpy_const(is_int, name, tp) + + _generate_cpy_constant_method = _generate_nothing + _loading_cpy_constant = _loaded_noop + _loaded_cpy_constant = _loaded_noop + + # ---------- + # enums + + def _check_int_constant_value(self, name, value, err_prefix=''): + prnt = self._prnt + if value <= 0: + prnt(' if ((%s) > 0 || (long)(%s) != %dL) {' % ( + name, name, value)) + else: + prnt(' if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % ( + name, name, value)) + prnt(' char buf[64];') + prnt(' if ((%s) <= 0)' % name) + prnt(' snprintf(buf, 63, "%%ld", (long)(%s));' % name) + prnt(' else') + prnt(' snprintf(buf, 63, "%%lu", (unsigned long)(%s));' % + name) + prnt(' PyErr_Format(_cffi_VerificationError,') + prnt(' "%s%s has the real value %s, not %s",') + prnt(' "%s", "%s", buf, "%d");' % ( + err_prefix, name, value)) + prnt(' return -1;') + prnt(' }') + + def _enum_funcname(self, prefix, name): + # "$enum_$1" => "___D_enum____D_1" + name = name.replace('$', '___D_') + return '_cffi_e_%s_%s' % (prefix, name) + + def _generate_cpy_enum_decl(self, tp, name, prefix='enum'): + if tp.partial: + for enumerator in tp.enumerators: + self._generate_cpy_const(True, enumerator, delayed=False) + return + # + funcname = self._enum_funcname(prefix, name) + prnt = self._prnt + prnt('static int %s(PyObject *lib)' % funcname) + prnt('{') + for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): + self._check_int_constant_value(enumerator, enumvalue, + "enum %s: " % name) + prnt(' return %s;' % self._chained_list_constants[True]) + self._chained_list_constants[True] = funcname + '(lib)' + prnt('}') + prnt() + + _generate_cpy_enum_collecttype = _generate_nothing + _generate_cpy_enum_method = _generate_nothing + + def _loading_cpy_enum(self, tp, name, module): + if tp.partial: + enumvalues = [getattr(module, enumerator) + for enumerator in tp.enumerators] + tp.enumvalues = tuple(enumvalues) + tp.partial_resolved = True + + def _loaded_cpy_enum(self, tp, name, module, library): + for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): + setattr(library, enumerator, enumvalue) + + # ---------- + # macros: for now only for integers + + def _generate_cpy_macro_decl(self, tp, name): + if tp == '...': + check_value = None + else: + check_value = tp # an integer + self._generate_cpy_const(True, name, check_value=check_value) + + _generate_cpy_macro_collecttype = _generate_nothing + _generate_cpy_macro_method = _generate_nothing + _loading_cpy_macro = _loaded_noop + _loaded_cpy_macro = _loaded_noop + + # ---------- + # global variables + + def _generate_cpy_variable_collecttype(self, tp, name): + if isinstance(tp, model.ArrayType): + tp_ptr = model.PointerType(tp.item) + else: + tp_ptr = model.PointerType(tp) + self._do_collect_type(tp_ptr) + + def _generate_cpy_variable_decl(self, tp, name): + if isinstance(tp, model.ArrayType): + tp_ptr = model.PointerType(tp.item) + self._generate_cpy_const(False, name, tp, vartp=tp_ptr, + size_too = tp.length_is_unknown()) + else: + tp_ptr = model.PointerType(tp) + self._generate_cpy_const(False, name, tp_ptr, category='var') + + _generate_cpy_variable_method = _generate_nothing + _loading_cpy_variable = _loaded_noop + + def _loaded_cpy_variable(self, tp, name, module, library): + value = getattr(library, name) + if isinstance(tp, model.ArrayType): # int a[5] is "constant" in the + # sense that "a=..." is forbidden + if tp.length_is_unknown(): + assert isinstance(value, tuple) + (value, size) = value + BItemType = self.ffi._get_cached_btype(tp.item) + length, rest = divmod(size, self.ffi.sizeof(BItemType)) + if rest != 0: + raise VerificationError( + "bad size: %r does not seem to be an array of %s" % + (name, tp.item)) + tp = tp.resolve_length(length) + # 'value' is a which we have to replace with + # a if the N is actually known + if tp.length is not None: + BArray = self.ffi._get_cached_btype(tp) + value = self.ffi.cast(BArray, value) + setattr(library, name, value) + return + # remove ptr= from the library instance, and replace + # it by a property on the class, which reads/writes into ptr[0]. + ptr = value + delattr(library, name) + def getter(library): + return ptr[0] + def setter(library, value): + ptr[0] = value + setattr(type(library), name, property(getter, setter)) + type(library)._cffi_dir.append(name) + + # ---------- + + def _generate_setup_custom(self): + prnt = self._prnt + prnt('static int _cffi_setup_custom(PyObject *lib)') + prnt('{') + prnt(' return %s;' % self._chained_list_constants[True]) + prnt('}') + +cffimod_header = r''' +#include +#include + +/* this block of #ifs should be kept exactly identical between + c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py + and cffi/_cffi_include.h */ +#if defined(_MSC_VER) +# include /* for alloca() */ +# if _MSC_VER < 1600 /* MSVC < 2010 */ + typedef __int8 int8_t; + typedef __int16 int16_t; + typedef __int32 int32_t; + typedef __int64 int64_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + typedef unsigned __int64 uint64_t; + typedef __int8 int_least8_t; + typedef __int16 int_least16_t; + typedef __int32 int_least32_t; + typedef __int64 int_least64_t; + typedef unsigned __int8 uint_least8_t; + typedef unsigned __int16 uint_least16_t; + typedef unsigned __int32 uint_least32_t; + typedef unsigned __int64 uint_least64_t; + typedef __int8 int_fast8_t; + typedef __int16 int_fast16_t; + typedef __int32 int_fast32_t; + typedef __int64 int_fast64_t; + typedef unsigned __int8 uint_fast8_t; + typedef unsigned __int16 uint_fast16_t; + typedef unsigned __int32 uint_fast32_t; + typedef unsigned __int64 uint_fast64_t; + typedef __int64 intmax_t; + typedef unsigned __int64 uintmax_t; +# else +# include +# endif +# if _MSC_VER < 1800 /* MSVC < 2013 */ +# ifndef __cplusplus + typedef unsigned char _Bool; +# endif +# endif +#else +# include +# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) +# include +# endif +#endif + +#if PY_MAJOR_VERSION < 3 +# undef PyCapsule_CheckExact +# undef PyCapsule_GetPointer +# define PyCapsule_CheckExact(capsule) (PyCObject_Check(capsule)) +# define PyCapsule_GetPointer(capsule, name) \ + (PyCObject_AsVoidPtr(capsule)) +#endif + +#if PY_MAJOR_VERSION >= 3 +# define PyInt_FromLong PyLong_FromLong +#endif + +#define _cffi_from_c_double PyFloat_FromDouble +#define _cffi_from_c_float PyFloat_FromDouble +#define _cffi_from_c_long PyInt_FromLong +#define _cffi_from_c_ulong PyLong_FromUnsignedLong +#define _cffi_from_c_longlong PyLong_FromLongLong +#define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong +#define _cffi_from_c__Bool PyBool_FromLong + +#define _cffi_to_c_double PyFloat_AsDouble +#define _cffi_to_c_float PyFloat_AsDouble + +#define _cffi_from_c_int_const(x) \ + (((x) > 0) ? \ + ((unsigned long long)(x) <= (unsigned long long)LONG_MAX) ? \ + PyInt_FromLong((long)(x)) : \ + PyLong_FromUnsignedLongLong((unsigned long long)(x)) : \ + ((long long)(x) >= (long long)LONG_MIN) ? \ + PyInt_FromLong((long)(x)) : \ + PyLong_FromLongLong((long long)(x))) + +#define _cffi_from_c_int(x, type) \ + (((type)-1) > 0 ? /* unsigned */ \ + (sizeof(type) < sizeof(long) ? \ + PyInt_FromLong((long)x) : \ + sizeof(type) == sizeof(long) ? \ + PyLong_FromUnsignedLong((unsigned long)x) : \ + PyLong_FromUnsignedLongLong((unsigned long long)x)) : \ + (sizeof(type) <= sizeof(long) ? \ + PyInt_FromLong((long)x) : \ + PyLong_FromLongLong((long long)x))) + +#define _cffi_to_c_int(o, type) \ + ((type)( \ + sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \ + : (type)_cffi_to_c_i8(o)) : \ + sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o) \ + : (type)_cffi_to_c_i16(o)) : \ + sizeof(type) == 4 ? (((type)-1) > 0 ? (type)_cffi_to_c_u32(o) \ + : (type)_cffi_to_c_i32(o)) : \ + sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o) \ + : (type)_cffi_to_c_i64(o)) : \ + (Py_FatalError("unsupported size for type " #type), (type)0))) + +#define _cffi_to_c_i8 \ + ((int(*)(PyObject *))_cffi_exports[1]) +#define _cffi_to_c_u8 \ + ((int(*)(PyObject *))_cffi_exports[2]) +#define _cffi_to_c_i16 \ + ((int(*)(PyObject *))_cffi_exports[3]) +#define _cffi_to_c_u16 \ + ((int(*)(PyObject *))_cffi_exports[4]) +#define _cffi_to_c_i32 \ + ((int(*)(PyObject *))_cffi_exports[5]) +#define _cffi_to_c_u32 \ + ((unsigned int(*)(PyObject *))_cffi_exports[6]) +#define _cffi_to_c_i64 \ + ((long long(*)(PyObject *))_cffi_exports[7]) +#define _cffi_to_c_u64 \ + ((unsigned long long(*)(PyObject *))_cffi_exports[8]) +#define _cffi_to_c_char \ + ((int(*)(PyObject *))_cffi_exports[9]) +#define _cffi_from_c_pointer \ + ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[10]) +#define _cffi_to_c_pointer \ + ((char *(*)(PyObject *, CTypeDescrObject *))_cffi_exports[11]) +#define _cffi_get_struct_layout \ + ((PyObject *(*)(Py_ssize_t[]))_cffi_exports[12]) +#define _cffi_restore_errno \ + ((void(*)(void))_cffi_exports[13]) +#define _cffi_save_errno \ + ((void(*)(void))_cffi_exports[14]) +#define _cffi_from_c_char \ + ((PyObject *(*)(char))_cffi_exports[15]) +#define _cffi_from_c_deref \ + ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[16]) +#define _cffi_to_c \ + ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[17]) +#define _cffi_from_c_struct \ + ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[18]) +#define _cffi_to_c_wchar_t \ + ((wchar_t(*)(PyObject *))_cffi_exports[19]) +#define _cffi_from_c_wchar_t \ + ((PyObject *(*)(wchar_t))_cffi_exports[20]) +#define _cffi_to_c_long_double \ + ((long double(*)(PyObject *))_cffi_exports[21]) +#define _cffi_to_c__Bool \ + ((_Bool(*)(PyObject *))_cffi_exports[22]) +#define _cffi_prepare_pointer_call_argument \ + ((Py_ssize_t(*)(CTypeDescrObject *, PyObject *, char **))_cffi_exports[23]) +#define _cffi_convert_array_from_object \ + ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[24]) +#define _CFFI_NUM_EXPORTS 25 + +typedef struct _ctypedescr CTypeDescrObject; + +static void *_cffi_exports[_CFFI_NUM_EXPORTS]; +static PyObject *_cffi_types, *_cffi_VerificationError; + +static int _cffi_setup_custom(PyObject *lib); /* forward */ + +static PyObject *_cffi_setup(PyObject *self, PyObject *args) +{ + PyObject *library; + int was_alive = (_cffi_types != NULL); + (void)self; /* unused */ + if (!PyArg_ParseTuple(args, "OOO", &_cffi_types, &_cffi_VerificationError, + &library)) + return NULL; + Py_INCREF(_cffi_types); + Py_INCREF(_cffi_VerificationError); + if (_cffi_setup_custom(library) < 0) + return NULL; + return PyBool_FromLong(was_alive); +} + +union _cffi_union_alignment_u { + unsigned char m_char; + unsigned short m_short; + unsigned int m_int; + unsigned long m_long; + unsigned long long m_longlong; + float m_float; + double m_double; + long double m_longdouble; +}; + +struct _cffi_freeme_s { + struct _cffi_freeme_s *next; + union _cffi_union_alignment_u alignment; +}; + +#ifdef __GNUC__ + __attribute__((unused)) +#endif +static int _cffi_convert_array_argument(CTypeDescrObject *ctptr, PyObject *arg, + char **output_data, Py_ssize_t datasize, + struct _cffi_freeme_s **freeme) +{ + char *p; + if (datasize < 0) + return -1; + + p = *output_data; + if (p == NULL) { + struct _cffi_freeme_s *fp = (struct _cffi_freeme_s *)PyObject_Malloc( + offsetof(struct _cffi_freeme_s, alignment) + (size_t)datasize); + if (fp == NULL) + return -1; + fp->next = *freeme; + *freeme = fp; + p = *output_data = (char *)&fp->alignment; + } + memset((void *)p, 0, (size_t)datasize); + return _cffi_convert_array_from_object(p, ctptr, arg); +} + +#ifdef __GNUC__ + __attribute__((unused)) +#endif +static void _cffi_free_array_arguments(struct _cffi_freeme_s *freeme) +{ + do { + void *p = (void *)freeme; + freeme = freeme->next; + PyObject_Free(p); + } while (freeme != NULL); +} + +static int _cffi_init(void) +{ + PyObject *module, *c_api_object = NULL; + + module = PyImport_ImportModule("_cffi_backend"); + if (module == NULL) + goto failure; + + c_api_object = PyObject_GetAttrString(module, "_C_API"); + if (c_api_object == NULL) + goto failure; + if (!PyCapsule_CheckExact(c_api_object)) { + PyErr_SetNone(PyExc_ImportError); + goto failure; + } + memcpy(_cffi_exports, PyCapsule_GetPointer(c_api_object, "cffi"), + _CFFI_NUM_EXPORTS * sizeof(void *)); + + Py_DECREF(module); + Py_DECREF(c_api_object); + return 0; + + failure: + Py_XDECREF(module); + Py_XDECREF(c_api_object); + return -1; +} + +#define _cffi_type(num) ((CTypeDescrObject *)PyList_GET_ITEM(_cffi_types, num)) + +/**********/ +''' diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/vengine_gen.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/vengine_gen.py new file mode 100644 index 0000000..2642152 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/vengine_gen.py @@ -0,0 +1,675 @@ +# +# DEPRECATED: implementation for ffi.verify() +# +import sys, os +import types + +from . import model +from .error import VerificationError + + +class VGenericEngine(object): + _class_key = 'g' + _gen_python_module = False + + def __init__(self, verifier): + self.verifier = verifier + self.ffi = verifier.ffi + self.export_symbols = [] + self._struct_pending_verification = {} + + def patch_extension_kwds(self, kwds): + # add 'export_symbols' to the dictionary. Note that we add the + # list before filling it. When we fill it, it will thus also show + # up in kwds['export_symbols']. + kwds.setdefault('export_symbols', self.export_symbols) + + def find_module(self, module_name, path, so_suffixes): + for so_suffix in so_suffixes: + basename = module_name + so_suffix + if path is None: + path = sys.path + for dirname in path: + filename = os.path.join(dirname, basename) + if os.path.isfile(filename): + return filename + + def collect_types(self): + pass # not needed in the generic engine + + def _prnt(self, what=''): + self._f.write(what + '\n') + + def write_source_to_f(self): + prnt = self._prnt + # first paste some standard set of lines that are mostly '#include' + prnt(cffimod_header) + # then paste the C source given by the user, verbatim. + prnt(self.verifier.preamble) + # + # call generate_gen_xxx_decl(), for every xxx found from + # ffi._parser._declarations. This generates all the functions. + self._generate('decl') + # + # on Windows, distutils insists on putting init_cffi_xyz in + # 'export_symbols', so instead of fighting it, just give up and + # give it one + if sys.platform == 'win32': + if sys.version_info >= (3,): + prefix = 'PyInit_' + else: + prefix = 'init' + modname = self.verifier.get_module_name() + prnt("void %s%s(void) { }\n" % (prefix, modname)) + + def load_library(self, flags=0): + # import it with the CFFI backend + backend = self.ffi._backend + # needs to make a path that contains '/', on Posix + filename = os.path.join(os.curdir, self.verifier.modulefilename) + module = backend.load_library(filename, flags) + # + # call loading_gen_struct() to get the struct layout inferred by + # the C compiler + self._load(module, 'loading') + + # build the FFILibrary class and instance, this is a module subclass + # because modules are expected to have usually-constant-attributes and + # in PyPy this means the JIT is able to treat attributes as constant, + # which we want. + class FFILibrary(types.ModuleType): + _cffi_generic_module = module + _cffi_ffi = self.ffi + _cffi_dir = [] + def __dir__(self): + return FFILibrary._cffi_dir + library = FFILibrary("") + # + # finally, call the loaded_gen_xxx() functions. This will set + # up the 'library' object. + self._load(module, 'loaded', library=library) + return library + + def _get_declarations(self): + lst = [(key, tp) for (key, (tp, qual)) in + self.ffi._parser._declarations.items()] + lst.sort() + return lst + + def _generate(self, step_name): + for name, tp in self._get_declarations(): + kind, realname = name.split(' ', 1) + try: + method = getattr(self, '_generate_gen_%s_%s' % (kind, + step_name)) + except AttributeError: + raise VerificationError( + "not implemented in verify(): %r" % name) + try: + method(tp, realname) + except Exception as e: + model.attach_exception_info(e, name) + raise + + def _load(self, module, step_name, **kwds): + for name, tp in self._get_declarations(): + kind, realname = name.split(' ', 1) + method = getattr(self, '_%s_gen_%s' % (step_name, kind)) + try: + method(tp, realname, module, **kwds) + except Exception as e: + model.attach_exception_info(e, name) + raise + + def _generate_nothing(self, tp, name): + pass + + def _loaded_noop(self, tp, name, module, **kwds): + pass + + # ---------- + # typedefs: generates no code so far + + _generate_gen_typedef_decl = _generate_nothing + _loading_gen_typedef = _loaded_noop + _loaded_gen_typedef = _loaded_noop + + # ---------- + # function declarations + + def _generate_gen_function_decl(self, tp, name): + assert isinstance(tp, model.FunctionPtrType) + if tp.ellipsis: + # cannot support vararg functions better than this: check for its + # exact type (including the fixed arguments), and build it as a + # constant function pointer (no _cffi_f_%s wrapper) + self._generate_gen_const(False, name, tp) + return + prnt = self._prnt + numargs = len(tp.args) + argnames = [] + for i, type in enumerate(tp.args): + indirection = '' + if isinstance(type, model.StructOrUnion): + indirection = '*' + argnames.append('%sx%d' % (indirection, i)) + context = 'argument of %s' % name + arglist = [type.get_c_name(' %s' % arg, context) + for type, arg in zip(tp.args, argnames)] + tpresult = tp.result + if isinstance(tpresult, model.StructOrUnion): + arglist.insert(0, tpresult.get_c_name(' *r', context)) + tpresult = model.void_type + arglist = ', '.join(arglist) or 'void' + wrappername = '_cffi_f_%s' % name + self.export_symbols.append(wrappername) + if tp.abi: + abi = tp.abi + ' ' + else: + abi = '' + funcdecl = ' %s%s(%s)' % (abi, wrappername, arglist) + context = 'result of %s' % name + prnt(tpresult.get_c_name(funcdecl, context)) + prnt('{') + # + if isinstance(tp.result, model.StructOrUnion): + result_code = '*r = ' + elif not isinstance(tp.result, model.VoidType): + result_code = 'return ' + else: + result_code = '' + prnt(' %s%s(%s);' % (result_code, name, ', '.join(argnames))) + prnt('}') + prnt() + + _loading_gen_function = _loaded_noop + + def _loaded_gen_function(self, tp, name, module, library): + assert isinstance(tp, model.FunctionPtrType) + if tp.ellipsis: + newfunction = self._load_constant(False, tp, name, module) + else: + indirections = [] + base_tp = tp + if (any(isinstance(typ, model.StructOrUnion) for typ in tp.args) + or isinstance(tp.result, model.StructOrUnion)): + indirect_args = [] + for i, typ in enumerate(tp.args): + if isinstance(typ, model.StructOrUnion): + typ = model.PointerType(typ) + indirections.append((i, typ)) + indirect_args.append(typ) + indirect_result = tp.result + if isinstance(indirect_result, model.StructOrUnion): + if indirect_result.fldtypes is None: + raise TypeError("'%s' is used as result type, " + "but is opaque" % ( + indirect_result._get_c_name(),)) + indirect_result = model.PointerType(indirect_result) + indirect_args.insert(0, indirect_result) + indirections.insert(0, ("result", indirect_result)) + indirect_result = model.void_type + tp = model.FunctionPtrType(tuple(indirect_args), + indirect_result, tp.ellipsis) + BFunc = self.ffi._get_cached_btype(tp) + wrappername = '_cffi_f_%s' % name + newfunction = module.load_function(BFunc, wrappername) + for i, typ in indirections: + newfunction = self._make_struct_wrapper(newfunction, i, typ, + base_tp) + setattr(library, name, newfunction) + type(library)._cffi_dir.append(name) + + def _make_struct_wrapper(self, oldfunc, i, tp, base_tp): + backend = self.ffi._backend + BType = self.ffi._get_cached_btype(tp) + if i == "result": + ffi = self.ffi + def newfunc(*args): + res = ffi.new(BType) + oldfunc(res, *args) + return res[0] + else: + def newfunc(*args): + args = args[:i] + (backend.newp(BType, args[i]),) + args[i+1:] + return oldfunc(*args) + newfunc._cffi_base_type = base_tp + return newfunc + + # ---------- + # named structs + + def _generate_gen_struct_decl(self, tp, name): + assert name == tp.name + self._generate_struct_or_union_decl(tp, 'struct', name) + + def _loading_gen_struct(self, tp, name, module): + self._loading_struct_or_union(tp, 'struct', name, module) + + def _loaded_gen_struct(self, tp, name, module, **kwds): + self._loaded_struct_or_union(tp) + + def _generate_gen_union_decl(self, tp, name): + assert name == tp.name + self._generate_struct_or_union_decl(tp, 'union', name) + + def _loading_gen_union(self, tp, name, module): + self._loading_struct_or_union(tp, 'union', name, module) + + def _loaded_gen_union(self, tp, name, module, **kwds): + self._loaded_struct_or_union(tp) + + def _generate_struct_or_union_decl(self, tp, prefix, name): + if tp.fldnames is None: + return # nothing to do with opaque structs + checkfuncname = '_cffi_check_%s_%s' % (prefix, name) + layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) + cname = ('%s %s' % (prefix, name)).strip() + # + prnt = self._prnt + prnt('static void %s(%s *p)' % (checkfuncname, cname)) + prnt('{') + prnt(' /* only to generate compile-time warnings or errors */') + prnt(' (void)p;') + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if (isinstance(ftype, model.PrimitiveType) + and ftype.is_integer_type()) or fbitsize >= 0: + # accept all integers, but complain on float or double + prnt(' (void)((p->%s) << 1);' % fname) + else: + # only accept exactly the type declared. + try: + prnt(' { %s = &p->%s; (void)tmp; }' % ( + ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), + fname)) + except VerificationError as e: + prnt(' /* %s */' % str(e)) # cannot verify it, ignore + prnt('}') + self.export_symbols.append(layoutfuncname) + prnt('intptr_t %s(intptr_t i)' % (layoutfuncname,)) + prnt('{') + prnt(' struct _cffi_aligncheck { char x; %s y; };' % cname) + prnt(' static intptr_t nums[] = {') + prnt(' sizeof(%s),' % cname) + prnt(' offsetof(struct _cffi_aligncheck, y),') + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if fbitsize >= 0: + continue # xxx ignore fbitsize for now + prnt(' offsetof(%s, %s),' % (cname, fname)) + if isinstance(ftype, model.ArrayType) and ftype.length is None: + prnt(' 0, /* %s */' % ftype._get_c_name()) + else: + prnt(' sizeof(((%s *)0)->%s),' % (cname, fname)) + prnt(' -1') + prnt(' };') + prnt(' return nums[i];') + prnt(' /* the next line is not executed, but compiled */') + prnt(' %s(0);' % (checkfuncname,)) + prnt('}') + prnt() + + def _loading_struct_or_union(self, tp, prefix, name, module): + if tp.fldnames is None: + return # nothing to do with opaque structs + layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) + # + BFunc = self.ffi._typeof_locked("intptr_t(*)(intptr_t)")[0] + function = module.load_function(BFunc, layoutfuncname) + layout = [] + num = 0 + while True: + x = function(num) + if x < 0: break + layout.append(x) + num += 1 + if isinstance(tp, model.StructOrUnion) and tp.partial: + # use the function()'s sizes and offsets to guide the + # layout of the struct + totalsize = layout[0] + totalalignment = layout[1] + fieldofs = layout[2::2] + fieldsize = layout[3::2] + tp.force_flatten() + assert len(fieldofs) == len(fieldsize) == len(tp.fldnames) + tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment + else: + cname = ('%s %s' % (prefix, name)).strip() + self._struct_pending_verification[tp] = layout, cname + + def _loaded_struct_or_union(self, tp): + if tp.fldnames is None: + return # nothing to do with opaque structs + self.ffi._get_cached_btype(tp) # force 'fixedlayout' to be considered + + if tp in self._struct_pending_verification: + # check that the layout sizes and offsets match the real ones + def check(realvalue, expectedvalue, msg): + if realvalue != expectedvalue: + raise VerificationError( + "%s (we have %d, but C compiler says %d)" + % (msg, expectedvalue, realvalue)) + ffi = self.ffi + BStruct = ffi._get_cached_btype(tp) + layout, cname = self._struct_pending_verification.pop(tp) + check(layout[0], ffi.sizeof(BStruct), "wrong total size") + check(layout[1], ffi.alignof(BStruct), "wrong total alignment") + i = 2 + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if fbitsize >= 0: + continue # xxx ignore fbitsize for now + check(layout[i], ffi.offsetof(BStruct, fname), + "wrong offset for field %r" % (fname,)) + if layout[i+1] != 0: + BField = ffi._get_cached_btype(ftype) + check(layout[i+1], ffi.sizeof(BField), + "wrong size for field %r" % (fname,)) + i += 2 + assert i == len(layout) + + # ---------- + # 'anonymous' declarations. These are produced for anonymous structs + # or unions; the 'name' is obtained by a typedef. + + def _generate_gen_anonymous_decl(self, tp, name): + if isinstance(tp, model.EnumType): + self._generate_gen_enum_decl(tp, name, '') + else: + self._generate_struct_or_union_decl(tp, '', name) + + def _loading_gen_anonymous(self, tp, name, module): + if isinstance(tp, model.EnumType): + self._loading_gen_enum(tp, name, module, '') + else: + self._loading_struct_or_union(tp, '', name, module) + + def _loaded_gen_anonymous(self, tp, name, module, **kwds): + if isinstance(tp, model.EnumType): + self._loaded_gen_enum(tp, name, module, **kwds) + else: + self._loaded_struct_or_union(tp) + + # ---------- + # constants, likely declared with '#define' + + def _generate_gen_const(self, is_int, name, tp=None, category='const', + check_value=None): + prnt = self._prnt + funcname = '_cffi_%s_%s' % (category, name) + self.export_symbols.append(funcname) + if check_value is not None: + assert is_int + assert category == 'const' + prnt('int %s(char *out_error)' % funcname) + prnt('{') + self._check_int_constant_value(name, check_value) + prnt(' return 0;') + prnt('}') + elif is_int: + assert category == 'const' + prnt('int %s(long long *out_value)' % funcname) + prnt('{') + prnt(' *out_value = (long long)(%s);' % (name,)) + prnt(' return (%s) <= 0;' % (name,)) + prnt('}') + else: + assert tp is not None + assert check_value is None + if category == 'var': + ampersand = '&' + else: + ampersand = '' + extra = '' + if category == 'const' and isinstance(tp, model.StructOrUnion): + extra = 'const *' + ampersand = '&' + prnt(tp.get_c_name(' %s%s(void)' % (extra, funcname), name)) + prnt('{') + prnt(' return (%s%s);' % (ampersand, name)) + prnt('}') + prnt() + + def _generate_gen_constant_decl(self, tp, name): + is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() + self._generate_gen_const(is_int, name, tp) + + _loading_gen_constant = _loaded_noop + + def _load_constant(self, is_int, tp, name, module, check_value=None): + funcname = '_cffi_const_%s' % name + if check_value is not None: + assert is_int + self._load_known_int_constant(module, funcname) + value = check_value + elif is_int: + BType = self.ffi._typeof_locked("long long*")[0] + BFunc = self.ffi._typeof_locked("int(*)(long long*)")[0] + function = module.load_function(BFunc, funcname) + p = self.ffi.new(BType) + negative = function(p) + value = int(p[0]) + if value < 0 and not negative: + BLongLong = self.ffi._typeof_locked("long long")[0] + value += (1 << (8*self.ffi.sizeof(BLongLong))) + else: + assert check_value is None + fntypeextra = '(*)(void)' + if isinstance(tp, model.StructOrUnion): + fntypeextra = '*' + fntypeextra + BFunc = self.ffi._typeof_locked(tp.get_c_name(fntypeextra, name))[0] + function = module.load_function(BFunc, funcname) + value = function() + if isinstance(tp, model.StructOrUnion): + value = value[0] + return value + + def _loaded_gen_constant(self, tp, name, module, library): + is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() + value = self._load_constant(is_int, tp, name, module) + setattr(library, name, value) + type(library)._cffi_dir.append(name) + + # ---------- + # enums + + def _check_int_constant_value(self, name, value): + prnt = self._prnt + if value <= 0: + prnt(' if ((%s) > 0 || (long)(%s) != %dL) {' % ( + name, name, value)) + else: + prnt(' if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % ( + name, name, value)) + prnt(' char buf[64];') + prnt(' if ((%s) <= 0)' % name) + prnt(' sprintf(buf, "%%ld", (long)(%s));' % name) + prnt(' else') + prnt(' sprintf(buf, "%%lu", (unsigned long)(%s));' % + name) + prnt(' sprintf(out_error, "%s has the real value %s, not %s",') + prnt(' "%s", buf, "%d");' % (name[:100], value)) + prnt(' return -1;') + prnt(' }') + + def _load_known_int_constant(self, module, funcname): + BType = self.ffi._typeof_locked("char[]")[0] + BFunc = self.ffi._typeof_locked("int(*)(char*)")[0] + function = module.load_function(BFunc, funcname) + p = self.ffi.new(BType, 256) + if function(p) < 0: + error = self.ffi.string(p) + if sys.version_info >= (3,): + error = str(error, 'utf-8') + raise VerificationError(error) + + def _enum_funcname(self, prefix, name): + # "$enum_$1" => "___D_enum____D_1" + name = name.replace('$', '___D_') + return '_cffi_e_%s_%s' % (prefix, name) + + def _generate_gen_enum_decl(self, tp, name, prefix='enum'): + if tp.partial: + for enumerator in tp.enumerators: + self._generate_gen_const(True, enumerator) + return + # + funcname = self._enum_funcname(prefix, name) + self.export_symbols.append(funcname) + prnt = self._prnt + prnt('int %s(char *out_error)' % funcname) + prnt('{') + for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): + self._check_int_constant_value(enumerator, enumvalue) + prnt(' return 0;') + prnt('}') + prnt() + + def _loading_gen_enum(self, tp, name, module, prefix='enum'): + if tp.partial: + enumvalues = [self._load_constant(True, tp, enumerator, module) + for enumerator in tp.enumerators] + tp.enumvalues = tuple(enumvalues) + tp.partial_resolved = True + else: + funcname = self._enum_funcname(prefix, name) + self._load_known_int_constant(module, funcname) + + def _loaded_gen_enum(self, tp, name, module, library): + for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): + setattr(library, enumerator, enumvalue) + type(library)._cffi_dir.append(enumerator) + + # ---------- + # macros: for now only for integers + + def _generate_gen_macro_decl(self, tp, name): + if tp == '...': + check_value = None + else: + check_value = tp # an integer + self._generate_gen_const(True, name, check_value=check_value) + + _loading_gen_macro = _loaded_noop + + def _loaded_gen_macro(self, tp, name, module, library): + if tp == '...': + check_value = None + else: + check_value = tp # an integer + value = self._load_constant(True, tp, name, module, + check_value=check_value) + setattr(library, name, value) + type(library)._cffi_dir.append(name) + + # ---------- + # global variables + + def _generate_gen_variable_decl(self, tp, name): + if isinstance(tp, model.ArrayType): + if tp.length_is_unknown(): + prnt = self._prnt + funcname = '_cffi_sizeof_%s' % (name,) + self.export_symbols.append(funcname) + prnt("size_t %s(void)" % funcname) + prnt("{") + prnt(" return sizeof(%s);" % (name,)) + prnt("}") + tp_ptr = model.PointerType(tp.item) + self._generate_gen_const(False, name, tp_ptr) + else: + tp_ptr = model.PointerType(tp) + self._generate_gen_const(False, name, tp_ptr, category='var') + + _loading_gen_variable = _loaded_noop + + def _loaded_gen_variable(self, tp, name, module, library): + if isinstance(tp, model.ArrayType): # int a[5] is "constant" in the + # sense that "a=..." is forbidden + if tp.length_is_unknown(): + funcname = '_cffi_sizeof_%s' % (name,) + BFunc = self.ffi._typeof_locked('size_t(*)(void)')[0] + function = module.load_function(BFunc, funcname) + size = function() + BItemType = self.ffi._get_cached_btype(tp.item) + length, rest = divmod(size, self.ffi.sizeof(BItemType)) + if rest != 0: + raise VerificationError( + "bad size: %r does not seem to be an array of %s" % + (name, tp.item)) + tp = tp.resolve_length(length) + tp_ptr = model.PointerType(tp.item) + value = self._load_constant(False, tp_ptr, name, module) + # 'value' is a which we have to replace with + # a if the N is actually known + if tp.length is not None: + BArray = self.ffi._get_cached_btype(tp) + value = self.ffi.cast(BArray, value) + setattr(library, name, value) + type(library)._cffi_dir.append(name) + return + # remove ptr= from the library instance, and replace + # it by a property on the class, which reads/writes into ptr[0]. + funcname = '_cffi_var_%s' % name + BFunc = self.ffi._typeof_locked(tp.get_c_name('*(*)(void)', name))[0] + function = module.load_function(BFunc, funcname) + ptr = function() + def getter(library): + return ptr[0] + def setter(library, value): + ptr[0] = value + setattr(type(library), name, property(getter, setter)) + type(library)._cffi_dir.append(name) + +cffimod_header = r''' +#include +#include +#include +#include +#include /* XXX for ssize_t on some platforms */ + +/* this block of #ifs should be kept exactly identical between + c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py + and cffi/_cffi_include.h */ +#if defined(_MSC_VER) +# include /* for alloca() */ +# if _MSC_VER < 1600 /* MSVC < 2010 */ + typedef __int8 int8_t; + typedef __int16 int16_t; + typedef __int32 int32_t; + typedef __int64 int64_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + typedef unsigned __int64 uint64_t; + typedef __int8 int_least8_t; + typedef __int16 int_least16_t; + typedef __int32 int_least32_t; + typedef __int64 int_least64_t; + typedef unsigned __int8 uint_least8_t; + typedef unsigned __int16 uint_least16_t; + typedef unsigned __int32 uint_least32_t; + typedef unsigned __int64 uint_least64_t; + typedef __int8 int_fast8_t; + typedef __int16 int_fast16_t; + typedef __int32 int_fast32_t; + typedef __int64 int_fast64_t; + typedef unsigned __int8 uint_fast8_t; + typedef unsigned __int16 uint_fast16_t; + typedef unsigned __int32 uint_fast32_t; + typedef unsigned __int64 uint_fast64_t; + typedef __int64 intmax_t; + typedef unsigned __int64 uintmax_t; +# else +# include +# endif +# if _MSC_VER < 1800 /* MSVC < 2013 */ +# ifndef __cplusplus + typedef unsigned char _Bool; +# endif +# endif +#else +# include +# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) +# include +# endif +#endif +''' diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/verifier.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/verifier.py new file mode 100644 index 0000000..59b78c2 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cffi/verifier.py @@ -0,0 +1,306 @@ +# +# DEPRECATED: implementation for ffi.verify() +# +import sys, os, binascii, shutil, io +from . import __version_verifier_modules__ +from . import ffiplatform +from .error import VerificationError + +if sys.version_info >= (3, 3): + import importlib.machinery + def _extension_suffixes(): + return importlib.machinery.EXTENSION_SUFFIXES[:] +else: + import imp + def _extension_suffixes(): + return [suffix for suffix, _, type in imp.get_suffixes() + if type == imp.C_EXTENSION] + + +if sys.version_info >= (3,): + NativeIO = io.StringIO +else: + class NativeIO(io.BytesIO): + def write(self, s): + if isinstance(s, unicode): + s = s.encode('ascii') + super(NativeIO, self).write(s) + + +class Verifier(object): + + def __init__(self, ffi, preamble, tmpdir=None, modulename=None, + ext_package=None, tag='', force_generic_engine=False, + source_extension='.c', flags=None, relative_to=None, **kwds): + if ffi._parser._uses_new_feature: + raise VerificationError( + "feature not supported with ffi.verify(), but only " + "with ffi.set_source(): %s" % (ffi._parser._uses_new_feature,)) + self.ffi = ffi + self.preamble = preamble + if not modulename: + flattened_kwds = ffiplatform.flatten(kwds) + vengine_class = _locate_engine_class(ffi, force_generic_engine) + self._vengine = vengine_class(self) + self._vengine.patch_extension_kwds(kwds) + self.flags = flags + self.kwds = self.make_relative_to(kwds, relative_to) + # + if modulename: + if tag: + raise TypeError("can't specify both 'modulename' and 'tag'") + else: + key = '\x00'.join([sys.version[:3], __version_verifier_modules__, + preamble, flattened_kwds] + + ffi._cdefsources) + if sys.version_info >= (3,): + key = key.encode('utf-8') + k1 = hex(binascii.crc32(key[0::2]) & 0xffffffff) + k1 = k1.lstrip('0x').rstrip('L') + k2 = hex(binascii.crc32(key[1::2]) & 0xffffffff) + k2 = k2.lstrip('0').rstrip('L') + modulename = '_cffi_%s_%s%s%s' % (tag, self._vengine._class_key, + k1, k2) + suffix = _get_so_suffixes()[0] + self.tmpdir = tmpdir or _caller_dir_pycache() + self.sourcefilename = os.path.join(self.tmpdir, modulename + source_extension) + self.modulefilename = os.path.join(self.tmpdir, modulename + suffix) + self.ext_package = ext_package + self._has_source = False + self._has_module = False + + def write_source(self, file=None): + """Write the C source code. It is produced in 'self.sourcefilename', + which can be tweaked beforehand.""" + with self.ffi._lock: + if self._has_source and file is None: + raise VerificationError( + "source code already written") + self._write_source(file) + + def compile_module(self): + """Write the C source code (if not done already) and compile it. + This produces a dynamic link library in 'self.modulefilename'.""" + with self.ffi._lock: + if self._has_module: + raise VerificationError("module already compiled") + if not self._has_source: + self._write_source() + self._compile_module() + + def load_library(self): + """Get a C module from this Verifier instance. + Returns an instance of a FFILibrary class that behaves like the + objects returned by ffi.dlopen(), but that delegates all + operations to the C module. If necessary, the C code is written + and compiled first. + """ + with self.ffi._lock: + if not self._has_module: + self._locate_module() + if not self._has_module: + if not self._has_source: + self._write_source() + self._compile_module() + return self._load_library() + + def get_module_name(self): + basename = os.path.basename(self.modulefilename) + # kill both the .so extension and the other .'s, as introduced + # by Python 3: 'basename.cpython-33m.so' + basename = basename.split('.', 1)[0] + # and the _d added in Python 2 debug builds --- but try to be + # conservative and not kill a legitimate _d + if basename.endswith('_d') and hasattr(sys, 'gettotalrefcount'): + basename = basename[:-2] + return basename + + def get_extension(self): + ffiplatform._hack_at_distutils() # backward compatibility hack + if not self._has_source: + with self.ffi._lock: + if not self._has_source: + self._write_source() + sourcename = ffiplatform.maybe_relative_path(self.sourcefilename) + modname = self.get_module_name() + return ffiplatform.get_extension(sourcename, modname, **self.kwds) + + def generates_python_module(self): + return self._vengine._gen_python_module + + def make_relative_to(self, kwds, relative_to): + if relative_to and os.path.dirname(relative_to): + dirname = os.path.dirname(relative_to) + kwds = kwds.copy() + for key in ffiplatform.LIST_OF_FILE_NAMES: + if key in kwds: + lst = kwds[key] + if not isinstance(lst, (list, tuple)): + raise TypeError("keyword '%s' should be a list or tuple" + % (key,)) + lst = [os.path.join(dirname, fn) for fn in lst] + kwds[key] = lst + return kwds + + # ---------- + + def _locate_module(self): + if not os.path.isfile(self.modulefilename): + if self.ext_package: + try: + pkg = __import__(self.ext_package, None, None, ['__doc__']) + except ImportError: + return # cannot import the package itself, give up + # (e.g. it might be called differently before installation) + path = pkg.__path__ + else: + path = None + filename = self._vengine.find_module(self.get_module_name(), path, + _get_so_suffixes()) + if filename is None: + return + self.modulefilename = filename + self._vengine.collect_types() + self._has_module = True + + def _write_source_to(self, file): + self._vengine._f = file + try: + self._vengine.write_source_to_f() + finally: + del self._vengine._f + + def _write_source(self, file=None): + if file is not None: + self._write_source_to(file) + else: + # Write our source file to an in memory file. + f = NativeIO() + self._write_source_to(f) + source_data = f.getvalue() + + # Determine if this matches the current file + if os.path.exists(self.sourcefilename): + with open(self.sourcefilename, "r") as fp: + needs_written = not (fp.read() == source_data) + else: + needs_written = True + + # Actually write the file out if it doesn't match + if needs_written: + _ensure_dir(self.sourcefilename) + with open(self.sourcefilename, "w") as fp: + fp.write(source_data) + + # Set this flag + self._has_source = True + + def _compile_module(self): + # compile this C source + tmpdir = os.path.dirname(self.sourcefilename) + outputfilename = ffiplatform.compile(tmpdir, self.get_extension()) + try: + same = ffiplatform.samefile(outputfilename, self.modulefilename) + except OSError: + same = False + if not same: + _ensure_dir(self.modulefilename) + shutil.move(outputfilename, self.modulefilename) + self._has_module = True + + def _load_library(self): + assert self._has_module + if self.flags is not None: + return self._vengine.load_library(self.flags) + else: + return self._vengine.load_library() + +# ____________________________________________________________ + +_FORCE_GENERIC_ENGINE = False # for tests + +def _locate_engine_class(ffi, force_generic_engine): + if _FORCE_GENERIC_ENGINE: + force_generic_engine = True + if not force_generic_engine: + if '__pypy__' in sys.builtin_module_names: + force_generic_engine = True + else: + try: + import _cffi_backend + except ImportError: + _cffi_backend = '?' + if ffi._backend is not _cffi_backend: + force_generic_engine = True + if force_generic_engine: + from . import vengine_gen + return vengine_gen.VGenericEngine + else: + from . import vengine_cpy + return vengine_cpy.VCPythonEngine + +# ____________________________________________________________ + +_TMPDIR = None + +def _caller_dir_pycache(): + if _TMPDIR: + return _TMPDIR + result = os.environ.get('CFFI_TMPDIR') + if result: + return result + filename = sys._getframe(2).f_code.co_filename + return os.path.abspath(os.path.join(os.path.dirname(filename), + '__pycache__')) + +def set_tmpdir(dirname): + """Set the temporary directory to use instead of __pycache__.""" + global _TMPDIR + _TMPDIR = dirname + +def cleanup_tmpdir(tmpdir=None, keep_so=False): + """Clean up the temporary directory by removing all files in it + called `_cffi_*.{c,so}` as well as the `build` subdirectory.""" + tmpdir = tmpdir or _caller_dir_pycache() + try: + filelist = os.listdir(tmpdir) + except OSError: + return + if keep_so: + suffix = '.c' # only remove .c files + else: + suffix = _get_so_suffixes()[0].lower() + for fn in filelist: + if fn.lower().startswith('_cffi_') and ( + fn.lower().endswith(suffix) or fn.lower().endswith('.c')): + try: + os.unlink(os.path.join(tmpdir, fn)) + except OSError: + pass + clean_dir = [os.path.join(tmpdir, 'build')] + for dir in clean_dir: + try: + for fn in os.listdir(dir): + fn = os.path.join(dir, fn) + if os.path.isdir(fn): + clean_dir.append(fn) + else: + os.unlink(fn) + except OSError: + pass + +def _get_so_suffixes(): + suffixes = _extension_suffixes() + if not suffixes: + # bah, no C_EXTENSION available. Occurs on pypy without cpyext + if sys.platform == 'win32': + suffixes = [".pyd"] + else: + suffixes = [".so"] + + return suffixes + +def _ensure_dir(filename): + dirname = os.path.dirname(filename) + if dirname and not os.path.isdir(dirname): + os.makedirs(dirname) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/DESCRIPTION.rst b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/DESCRIPTION.rst new file mode 100644 index 0000000..c0f044d --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/DESCRIPTION.rst @@ -0,0 +1,70 @@ +Chardet: The Universal Character Encoding Detector +-------------------------------------------------- + +.. image:: https://img.shields.io/travis/chardet/chardet/stable.svg + :alt: Build status + :target: https://travis-ci.org/chardet/chardet + +.. image:: https://img.shields.io/coveralls/chardet/chardet/stable.svg + :target: https://coveralls.io/r/chardet/chardet + +.. image:: https://img.shields.io/pypi/v/chardet.svg + :target: https://warehouse.python.org/project/chardet/ + :alt: Latest version on PyPI + +.. image:: https://img.shields.io/pypi/l/chardet.svg + :alt: License + + +Detects + - ASCII, UTF-8, UTF-16 (2 variants), UTF-32 (4 variants) + - Big5, GB2312, EUC-TW, HZ-GB-2312, ISO-2022-CN (Traditional and Simplified Chinese) + - EUC-JP, SHIFT_JIS, CP932, ISO-2022-JP (Japanese) + - EUC-KR, ISO-2022-KR (Korean) + - KOI8-R, MacCyrillic, IBM855, IBM866, ISO-8859-5, windows-1251 (Cyrillic) + - ISO-8859-5, windows-1251 (Bulgarian) + - ISO-8859-1, windows-1252 (Western European languages) + - ISO-8859-7, windows-1253 (Greek) + - ISO-8859-8, windows-1255 (Visual and Logical Hebrew) + - TIS-620 (Thai) + +.. note:: + Our ISO-8859-2 and windows-1250 (Hungarian) probers have been temporarily + disabled until we can retrain the models. + +Requires Python 2.6, 2.7, or 3.3+. + +Installation +------------ + +Install from `PyPI `_:: + + pip install chardet + +Documentation +------------- + +For users, docs are now available at https://chardet.readthedocs.io/. + +Command-line Tool +----------------- + +chardet comes with a command-line script which reports on the encodings of one +or more files:: + + % chardetect somefile someotherfile + somefile: windows-1252 with confidence 0.5 + someotherfile: ascii with confidence 1.0 + +About +----- + +This is a continuation of Mark Pilgrim's excellent chardet. Previously, two +versions needed to be maintained: one that supported python 2.x and one that +supported python 3.x. We've recently merged with `Ian Cordasco `_'s +`charade `_ fork, so now we have one +coherent version that works for Python 2.6+. + +:maintainer: Dan Blanchard + + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/INSTALLER b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/METADATA b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/METADATA new file mode 100644 index 0000000..1427867 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/METADATA @@ -0,0 +1,96 @@ +Metadata-Version: 2.0 +Name: chardet +Version: 3.0.4 +Summary: Universal encoding detector for Python 2 and 3 +Home-page: https://github.com/chardet/chardet +Author: Daniel Blanchard +Author-email: dan.blanchard@gmail.com +License: LGPL +Keywords: encoding,i18n,xml +Platform: UNKNOWN +Classifier: Development Status :: 4 - Beta +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL) +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Text Processing :: Linguistic + +Chardet: The Universal Character Encoding Detector +-------------------------------------------------- + +.. image:: https://img.shields.io/travis/chardet/chardet/stable.svg + :alt: Build status + :target: https://travis-ci.org/chardet/chardet + +.. image:: https://img.shields.io/coveralls/chardet/chardet/stable.svg + :target: https://coveralls.io/r/chardet/chardet + +.. image:: https://img.shields.io/pypi/v/chardet.svg + :target: https://warehouse.python.org/project/chardet/ + :alt: Latest version on PyPI + +.. image:: https://img.shields.io/pypi/l/chardet.svg + :alt: License + + +Detects + - ASCII, UTF-8, UTF-16 (2 variants), UTF-32 (4 variants) + - Big5, GB2312, EUC-TW, HZ-GB-2312, ISO-2022-CN (Traditional and Simplified Chinese) + - EUC-JP, SHIFT_JIS, CP932, ISO-2022-JP (Japanese) + - EUC-KR, ISO-2022-KR (Korean) + - KOI8-R, MacCyrillic, IBM855, IBM866, ISO-8859-5, windows-1251 (Cyrillic) + - ISO-8859-5, windows-1251 (Bulgarian) + - ISO-8859-1, windows-1252 (Western European languages) + - ISO-8859-7, windows-1253 (Greek) + - ISO-8859-8, windows-1255 (Visual and Logical Hebrew) + - TIS-620 (Thai) + +.. note:: + Our ISO-8859-2 and windows-1250 (Hungarian) probers have been temporarily + disabled until we can retrain the models. + +Requires Python 2.6, 2.7, or 3.3+. + +Installation +------------ + +Install from `PyPI `_:: + + pip install chardet + +Documentation +------------- + +For users, docs are now available at https://chardet.readthedocs.io/. + +Command-line Tool +----------------- + +chardet comes with a command-line script which reports on the encodings of one +or more files:: + + % chardetect somefile someotherfile + somefile: windows-1252 with confidence 0.5 + someotherfile: ascii with confidence 1.0 + +About +----- + +This is a continuation of Mark Pilgrim's excellent chardet. Previously, two +versions needed to be maintained: one that supported python 2.x and one that +supported python 3.x. We've recently merged with `Ian Cordasco `_'s +`charade `_ fork, so now we have one +coherent version that works for Python 2.6+. + +:maintainer: Dan Blanchard + + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/RECORD b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/RECORD new file mode 100644 index 0000000..185e7c0 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/RECORD @@ -0,0 +1,91 @@ +../../../bin/chardetect,sha256=qJtcYl-HzPNgJmqGKT0ut8NNbB6uRtmU6d_qTf4tx8w,306 +chardet-3.0.4.dist-info/DESCRIPTION.rst,sha256=PQ4sBsMyKFZkjC6QpmbpLn0UtCNyeb-ZqvCGEgyZMGk,2174 +chardet-3.0.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +chardet-3.0.4.dist-info/METADATA,sha256=RV_2I4B1Z586DL8oVO5Kp7X5bUdQ5EuKAvNoAEF8wSw,3239 +chardet-3.0.4.dist-info/RECORD,, +chardet-3.0.4.dist-info/WHEEL,sha256=o2k-Qa-RMNIJmUdIc7KU6VWR_ErNRbWNlxDIpl7lm34,110 +chardet-3.0.4.dist-info/entry_points.txt,sha256=fAMmhu5eJ-zAJ-smfqQwRClQ3-nozOCmvJ6-E8lgGJo,60 +chardet-3.0.4.dist-info/metadata.json,sha256=0htbRM18ujyGZDdfowgAqj6Hq2eQtwzwyhaEveKntgo,1375 +chardet-3.0.4.dist-info/top_level.txt,sha256=AowzBbZy4x8EirABDdJSLJZMkJ_53iIag8xfKR6D7kI,8 +chardet/__init__.py,sha256=YsP5wQlsHJ2auF1RZJfypiSrCA7_bQiRm3ES_NI76-Y,1559 +chardet/__pycache__/__init__.cpython-38.pyc,, +chardet/__pycache__/big5freq.cpython-38.pyc,, +chardet/__pycache__/big5prober.cpython-38.pyc,, +chardet/__pycache__/chardistribution.cpython-38.pyc,, +chardet/__pycache__/charsetgroupprober.cpython-38.pyc,, +chardet/__pycache__/charsetprober.cpython-38.pyc,, +chardet/__pycache__/codingstatemachine.cpython-38.pyc,, +chardet/__pycache__/compat.cpython-38.pyc,, +chardet/__pycache__/cp949prober.cpython-38.pyc,, +chardet/__pycache__/enums.cpython-38.pyc,, +chardet/__pycache__/escprober.cpython-38.pyc,, +chardet/__pycache__/escsm.cpython-38.pyc,, +chardet/__pycache__/eucjpprober.cpython-38.pyc,, +chardet/__pycache__/euckrfreq.cpython-38.pyc,, +chardet/__pycache__/euckrprober.cpython-38.pyc,, +chardet/__pycache__/euctwfreq.cpython-38.pyc,, +chardet/__pycache__/euctwprober.cpython-38.pyc,, +chardet/__pycache__/gb2312freq.cpython-38.pyc,, +chardet/__pycache__/gb2312prober.cpython-38.pyc,, +chardet/__pycache__/hebrewprober.cpython-38.pyc,, +chardet/__pycache__/jisfreq.cpython-38.pyc,, +chardet/__pycache__/jpcntx.cpython-38.pyc,, +chardet/__pycache__/langbulgarianmodel.cpython-38.pyc,, +chardet/__pycache__/langcyrillicmodel.cpython-38.pyc,, +chardet/__pycache__/langgreekmodel.cpython-38.pyc,, +chardet/__pycache__/langhebrewmodel.cpython-38.pyc,, +chardet/__pycache__/langhungarianmodel.cpython-38.pyc,, +chardet/__pycache__/langthaimodel.cpython-38.pyc,, +chardet/__pycache__/langturkishmodel.cpython-38.pyc,, +chardet/__pycache__/latin1prober.cpython-38.pyc,, +chardet/__pycache__/mbcharsetprober.cpython-38.pyc,, +chardet/__pycache__/mbcsgroupprober.cpython-38.pyc,, +chardet/__pycache__/mbcssm.cpython-38.pyc,, +chardet/__pycache__/sbcharsetprober.cpython-38.pyc,, +chardet/__pycache__/sbcsgroupprober.cpython-38.pyc,, +chardet/__pycache__/sjisprober.cpython-38.pyc,, +chardet/__pycache__/universaldetector.cpython-38.pyc,, +chardet/__pycache__/utf8prober.cpython-38.pyc,, +chardet/__pycache__/version.cpython-38.pyc,, +chardet/big5freq.py,sha256=D_zK5GyzoVsRes0HkLJziltFQX0bKCLOrFe9_xDvO_8,31254 +chardet/big5prober.py,sha256=kBxHbdetBpPe7xrlb-e990iot64g_eGSLd32lB7_h3M,1757 +chardet/chardistribution.py,sha256=3woWS62KrGooKyqz4zQSnjFbJpa6V7g02daAibTwcl8,9411 +chardet/charsetgroupprober.py,sha256=6bDu8YIiRuScX4ca9Igb0U69TA2PGXXDej6Cc4_9kO4,3787 +chardet/charsetprober.py,sha256=KSmwJErjypyj0bRZmC5F5eM7c8YQgLYIjZXintZNstg,5110 +chardet/cli/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 +chardet/cli/__pycache__/__init__.cpython-38.pyc,, +chardet/cli/__pycache__/chardetect.cpython-38.pyc,, +chardet/cli/chardetect.py,sha256=YBO8L4mXo0WR6_-Fjh_8QxPBoEBNqB9oNxNrdc54AQs,2738 +chardet/codingstatemachine.py,sha256=VYp_6cyyki5sHgXDSZnXW4q1oelHc3cu9AyQTX7uug8,3590 +chardet/compat.py,sha256=PKTzHkSbtbHDqS9PyujMbX74q1a8mMpeQTDVsQhZMRw,1134 +chardet/cp949prober.py,sha256=TZ434QX8zzBsnUvL_8wm4AQVTZ2ZkqEEQL_lNw9f9ow,1855 +chardet/enums.py,sha256=Aimwdb9as1dJKZaFNUH2OhWIVBVd6ZkJJ_WK5sNY8cU,1661 +chardet/escprober.py,sha256=kkyqVg1Yw3DIOAMJ2bdlyQgUFQhuHAW8dUGskToNWSc,3950 +chardet/escsm.py,sha256=RuXlgNvTIDarndvllNCk5WZBIpdCxQ0kcd9EAuxUh84,10510 +chardet/eucjpprober.py,sha256=iD8Jdp0ISRjgjiVN7f0e8xGeQJ5GM2oeZ1dA8nbSeUw,3749 +chardet/euckrfreq.py,sha256=-7GdmvgWez4-eO4SuXpa7tBiDi5vRXQ8WvdFAzVaSfo,13546 +chardet/euckrprober.py,sha256=MqFMTQXxW4HbzIpZ9lKDHB3GN8SP4yiHenTmf8g_PxY,1748 +chardet/euctwfreq.py,sha256=No1WyduFOgB5VITUA7PLyC5oJRNzRyMbBxaKI1l16MA,31621 +chardet/euctwprober.py,sha256=13p6EP4yRaxqnP4iHtxHOJ6R2zxHq1_m8hTRjzVZ95c,1747 +chardet/gb2312freq.py,sha256=JX8lsweKLmnCwmk8UHEQsLgkr_rP_kEbvivC4qPOrlc,20715 +chardet/gb2312prober.py,sha256=gGvIWi9WhDjE-xQXHvNIyrnLvEbMAYgyUSZ65HUfylw,1754 +chardet/hebrewprober.py,sha256=c3SZ-K7hvyzGY6JRAZxJgwJ_sUS9k0WYkvMY00YBYFo,13838 +chardet/jisfreq.py,sha256=vpmJv2Bu0J8gnMVRPHMFefTRvo_ha1mryLig8CBwgOg,25777 +chardet/jpcntx.py,sha256=PYlNqRUQT8LM3cT5FmHGP0iiscFlTWED92MALvBungo,19643 +chardet/langbulgarianmodel.py,sha256=1HqQS9Pbtnj1xQgxitJMvw8X6kKr5OockNCZWfEQrPE,12839 +chardet/langcyrillicmodel.py,sha256=LODajvsetH87yYDDQKA2CULXUH87tI223dhfjh9Zx9c,17948 +chardet/langgreekmodel.py,sha256=8YAW7bU8YwSJap0kIJSbPMw1BEqzGjWzqcqf0WgUKAA,12688 +chardet/langhebrewmodel.py,sha256=JSnqmE5E62tDLTPTvLpQsg5gOMO4PbdWRvV7Avkc0HA,11345 +chardet/langhungarianmodel.py,sha256=RhapYSG5l0ZaO-VV4Fan5sW0WRGQqhwBM61yx3yxyOA,12592 +chardet/langthaimodel.py,sha256=8l0173Gu_W6G8mxmQOTEF4ls2YdE7FxWf3QkSxEGXJQ,11290 +chardet/langturkishmodel.py,sha256=W22eRNJsqI6uWAfwXSKVWWnCerYqrI8dZQTm_M0lRFk,11102 +chardet/latin1prober.py,sha256=S2IoORhFk39FEFOlSFWtgVybRiP6h7BlLldHVclNkU8,5370 +chardet/mbcharsetprober.py,sha256=AR95eFH9vuqSfvLQZN-L5ijea25NOBCoXqw8s5O9xLQ,3413 +chardet/mbcsgroupprober.py,sha256=h6TRnnYq2OxG1WdD5JOyxcdVpn7dG0q-vB8nWr5mbh4,2012 +chardet/mbcssm.py,sha256=SY32wVIF3HzcjY3BaEspy9metbNSKxIIB0RKPn7tjpI,25481 +chardet/sbcharsetprober.py,sha256=LDSpCldDCFlYwUkGkwD2oFxLlPWIWXT09akH_2PiY74,5657 +chardet/sbcsgroupprober.py,sha256=1IprcCB_k1qfmnxGC6MBbxELlKqD3scW6S8YIwdeyXA,3546 +chardet/sjisprober.py,sha256=IIt-lZj0WJqK4rmUZzKZP4GJlE8KUEtFYVuY96ek5MQ,3774 +chardet/universaldetector.py,sha256=qL0174lSZE442eB21nnktT9_VcAye07laFWUeUrjttY,12485 +chardet/utf8prober.py,sha256=IdD8v3zWOsB8OLiyPi-y_fqwipRFxV9Nc1eKBLSuIEw,2766 +chardet/version.py,sha256=sp3B08mrDXB-pf3K9fqJ_zeDHOCLC8RrngQyDFap_7g,242 diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/WHEEL b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/WHEEL new file mode 100644 index 0000000..8b6dd1b --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.29.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/entry_points.txt b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/entry_points.txt new file mode 100644 index 0000000..a884269 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[console_scripts] +chardetect = chardet.cli.chardetect:main + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/metadata.json b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/metadata.json new file mode 100644 index 0000000..8cdf025 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/metadata.json @@ -0,0 +1 @@ +{"classifiers": ["Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL)", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Topic :: Software Development :: Libraries :: Python Modules", "Topic :: Text Processing :: Linguistic"], "extensions": {"python.commands": {"wrap_console": {"chardetect": "chardet.cli.chardetect:main"}}, "python.details": {"contacts": [{"email": "dan.blanchard@gmail.com", "name": "Daniel Blanchard", "role": "author"}], "document_names": {"description": "DESCRIPTION.rst"}, "project_urls": {"Home": "https://github.com/chardet/chardet"}}, "python.exports": {"console_scripts": {"chardetect": "chardet.cli.chardetect:main"}}}, "generator": "bdist_wheel (0.29.0)", "keywords": ["encoding", "i18n", "xml"], "license": "LGPL", "metadata_version": "2.0", "name": "chardet", "summary": "Universal encoding detector for Python 2 and 3", "test_requires": [{"requires": ["hypothesis", "pytest"]}], "version": "3.0.4"} \ No newline at end of file diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/top_level.txt b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/top_level.txt new file mode 100644 index 0000000..79236f2 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet-3.0.4.dist-info/top_level.txt @@ -0,0 +1 @@ +chardet diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/__init__.py new file mode 100644 index 0000000..0f9f820 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/__init__.py @@ -0,0 +1,39 @@ +######################## BEGIN LICENSE BLOCK ######################## +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + + +from .compat import PY2, PY3 +from .universaldetector import UniversalDetector +from .version import __version__, VERSION + + +def detect(byte_str): + """ + Detect the encoding of the given byte string. + + :param byte_str: The byte sequence to examine. + :type byte_str: ``bytes`` or ``bytearray`` + """ + if not isinstance(byte_str, bytearray): + if not isinstance(byte_str, bytes): + raise TypeError('Expected object of type bytes or bytearray, got: ' + '{0}'.format(type(byte_str))) + else: + byte_str = bytearray(byte_str) + detector = UniversalDetector() + detector.feed(byte_str) + return detector.close() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/big5freq.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/big5freq.py new file mode 100644 index 0000000..38f3251 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/big5freq.py @@ -0,0 +1,386 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# Big5 frequency table +# by Taiwan's Mandarin Promotion Council +# +# +# 128 --> 0.42261 +# 256 --> 0.57851 +# 512 --> 0.74851 +# 1024 --> 0.89384 +# 2048 --> 0.97583 +# +# Ideal Distribution Ratio = 0.74851/(1-0.74851) =2.98 +# Random Distribution Ration = 512/(5401-512)=0.105 +# +# Typical Distribution Ratio about 25% of Ideal one, still much higher than RDR + +BIG5_TYPICAL_DISTRIBUTION_RATIO = 0.75 + +#Char to FreqOrder table +BIG5_TABLE_SIZE = 5376 + +BIG5_CHAR_TO_FREQ_ORDER = ( + 1,1801,1506, 255,1431, 198, 9, 82, 6,5008, 177, 202,3681,1256,2821, 110, # 16 +3814, 33,3274, 261, 76, 44,2114, 16,2946,2187,1176, 659,3971, 26,3451,2653, # 32 +1198,3972,3350,4202, 410,2215, 302, 590, 361,1964, 8, 204, 58,4510,5009,1932, # 48 + 63,5010,5011, 317,1614, 75, 222, 159,4203,2417,1480,5012,3555,3091, 224,2822, # 64 +3682, 3, 10,3973,1471, 29,2787,1135,2866,1940, 873, 130,3275,1123, 312,5013, # 80 +4511,2052, 507, 252, 682,5014, 142,1915, 124, 206,2947, 34,3556,3204, 64, 604, # 96 +5015,2501,1977,1978, 155,1991, 645, 641,1606,5016,3452, 337, 72, 406,5017, 80, # 112 + 630, 238,3205,1509, 263, 939,1092,2654, 756,1440,1094,3453, 449, 69,2987, 591, # 128 + 179,2096, 471, 115,2035,1844, 60, 50,2988, 134, 806,1869, 734,2036,3454, 180, # 144 + 995,1607, 156, 537,2907, 688,5018, 319,1305, 779,2145, 514,2379, 298,4512, 359, # 160 +2502, 90,2716,1338, 663, 11, 906,1099,2553, 20,2441, 182, 532,1716,5019, 732, # 176 +1376,4204,1311,1420,3206, 25,2317,1056, 113, 399, 382,1950, 242,3455,2474, 529, # 192 +3276, 475,1447,3683,5020, 117, 21, 656, 810,1297,2300,2334,3557,5021, 126,4205, # 208 + 706, 456, 150, 613,4513, 71,1118,2037,4206, 145,3092, 85, 835, 486,2115,1246, # 224 +1426, 428, 727,1285,1015, 800, 106, 623, 303,1281,5022,2128,2359, 347,3815, 221, # 240 +3558,3135,5023,1956,1153,4207, 83, 296,1199,3093, 192, 624, 93,5024, 822,1898, # 256 +2823,3136, 795,2065, 991,1554,1542,1592, 27, 43,2867, 859, 139,1456, 860,4514, # 272 + 437, 712,3974, 164,2397,3137, 695, 211,3037,2097, 195,3975,1608,3559,3560,3684, # 288 +3976, 234, 811,2989,2098,3977,2233,1441,3561,1615,2380, 668,2077,1638, 305, 228, # 304 +1664,4515, 467, 415,5025, 262,2099,1593, 239, 108, 300, 200,1033, 512,1247,2078, # 320 +5026,5027,2176,3207,3685,2682, 593, 845,1062,3277, 88,1723,2038,3978,1951, 212, # 336 + 266, 152, 149, 468,1899,4208,4516, 77, 187,5028,3038, 37, 5,2990,5029,3979, # 352 +5030,5031, 39,2524,4517,2908,3208,2079, 55, 148, 74,4518, 545, 483,1474,1029, # 368 +1665, 217,1870,1531,3138,1104,2655,4209, 24, 172,3562, 900,3980,3563,3564,4519, # 384 + 32,1408,2824,1312, 329, 487,2360,2251,2717, 784,2683, 4,3039,3351,1427,1789, # 400 + 188, 109, 499,5032,3686,1717,1790, 888,1217,3040,4520,5033,3565,5034,3352,1520, # 416 +3687,3981, 196,1034, 775,5035,5036, 929,1816, 249, 439, 38,5037,1063,5038, 794, # 432 +3982,1435,2301, 46, 178,3278,2066,5039,2381,5040, 214,1709,4521, 804, 35, 707, # 448 + 324,3688,1601,2554, 140, 459,4210,5041,5042,1365, 839, 272, 978,2262,2580,3456, # 464 +2129,1363,3689,1423, 697, 100,3094, 48, 70,1231, 495,3139,2196,5043,1294,5044, # 480 +2080, 462, 586,1042,3279, 853, 256, 988, 185,2382,3457,1698, 434,1084,5045,3458, # 496 + 314,2625,2788,4522,2335,2336, 569,2285, 637,1817,2525, 757,1162,1879,1616,3459, # 512 + 287,1577,2116, 768,4523,1671,2868,3566,2526,1321,3816, 909,2418,5046,4211, 933, # 528 +3817,4212,2053,2361,1222,4524, 765,2419,1322, 786,4525,5047,1920,1462,1677,2909, # 544 +1699,5048,4526,1424,2442,3140,3690,2600,3353,1775,1941,3460,3983,4213, 309,1369, # 560 +1130,2825, 364,2234,1653,1299,3984,3567,3985,3986,2656, 525,1085,3041, 902,2001, # 576 +1475, 964,4527, 421,1845,1415,1057,2286, 940,1364,3141, 376,4528,4529,1381, 7, # 592 +2527, 983,2383, 336,1710,2684,1846, 321,3461, 559,1131,3042,2752,1809,1132,1313, # 608 + 265,1481,1858,5049, 352,1203,2826,3280, 167,1089, 420,2827, 776, 792,1724,3568, # 624 +4214,2443,3281,5050,4215,5051, 446, 229, 333,2753, 901,3818,1200,1557,4530,2657, # 640 +1921, 395,2754,2685,3819,4216,1836, 125, 916,3209,2626,4531,5052,5053,3820,5054, # 656 +5055,5056,4532,3142,3691,1133,2555,1757,3462,1510,2318,1409,3569,5057,2146, 438, # 672 +2601,2910,2384,3354,1068, 958,3043, 461, 311,2869,2686,4217,1916,3210,4218,1979, # 688 + 383, 750,2755,2627,4219, 274, 539, 385,1278,1442,5058,1154,1965, 384, 561, 210, # 704 + 98,1295,2556,3570,5059,1711,2420,1482,3463,3987,2911,1257, 129,5060,3821, 642, # 720 + 523,2789,2790,2658,5061, 141,2235,1333, 68, 176, 441, 876, 907,4220, 603,2602, # 736 + 710, 171,3464, 404, 549, 18,3143,2398,1410,3692,1666,5062,3571,4533,2912,4534, # 752 +5063,2991, 368,5064, 146, 366, 99, 871,3693,1543, 748, 807,1586,1185, 22,2263, # 768 + 379,3822,3211,5065,3212, 505,1942,2628,1992,1382,2319,5066, 380,2362, 218, 702, # 784 +1818,1248,3465,3044,3572,3355,3282,5067,2992,3694, 930,3283,3823,5068, 59,5069, # 800 + 585, 601,4221, 497,3466,1112,1314,4535,1802,5070,1223,1472,2177,5071, 749,1837, # 816 + 690,1900,3824,1773,3988,1476, 429,1043,1791,2236,2117, 917,4222, 447,1086,1629, # 832 +5072, 556,5073,5074,2021,1654, 844,1090, 105, 550, 966,1758,2828,1008,1783, 686, # 848 +1095,5075,2287, 793,1602,5076,3573,2603,4536,4223,2948,2302,4537,3825, 980,2503, # 864 + 544, 353, 527,4538, 908,2687,2913,5077, 381,2629,1943,1348,5078,1341,1252, 560, # 880 +3095,5079,3467,2870,5080,2054, 973, 886,2081, 143,4539,5081,5082, 157,3989, 496, # 896 +4224, 57, 840, 540,2039,4540,4541,3468,2118,1445, 970,2264,1748,1966,2082,4225, # 912 +3144,1234,1776,3284,2829,3695, 773,1206,2130,1066,2040,1326,3990,1738,1725,4226, # 928 + 279,3145, 51,1544,2604, 423,1578,2131,2067, 173,4542,1880,5083,5084,1583, 264, # 944 + 610,3696,4543,2444, 280, 154,5085,5086,5087,1739, 338,1282,3096, 693,2871,1411, # 960 +1074,3826,2445,5088,4544,5089,5090,1240, 952,2399,5091,2914,1538,2688, 685,1483, # 976 +4227,2475,1436, 953,4228,2055,4545, 671,2400, 79,4229,2446,3285, 608, 567,2689, # 992 +3469,4230,4231,1691, 393,1261,1792,2401,5092,4546,5093,5094,5095,5096,1383,1672, # 1008 +3827,3213,1464, 522,1119, 661,1150, 216, 675,4547,3991,1432,3574, 609,4548,2690, # 1024 +2402,5097,5098,5099,4232,3045, 0,5100,2476, 315, 231,2447, 301,3356,4549,2385, # 1040 +5101, 233,4233,3697,1819,4550,4551,5102, 96,1777,1315,2083,5103, 257,5104,1810, # 1056 +3698,2718,1139,1820,4234,2022,1124,2164,2791,1778,2659,5105,3097, 363,1655,3214, # 1072 +5106,2993,5107,5108,5109,3992,1567,3993, 718, 103,3215, 849,1443, 341,3357,2949, # 1088 +1484,5110,1712, 127, 67, 339,4235,2403, 679,1412, 821,5111,5112, 834, 738, 351, # 1104 +2994,2147, 846, 235,1497,1881, 418,1993,3828,2719, 186,1100,2148,2756,3575,1545, # 1120 +1355,2950,2872,1377, 583,3994,4236,2581,2995,5113,1298,3699,1078,2557,3700,2363, # 1136 + 78,3829,3830, 267,1289,2100,2002,1594,4237, 348, 369,1274,2197,2178,1838,4552, # 1152 +1821,2830,3701,2757,2288,2003,4553,2951,2758, 144,3358, 882,4554,3995,2759,3470, # 1168 +4555,2915,5114,4238,1726, 320,5115,3996,3046, 788,2996,5116,2831,1774,1327,2873, # 1184 +3997,2832,5117,1306,4556,2004,1700,3831,3576,2364,2660, 787,2023, 506, 824,3702, # 1200 + 534, 323,4557,1044,3359,2024,1901, 946,3471,5118,1779,1500,1678,5119,1882,4558, # 1216 + 165, 243,4559,3703,2528, 123, 683,4239, 764,4560, 36,3998,1793, 589,2916, 816, # 1232 + 626,1667,3047,2237,1639,1555,1622,3832,3999,5120,4000,2874,1370,1228,1933, 891, # 1248 +2084,2917, 304,4240,5121, 292,2997,2720,3577, 691,2101,4241,1115,4561, 118, 662, # 1264 +5122, 611,1156, 854,2386,1316,2875, 2, 386, 515,2918,5123,5124,3286, 868,2238, # 1280 +1486, 855,2661, 785,2216,3048,5125,1040,3216,3578,5126,3146, 448,5127,1525,5128, # 1296 +2165,4562,5129,3833,5130,4242,2833,3579,3147, 503, 818,4001,3148,1568, 814, 676, # 1312 +1444, 306,1749,5131,3834,1416,1030, 197,1428, 805,2834,1501,4563,5132,5133,5134, # 1328 +1994,5135,4564,5136,5137,2198, 13,2792,3704,2998,3149,1229,1917,5138,3835,2132, # 1344 +5139,4243,4565,2404,3580,5140,2217,1511,1727,1120,5141,5142, 646,3836,2448, 307, # 1360 +5143,5144,1595,3217,5145,5146,5147,3705,1113,1356,4002,1465,2529,2530,5148, 519, # 1376 +5149, 128,2133, 92,2289,1980,5150,4003,1512, 342,3150,2199,5151,2793,2218,1981, # 1392 +3360,4244, 290,1656,1317, 789, 827,2365,5152,3837,4566, 562, 581,4004,5153, 401, # 1408 +4567,2252, 94,4568,5154,1399,2794,5155,1463,2025,4569,3218,1944,5156, 828,1105, # 1424 +4245,1262,1394,5157,4246, 605,4570,5158,1784,2876,5159,2835, 819,2102, 578,2200, # 1440 +2952,5160,1502, 436,3287,4247,3288,2836,4005,2919,3472,3473,5161,2721,2320,5162, # 1456 +5163,2337,2068, 23,4571, 193, 826,3838,2103, 699,1630,4248,3098, 390,1794,1064, # 1472 +3581,5164,1579,3099,3100,1400,5165,4249,1839,1640,2877,5166,4572,4573, 137,4250, # 1488 + 598,3101,1967, 780, 104, 974,2953,5167, 278, 899, 253, 402, 572, 504, 493,1339, # 1504 +5168,4006,1275,4574,2582,2558,5169,3706,3049,3102,2253, 565,1334,2722, 863, 41, # 1520 +5170,5171,4575,5172,1657,2338, 19, 463,2760,4251, 606,5173,2999,3289,1087,2085, # 1536 +1323,2662,3000,5174,1631,1623,1750,4252,2691,5175,2878, 791,2723,2663,2339, 232, # 1552 +2421,5176,3001,1498,5177,2664,2630, 755,1366,3707,3290,3151,2026,1609, 119,1918, # 1568 +3474, 862,1026,4253,5178,4007,3839,4576,4008,4577,2265,1952,2477,5179,1125, 817, # 1584 +4254,4255,4009,1513,1766,2041,1487,4256,3050,3291,2837,3840,3152,5180,5181,1507, # 1600 +5182,2692, 733, 40,1632,1106,2879, 345,4257, 841,2531, 230,4578,3002,1847,3292, # 1616 +3475,5183,1263, 986,3476,5184, 735, 879, 254,1137, 857, 622,1300,1180,1388,1562, # 1632 +4010,4011,2954, 967,2761,2665,1349, 592,2134,1692,3361,3003,1995,4258,1679,4012, # 1648 +1902,2188,5185, 739,3708,2724,1296,1290,5186,4259,2201,2202,1922,1563,2605,2559, # 1664 +1871,2762,3004,5187, 435,5188, 343,1108, 596, 17,1751,4579,2239,3477,3709,5189, # 1680 +4580, 294,3582,2955,1693, 477, 979, 281,2042,3583, 643,2043,3710,2631,2795,2266, # 1696 +1031,2340,2135,2303,3584,4581, 367,1249,2560,5190,3585,5191,4582,1283,3362,2005, # 1712 + 240,1762,3363,4583,4584, 836,1069,3153, 474,5192,2149,2532, 268,3586,5193,3219, # 1728 +1521,1284,5194,1658,1546,4260,5195,3587,3588,5196,4261,3364,2693,1685,4262, 961, # 1744 +1673,2632, 190,2006,2203,3841,4585,4586,5197, 570,2504,3711,1490,5198,4587,2633, # 1760 +3293,1957,4588, 584,1514, 396,1045,1945,5199,4589,1968,2449,5200,5201,4590,4013, # 1776 + 619,5202,3154,3294, 215,2007,2796,2561,3220,4591,3221,4592, 763,4263,3842,4593, # 1792 +5203,5204,1958,1767,2956,3365,3712,1174, 452,1477,4594,3366,3155,5205,2838,1253, # 1808 +2387,2189,1091,2290,4264, 492,5206, 638,1169,1825,2136,1752,4014, 648, 926,1021, # 1824 +1324,4595, 520,4596, 997, 847,1007, 892,4597,3843,2267,1872,3713,2405,1785,4598, # 1840 +1953,2957,3103,3222,1728,4265,2044,3714,4599,2008,1701,3156,1551, 30,2268,4266, # 1856 +5207,2027,4600,3589,5208, 501,5209,4267, 594,3478,2166,1822,3590,3479,3591,3223, # 1872 + 829,2839,4268,5210,1680,3157,1225,4269,5211,3295,4601,4270,3158,2341,5212,4602, # 1888 +4271,5213,4015,4016,5214,1848,2388,2606,3367,5215,4603, 374,4017, 652,4272,4273, # 1904 + 375,1140, 798,5216,5217,5218,2366,4604,2269, 546,1659, 138,3051,2450,4605,5219, # 1920 +2254, 612,1849, 910, 796,3844,1740,1371, 825,3845,3846,5220,2920,2562,5221, 692, # 1936 + 444,3052,2634, 801,4606,4274,5222,1491, 244,1053,3053,4275,4276, 340,5223,4018, # 1952 +1041,3005, 293,1168, 87,1357,5224,1539, 959,5225,2240, 721, 694,4277,3847, 219, # 1968 +1478, 644,1417,3368,2666,1413,1401,1335,1389,4019,5226,5227,3006,2367,3159,1826, # 1984 + 730,1515, 184,2840, 66,4607,5228,1660,2958, 246,3369, 378,1457, 226,3480, 975, # 2000 +4020,2959,1264,3592, 674, 696,5229, 163,5230,1141,2422,2167, 713,3593,3370,4608, # 2016 +4021,5231,5232,1186, 15,5233,1079,1070,5234,1522,3224,3594, 276,1050,2725, 758, # 2032 +1126, 653,2960,3296,5235,2342, 889,3595,4022,3104,3007, 903,1250,4609,4023,3481, # 2048 +3596,1342,1681,1718, 766,3297, 286, 89,2961,3715,5236,1713,5237,2607,3371,3008, # 2064 +5238,2962,2219,3225,2880,5239,4610,2505,2533, 181, 387,1075,4024, 731,2190,3372, # 2080 +5240,3298, 310, 313,3482,2304, 770,4278, 54,3054, 189,4611,3105,3848,4025,5241, # 2096 +1230,1617,1850, 355,3597,4279,4612,3373, 111,4280,3716,1350,3160,3483,3055,4281, # 2112 +2150,3299,3598,5242,2797,4026,4027,3009, 722,2009,5243,1071, 247,1207,2343,2478, # 2128 +1378,4613,2010, 864,1437,1214,4614, 373,3849,1142,2220, 667,4615, 442,2763,2563, # 2144 +3850,4028,1969,4282,3300,1840, 837, 170,1107, 934,1336,1883,5244,5245,2119,4283, # 2160 +2841, 743,1569,5246,4616,4284, 582,2389,1418,3484,5247,1803,5248, 357,1395,1729, # 2176 +3717,3301,2423,1564,2241,5249,3106,3851,1633,4617,1114,2086,4285,1532,5250, 482, # 2192 +2451,4618,5251,5252,1492, 833,1466,5253,2726,3599,1641,2842,5254,1526,1272,3718, # 2208 +4286,1686,1795, 416,2564,1903,1954,1804,5255,3852,2798,3853,1159,2321,5256,2881, # 2224 +4619,1610,1584,3056,2424,2764, 443,3302,1163,3161,5257,5258,4029,5259,4287,2506, # 2240 +3057,4620,4030,3162,2104,1647,3600,2011,1873,4288,5260,4289, 431,3485,5261, 250, # 2256 + 97, 81,4290,5262,1648,1851,1558, 160, 848,5263, 866, 740,1694,5264,2204,2843, # 2272 +3226,4291,4621,3719,1687, 950,2479, 426, 469,3227,3720,3721,4031,5265,5266,1188, # 2288 + 424,1996, 861,3601,4292,3854,2205,2694, 168,1235,3602,4293,5267,2087,1674,4622, # 2304 +3374,3303, 220,2565,1009,5268,3855, 670,3010, 332,1208, 717,5269,5270,3603,2452, # 2320 +4032,3375,5271, 513,5272,1209,2882,3376,3163,4623,1080,5273,5274,5275,5276,2534, # 2336 +3722,3604, 815,1587,4033,4034,5277,3605,3486,3856,1254,4624,1328,3058,1390,4035, # 2352 +1741,4036,3857,4037,5278, 236,3858,2453,3304,5279,5280,3723,3859,1273,3860,4625, # 2368 +5281, 308,5282,4626, 245,4627,1852,2480,1307,2583, 430, 715,2137,2454,5283, 270, # 2384 + 199,2883,4038,5284,3606,2727,1753, 761,1754, 725,1661,1841,4628,3487,3724,5285, # 2400 +5286, 587, 14,3305, 227,2608, 326, 480,2270, 943,2765,3607, 291, 650,1884,5287, # 2416 +1702,1226, 102,1547, 62,3488, 904,4629,3489,1164,4294,5288,5289,1224,1548,2766, # 2432 + 391, 498,1493,5290,1386,1419,5291,2056,1177,4630, 813, 880,1081,2368, 566,1145, # 2448 +4631,2291,1001,1035,2566,2609,2242, 394,1286,5292,5293,2069,5294, 86,1494,1730, # 2464 +4039, 491,1588, 745, 897,2963, 843,3377,4040,2767,2884,3306,1768, 998,2221,2070, # 2480 + 397,1827,1195,1970,3725,3011,3378, 284,5295,3861,2507,2138,2120,1904,5296,4041, # 2496 +2151,4042,4295,1036,3490,1905, 114,2567,4296, 209,1527,5297,5298,2964,2844,2635, # 2512 +2390,2728,3164, 812,2568,5299,3307,5300,1559, 737,1885,3726,1210, 885, 28,2695, # 2528 +3608,3862,5301,4297,1004,1780,4632,5302, 346,1982,2222,2696,4633,3863,1742, 797, # 2544 +1642,4043,1934,1072,1384,2152, 896,4044,3308,3727,3228,2885,3609,5303,2569,1959, # 2560 +4634,2455,1786,5304,5305,5306,4045,4298,1005,1308,3728,4299,2729,4635,4636,1528, # 2576 +2610, 161,1178,4300,1983, 987,4637,1101,4301, 631,4046,1157,3229,2425,1343,1241, # 2592 +1016,2243,2570, 372, 877,2344,2508,1160, 555,1935, 911,4047,5307, 466,1170, 169, # 2608 +1051,2921,2697,3729,2481,3012,1182,2012,2571,1251,2636,5308, 992,2345,3491,1540, # 2624 +2730,1201,2071,2406,1997,2482,5309,4638, 528,1923,2191,1503,1874,1570,2369,3379, # 2640 +3309,5310, 557,1073,5311,1828,3492,2088,2271,3165,3059,3107, 767,3108,2799,4639, # 2656 +1006,4302,4640,2346,1267,2179,3730,3230, 778,4048,3231,2731,1597,2667,5312,4641, # 2672 +5313,3493,5314,5315,5316,3310,2698,1433,3311, 131, 95,1504,4049, 723,4303,3166, # 2688 +1842,3610,2768,2192,4050,2028,2105,3731,5317,3013,4051,1218,5318,3380,3232,4052, # 2704 +4304,2584, 248,1634,3864, 912,5319,2845,3732,3060,3865, 654, 53,5320,3014,5321, # 2720 +1688,4642, 777,3494,1032,4053,1425,5322, 191, 820,2121,2846, 971,4643, 931,3233, # 2736 + 135, 664, 783,3866,1998, 772,2922,1936,4054,3867,4644,2923,3234, 282,2732, 640, # 2752 +1372,3495,1127, 922, 325,3381,5323,5324, 711,2045,5325,5326,4055,2223,2800,1937, # 2768 +4056,3382,2224,2255,3868,2305,5327,4645,3869,1258,3312,4057,3235,2139,2965,4058, # 2784 +4059,5328,2225, 258,3236,4646, 101,1227,5329,3313,1755,5330,1391,3314,5331,2924, # 2800 +2057, 893,5332,5333,5334,1402,4305,2347,5335,5336,3237,3611,5337,5338, 878,1325, # 2816 +1781,2801,4647, 259,1385,2585, 744,1183,2272,4648,5339,4060,2509,5340, 684,1024, # 2832 +4306,5341, 472,3612,3496,1165,3315,4061,4062, 322,2153, 881, 455,1695,1152,1340, # 2848 + 660, 554,2154,4649,1058,4650,4307, 830,1065,3383,4063,4651,1924,5342,1703,1919, # 2864 +5343, 932,2273, 122,5344,4652, 947, 677,5345,3870,2637, 297,1906,1925,2274,4653, # 2880 +2322,3316,5346,5347,4308,5348,4309, 84,4310, 112, 989,5349, 547,1059,4064, 701, # 2896 +3613,1019,5350,4311,5351,3497, 942, 639, 457,2306,2456, 993,2966, 407, 851, 494, # 2912 +4654,3384, 927,5352,1237,5353,2426,3385, 573,4312, 680, 921,2925,1279,1875, 285, # 2928 + 790,1448,1984, 719,2168,5354,5355,4655,4065,4066,1649,5356,1541, 563,5357,1077, # 2944 +5358,3386,3061,3498, 511,3015,4067,4068,3733,4069,1268,2572,3387,3238,4656,4657, # 2960 +5359, 535,1048,1276,1189,2926,2029,3167,1438,1373,2847,2967,1134,2013,5360,4313, # 2976 +1238,2586,3109,1259,5361, 700,5362,2968,3168,3734,4314,5363,4315,1146,1876,1907, # 2992 +4658,2611,4070, 781,2427, 132,1589, 203, 147, 273,2802,2407, 898,1787,2155,4071, # 3008 +4072,5364,3871,2803,5365,5366,4659,4660,5367,3239,5368,1635,3872, 965,5369,1805, # 3024 +2699,1516,3614,1121,1082,1329,3317,4073,1449,3873, 65,1128,2848,2927,2769,1590, # 3040 +3874,5370,5371, 12,2668, 45, 976,2587,3169,4661, 517,2535,1013,1037,3240,5372, # 3056 +3875,2849,5373,3876,5374,3499,5375,2612, 614,1999,2323,3877,3110,2733,2638,5376, # 3072 +2588,4316, 599,1269,5377,1811,3735,5378,2700,3111, 759,1060, 489,1806,3388,3318, # 3088 +1358,5379,5380,2391,1387,1215,2639,2256, 490,5381,5382,4317,1759,2392,2348,5383, # 3104 +4662,3878,1908,4074,2640,1807,3241,4663,3500,3319,2770,2349, 874,5384,5385,3501, # 3120 +3736,1859, 91,2928,3737,3062,3879,4664,5386,3170,4075,2669,5387,3502,1202,1403, # 3136 +3880,2969,2536,1517,2510,4665,3503,2511,5388,4666,5389,2701,1886,1495,1731,4076, # 3152 +2370,4667,5390,2030,5391,5392,4077,2702,1216, 237,2589,4318,2324,4078,3881,4668, # 3168 +4669,2703,3615,3504, 445,4670,5393,5394,5395,5396,2771, 61,4079,3738,1823,4080, # 3184 +5397, 687,2046, 935, 925, 405,2670, 703,1096,1860,2734,4671,4081,1877,1367,2704, # 3200 +3389, 918,2106,1782,2483, 334,3320,1611,1093,4672, 564,3171,3505,3739,3390, 945, # 3216 +2641,2058,4673,5398,1926, 872,4319,5399,3506,2705,3112, 349,4320,3740,4082,4674, # 3232 +3882,4321,3741,2156,4083,4675,4676,4322,4677,2408,2047, 782,4084, 400, 251,4323, # 3248 +1624,5400,5401, 277,3742, 299,1265, 476,1191,3883,2122,4324,4325,1109, 205,5402, # 3264 +2590,1000,2157,3616,1861,5403,5404,5405,4678,5406,4679,2573, 107,2484,2158,4085, # 3280 +3507,3172,5407,1533, 541,1301, 158, 753,4326,2886,3617,5408,1696, 370,1088,4327, # 3296 +4680,3618, 579, 327, 440, 162,2244, 269,1938,1374,3508, 968,3063, 56,1396,3113, # 3312 +2107,3321,3391,5409,1927,2159,4681,3016,5410,3619,5411,5412,3743,4682,2485,5413, # 3328 +2804,5414,1650,4683,5415,2613,5416,5417,4086,2671,3392,1149,3393,4087,3884,4088, # 3344 +5418,1076, 49,5419, 951,3242,3322,3323, 450,2850, 920,5420,1812,2805,2371,4328, # 3360 +1909,1138,2372,3885,3509,5421,3243,4684,1910,1147,1518,2428,4685,3886,5422,4686, # 3376 +2393,2614, 260,1796,3244,5423,5424,3887,3324, 708,5425,3620,1704,5426,3621,1351, # 3392 +1618,3394,3017,1887, 944,4329,3395,4330,3064,3396,4331,5427,3744, 422, 413,1714, # 3408 +3325, 500,2059,2350,4332,2486,5428,1344,1911, 954,5429,1668,5430,5431,4089,2409, # 3424 +4333,3622,3888,4334,5432,2307,1318,2512,3114, 133,3115,2887,4687, 629, 31,2851, # 3440 +2706,3889,4688, 850, 949,4689,4090,2970,1732,2089,4335,1496,1853,5433,4091, 620, # 3456 +3245, 981,1242,3745,3397,1619,3746,1643,3326,2140,2457,1971,1719,3510,2169,5434, # 3472 +3246,5435,5436,3398,1829,5437,1277,4690,1565,2048,5438,1636,3623,3116,5439, 869, # 3488 +2852, 655,3890,3891,3117,4092,3018,3892,1310,3624,4691,5440,5441,5442,1733, 558, # 3504 +4692,3747, 335,1549,3065,1756,4336,3748,1946,3511,1830,1291,1192, 470,2735,2108, # 3520 +2806, 913,1054,4093,5443,1027,5444,3066,4094,4693, 982,2672,3399,3173,3512,3247, # 3536 +3248,1947,2807,5445, 571,4694,5446,1831,5447,3625,2591,1523,2429,5448,2090, 984, # 3552 +4695,3749,1960,5449,3750, 852, 923,2808,3513,3751, 969,1519, 999,2049,2325,1705, # 3568 +5450,3118, 615,1662, 151, 597,4095,2410,2326,1049, 275,4696,3752,4337, 568,3753, # 3584 +3626,2487,4338,3754,5451,2430,2275, 409,3249,5452,1566,2888,3514,1002, 769,2853, # 3600 + 194,2091,3174,3755,2226,3327,4339, 628,1505,5453,5454,1763,2180,3019,4096, 521, # 3616 +1161,2592,1788,2206,2411,4697,4097,1625,4340,4341, 412, 42,3119, 464,5455,2642, # 3632 +4698,3400,1760,1571,2889,3515,2537,1219,2207,3893,2643,2141,2373,4699,4700,3328, # 3648 +1651,3401,3627,5456,5457,3628,2488,3516,5458,3756,5459,5460,2276,2092, 460,5461, # 3664 +4701,5462,3020, 962, 588,3629, 289,3250,2644,1116, 52,5463,3067,1797,5464,5465, # 3680 +5466,1467,5467,1598,1143,3757,4342,1985,1734,1067,4702,1280,3402, 465,4703,1572, # 3696 + 510,5468,1928,2245,1813,1644,3630,5469,4704,3758,5470,5471,2673,1573,1534,5472, # 3712 +5473, 536,1808,1761,3517,3894,3175,2645,5474,5475,5476,4705,3518,2929,1912,2809, # 3728 +5477,3329,1122, 377,3251,5478, 360,5479,5480,4343,1529, 551,5481,2060,3759,1769, # 3744 +2431,5482,2930,4344,3330,3120,2327,2109,2031,4706,1404, 136,1468,1479, 672,1171, # 3760 +3252,2308, 271,3176,5483,2772,5484,2050, 678,2736, 865,1948,4707,5485,2014,4098, # 3776 +2971,5486,2737,2227,1397,3068,3760,4708,4709,1735,2931,3403,3631,5487,3895, 509, # 3792 +2854,2458,2890,3896,5488,5489,3177,3178,4710,4345,2538,4711,2309,1166,1010, 552, # 3808 + 681,1888,5490,5491,2972,2973,4099,1287,1596,1862,3179, 358, 453, 736, 175, 478, # 3824 +1117, 905,1167,1097,5492,1854,1530,5493,1706,5494,2181,3519,2292,3761,3520,3632, # 3840 +4346,2093,4347,5495,3404,1193,2489,4348,1458,2193,2208,1863,1889,1421,3331,2932, # 3856 +3069,2182,3521, 595,2123,5496,4100,5497,5498,4349,1707,2646, 223,3762,1359, 751, # 3872 +3121, 183,3522,5499,2810,3021, 419,2374, 633, 704,3897,2394, 241,5500,5501,5502, # 3888 + 838,3022,3763,2277,2773,2459,3898,1939,2051,4101,1309,3122,2246,1181,5503,1136, # 3904 +2209,3899,2375,1446,4350,2310,4712,5504,5505,4351,1055,2615, 484,3764,5506,4102, # 3920 + 625,4352,2278,3405,1499,4353,4103,5507,4104,4354,3253,2279,2280,3523,5508,5509, # 3936 +2774, 808,2616,3765,3406,4105,4355,3123,2539, 526,3407,3900,4356, 955,5510,1620, # 3952 +4357,2647,2432,5511,1429,3766,1669,1832, 994, 928,5512,3633,1260,5513,5514,5515, # 3968 +1949,2293, 741,2933,1626,4358,2738,2460, 867,1184, 362,3408,1392,5516,5517,4106, # 3984 +4359,1770,1736,3254,2934,4713,4714,1929,2707,1459,1158,5518,3070,3409,2891,1292, # 4000 +1930,2513,2855,3767,1986,1187,2072,2015,2617,4360,5519,2574,2514,2170,3768,2490, # 4016 +3332,5520,3769,4715,5521,5522, 666,1003,3023,1022,3634,4361,5523,4716,1814,2257, # 4032 + 574,3901,1603, 295,1535, 705,3902,4362, 283, 858, 417,5524,5525,3255,4717,4718, # 4048 +3071,1220,1890,1046,2281,2461,4107,1393,1599, 689,2575, 388,4363,5526,2491, 802, # 4064 +5527,2811,3903,2061,1405,2258,5528,4719,3904,2110,1052,1345,3256,1585,5529, 809, # 4080 +5530,5531,5532, 575,2739,3524, 956,1552,1469,1144,2328,5533,2329,1560,2462,3635, # 4096 +3257,4108, 616,2210,4364,3180,2183,2294,5534,1833,5535,3525,4720,5536,1319,3770, # 4112 +3771,1211,3636,1023,3258,1293,2812,5537,5538,5539,3905, 607,2311,3906, 762,2892, # 4128 +1439,4365,1360,4721,1485,3072,5540,4722,1038,4366,1450,2062,2648,4367,1379,4723, # 4144 +2593,5541,5542,4368,1352,1414,2330,2935,1172,5543,5544,3907,3908,4724,1798,1451, # 4160 +5545,5546,5547,5548,2936,4109,4110,2492,2351, 411,4111,4112,3637,3333,3124,4725, # 4176 +1561,2674,1452,4113,1375,5549,5550, 47,2974, 316,5551,1406,1591,2937,3181,5552, # 4192 +1025,2142,3125,3182, 354,2740, 884,2228,4369,2412, 508,3772, 726,3638, 996,2433, # 4208 +3639, 729,5553, 392,2194,1453,4114,4726,3773,5554,5555,2463,3640,2618,1675,2813, # 4224 + 919,2352,2975,2353,1270,4727,4115, 73,5556,5557, 647,5558,3259,2856,2259,1550, # 4240 +1346,3024,5559,1332, 883,3526,5560,5561,5562,5563,3334,2775,5564,1212, 831,1347, # 4256 +4370,4728,2331,3909,1864,3073, 720,3910,4729,4730,3911,5565,4371,5566,5567,4731, # 4272 +5568,5569,1799,4732,3774,2619,4733,3641,1645,2376,4734,5570,2938, 669,2211,2675, # 4288 +2434,5571,2893,5572,5573,1028,3260,5574,4372,2413,5575,2260,1353,5576,5577,4735, # 4304 +3183, 518,5578,4116,5579,4373,1961,5580,2143,4374,5581,5582,3025,2354,2355,3912, # 4320 + 516,1834,1454,4117,2708,4375,4736,2229,2620,1972,1129,3642,5583,2776,5584,2976, # 4336 +1422, 577,1470,3026,1524,3410,5585,5586, 432,4376,3074,3527,5587,2594,1455,2515, # 4352 +2230,1973,1175,5588,1020,2741,4118,3528,4737,5589,2742,5590,1743,1361,3075,3529, # 4368 +2649,4119,4377,4738,2295, 895, 924,4378,2171, 331,2247,3076, 166,1627,3077,1098, # 4384 +5591,1232,2894,2231,3411,4739, 657, 403,1196,2377, 542,3775,3412,1600,4379,3530, # 4400 +5592,4740,2777,3261, 576, 530,1362,4741,4742,2540,2676,3776,4120,5593, 842,3913, # 4416 +5594,2814,2032,1014,4121, 213,2709,3413, 665, 621,4380,5595,3777,2939,2435,5596, # 4432 +2436,3335,3643,3414,4743,4381,2541,4382,4744,3644,1682,4383,3531,1380,5597, 724, # 4448 +2282, 600,1670,5598,1337,1233,4745,3126,2248,5599,1621,4746,5600, 651,4384,5601, # 4464 +1612,4385,2621,5602,2857,5603,2743,2312,3078,5604, 716,2464,3079, 174,1255,2710, # 4480 +4122,3645, 548,1320,1398, 728,4123,1574,5605,1891,1197,3080,4124,5606,3081,3082, # 4496 +3778,3646,3779, 747,5607, 635,4386,4747,5608,5609,5610,4387,5611,5612,4748,5613, # 4512 +3415,4749,2437, 451,5614,3780,2542,2073,4388,2744,4389,4125,5615,1764,4750,5616, # 4528 +4390, 350,4751,2283,2395,2493,5617,4391,4126,2249,1434,4127, 488,4752, 458,4392, # 4544 +4128,3781, 771,1330,2396,3914,2576,3184,2160,2414,1553,2677,3185,4393,5618,2494, # 4560 +2895,2622,1720,2711,4394,3416,4753,5619,2543,4395,5620,3262,4396,2778,5621,2016, # 4576 +2745,5622,1155,1017,3782,3915,5623,3336,2313, 201,1865,4397,1430,5624,4129,5625, # 4592 +5626,5627,5628,5629,4398,1604,5630, 414,1866, 371,2595,4754,4755,3532,2017,3127, # 4608 +4756,1708, 960,4399, 887, 389,2172,1536,1663,1721,5631,2232,4130,2356,2940,1580, # 4624 +5632,5633,1744,4757,2544,4758,4759,5634,4760,5635,2074,5636,4761,3647,3417,2896, # 4640 +4400,5637,4401,2650,3418,2815, 673,2712,2465, 709,3533,4131,3648,4402,5638,1148, # 4656 + 502, 634,5639,5640,1204,4762,3649,1575,4763,2623,3783,5641,3784,3128, 948,3263, # 4672 + 121,1745,3916,1110,5642,4403,3083,2516,3027,4132,3785,1151,1771,3917,1488,4133, # 4688 +1987,5643,2438,3534,5644,5645,2094,5646,4404,3918,1213,1407,2816, 531,2746,2545, # 4704 +3264,1011,1537,4764,2779,4405,3129,1061,5647,3786,3787,1867,2897,5648,2018, 120, # 4720 +4406,4407,2063,3650,3265,2314,3919,2678,3419,1955,4765,4134,5649,3535,1047,2713, # 4736 +1266,5650,1368,4766,2858, 649,3420,3920,2546,2747,1102,2859,2679,5651,5652,2000, # 4752 +5653,1111,3651,2977,5654,2495,3921,3652,2817,1855,3421,3788,5655,5656,3422,2415, # 4768 +2898,3337,3266,3653,5657,2577,5658,3654,2818,4135,1460, 856,5659,3655,5660,2899, # 4784 +2978,5661,2900,3922,5662,4408, 632,2517, 875,3923,1697,3924,2296,5663,5664,4767, # 4800 +3028,1239, 580,4768,4409,5665, 914, 936,2075,1190,4136,1039,2124,5666,5667,5668, # 4816 +5669,3423,1473,5670,1354,4410,3925,4769,2173,3084,4137, 915,3338,4411,4412,3339, # 4832 +1605,1835,5671,2748, 398,3656,4413,3926,4138, 328,1913,2860,4139,3927,1331,4414, # 4848 +3029, 937,4415,5672,3657,4140,4141,3424,2161,4770,3425, 524, 742, 538,3085,1012, # 4864 +5673,5674,3928,2466,5675, 658,1103, 225,3929,5676,5677,4771,5678,4772,5679,3267, # 4880 +1243,5680,4142, 963,2250,4773,5681,2714,3658,3186,5682,5683,2596,2332,5684,4774, # 4896 +5685,5686,5687,3536, 957,3426,2547,2033,1931,2941,2467, 870,2019,3659,1746,2780, # 4912 +2781,2439,2468,5688,3930,5689,3789,3130,3790,3537,3427,3791,5690,1179,3086,5691, # 4928 +3187,2378,4416,3792,2548,3188,3131,2749,4143,5692,3428,1556,2549,2297, 977,2901, # 4944 +2034,4144,1205,3429,5693,1765,3430,3189,2125,1271, 714,1689,4775,3538,5694,2333, # 4960 +3931, 533,4417,3660,2184, 617,5695,2469,3340,3539,2315,5696,5697,3190,5698,5699, # 4976 +3932,1988, 618, 427,2651,3540,3431,5700,5701,1244,1690,5702,2819,4418,4776,5703, # 4992 +3541,4777,5704,2284,1576, 473,3661,4419,3432, 972,5705,3662,5706,3087,5707,5708, # 5008 +4778,4779,5709,3793,4145,4146,5710, 153,4780, 356,5711,1892,2902,4420,2144, 408, # 5024 + 803,2357,5712,3933,5713,4421,1646,2578,2518,4781,4782,3934,5714,3935,4422,5715, # 5040 +2416,3433, 752,5716,5717,1962,3341,2979,5718, 746,3030,2470,4783,4423,3794, 698, # 5056 +4784,1893,4424,3663,2550,4785,3664,3936,5719,3191,3434,5720,1824,1302,4147,2715, # 5072 +3937,1974,4425,5721,4426,3192, 823,1303,1288,1236,2861,3542,4148,3435, 774,3938, # 5088 +5722,1581,4786,1304,2862,3939,4787,5723,2440,2162,1083,3268,4427,4149,4428, 344, # 5104 +1173, 288,2316, 454,1683,5724,5725,1461,4788,4150,2597,5726,5727,4789, 985, 894, # 5120 +5728,3436,3193,5729,1914,2942,3795,1989,5730,2111,1975,5731,4151,5732,2579,1194, # 5136 + 425,5733,4790,3194,1245,3796,4429,5734,5735,2863,5736, 636,4791,1856,3940, 760, # 5152 +1800,5737,4430,2212,1508,4792,4152,1894,1684,2298,5738,5739,4793,4431,4432,2213, # 5168 + 479,5740,5741, 832,5742,4153,2496,5743,2980,2497,3797, 990,3132, 627,1815,2652, # 5184 +4433,1582,4434,2126,2112,3543,4794,5744, 799,4435,3195,5745,4795,2113,1737,3031, # 5200 +1018, 543, 754,4436,3342,1676,4796,4797,4154,4798,1489,5746,3544,5747,2624,2903, # 5216 +4155,5748,5749,2981,5750,5751,5752,5753,3196,4799,4800,2185,1722,5754,3269,3270, # 5232 +1843,3665,1715, 481, 365,1976,1857,5755,5756,1963,2498,4801,5757,2127,3666,3271, # 5248 + 433,1895,2064,2076,5758, 602,2750,5759,5760,5761,5762,5763,3032,1628,3437,5764, # 5264 +3197,4802,4156,2904,4803,2519,5765,2551,2782,5766,5767,5768,3343,4804,2905,5769, # 5280 +4805,5770,2864,4806,4807,1221,2982,4157,2520,5771,5772,5773,1868,1990,5774,5775, # 5296 +5776,1896,5777,5778,4808,1897,4158, 318,5779,2095,4159,4437,5780,5781, 485,5782, # 5312 + 938,3941, 553,2680, 116,5783,3942,3667,5784,3545,2681,2783,3438,3344,2820,5785, # 5328 +3668,2943,4160,1747,2944,2983,5786,5787, 207,5788,4809,5789,4810,2521,5790,3033, # 5344 + 890,3669,3943,5791,1878,3798,3439,5792,2186,2358,3440,1652,5793,5794,5795, 941, # 5360 +2299, 208,3546,4161,2020, 330,4438,3944,2906,2499,3799,4439,4811,5796,5797,5798, # 5376 +) + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/big5prober.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/big5prober.py new file mode 100644 index 0000000..98f9970 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/big5prober.py @@ -0,0 +1,47 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import Big5DistributionAnalysis +from .mbcssm import BIG5_SM_MODEL + + +class Big5Prober(MultiByteCharSetProber): + def __init__(self): + super(Big5Prober, self).__init__() + self.coding_sm = CodingStateMachine(BIG5_SM_MODEL) + self.distribution_analyzer = Big5DistributionAnalysis() + self.reset() + + @property + def charset_name(self): + return "Big5" + + @property + def language(self): + return "Chinese" diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/chardistribution.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/chardistribution.py new file mode 100644 index 0000000..c0395f4 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/chardistribution.py @@ -0,0 +1,233 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .euctwfreq import (EUCTW_CHAR_TO_FREQ_ORDER, EUCTW_TABLE_SIZE, + EUCTW_TYPICAL_DISTRIBUTION_RATIO) +from .euckrfreq import (EUCKR_CHAR_TO_FREQ_ORDER, EUCKR_TABLE_SIZE, + EUCKR_TYPICAL_DISTRIBUTION_RATIO) +from .gb2312freq import (GB2312_CHAR_TO_FREQ_ORDER, GB2312_TABLE_SIZE, + GB2312_TYPICAL_DISTRIBUTION_RATIO) +from .big5freq import (BIG5_CHAR_TO_FREQ_ORDER, BIG5_TABLE_SIZE, + BIG5_TYPICAL_DISTRIBUTION_RATIO) +from .jisfreq import (JIS_CHAR_TO_FREQ_ORDER, JIS_TABLE_SIZE, + JIS_TYPICAL_DISTRIBUTION_RATIO) + + +class CharDistributionAnalysis(object): + ENOUGH_DATA_THRESHOLD = 1024 + SURE_YES = 0.99 + SURE_NO = 0.01 + MINIMUM_DATA_THRESHOLD = 3 + + def __init__(self): + # Mapping table to get frequency order from char order (get from + # GetOrder()) + self._char_to_freq_order = None + self._table_size = None # Size of above table + # This is a constant value which varies from language to language, + # used in calculating confidence. See + # http://www.mozilla.org/projects/intl/UniversalCharsetDetection.html + # for further detail. + self.typical_distribution_ratio = None + self._done = None + self._total_chars = None + self._freq_chars = None + self.reset() + + def reset(self): + """reset analyser, clear any state""" + # If this flag is set to True, detection is done and conclusion has + # been made + self._done = False + self._total_chars = 0 # Total characters encountered + # The number of characters whose frequency order is less than 512 + self._freq_chars = 0 + + def feed(self, char, char_len): + """feed a character with known length""" + if char_len == 2: + # we only care about 2-bytes character in our distribution analysis + order = self.get_order(char) + else: + order = -1 + if order >= 0: + self._total_chars += 1 + # order is valid + if order < self._table_size: + if 512 > self._char_to_freq_order[order]: + self._freq_chars += 1 + + def get_confidence(self): + """return confidence based on existing data""" + # if we didn't receive any character in our consideration range, + # return negative answer + if self._total_chars <= 0 or self._freq_chars <= self.MINIMUM_DATA_THRESHOLD: + return self.SURE_NO + + if self._total_chars != self._freq_chars: + r = (self._freq_chars / ((self._total_chars - self._freq_chars) + * self.typical_distribution_ratio)) + if r < self.SURE_YES: + return r + + # normalize confidence (we don't want to be 100% sure) + return self.SURE_YES + + def got_enough_data(self): + # It is not necessary to receive all data to draw conclusion. + # For charset detection, certain amount of data is enough + return self._total_chars > self.ENOUGH_DATA_THRESHOLD + + def get_order(self, byte_str): + # We do not handle characters based on the original encoding string, + # but convert this encoding string to a number, here called order. + # This allows multiple encodings of a language to share one frequency + # table. + return -1 + + +class EUCTWDistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + super(EUCTWDistributionAnalysis, self).__init__() + self._char_to_freq_order = EUCTW_CHAR_TO_FREQ_ORDER + self._table_size = EUCTW_TABLE_SIZE + self.typical_distribution_ratio = EUCTW_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, byte_str): + # for euc-TW encoding, we are interested + # first byte range: 0xc4 -- 0xfe + # second byte range: 0xa1 -- 0xfe + # no validation needed here. State machine has done that + first_char = byte_str[0] + if first_char >= 0xC4: + return 94 * (first_char - 0xC4) + byte_str[1] - 0xA1 + else: + return -1 + + +class EUCKRDistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + super(EUCKRDistributionAnalysis, self).__init__() + self._char_to_freq_order = EUCKR_CHAR_TO_FREQ_ORDER + self._table_size = EUCKR_TABLE_SIZE + self.typical_distribution_ratio = EUCKR_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, byte_str): + # for euc-KR encoding, we are interested + # first byte range: 0xb0 -- 0xfe + # second byte range: 0xa1 -- 0xfe + # no validation needed here. State machine has done that + first_char = byte_str[0] + if first_char >= 0xB0: + return 94 * (first_char - 0xB0) + byte_str[1] - 0xA1 + else: + return -1 + + +class GB2312DistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + super(GB2312DistributionAnalysis, self).__init__() + self._char_to_freq_order = GB2312_CHAR_TO_FREQ_ORDER + self._table_size = GB2312_TABLE_SIZE + self.typical_distribution_ratio = GB2312_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, byte_str): + # for GB2312 encoding, we are interested + # first byte range: 0xb0 -- 0xfe + # second byte range: 0xa1 -- 0xfe + # no validation needed here. State machine has done that + first_char, second_char = byte_str[0], byte_str[1] + if (first_char >= 0xB0) and (second_char >= 0xA1): + return 94 * (first_char - 0xB0) + second_char - 0xA1 + else: + return -1 + + +class Big5DistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + super(Big5DistributionAnalysis, self).__init__() + self._char_to_freq_order = BIG5_CHAR_TO_FREQ_ORDER + self._table_size = BIG5_TABLE_SIZE + self.typical_distribution_ratio = BIG5_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, byte_str): + # for big5 encoding, we are interested + # first byte range: 0xa4 -- 0xfe + # second byte range: 0x40 -- 0x7e , 0xa1 -- 0xfe + # no validation needed here. State machine has done that + first_char, second_char = byte_str[0], byte_str[1] + if first_char >= 0xA4: + if second_char >= 0xA1: + return 157 * (first_char - 0xA4) + second_char - 0xA1 + 63 + else: + return 157 * (first_char - 0xA4) + second_char - 0x40 + else: + return -1 + + +class SJISDistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + super(SJISDistributionAnalysis, self).__init__() + self._char_to_freq_order = JIS_CHAR_TO_FREQ_ORDER + self._table_size = JIS_TABLE_SIZE + self.typical_distribution_ratio = JIS_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, byte_str): + # for sjis encoding, we are interested + # first byte range: 0x81 -- 0x9f , 0xe0 -- 0xfe + # second byte range: 0x40 -- 0x7e, 0x81 -- oxfe + # no validation needed here. State machine has done that + first_char, second_char = byte_str[0], byte_str[1] + if (first_char >= 0x81) and (first_char <= 0x9F): + order = 188 * (first_char - 0x81) + elif (first_char >= 0xE0) and (first_char <= 0xEF): + order = 188 * (first_char - 0xE0 + 31) + else: + return -1 + order = order + second_char - 0x40 + if second_char > 0x7F: + order = -1 + return order + + +class EUCJPDistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + super(EUCJPDistributionAnalysis, self).__init__() + self._char_to_freq_order = JIS_CHAR_TO_FREQ_ORDER + self._table_size = JIS_TABLE_SIZE + self.typical_distribution_ratio = JIS_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, byte_str): + # for euc-JP encoding, we are interested + # first byte range: 0xa0 -- 0xfe + # second byte range: 0xa1 -- 0xfe + # no validation needed here. State machine has done that + char = byte_str[0] + if char >= 0xA0: + return 94 * (char - 0xA1) + byte_str[1] - 0xa1 + else: + return -1 diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/charsetgroupprober.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/charsetgroupprober.py new file mode 100644 index 0000000..8b3738e --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/charsetgroupprober.py @@ -0,0 +1,106 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .enums import ProbingState +from .charsetprober import CharSetProber + + +class CharSetGroupProber(CharSetProber): + def __init__(self, lang_filter=None): + super(CharSetGroupProber, self).__init__(lang_filter=lang_filter) + self._active_num = 0 + self.probers = [] + self._best_guess_prober = None + + def reset(self): + super(CharSetGroupProber, self).reset() + self._active_num = 0 + for prober in self.probers: + if prober: + prober.reset() + prober.active = True + self._active_num += 1 + self._best_guess_prober = None + + @property + def charset_name(self): + if not self._best_guess_prober: + self.get_confidence() + if not self._best_guess_prober: + return None + return self._best_guess_prober.charset_name + + @property + def language(self): + if not self._best_guess_prober: + self.get_confidence() + if not self._best_guess_prober: + return None + return self._best_guess_prober.language + + def feed(self, byte_str): + for prober in self.probers: + if not prober: + continue + if not prober.active: + continue + state = prober.feed(byte_str) + if not state: + continue + if state == ProbingState.FOUND_IT: + self._best_guess_prober = prober + return self.state + elif state == ProbingState.NOT_ME: + prober.active = False + self._active_num -= 1 + if self._active_num <= 0: + self._state = ProbingState.NOT_ME + return self.state + return self.state + + def get_confidence(self): + state = self.state + if state == ProbingState.FOUND_IT: + return 0.99 + elif state == ProbingState.NOT_ME: + return 0.01 + best_conf = 0.0 + self._best_guess_prober = None + for prober in self.probers: + if not prober: + continue + if not prober.active: + self.logger.debug('%s not active', prober.charset_name) + continue + conf = prober.get_confidence() + self.logger.debug('%s %s confidence = %s', prober.charset_name, prober.language, conf) + if best_conf < conf: + best_conf = conf + self._best_guess_prober = prober + if not self._best_guess_prober: + return 0.0 + return best_conf diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/charsetprober.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/charsetprober.py new file mode 100644 index 0000000..eac4e59 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/charsetprober.py @@ -0,0 +1,145 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import logging +import re + +from .enums import ProbingState + + +class CharSetProber(object): + + SHORTCUT_THRESHOLD = 0.95 + + def __init__(self, lang_filter=None): + self._state = None + self.lang_filter = lang_filter + self.logger = logging.getLogger(__name__) + + def reset(self): + self._state = ProbingState.DETECTING + + @property + def charset_name(self): + return None + + def feed(self, buf): + pass + + @property + def state(self): + return self._state + + def get_confidence(self): + return 0.0 + + @staticmethod + def filter_high_byte_only(buf): + buf = re.sub(b'([\x00-\x7F])+', b' ', buf) + return buf + + @staticmethod + def filter_international_words(buf): + """ + We define three types of bytes: + alphabet: english alphabets [a-zA-Z] + international: international characters [\x80-\xFF] + marker: everything else [^a-zA-Z\x80-\xFF] + + The input buffer can be thought to contain a series of words delimited + by markers. This function works to filter all words that contain at + least one international character. All contiguous sequences of markers + are replaced by a single space ascii character. + + This filter applies to all scripts which do not use English characters. + """ + filtered = bytearray() + + # This regex expression filters out only words that have at-least one + # international character. The word may include one marker character at + # the end. + words = re.findall(b'[a-zA-Z]*[\x80-\xFF]+[a-zA-Z]*[^a-zA-Z\x80-\xFF]?', + buf) + + for word in words: + filtered.extend(word[:-1]) + + # If the last character in the word is a marker, replace it with a + # space as markers shouldn't affect our analysis (they are used + # similarly across all languages and may thus have similar + # frequencies). + last_char = word[-1:] + if not last_char.isalpha() and last_char < b'\x80': + last_char = b' ' + filtered.extend(last_char) + + return filtered + + @staticmethod + def filter_with_english_letters(buf): + """ + Returns a copy of ``buf`` that retains only the sequences of English + alphabet and high byte characters that are not between <> characters. + Also retains English alphabet and high byte characters immediately + before occurrences of >. + + This filter can be applied to all scripts which contain both English + characters and extended ASCII characters, but is currently only used by + ``Latin1Prober``. + """ + filtered = bytearray() + in_tag = False + prev = 0 + + for curr in range(len(buf)): + # Slice here to get bytes instead of an int with Python 3 + buf_char = buf[curr:curr + 1] + # Check if we're coming out of or entering an HTML tag + if buf_char == b'>': + in_tag = False + elif buf_char == b'<': + in_tag = True + + # If current character is not extended-ASCII and not alphabetic... + if buf_char < b'\x80' and not buf_char.isalpha(): + # ...and we're not in a tag + if curr > prev and not in_tag: + # Keep everything after last non-extended-ASCII, + # non-alphabetic character + filtered.extend(buf[prev:curr]) + # Output a space to delimit stretch we kept + filtered.extend(b' ') + prev = curr + 1 + + # If we're not in a tag... + if not in_tag: + # Keep everything after last non-extended-ASCII, non-alphabetic + # character + filtered.extend(buf[prev:]) + + return filtered diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/cli/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/cli/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/cli/__init__.py @@ -0,0 +1 @@ + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/cli/chardetect.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/cli/chardetect.py new file mode 100644 index 0000000..f0a4cc5 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/cli/chardetect.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python +""" +Script which takes one or more file paths and reports on their detected +encodings + +Example:: + + % chardetect somefile someotherfile + somefile: windows-1252 with confidence 0.5 + someotherfile: ascii with confidence 1.0 + +If no paths are provided, it takes its input from stdin. + +""" + +from __future__ import absolute_import, print_function, unicode_literals + +import argparse +import sys + +from chardet import __version__ +from chardet.compat import PY2 +from chardet.universaldetector import UniversalDetector + + +def description_of(lines, name='stdin'): + """ + Return a string describing the probable encoding of a file or + list of strings. + + :param lines: The lines to get the encoding of. + :type lines: Iterable of bytes + :param name: Name of file or collection of lines + :type name: str + """ + u = UniversalDetector() + for line in lines: + line = bytearray(line) + u.feed(line) + # shortcut out of the loop to save reading further - particularly useful if we read a BOM. + if u.done: + break + u.close() + result = u.result + if PY2: + name = name.decode(sys.getfilesystemencoding(), 'ignore') + if result['encoding']: + return '{0}: {1} with confidence {2}'.format(name, result['encoding'], + result['confidence']) + else: + return '{0}: no result'.format(name) + + +def main(argv=None): + """ + Handles command line arguments and gets things started. + + :param argv: List of arguments, as if specified on the command-line. + If None, ``sys.argv[1:]`` is used instead. + :type argv: list of str + """ + # Get command line arguments + parser = argparse.ArgumentParser( + description="Takes one or more file paths and reports their detected \ + encodings") + parser.add_argument('input', + help='File whose encoding we would like to determine. \ + (default: stdin)', + type=argparse.FileType('rb'), nargs='*', + default=[sys.stdin if PY2 else sys.stdin.buffer]) + parser.add_argument('--version', action='version', + version='%(prog)s {0}'.format(__version__)) + args = parser.parse_args(argv) + + for f in args.input: + if f.isatty(): + print("You are running chardetect interactively. Press " + + "CTRL-D twice at the start of a blank line to signal the " + + "end of your input. If you want help, run chardetect " + + "--help\n", file=sys.stderr) + print(description_of(f, f.name)) + + +if __name__ == '__main__': + main() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/codingstatemachine.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/codingstatemachine.py new file mode 100644 index 0000000..68fba44 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/codingstatemachine.py @@ -0,0 +1,88 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import logging + +from .enums import MachineState + + +class CodingStateMachine(object): + """ + A state machine to verify a byte sequence for a particular encoding. For + each byte the detector receives, it will feed that byte to every active + state machine available, one byte at a time. The state machine changes its + state based on its previous state and the byte it receives. There are 3 + states in a state machine that are of interest to an auto-detector: + + START state: This is the state to start with, or a legal byte sequence + (i.e. a valid code point) for character has been identified. + + ME state: This indicates that the state machine identified a byte sequence + that is specific to the charset it is designed for and that + there is no other possible encoding which can contain this byte + sequence. This will to lead to an immediate positive answer for + the detector. + + ERROR state: This indicates the state machine identified an illegal byte + sequence for that encoding. This will lead to an immediate + negative answer for this encoding. Detector will exclude this + encoding from consideration from here on. + """ + def __init__(self, sm): + self._model = sm + self._curr_byte_pos = 0 + self._curr_char_len = 0 + self._curr_state = None + self.logger = logging.getLogger(__name__) + self.reset() + + def reset(self): + self._curr_state = MachineState.START + + def next_state(self, c): + # for each byte we get its class + # if it is first byte, we also get byte length + byte_class = self._model['class_table'][c] + if self._curr_state == MachineState.START: + self._curr_byte_pos = 0 + self._curr_char_len = self._model['char_len_table'][byte_class] + # from byte's class and state_table, we get its next state + curr_state = (self._curr_state * self._model['class_factor'] + + byte_class) + self._curr_state = self._model['state_table'][curr_state] + self._curr_byte_pos += 1 + return self._curr_state + + def get_current_charlen(self): + return self._curr_char_len + + def get_coding_state_machine(self): + return self._model['name'] + + @property + def language(self): + return self._model['language'] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/compat.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/compat.py new file mode 100644 index 0000000..ddd7468 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/compat.py @@ -0,0 +1,34 @@ +######################## BEGIN LICENSE BLOCK ######################## +# Contributor(s): +# Dan Blanchard +# Ian Cordasco +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import sys + + +if sys.version_info < (3, 0): + PY2 = True + PY3 = False + base_str = (str, unicode) + text_type = unicode +else: + PY2 = False + PY3 = True + base_str = (bytes, str) + text_type = str diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/cp949prober.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/cp949prober.py new file mode 100644 index 0000000..efd793a --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/cp949prober.py @@ -0,0 +1,49 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .chardistribution import EUCKRDistributionAnalysis +from .codingstatemachine import CodingStateMachine +from .mbcharsetprober import MultiByteCharSetProber +from .mbcssm import CP949_SM_MODEL + + +class CP949Prober(MultiByteCharSetProber): + def __init__(self): + super(CP949Prober, self).__init__() + self.coding_sm = CodingStateMachine(CP949_SM_MODEL) + # NOTE: CP949 is a superset of EUC-KR, so the distribution should be + # not different. + self.distribution_analyzer = EUCKRDistributionAnalysis() + self.reset() + + @property + def charset_name(self): + return "CP949" + + @property + def language(self): + return "Korean" diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/enums.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/enums.py new file mode 100644 index 0000000..0451207 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/enums.py @@ -0,0 +1,76 @@ +""" +All of the Enums that are used throughout the chardet package. + +:author: Dan Blanchard (dan.blanchard@gmail.com) +""" + + +class InputState(object): + """ + This enum represents the different states a universal detector can be in. + """ + PURE_ASCII = 0 + ESC_ASCII = 1 + HIGH_BYTE = 2 + + +class LanguageFilter(object): + """ + This enum represents the different language filters we can apply to a + ``UniversalDetector``. + """ + CHINESE_SIMPLIFIED = 0x01 + CHINESE_TRADITIONAL = 0x02 + JAPANESE = 0x04 + KOREAN = 0x08 + NON_CJK = 0x10 + ALL = 0x1F + CHINESE = CHINESE_SIMPLIFIED | CHINESE_TRADITIONAL + CJK = CHINESE | JAPANESE | KOREAN + + +class ProbingState(object): + """ + This enum represents the different states a prober can be in. + """ + DETECTING = 0 + FOUND_IT = 1 + NOT_ME = 2 + + +class MachineState(object): + """ + This enum represents the different states a state machine can be in. + """ + START = 0 + ERROR = 1 + ITS_ME = 2 + + +class SequenceLikelihood(object): + """ + This enum represents the likelihood of a character following the previous one. + """ + NEGATIVE = 0 + UNLIKELY = 1 + LIKELY = 2 + POSITIVE = 3 + + @classmethod + def get_num_categories(cls): + """:returns: The number of likelihood categories in the enum.""" + return 4 + + +class CharacterCategory(object): + """ + This enum represents the different categories language models for + ``SingleByteCharsetProber`` put characters into. + + Anything less than CONTROL is considered a letter. + """ + UNDEFINED = 255 + LINE_BREAK = 254 + SYMBOL = 253 + DIGIT = 252 + CONTROL = 251 diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/escprober.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/escprober.py new file mode 100644 index 0000000..c70493f --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/escprober.py @@ -0,0 +1,101 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetprober import CharSetProber +from .codingstatemachine import CodingStateMachine +from .enums import LanguageFilter, ProbingState, MachineState +from .escsm import (HZ_SM_MODEL, ISO2022CN_SM_MODEL, ISO2022JP_SM_MODEL, + ISO2022KR_SM_MODEL) + + +class EscCharSetProber(CharSetProber): + """ + This CharSetProber uses a "code scheme" approach for detecting encodings, + whereby easily recognizable escape or shift sequences are relied on to + identify these encodings. + """ + + def __init__(self, lang_filter=None): + super(EscCharSetProber, self).__init__(lang_filter=lang_filter) + self.coding_sm = [] + if self.lang_filter & LanguageFilter.CHINESE_SIMPLIFIED: + self.coding_sm.append(CodingStateMachine(HZ_SM_MODEL)) + self.coding_sm.append(CodingStateMachine(ISO2022CN_SM_MODEL)) + if self.lang_filter & LanguageFilter.JAPANESE: + self.coding_sm.append(CodingStateMachine(ISO2022JP_SM_MODEL)) + if self.lang_filter & LanguageFilter.KOREAN: + self.coding_sm.append(CodingStateMachine(ISO2022KR_SM_MODEL)) + self.active_sm_count = None + self._detected_charset = None + self._detected_language = None + self._state = None + self.reset() + + def reset(self): + super(EscCharSetProber, self).reset() + for coding_sm in self.coding_sm: + if not coding_sm: + continue + coding_sm.active = True + coding_sm.reset() + self.active_sm_count = len(self.coding_sm) + self._detected_charset = None + self._detected_language = None + + @property + def charset_name(self): + return self._detected_charset + + @property + def language(self): + return self._detected_language + + def get_confidence(self): + if self._detected_charset: + return 0.99 + else: + return 0.00 + + def feed(self, byte_str): + for c in byte_str: + for coding_sm in self.coding_sm: + if not coding_sm or not coding_sm.active: + continue + coding_state = coding_sm.next_state(c) + if coding_state == MachineState.ERROR: + coding_sm.active = False + self.active_sm_count -= 1 + if self.active_sm_count <= 0: + self._state = ProbingState.NOT_ME + return self.state + elif coding_state == MachineState.ITS_ME: + self._state = ProbingState.FOUND_IT + self._detected_charset = coding_sm.get_coding_state_machine() + self._detected_language = coding_sm.language + return self.state + + return self.state diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/escsm.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/escsm.py new file mode 100644 index 0000000..0069523 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/escsm.py @@ -0,0 +1,246 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .enums import MachineState + +HZ_CLS = ( +1,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,0,0, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,0,0,0,0, # 20 - 27 +0,0,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +0,0,0,0,0,0,0,0, # 40 - 47 +0,0,0,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,4,0,5,2,0, # 78 - 7f +1,1,1,1,1,1,1,1, # 80 - 87 +1,1,1,1,1,1,1,1, # 88 - 8f +1,1,1,1,1,1,1,1, # 90 - 97 +1,1,1,1,1,1,1,1, # 98 - 9f +1,1,1,1,1,1,1,1, # a0 - a7 +1,1,1,1,1,1,1,1, # a8 - af +1,1,1,1,1,1,1,1, # b0 - b7 +1,1,1,1,1,1,1,1, # b8 - bf +1,1,1,1,1,1,1,1, # c0 - c7 +1,1,1,1,1,1,1,1, # c8 - cf +1,1,1,1,1,1,1,1, # d0 - d7 +1,1,1,1,1,1,1,1, # d8 - df +1,1,1,1,1,1,1,1, # e0 - e7 +1,1,1,1,1,1,1,1, # e8 - ef +1,1,1,1,1,1,1,1, # f0 - f7 +1,1,1,1,1,1,1,1, # f8 - ff +) + +HZ_ST = ( +MachineState.START,MachineState.ERROR, 3,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,# 00-07 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 08-0f +MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START, 4,MachineState.ERROR,# 10-17 + 5,MachineState.ERROR, 6,MachineState.ERROR, 5, 5, 4,MachineState.ERROR,# 18-1f + 4,MachineState.ERROR, 4, 4, 4,MachineState.ERROR, 4,MachineState.ERROR,# 20-27 + 4,MachineState.ITS_ME,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 28-2f +) + +HZ_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0) + +HZ_SM_MODEL = {'class_table': HZ_CLS, + 'class_factor': 6, + 'state_table': HZ_ST, + 'char_len_table': HZ_CHAR_LEN_TABLE, + 'name': "HZ-GB-2312", + 'language': 'Chinese'} + +ISO2022CN_CLS = ( +2,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,0,0, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,0,0,0,0, # 20 - 27 +0,3,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +0,0,0,4,0,0,0,0, # 40 - 47 +0,0,0,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,0,0,0,0,0, # 78 - 7f +2,2,2,2,2,2,2,2, # 80 - 87 +2,2,2,2,2,2,2,2, # 88 - 8f +2,2,2,2,2,2,2,2, # 90 - 97 +2,2,2,2,2,2,2,2, # 98 - 9f +2,2,2,2,2,2,2,2, # a0 - a7 +2,2,2,2,2,2,2,2, # a8 - af +2,2,2,2,2,2,2,2, # b0 - b7 +2,2,2,2,2,2,2,2, # b8 - bf +2,2,2,2,2,2,2,2, # c0 - c7 +2,2,2,2,2,2,2,2, # c8 - cf +2,2,2,2,2,2,2,2, # d0 - d7 +2,2,2,2,2,2,2,2, # d8 - df +2,2,2,2,2,2,2,2, # e0 - e7 +2,2,2,2,2,2,2,2, # e8 - ef +2,2,2,2,2,2,2,2, # f0 - f7 +2,2,2,2,2,2,2,2, # f8 - ff +) + +ISO2022CN_ST = ( +MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 00-07 +MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 08-0f +MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 10-17 +MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 4,MachineState.ERROR,# 18-1f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 20-27 + 5, 6,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 28-2f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 30-37 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.START,# 38-3f +) + +ISO2022CN_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0, 0, 0, 0) + +ISO2022CN_SM_MODEL = {'class_table': ISO2022CN_CLS, + 'class_factor': 9, + 'state_table': ISO2022CN_ST, + 'char_len_table': ISO2022CN_CHAR_LEN_TABLE, + 'name': "ISO-2022-CN", + 'language': 'Chinese'} + +ISO2022JP_CLS = ( +2,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,2,2, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,7,0,0,0, # 20 - 27 +3,0,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +6,0,4,0,8,0,0,0, # 40 - 47 +0,9,5,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,0,0,0,0,0, # 78 - 7f +2,2,2,2,2,2,2,2, # 80 - 87 +2,2,2,2,2,2,2,2, # 88 - 8f +2,2,2,2,2,2,2,2, # 90 - 97 +2,2,2,2,2,2,2,2, # 98 - 9f +2,2,2,2,2,2,2,2, # a0 - a7 +2,2,2,2,2,2,2,2, # a8 - af +2,2,2,2,2,2,2,2, # b0 - b7 +2,2,2,2,2,2,2,2, # b8 - bf +2,2,2,2,2,2,2,2, # c0 - c7 +2,2,2,2,2,2,2,2, # c8 - cf +2,2,2,2,2,2,2,2, # d0 - d7 +2,2,2,2,2,2,2,2, # d8 - df +2,2,2,2,2,2,2,2, # e0 - e7 +2,2,2,2,2,2,2,2, # e8 - ef +2,2,2,2,2,2,2,2, # f0 - f7 +2,2,2,2,2,2,2,2, # f8 - ff +) + +ISO2022JP_ST = ( +MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 00-07 +MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 08-0f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 10-17 +MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,# 18-1f +MachineState.ERROR, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 4,MachineState.ERROR,MachineState.ERROR,# 20-27 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 6,MachineState.ITS_ME,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,# 28-2f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,# 30-37 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 38-3f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.START,MachineState.START,# 40-47 +) + +ISO2022JP_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + +ISO2022JP_SM_MODEL = {'class_table': ISO2022JP_CLS, + 'class_factor': 10, + 'state_table': ISO2022JP_ST, + 'char_len_table': ISO2022JP_CHAR_LEN_TABLE, + 'name': "ISO-2022-JP", + 'language': 'Japanese'} + +ISO2022KR_CLS = ( +2,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,0,0, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,3,0,0,0, # 20 - 27 +0,4,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +0,0,0,5,0,0,0,0, # 40 - 47 +0,0,0,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,0,0,0,0,0, # 78 - 7f +2,2,2,2,2,2,2,2, # 80 - 87 +2,2,2,2,2,2,2,2, # 88 - 8f +2,2,2,2,2,2,2,2, # 90 - 97 +2,2,2,2,2,2,2,2, # 98 - 9f +2,2,2,2,2,2,2,2, # a0 - a7 +2,2,2,2,2,2,2,2, # a8 - af +2,2,2,2,2,2,2,2, # b0 - b7 +2,2,2,2,2,2,2,2, # b8 - bf +2,2,2,2,2,2,2,2, # c0 - c7 +2,2,2,2,2,2,2,2, # c8 - cf +2,2,2,2,2,2,2,2, # d0 - d7 +2,2,2,2,2,2,2,2, # d8 - df +2,2,2,2,2,2,2,2, # e0 - e7 +2,2,2,2,2,2,2,2, # e8 - ef +2,2,2,2,2,2,2,2, # f0 - f7 +2,2,2,2,2,2,2,2, # f8 - ff +) + +ISO2022KR_ST = ( +MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,# 00-07 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 08-0f +MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 4,MachineState.ERROR,MachineState.ERROR,# 10-17 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 18-1f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 20-27 +) + +ISO2022KR_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0) + +ISO2022KR_SM_MODEL = {'class_table': ISO2022KR_CLS, + 'class_factor': 6, + 'state_table': ISO2022KR_ST, + 'char_len_table': ISO2022KR_CHAR_LEN_TABLE, + 'name': "ISO-2022-KR", + 'language': 'Korean'} + + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/eucjpprober.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/eucjpprober.py new file mode 100644 index 0000000..20ce8f7 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/eucjpprober.py @@ -0,0 +1,92 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .enums import ProbingState, MachineState +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import EUCJPDistributionAnalysis +from .jpcntx import EUCJPContextAnalysis +from .mbcssm import EUCJP_SM_MODEL + + +class EUCJPProber(MultiByteCharSetProber): + def __init__(self): + super(EUCJPProber, self).__init__() + self.coding_sm = CodingStateMachine(EUCJP_SM_MODEL) + self.distribution_analyzer = EUCJPDistributionAnalysis() + self.context_analyzer = EUCJPContextAnalysis() + self.reset() + + def reset(self): + super(EUCJPProber, self).reset() + self.context_analyzer.reset() + + @property + def charset_name(self): + return "EUC-JP" + + @property + def language(self): + return "Japanese" + + def feed(self, byte_str): + for i in range(len(byte_str)): + # PY3K: byte_str is a byte array, so byte_str[i] is an int, not a byte + coding_state = self.coding_sm.next_state(byte_str[i]) + if coding_state == MachineState.ERROR: + self.logger.debug('%s %s prober hit error at byte %s', + self.charset_name, self.language, i) + self._state = ProbingState.NOT_ME + break + elif coding_state == MachineState.ITS_ME: + self._state = ProbingState.FOUND_IT + break + elif coding_state == MachineState.START: + char_len = self.coding_sm.get_current_charlen() + if i == 0: + self._last_char[1] = byte_str[0] + self.context_analyzer.feed(self._last_char, char_len) + self.distribution_analyzer.feed(self._last_char, char_len) + else: + self.context_analyzer.feed(byte_str[i - 1:i + 1], + char_len) + self.distribution_analyzer.feed(byte_str[i - 1:i + 1], + char_len) + + self._last_char[0] = byte_str[-1] + + if self.state == ProbingState.DETECTING: + if (self.context_analyzer.got_enough_data() and + (self.get_confidence() > self.SHORTCUT_THRESHOLD)): + self._state = ProbingState.FOUND_IT + + return self.state + + def get_confidence(self): + context_conf = self.context_analyzer.get_confidence() + distrib_conf = self.distribution_analyzer.get_confidence() + return max(context_conf, distrib_conf) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/euckrfreq.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/euckrfreq.py new file mode 100644 index 0000000..b68078c --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/euckrfreq.py @@ -0,0 +1,195 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# Sampling from about 20M text materials include literature and computer technology + +# 128 --> 0.79 +# 256 --> 0.92 +# 512 --> 0.986 +# 1024 --> 0.99944 +# 2048 --> 0.99999 +# +# Idea Distribution Ratio = 0.98653 / (1-0.98653) = 73.24 +# Random Distribution Ration = 512 / (2350-512) = 0.279. +# +# Typical Distribution Ratio + +EUCKR_TYPICAL_DISTRIBUTION_RATIO = 6.0 + +EUCKR_TABLE_SIZE = 2352 + +# Char to FreqOrder table , +EUCKR_CHAR_TO_FREQ_ORDER = ( + 13, 130, 120,1396, 481,1719,1720, 328, 609, 212,1721, 707, 400, 299,1722, 87, +1397,1723, 104, 536,1117,1203,1724,1267, 685,1268, 508,1725,1726,1727,1728,1398, +1399,1729,1730,1731, 141, 621, 326,1057, 368,1732, 267, 488, 20,1733,1269,1734, + 945,1400,1735, 47, 904,1270,1736,1737, 773, 248,1738, 409, 313, 786, 429,1739, + 116, 987, 813,1401, 683, 75,1204, 145,1740,1741,1742,1743, 16, 847, 667, 622, + 708,1744,1745,1746, 966, 787, 304, 129,1747, 60, 820, 123, 676,1748,1749,1750, +1751, 617,1752, 626,1753,1754,1755,1756, 653,1757,1758,1759,1760,1761,1762, 856, + 344,1763,1764,1765,1766, 89, 401, 418, 806, 905, 848,1767,1768,1769, 946,1205, + 709,1770,1118,1771, 241,1772,1773,1774,1271,1775, 569,1776, 999,1777,1778,1779, +1780, 337, 751,1058, 28, 628, 254,1781, 177, 906, 270, 349, 891,1079,1782, 19, +1783, 379,1784, 315,1785, 629, 754,1402, 559,1786, 636, 203,1206,1787, 710, 567, +1788, 935, 814,1789,1790,1207, 766, 528,1791,1792,1208,1793,1794,1795,1796,1797, +1403,1798,1799, 533,1059,1404,1405,1156,1406, 936, 884,1080,1800, 351,1801,1802, +1803,1804,1805, 801,1806,1807,1808,1119,1809,1157, 714, 474,1407,1810, 298, 899, + 885,1811,1120, 802,1158,1812, 892,1813,1814,1408, 659,1815,1816,1121,1817,1818, +1819,1820,1821,1822, 319,1823, 594, 545,1824, 815, 937,1209,1825,1826, 573,1409, +1022,1827,1210,1828,1829,1830,1831,1832,1833, 556, 722, 807,1122,1060,1834, 697, +1835, 900, 557, 715,1836,1410, 540,1411, 752,1159, 294, 597,1211, 976, 803, 770, +1412,1837,1838, 39, 794,1413, 358,1839, 371, 925,1840, 453, 661, 788, 531, 723, + 544,1023,1081, 869, 91,1841, 392, 430, 790, 602,1414, 677,1082, 457,1415,1416, +1842,1843, 475, 327,1024,1417, 795, 121,1844, 733, 403,1418,1845,1846,1847, 300, + 119, 711,1212, 627,1848,1272, 207,1849,1850, 796,1213, 382,1851, 519,1852,1083, + 893,1853,1854,1855, 367, 809, 487, 671,1856, 663,1857,1858, 956, 471, 306, 857, +1859,1860,1160,1084,1861,1862,1863,1864,1865,1061,1866,1867,1868,1869,1870,1871, + 282, 96, 574,1872, 502,1085,1873,1214,1874, 907,1875,1876, 827, 977,1419,1420, +1421, 268,1877,1422,1878,1879,1880, 308,1881, 2, 537,1882,1883,1215,1884,1885, + 127, 791,1886,1273,1423,1887, 34, 336, 404, 643,1888, 571, 654, 894, 840,1889, + 0, 886,1274, 122, 575, 260, 908, 938,1890,1275, 410, 316,1891,1892, 100,1893, +1894,1123, 48,1161,1124,1025,1895, 633, 901,1276,1896,1897, 115, 816,1898, 317, +1899, 694,1900, 909, 734,1424, 572, 866,1425, 691, 85, 524,1010, 543, 394, 841, +1901,1902,1903,1026,1904,1905,1906,1907,1908,1909, 30, 451, 651, 988, 310,1910, +1911,1426, 810,1216, 93,1912,1913,1277,1217,1914, 858, 759, 45, 58, 181, 610, + 269,1915,1916, 131,1062, 551, 443,1000, 821,1427, 957, 895,1086,1917,1918, 375, +1919, 359,1920, 687,1921, 822,1922, 293,1923,1924, 40, 662, 118, 692, 29, 939, + 887, 640, 482, 174,1925, 69,1162, 728,1428, 910,1926,1278,1218,1279, 386, 870, + 217, 854,1163, 823,1927,1928,1929,1930, 834,1931, 78,1932, 859,1933,1063,1934, +1935,1936,1937, 438,1164, 208, 595,1938,1939,1940,1941,1219,1125,1942, 280, 888, +1429,1430,1220,1431,1943,1944,1945,1946,1947,1280, 150, 510,1432,1948,1949,1950, +1951,1952,1953,1954,1011,1087,1955,1433,1043,1956, 881,1957, 614, 958,1064,1065, +1221,1958, 638,1001, 860, 967, 896,1434, 989, 492, 553,1281,1165,1959,1282,1002, +1283,1222,1960,1961,1962,1963, 36, 383, 228, 753, 247, 454,1964, 876, 678,1965, +1966,1284, 126, 464, 490, 835, 136, 672, 529, 940,1088,1435, 473,1967,1968, 467, + 50, 390, 227, 587, 279, 378, 598, 792, 968, 240, 151, 160, 849, 882,1126,1285, + 639,1044, 133, 140, 288, 360, 811, 563,1027, 561, 142, 523,1969,1970,1971, 7, + 103, 296, 439, 407, 506, 634, 990,1972,1973,1974,1975, 645,1976,1977,1978,1979, +1980,1981, 236,1982,1436,1983,1984,1089, 192, 828, 618, 518,1166, 333,1127,1985, + 818,1223,1986,1987,1988,1989,1990,1991,1992,1993, 342,1128,1286, 746, 842,1994, +1995, 560, 223,1287, 98, 8, 189, 650, 978,1288,1996,1437,1997, 17, 345, 250, + 423, 277, 234, 512, 226, 97, 289, 42, 167,1998, 201,1999,2000, 843, 836, 824, + 532, 338, 783,1090, 182, 576, 436,1438,1439, 527, 500,2001, 947, 889,2002,2003, +2004,2005, 262, 600, 314, 447,2006, 547,2007, 693, 738,1129,2008, 71,1440, 745, + 619, 688,2009, 829,2010,2011, 147,2012, 33, 948,2013,2014, 74, 224,2015, 61, + 191, 918, 399, 637,2016,1028,1130, 257, 902,2017,2018,2019,2020,2021,2022,2023, +2024,2025,2026, 837,2027,2028,2029,2030, 179, 874, 591, 52, 724, 246,2031,2032, +2033,2034,1167, 969,2035,1289, 630, 605, 911,1091,1168,2036,2037,2038,1441, 912, +2039, 623,2040,2041, 253,1169,1290,2042,1442, 146, 620, 611, 577, 433,2043,1224, + 719,1170, 959, 440, 437, 534, 84, 388, 480,1131, 159, 220, 198, 679,2044,1012, + 819,1066,1443, 113,1225, 194, 318,1003,1029,2045,2046,2047,2048,1067,2049,2050, +2051,2052,2053, 59, 913, 112,2054, 632,2055, 455, 144, 739,1291,2056, 273, 681, + 499,2057, 448,2058,2059, 760,2060,2061, 970, 384, 169, 245,1132,2062,2063, 414, +1444,2064,2065, 41, 235,2066, 157, 252, 877, 568, 919, 789, 580,2067, 725,2068, +2069,1292,2070,2071,1445,2072,1446,2073,2074, 55, 588, 66,1447, 271,1092,2075, +1226,2076, 960,1013, 372,2077,2078,2079,2080,2081,1293,2082,2083,2084,2085, 850, +2086,2087,2088,2089,2090, 186,2091,1068, 180,2092,2093,2094, 109,1227, 522, 606, +2095, 867,1448,1093, 991,1171, 926, 353,1133,2096, 581,2097,2098,2099,1294,1449, +1450,2100, 596,1172,1014,1228,2101,1451,1295,1173,1229,2102,2103,1296,1134,1452, + 949,1135,2104,2105,1094,1453,1454,1455,2106,1095,2107,2108,2109,2110,2111,2112, +2113,2114,2115,2116,2117, 804,2118,2119,1230,1231, 805,1456, 405,1136,2120,2121, +2122,2123,2124, 720, 701,1297, 992,1457, 927,1004,2125,2126,2127,2128,2129,2130, + 22, 417,2131, 303,2132, 385,2133, 971, 520, 513,2134,1174, 73,1096, 231, 274, + 962,1458, 673,2135,1459,2136, 152,1137,2137,2138,2139,2140,1005,1138,1460,1139, +2141,2142,2143,2144, 11, 374, 844,2145, 154,1232, 46,1461,2146, 838, 830, 721, +1233, 106,2147, 90, 428, 462, 578, 566,1175, 352,2148,2149, 538,1234, 124,1298, +2150,1462, 761, 565,2151, 686,2152, 649,2153, 72, 173,2154, 460, 415,2155,1463, +2156,1235, 305,2157,2158,2159,2160,2161,2162, 579,2163,2164,2165,2166,2167, 747, +2168,2169,2170,2171,1464, 669,2172,2173,2174,2175,2176,1465,2177, 23, 530, 285, +2178, 335, 729,2179, 397,2180,2181,2182,1030,2183,2184, 698,2185,2186, 325,2187, +2188, 369,2189, 799,1097,1015, 348,2190,1069, 680,2191, 851,1466,2192,2193, 10, +2194, 613, 424,2195, 979, 108, 449, 589, 27, 172, 81,1031, 80, 774, 281, 350, +1032, 525, 301, 582,1176,2196, 674,1045,2197,2198,1467, 730, 762,2199,2200,2201, +2202,1468,2203, 993,2204,2205, 266,1070, 963,1140,2206,2207,2208, 664,1098, 972, +2209,2210,2211,1177,1469,1470, 871,2212,2213,2214,2215,2216,1471,2217,2218,2219, +2220,2221,2222,2223,2224,2225,2226,2227,1472,1236,2228,2229,2230,2231,2232,2233, +2234,2235,1299,2236,2237, 200,2238, 477, 373,2239,2240, 731, 825, 777,2241,2242, +2243, 521, 486, 548,2244,2245,2246,1473,1300, 53, 549, 137, 875, 76, 158,2247, +1301,1474, 469, 396,1016, 278, 712,2248, 321, 442, 503, 767, 744, 941,1237,1178, +1475,2249, 82, 178,1141,1179, 973,2250,1302,2251, 297,2252,2253, 570,2254,2255, +2256, 18, 450, 206,2257, 290, 292,1142,2258, 511, 162, 99, 346, 164, 735,2259, +1476,1477, 4, 554, 343, 798,1099,2260,1100,2261, 43, 171,1303, 139, 215,2262, +2263, 717, 775,2264,1033, 322, 216,2265, 831,2266, 149,2267,1304,2268,2269, 702, +1238, 135, 845, 347, 309,2270, 484,2271, 878, 655, 238,1006,1478,2272, 67,2273, + 295,2274,2275, 461,2276, 478, 942, 412,2277,1034,2278,2279,2280, 265,2281, 541, +2282,2283,2284,2285,2286, 70, 852,1071,2287,2288,2289,2290, 21, 56, 509, 117, + 432,2291,2292, 331, 980, 552,1101, 148, 284, 105, 393,1180,1239, 755,2293, 187, +2294,1046,1479,2295, 340,2296, 63,1047, 230,2297,2298,1305, 763,1306, 101, 800, + 808, 494,2299,2300,2301, 903,2302, 37,1072, 14, 5,2303, 79, 675,2304, 312, +2305,2306,2307,2308,2309,1480, 6,1307,2310,2311,2312, 1, 470, 35, 24, 229, +2313, 695, 210, 86, 778, 15, 784, 592, 779, 32, 77, 855, 964,2314, 259,2315, + 501, 380,2316,2317, 83, 981, 153, 689,1308,1481,1482,1483,2318,2319, 716,1484, +2320,2321,2322,2323,2324,2325,1485,2326,2327, 128, 57, 68, 261,1048, 211, 170, +1240, 31,2328, 51, 435, 742,2329,2330,2331, 635,2332, 264, 456,2333,2334,2335, + 425,2336,1486, 143, 507, 263, 943,2337, 363, 920,1487, 256,1488,1102, 243, 601, +1489,2338,2339,2340,2341,2342,2343,2344, 861,2345,2346,2347,2348,2349,2350, 395, +2351,1490,1491, 62, 535, 166, 225,2352,2353, 668, 419,1241, 138, 604, 928,2354, +1181,2355,1492,1493,2356,2357,2358,1143,2359, 696,2360, 387, 307,1309, 682, 476, +2361,2362, 332, 12, 222, 156,2363, 232,2364, 641, 276, 656, 517,1494,1495,1035, + 416, 736,1496,2365,1017, 586,2366,2367,2368,1497,2369, 242,2370,2371,2372,1498, +2373, 965, 713,2374,2375,2376,2377, 740, 982,1499, 944,1500,1007,2378,2379,1310, +1501,2380,2381,2382, 785, 329,2383,2384,1502,2385,2386,2387, 932,2388,1503,2389, +2390,2391,2392,1242,2393,2394,2395,2396,2397, 994, 950,2398,2399,2400,2401,1504, +1311,2402,2403,2404,2405,1049, 749,2406,2407, 853, 718,1144,1312,2408,1182,1505, +2409,2410, 255, 516, 479, 564, 550, 214,1506,1507,1313, 413, 239, 444, 339,1145, +1036,1508,1509,1314,1037,1510,1315,2411,1511,2412,2413,2414, 176, 703, 497, 624, + 593, 921, 302,2415, 341, 165,1103,1512,2416,1513,2417,2418,2419, 376,2420, 700, +2421,2422,2423, 258, 768,1316,2424,1183,2425, 995, 608,2426,2427,2428,2429, 221, +2430,2431,2432,2433,2434,2435,2436,2437, 195, 323, 726, 188, 897, 983,1317, 377, + 644,1050, 879,2438, 452,2439,2440,2441,2442,2443,2444, 914,2445,2446,2447,2448, + 915, 489,2449,1514,1184,2450,2451, 515, 64, 427, 495,2452, 583,2453, 483, 485, +1038, 562, 213,1515, 748, 666,2454,2455,2456,2457, 334,2458, 780, 996,1008, 705, +1243,2459,2460,2461,2462,2463, 114,2464, 493,1146, 366, 163,1516, 961,1104,2465, + 291,2466,1318,1105,2467,1517, 365,2468, 355, 951,1244,2469,1319,2470, 631,2471, +2472, 218,1320, 364, 320, 756,1518,1519,1321,1520,1322,2473,2474,2475,2476, 997, +2477,2478,2479,2480, 665,1185,2481, 916,1521,2482,2483,2484, 584, 684,2485,2486, + 797,2487,1051,1186,2488,2489,2490,1522,2491,2492, 370,2493,1039,1187, 65,2494, + 434, 205, 463,1188,2495, 125, 812, 391, 402, 826, 699, 286, 398, 155, 781, 771, + 585,2496, 590, 505,1073,2497, 599, 244, 219, 917,1018, 952, 646,1523,2498,1323, +2499,2500, 49, 984, 354, 741,2501, 625,2502,1324,2503,1019, 190, 357, 757, 491, + 95, 782, 868,2504,2505,2506,2507,2508,2509, 134,1524,1074, 422,1525, 898,2510, + 161,2511,2512,2513,2514, 769,2515,1526,2516,2517, 411,1325,2518, 472,1527,2519, +2520,2521,2522,2523,2524, 985,2525,2526,2527,2528,2529,2530, 764,2531,1245,2532, +2533, 25, 204, 311,2534, 496,2535,1052,2536,2537,2538,2539,2540,2541,2542, 199, + 704, 504, 468, 758, 657,1528, 196, 44, 839,1246, 272, 750,2543, 765, 862,2544, +2545,1326,2546, 132, 615, 933,2547, 732,2548,2549,2550,1189,1529,2551, 283,1247, +1053, 607, 929,2552,2553,2554, 930, 183, 872, 616,1040,1147,2555,1148,1020, 441, + 249,1075,2556,2557,2558, 466, 743,2559,2560,2561, 92, 514, 426, 420, 526,2562, +2563,2564,2565,2566,2567,2568, 185,2569,2570,2571,2572, 776,1530, 658,2573, 362, +2574, 361, 922,1076, 793,2575,2576,2577,2578,2579,2580,1531, 251,2581,2582,2583, +2584,1532, 54, 612, 237,1327,2585,2586, 275, 408, 647, 111,2587,1533,1106, 465, + 3, 458, 9, 38,2588, 107, 110, 890, 209, 26, 737, 498,2589,1534,2590, 431, + 202, 88,1535, 356, 287,1107, 660,1149,2591, 381,1536, 986,1150, 445,1248,1151, + 974,2592,2593, 846,2594, 446, 953, 184,1249,1250, 727,2595, 923, 193, 883,2596, +2597,2598, 102, 324, 539, 817,2599, 421,1041,2600, 832,2601, 94, 175, 197, 406, +2602, 459,2603,2604,2605,2606,2607, 330, 555,2608,2609,2610, 706,1108, 389,2611, +2612,2613,2614, 233,2615, 833, 558, 931, 954,1251,2616,2617,1537, 546,2618,2619, +1009,2620,2621,2622,1538, 690,1328,2623, 955,2624,1539,2625,2626, 772,2627,2628, +2629,2630,2631, 924, 648, 863, 603,2632,2633, 934,1540, 864, 865,2634, 642,1042, + 670,1190,2635,2636,2637,2638, 168,2639, 652, 873, 542,1054,1541,2640,2641,2642, # 512, 256 +) + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/euckrprober.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/euckrprober.py new file mode 100644 index 0000000..345a060 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/euckrprober.py @@ -0,0 +1,47 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import EUCKRDistributionAnalysis +from .mbcssm import EUCKR_SM_MODEL + + +class EUCKRProber(MultiByteCharSetProber): + def __init__(self): + super(EUCKRProber, self).__init__() + self.coding_sm = CodingStateMachine(EUCKR_SM_MODEL) + self.distribution_analyzer = EUCKRDistributionAnalysis() + self.reset() + + @property + def charset_name(self): + return "EUC-KR" + + @property + def language(self): + return "Korean" diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/euctwfreq.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/euctwfreq.py new file mode 100644 index 0000000..ed7a995 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/euctwfreq.py @@ -0,0 +1,387 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# EUCTW frequency table +# Converted from big5 work +# by Taiwan's Mandarin Promotion Council +# + +# 128 --> 0.42261 +# 256 --> 0.57851 +# 512 --> 0.74851 +# 1024 --> 0.89384 +# 2048 --> 0.97583 +# +# Idea Distribution Ratio = 0.74851/(1-0.74851) =2.98 +# Random Distribution Ration = 512/(5401-512)=0.105 +# +# Typical Distribution Ratio about 25% of Ideal one, still much higher than RDR + +EUCTW_TYPICAL_DISTRIBUTION_RATIO = 0.75 + +# Char to FreqOrder table , +EUCTW_TABLE_SIZE = 5376 + +EUCTW_CHAR_TO_FREQ_ORDER = ( + 1,1800,1506, 255,1431, 198, 9, 82, 6,7310, 177, 202,3615,1256,2808, 110, # 2742 +3735, 33,3241, 261, 76, 44,2113, 16,2931,2184,1176, 659,3868, 26,3404,2643, # 2758 +1198,3869,3313,4060, 410,2211, 302, 590, 361,1963, 8, 204, 58,4296,7311,1931, # 2774 + 63,7312,7313, 317,1614, 75, 222, 159,4061,2412,1480,7314,3500,3068, 224,2809, # 2790 +3616, 3, 10,3870,1471, 29,2774,1135,2852,1939, 873, 130,3242,1123, 312,7315, # 2806 +4297,2051, 507, 252, 682,7316, 142,1914, 124, 206,2932, 34,3501,3173, 64, 604, # 2822 +7317,2494,1976,1977, 155,1990, 645, 641,1606,7318,3405, 337, 72, 406,7319, 80, # 2838 + 630, 238,3174,1509, 263, 939,1092,2644, 756,1440,1094,3406, 449, 69,2969, 591, # 2854 + 179,2095, 471, 115,2034,1843, 60, 50,2970, 134, 806,1868, 734,2035,3407, 180, # 2870 + 995,1607, 156, 537,2893, 688,7320, 319,1305, 779,2144, 514,2374, 298,4298, 359, # 2886 +2495, 90,2707,1338, 663, 11, 906,1099,2545, 20,2436, 182, 532,1716,7321, 732, # 2902 +1376,4062,1311,1420,3175, 25,2312,1056, 113, 399, 382,1949, 242,3408,2467, 529, # 2918 +3243, 475,1447,3617,7322, 117, 21, 656, 810,1297,2295,2329,3502,7323, 126,4063, # 2934 + 706, 456, 150, 613,4299, 71,1118,2036,4064, 145,3069, 85, 835, 486,2114,1246, # 2950 +1426, 428, 727,1285,1015, 800, 106, 623, 303,1281,7324,2127,2354, 347,3736, 221, # 2966 +3503,3110,7325,1955,1153,4065, 83, 296,1199,3070, 192, 624, 93,7326, 822,1897, # 2982 +2810,3111, 795,2064, 991,1554,1542,1592, 27, 43,2853, 859, 139,1456, 860,4300, # 2998 + 437, 712,3871, 164,2392,3112, 695, 211,3017,2096, 195,3872,1608,3504,3505,3618, # 3014 +3873, 234, 811,2971,2097,3874,2229,1441,3506,1615,2375, 668,2076,1638, 305, 228, # 3030 +1664,4301, 467, 415,7327, 262,2098,1593, 239, 108, 300, 200,1033, 512,1247,2077, # 3046 +7328,7329,2173,3176,3619,2673, 593, 845,1062,3244, 88,1723,2037,3875,1950, 212, # 3062 + 266, 152, 149, 468,1898,4066,4302, 77, 187,7330,3018, 37, 5,2972,7331,3876, # 3078 +7332,7333, 39,2517,4303,2894,3177,2078, 55, 148, 74,4304, 545, 483,1474,1029, # 3094 +1665, 217,1869,1531,3113,1104,2645,4067, 24, 172,3507, 900,3877,3508,3509,4305, # 3110 + 32,1408,2811,1312, 329, 487,2355,2247,2708, 784,2674, 4,3019,3314,1427,1788, # 3126 + 188, 109, 499,7334,3620,1717,1789, 888,1217,3020,4306,7335,3510,7336,3315,1520, # 3142 +3621,3878, 196,1034, 775,7337,7338, 929,1815, 249, 439, 38,7339,1063,7340, 794, # 3158 +3879,1435,2296, 46, 178,3245,2065,7341,2376,7342, 214,1709,4307, 804, 35, 707, # 3174 + 324,3622,1601,2546, 140, 459,4068,7343,7344,1365, 839, 272, 978,2257,2572,3409, # 3190 +2128,1363,3623,1423, 697, 100,3071, 48, 70,1231, 495,3114,2193,7345,1294,7346, # 3206 +2079, 462, 586,1042,3246, 853, 256, 988, 185,2377,3410,1698, 434,1084,7347,3411, # 3222 + 314,2615,2775,4308,2330,2331, 569,2280, 637,1816,2518, 757,1162,1878,1616,3412, # 3238 + 287,1577,2115, 768,4309,1671,2854,3511,2519,1321,3737, 909,2413,7348,4069, 933, # 3254 +3738,7349,2052,2356,1222,4310, 765,2414,1322, 786,4311,7350,1919,1462,1677,2895, # 3270 +1699,7351,4312,1424,2437,3115,3624,2590,3316,1774,1940,3413,3880,4070, 309,1369, # 3286 +1130,2812, 364,2230,1653,1299,3881,3512,3882,3883,2646, 525,1085,3021, 902,2000, # 3302 +1475, 964,4313, 421,1844,1415,1057,2281, 940,1364,3116, 376,4314,4315,1381, 7, # 3318 +2520, 983,2378, 336,1710,2675,1845, 321,3414, 559,1131,3022,2742,1808,1132,1313, # 3334 + 265,1481,1857,7352, 352,1203,2813,3247, 167,1089, 420,2814, 776, 792,1724,3513, # 3350 +4071,2438,3248,7353,4072,7354, 446, 229, 333,2743, 901,3739,1200,1557,4316,2647, # 3366 +1920, 395,2744,2676,3740,4073,1835, 125, 916,3178,2616,4317,7355,7356,3741,7357, # 3382 +7358,7359,4318,3117,3625,1133,2547,1757,3415,1510,2313,1409,3514,7360,2145, 438, # 3398 +2591,2896,2379,3317,1068, 958,3023, 461, 311,2855,2677,4074,1915,3179,4075,1978, # 3414 + 383, 750,2745,2617,4076, 274, 539, 385,1278,1442,7361,1154,1964, 384, 561, 210, # 3430 + 98,1295,2548,3515,7362,1711,2415,1482,3416,3884,2897,1257, 129,7363,3742, 642, # 3446 + 523,2776,2777,2648,7364, 141,2231,1333, 68, 176, 441, 876, 907,4077, 603,2592, # 3462 + 710, 171,3417, 404, 549, 18,3118,2393,1410,3626,1666,7365,3516,4319,2898,4320, # 3478 +7366,2973, 368,7367, 146, 366, 99, 871,3627,1543, 748, 807,1586,1185, 22,2258, # 3494 + 379,3743,3180,7368,3181, 505,1941,2618,1991,1382,2314,7369, 380,2357, 218, 702, # 3510 +1817,1248,3418,3024,3517,3318,3249,7370,2974,3628, 930,3250,3744,7371, 59,7372, # 3526 + 585, 601,4078, 497,3419,1112,1314,4321,1801,7373,1223,1472,2174,7374, 749,1836, # 3542 + 690,1899,3745,1772,3885,1476, 429,1043,1790,2232,2116, 917,4079, 447,1086,1629, # 3558 +7375, 556,7376,7377,2020,1654, 844,1090, 105, 550, 966,1758,2815,1008,1782, 686, # 3574 +1095,7378,2282, 793,1602,7379,3518,2593,4322,4080,2933,2297,4323,3746, 980,2496, # 3590 + 544, 353, 527,4324, 908,2678,2899,7380, 381,2619,1942,1348,7381,1341,1252, 560, # 3606 +3072,7382,3420,2856,7383,2053, 973, 886,2080, 143,4325,7384,7385, 157,3886, 496, # 3622 +4081, 57, 840, 540,2038,4326,4327,3421,2117,1445, 970,2259,1748,1965,2081,4082, # 3638 +3119,1234,1775,3251,2816,3629, 773,1206,2129,1066,2039,1326,3887,1738,1725,4083, # 3654 + 279,3120, 51,1544,2594, 423,1578,2130,2066, 173,4328,1879,7386,7387,1583, 264, # 3670 + 610,3630,4329,2439, 280, 154,7388,7389,7390,1739, 338,1282,3073, 693,2857,1411, # 3686 +1074,3747,2440,7391,4330,7392,7393,1240, 952,2394,7394,2900,1538,2679, 685,1483, # 3702 +4084,2468,1436, 953,4085,2054,4331, 671,2395, 79,4086,2441,3252, 608, 567,2680, # 3718 +3422,4087,4088,1691, 393,1261,1791,2396,7395,4332,7396,7397,7398,7399,1383,1672, # 3734 +3748,3182,1464, 522,1119, 661,1150, 216, 675,4333,3888,1432,3519, 609,4334,2681, # 3750 +2397,7400,7401,7402,4089,3025, 0,7403,2469, 315, 231,2442, 301,3319,4335,2380, # 3766 +7404, 233,4090,3631,1818,4336,4337,7405, 96,1776,1315,2082,7406, 257,7407,1809, # 3782 +3632,2709,1139,1819,4091,2021,1124,2163,2778,1777,2649,7408,3074, 363,1655,3183, # 3798 +7409,2975,7410,7411,7412,3889,1567,3890, 718, 103,3184, 849,1443, 341,3320,2934, # 3814 +1484,7413,1712, 127, 67, 339,4092,2398, 679,1412, 821,7414,7415, 834, 738, 351, # 3830 +2976,2146, 846, 235,1497,1880, 418,1992,3749,2710, 186,1100,2147,2746,3520,1545, # 3846 +1355,2935,2858,1377, 583,3891,4093,2573,2977,7416,1298,3633,1078,2549,3634,2358, # 3862 + 78,3750,3751, 267,1289,2099,2001,1594,4094, 348, 369,1274,2194,2175,1837,4338, # 3878 +1820,2817,3635,2747,2283,2002,4339,2936,2748, 144,3321, 882,4340,3892,2749,3423, # 3894 +4341,2901,7417,4095,1726, 320,7418,3893,3026, 788,2978,7419,2818,1773,1327,2859, # 3910 +3894,2819,7420,1306,4342,2003,1700,3752,3521,2359,2650, 787,2022, 506, 824,3636, # 3926 + 534, 323,4343,1044,3322,2023,1900, 946,3424,7421,1778,1500,1678,7422,1881,4344, # 3942 + 165, 243,4345,3637,2521, 123, 683,4096, 764,4346, 36,3895,1792, 589,2902, 816, # 3958 + 626,1667,3027,2233,1639,1555,1622,3753,3896,7423,3897,2860,1370,1228,1932, 891, # 3974 +2083,2903, 304,4097,7424, 292,2979,2711,3522, 691,2100,4098,1115,4347, 118, 662, # 3990 +7425, 611,1156, 854,2381,1316,2861, 2, 386, 515,2904,7426,7427,3253, 868,2234, # 4006 +1486, 855,2651, 785,2212,3028,7428,1040,3185,3523,7429,3121, 448,7430,1525,7431, # 4022 +2164,4348,7432,3754,7433,4099,2820,3524,3122, 503, 818,3898,3123,1568, 814, 676, # 4038 +1444, 306,1749,7434,3755,1416,1030, 197,1428, 805,2821,1501,4349,7435,7436,7437, # 4054 +1993,7438,4350,7439,7440,2195, 13,2779,3638,2980,3124,1229,1916,7441,3756,2131, # 4070 +7442,4100,4351,2399,3525,7443,2213,1511,1727,1120,7444,7445, 646,3757,2443, 307, # 4086 +7446,7447,1595,3186,7448,7449,7450,3639,1113,1356,3899,1465,2522,2523,7451, 519, # 4102 +7452, 128,2132, 92,2284,1979,7453,3900,1512, 342,3125,2196,7454,2780,2214,1980, # 4118 +3323,7455, 290,1656,1317, 789, 827,2360,7456,3758,4352, 562, 581,3901,7457, 401, # 4134 +4353,2248, 94,4354,1399,2781,7458,1463,2024,4355,3187,1943,7459, 828,1105,4101, # 4150 +1262,1394,7460,4102, 605,4356,7461,1783,2862,7462,2822, 819,2101, 578,2197,2937, # 4166 +7463,1502, 436,3254,4103,3255,2823,3902,2905,3425,3426,7464,2712,2315,7465,7466, # 4182 +2332,2067, 23,4357, 193, 826,3759,2102, 699,1630,4104,3075, 390,1793,1064,3526, # 4198 +7467,1579,3076,3077,1400,7468,4105,1838,1640,2863,7469,4358,4359, 137,4106, 598, # 4214 +3078,1966, 780, 104, 974,2938,7470, 278, 899, 253, 402, 572, 504, 493,1339,7471, # 4230 +3903,1275,4360,2574,2550,7472,3640,3029,3079,2249, 565,1334,2713, 863, 41,7473, # 4246 +7474,4361,7475,1657,2333, 19, 463,2750,4107, 606,7476,2981,3256,1087,2084,1323, # 4262 +2652,2982,7477,1631,1623,1750,4108,2682,7478,2864, 791,2714,2653,2334, 232,2416, # 4278 +7479,2983,1498,7480,2654,2620, 755,1366,3641,3257,3126,2025,1609, 119,1917,3427, # 4294 + 862,1026,4109,7481,3904,3760,4362,3905,4363,2260,1951,2470,7482,1125, 817,4110, # 4310 +4111,3906,1513,1766,2040,1487,4112,3030,3258,2824,3761,3127,7483,7484,1507,7485, # 4326 +2683, 733, 40,1632,1106,2865, 345,4113, 841,2524, 230,4364,2984,1846,3259,3428, # 4342 +7486,1263, 986,3429,7487, 735, 879, 254,1137, 857, 622,1300,1180,1388,1562,3907, # 4358 +3908,2939, 967,2751,2655,1349, 592,2133,1692,3324,2985,1994,4114,1679,3909,1901, # 4374 +2185,7488, 739,3642,2715,1296,1290,7489,4115,2198,2199,1921,1563,2595,2551,1870, # 4390 +2752,2986,7490, 435,7491, 343,1108, 596, 17,1751,4365,2235,3430,3643,7492,4366, # 4406 + 294,3527,2940,1693, 477, 979, 281,2041,3528, 643,2042,3644,2621,2782,2261,1031, # 4422 +2335,2134,2298,3529,4367, 367,1249,2552,7493,3530,7494,4368,1283,3325,2004, 240, # 4438 +1762,3326,4369,4370, 836,1069,3128, 474,7495,2148,2525, 268,3531,7496,3188,1521, # 4454 +1284,7497,1658,1546,4116,7498,3532,3533,7499,4117,3327,2684,1685,4118, 961,1673, # 4470 +2622, 190,2005,2200,3762,4371,4372,7500, 570,2497,3645,1490,7501,4373,2623,3260, # 4486 +1956,4374, 584,1514, 396,1045,1944,7502,4375,1967,2444,7503,7504,4376,3910, 619, # 4502 +7505,3129,3261, 215,2006,2783,2553,3189,4377,3190,4378, 763,4119,3763,4379,7506, # 4518 +7507,1957,1767,2941,3328,3646,1174, 452,1477,4380,3329,3130,7508,2825,1253,2382, # 4534 +2186,1091,2285,4120, 492,7509, 638,1169,1824,2135,1752,3911, 648, 926,1021,1324, # 4550 +4381, 520,4382, 997, 847,1007, 892,4383,3764,2262,1871,3647,7510,2400,1784,4384, # 4566 +1952,2942,3080,3191,1728,4121,2043,3648,4385,2007,1701,3131,1551, 30,2263,4122, # 4582 +7511,2026,4386,3534,7512, 501,7513,4123, 594,3431,2165,1821,3535,3432,3536,3192, # 4598 + 829,2826,4124,7514,1680,3132,1225,4125,7515,3262,4387,4126,3133,2336,7516,4388, # 4614 +4127,7517,3912,3913,7518,1847,2383,2596,3330,7519,4389, 374,3914, 652,4128,4129, # 4630 + 375,1140, 798,7520,7521,7522,2361,4390,2264, 546,1659, 138,3031,2445,4391,7523, # 4646 +2250, 612,1848, 910, 796,3765,1740,1371, 825,3766,3767,7524,2906,2554,7525, 692, # 4662 + 444,3032,2624, 801,4392,4130,7526,1491, 244,1053,3033,4131,4132, 340,7527,3915, # 4678 +1041,2987, 293,1168, 87,1357,7528,1539, 959,7529,2236, 721, 694,4133,3768, 219, # 4694 +1478, 644,1417,3331,2656,1413,1401,1335,1389,3916,7530,7531,2988,2362,3134,1825, # 4710 + 730,1515, 184,2827, 66,4393,7532,1660,2943, 246,3332, 378,1457, 226,3433, 975, # 4726 +3917,2944,1264,3537, 674, 696,7533, 163,7534,1141,2417,2166, 713,3538,3333,4394, # 4742 +3918,7535,7536,1186, 15,7537,1079,1070,7538,1522,3193,3539, 276,1050,2716, 758, # 4758 +1126, 653,2945,3263,7539,2337, 889,3540,3919,3081,2989, 903,1250,4395,3920,3434, # 4774 +3541,1342,1681,1718, 766,3264, 286, 89,2946,3649,7540,1713,7541,2597,3334,2990, # 4790 +7542,2947,2215,3194,2866,7543,4396,2498,2526, 181, 387,1075,3921, 731,2187,3335, # 4806 +7544,3265, 310, 313,3435,2299, 770,4134, 54,3034, 189,4397,3082,3769,3922,7545, # 4822 +1230,1617,1849, 355,3542,4135,4398,3336, 111,4136,3650,1350,3135,3436,3035,4137, # 4838 +2149,3266,3543,7546,2784,3923,3924,2991, 722,2008,7547,1071, 247,1207,2338,2471, # 4854 +1378,4399,2009, 864,1437,1214,4400, 373,3770,1142,2216, 667,4401, 442,2753,2555, # 4870 +3771,3925,1968,4138,3267,1839, 837, 170,1107, 934,1336,1882,7548,7549,2118,4139, # 4886 +2828, 743,1569,7550,4402,4140, 582,2384,1418,3437,7551,1802,7552, 357,1395,1729, # 4902 +3651,3268,2418,1564,2237,7553,3083,3772,1633,4403,1114,2085,4141,1532,7554, 482, # 4918 +2446,4404,7555,7556,1492, 833,1466,7557,2717,3544,1641,2829,7558,1526,1272,3652, # 4934 +4142,1686,1794, 416,2556,1902,1953,1803,7559,3773,2785,3774,1159,2316,7560,2867, # 4950 +4405,1610,1584,3036,2419,2754, 443,3269,1163,3136,7561,7562,3926,7563,4143,2499, # 4966 +3037,4406,3927,3137,2103,1647,3545,2010,1872,4144,7564,4145, 431,3438,7565, 250, # 4982 + 97, 81,4146,7566,1648,1850,1558, 160, 848,7567, 866, 740,1694,7568,2201,2830, # 4998 +3195,4147,4407,3653,1687, 950,2472, 426, 469,3196,3654,3655,3928,7569,7570,1188, # 5014 + 424,1995, 861,3546,4148,3775,2202,2685, 168,1235,3547,4149,7571,2086,1674,4408, # 5030 +3337,3270, 220,2557,1009,7572,3776, 670,2992, 332,1208, 717,7573,7574,3548,2447, # 5046 +3929,3338,7575, 513,7576,1209,2868,3339,3138,4409,1080,7577,7578,7579,7580,2527, # 5062 +3656,3549, 815,1587,3930,3931,7581,3550,3439,3777,1254,4410,1328,3038,1390,3932, # 5078 +1741,3933,3778,3934,7582, 236,3779,2448,3271,7583,7584,3657,3780,1273,3781,4411, # 5094 +7585, 308,7586,4412, 245,4413,1851,2473,1307,2575, 430, 715,2136,2449,7587, 270, # 5110 + 199,2869,3935,7588,3551,2718,1753, 761,1754, 725,1661,1840,4414,3440,3658,7589, # 5126 +7590, 587, 14,3272, 227,2598, 326, 480,2265, 943,2755,3552, 291, 650,1883,7591, # 5142 +1702,1226, 102,1547, 62,3441, 904,4415,3442,1164,4150,7592,7593,1224,1548,2756, # 5158 + 391, 498,1493,7594,1386,1419,7595,2055,1177,4416, 813, 880,1081,2363, 566,1145, # 5174 +4417,2286,1001,1035,2558,2599,2238, 394,1286,7596,7597,2068,7598, 86,1494,1730, # 5190 +3936, 491,1588, 745, 897,2948, 843,3340,3937,2757,2870,3273,1768, 998,2217,2069, # 5206 + 397,1826,1195,1969,3659,2993,3341, 284,7599,3782,2500,2137,2119,1903,7600,3938, # 5222 +2150,3939,4151,1036,3443,1904, 114,2559,4152, 209,1527,7601,7602,2949,2831,2625, # 5238 +2385,2719,3139, 812,2560,7603,3274,7604,1559, 737,1884,3660,1210, 885, 28,2686, # 5254 +3553,3783,7605,4153,1004,1779,4418,7606, 346,1981,2218,2687,4419,3784,1742, 797, # 5270 +1642,3940,1933,1072,1384,2151, 896,3941,3275,3661,3197,2871,3554,7607,2561,1958, # 5286 +4420,2450,1785,7608,7609,7610,3942,4154,1005,1308,3662,4155,2720,4421,4422,1528, # 5302 +2600, 161,1178,4156,1982, 987,4423,1101,4157, 631,3943,1157,3198,2420,1343,1241, # 5318 +1016,2239,2562, 372, 877,2339,2501,1160, 555,1934, 911,3944,7611, 466,1170, 169, # 5334 +1051,2907,2688,3663,2474,2994,1182,2011,2563,1251,2626,7612, 992,2340,3444,1540, # 5350 +2721,1201,2070,2401,1996,2475,7613,4424, 528,1922,2188,1503,1873,1570,2364,3342, # 5366 +3276,7614, 557,1073,7615,1827,3445,2087,2266,3140,3039,3084, 767,3085,2786,4425, # 5382 +1006,4158,4426,2341,1267,2176,3664,3199, 778,3945,3200,2722,1597,2657,7616,4427, # 5398 +7617,3446,7618,7619,7620,3277,2689,1433,3278, 131, 95,1504,3946, 723,4159,3141, # 5414 +1841,3555,2758,2189,3947,2027,2104,3665,7621,2995,3948,1218,7622,3343,3201,3949, # 5430 +4160,2576, 248,1634,3785, 912,7623,2832,3666,3040,3786, 654, 53,7624,2996,7625, # 5446 +1688,4428, 777,3447,1032,3950,1425,7626, 191, 820,2120,2833, 971,4429, 931,3202, # 5462 + 135, 664, 783,3787,1997, 772,2908,1935,3951,3788,4430,2909,3203, 282,2723, 640, # 5478 +1372,3448,1127, 922, 325,3344,7627,7628, 711,2044,7629,7630,3952,2219,2787,1936, # 5494 +3953,3345,2220,2251,3789,2300,7631,4431,3790,1258,3279,3954,3204,2138,2950,3955, # 5510 +3956,7632,2221, 258,3205,4432, 101,1227,7633,3280,1755,7634,1391,3281,7635,2910, # 5526 +2056, 893,7636,7637,7638,1402,4161,2342,7639,7640,3206,3556,7641,7642, 878,1325, # 5542 +1780,2788,4433, 259,1385,2577, 744,1183,2267,4434,7643,3957,2502,7644, 684,1024, # 5558 +4162,7645, 472,3557,3449,1165,3282,3958,3959, 322,2152, 881, 455,1695,1152,1340, # 5574 + 660, 554,2153,4435,1058,4436,4163, 830,1065,3346,3960,4437,1923,7646,1703,1918, # 5590 +7647, 932,2268, 122,7648,4438, 947, 677,7649,3791,2627, 297,1905,1924,2269,4439, # 5606 +2317,3283,7650,7651,4164,7652,4165, 84,4166, 112, 989,7653, 547,1059,3961, 701, # 5622 +3558,1019,7654,4167,7655,3450, 942, 639, 457,2301,2451, 993,2951, 407, 851, 494, # 5638 +4440,3347, 927,7656,1237,7657,2421,3348, 573,4168, 680, 921,2911,1279,1874, 285, # 5654 + 790,1448,1983, 719,2167,7658,7659,4441,3962,3963,1649,7660,1541, 563,7661,1077, # 5670 +7662,3349,3041,3451, 511,2997,3964,3965,3667,3966,1268,2564,3350,3207,4442,4443, # 5686 +7663, 535,1048,1276,1189,2912,2028,3142,1438,1373,2834,2952,1134,2012,7664,4169, # 5702 +1238,2578,3086,1259,7665, 700,7666,2953,3143,3668,4170,7667,4171,1146,1875,1906, # 5718 +4444,2601,3967, 781,2422, 132,1589, 203, 147, 273,2789,2402, 898,1786,2154,3968, # 5734 +3969,7668,3792,2790,7669,7670,4445,4446,7671,3208,7672,1635,3793, 965,7673,1804, # 5750 +2690,1516,3559,1121,1082,1329,3284,3970,1449,3794, 65,1128,2835,2913,2759,1590, # 5766 +3795,7674,7675, 12,2658, 45, 976,2579,3144,4447, 517,2528,1013,1037,3209,7676, # 5782 +3796,2836,7677,3797,7678,3452,7679,2602, 614,1998,2318,3798,3087,2724,2628,7680, # 5798 +2580,4172, 599,1269,7681,1810,3669,7682,2691,3088, 759,1060, 489,1805,3351,3285, # 5814 +1358,7683,7684,2386,1387,1215,2629,2252, 490,7685,7686,4173,1759,2387,2343,7687, # 5830 +4448,3799,1907,3971,2630,1806,3210,4449,3453,3286,2760,2344, 874,7688,7689,3454, # 5846 +3670,1858, 91,2914,3671,3042,3800,4450,7690,3145,3972,2659,7691,3455,1202,1403, # 5862 +3801,2954,2529,1517,2503,4451,3456,2504,7692,4452,7693,2692,1885,1495,1731,3973, # 5878 +2365,4453,7694,2029,7695,7696,3974,2693,1216, 237,2581,4174,2319,3975,3802,4454, # 5894 +4455,2694,3560,3457, 445,4456,7697,7698,7699,7700,2761, 61,3976,3672,1822,3977, # 5910 +7701, 687,2045, 935, 925, 405,2660, 703,1096,1859,2725,4457,3978,1876,1367,2695, # 5926 +3352, 918,2105,1781,2476, 334,3287,1611,1093,4458, 564,3146,3458,3673,3353, 945, # 5942 +2631,2057,4459,7702,1925, 872,4175,7703,3459,2696,3089, 349,4176,3674,3979,4460, # 5958 +3803,4177,3675,2155,3980,4461,4462,4178,4463,2403,2046, 782,3981, 400, 251,4179, # 5974 +1624,7704,7705, 277,3676, 299,1265, 476,1191,3804,2121,4180,4181,1109, 205,7706, # 5990 +2582,1000,2156,3561,1860,7707,7708,7709,4464,7710,4465,2565, 107,2477,2157,3982, # 6006 +3460,3147,7711,1533, 541,1301, 158, 753,4182,2872,3562,7712,1696, 370,1088,4183, # 6022 +4466,3563, 579, 327, 440, 162,2240, 269,1937,1374,3461, 968,3043, 56,1396,3090, # 6038 +2106,3288,3354,7713,1926,2158,4467,2998,7714,3564,7715,7716,3677,4468,2478,7717, # 6054 +2791,7718,1650,4469,7719,2603,7720,7721,3983,2661,3355,1149,3356,3984,3805,3985, # 6070 +7722,1076, 49,7723, 951,3211,3289,3290, 450,2837, 920,7724,1811,2792,2366,4184, # 6086 +1908,1138,2367,3806,3462,7725,3212,4470,1909,1147,1518,2423,4471,3807,7726,4472, # 6102 +2388,2604, 260,1795,3213,7727,7728,3808,3291, 708,7729,3565,1704,7730,3566,1351, # 6118 +1618,3357,2999,1886, 944,4185,3358,4186,3044,3359,4187,7731,3678, 422, 413,1714, # 6134 +3292, 500,2058,2345,4188,2479,7732,1344,1910, 954,7733,1668,7734,7735,3986,2404, # 6150 +4189,3567,3809,4190,7736,2302,1318,2505,3091, 133,3092,2873,4473, 629, 31,2838, # 6166 +2697,3810,4474, 850, 949,4475,3987,2955,1732,2088,4191,1496,1852,7737,3988, 620, # 6182 +3214, 981,1242,3679,3360,1619,3680,1643,3293,2139,2452,1970,1719,3463,2168,7738, # 6198 +3215,7739,7740,3361,1828,7741,1277,4476,1565,2047,7742,1636,3568,3093,7743, 869, # 6214 +2839, 655,3811,3812,3094,3989,3000,3813,1310,3569,4477,7744,7745,7746,1733, 558, # 6230 +4478,3681, 335,1549,3045,1756,4192,3682,1945,3464,1829,1291,1192, 470,2726,2107, # 6246 +2793, 913,1054,3990,7747,1027,7748,3046,3991,4479, 982,2662,3362,3148,3465,3216, # 6262 +3217,1946,2794,7749, 571,4480,7750,1830,7751,3570,2583,1523,2424,7752,2089, 984, # 6278 +4481,3683,1959,7753,3684, 852, 923,2795,3466,3685, 969,1519, 999,2048,2320,1705, # 6294 +7754,3095, 615,1662, 151, 597,3992,2405,2321,1049, 275,4482,3686,4193, 568,3687, # 6310 +3571,2480,4194,3688,7755,2425,2270, 409,3218,7756,1566,2874,3467,1002, 769,2840, # 6326 + 194,2090,3149,3689,2222,3294,4195, 628,1505,7757,7758,1763,2177,3001,3993, 521, # 6342 +1161,2584,1787,2203,2406,4483,3994,1625,4196,4197, 412, 42,3096, 464,7759,2632, # 6358 +4484,3363,1760,1571,2875,3468,2530,1219,2204,3814,2633,2140,2368,4485,4486,3295, # 6374 +1651,3364,3572,7760,7761,3573,2481,3469,7762,3690,7763,7764,2271,2091, 460,7765, # 6390 +4487,7766,3002, 962, 588,3574, 289,3219,2634,1116, 52,7767,3047,1796,7768,7769, # 6406 +7770,1467,7771,1598,1143,3691,4198,1984,1734,1067,4488,1280,3365, 465,4489,1572, # 6422 + 510,7772,1927,2241,1812,1644,3575,7773,4490,3692,7774,7775,2663,1573,1534,7776, # 6438 +7777,4199, 536,1807,1761,3470,3815,3150,2635,7778,7779,7780,4491,3471,2915,1911, # 6454 +2796,7781,3296,1122, 377,3220,7782, 360,7783,7784,4200,1529, 551,7785,2059,3693, # 6470 +1769,2426,7786,2916,4201,3297,3097,2322,2108,2030,4492,1404, 136,1468,1479, 672, # 6486 +1171,3221,2303, 271,3151,7787,2762,7788,2049, 678,2727, 865,1947,4493,7789,2013, # 6502 +3995,2956,7790,2728,2223,1397,3048,3694,4494,4495,1735,2917,3366,3576,7791,3816, # 6518 + 509,2841,2453,2876,3817,7792,7793,3152,3153,4496,4202,2531,4497,2304,1166,1010, # 6534 + 552, 681,1887,7794,7795,2957,2958,3996,1287,1596,1861,3154, 358, 453, 736, 175, # 6550 + 478,1117, 905,1167,1097,7796,1853,1530,7797,1706,7798,2178,3472,2287,3695,3473, # 6566 +3577,4203,2092,4204,7799,3367,1193,2482,4205,1458,2190,2205,1862,1888,1421,3298, # 6582 +2918,3049,2179,3474, 595,2122,7800,3997,7801,7802,4206,1707,2636, 223,3696,1359, # 6598 + 751,3098, 183,3475,7803,2797,3003, 419,2369, 633, 704,3818,2389, 241,7804,7805, # 6614 +7806, 838,3004,3697,2272,2763,2454,3819,1938,2050,3998,1309,3099,2242,1181,7807, # 6630 +1136,2206,3820,2370,1446,4207,2305,4498,7808,7809,4208,1055,2605, 484,3698,7810, # 6646 +3999, 625,4209,2273,3368,1499,4210,4000,7811,4001,4211,3222,2274,2275,3476,7812, # 6662 +7813,2764, 808,2606,3699,3369,4002,4212,3100,2532, 526,3370,3821,4213, 955,7814, # 6678 +1620,4214,2637,2427,7815,1429,3700,1669,1831, 994, 928,7816,3578,1260,7817,7818, # 6694 +7819,1948,2288, 741,2919,1626,4215,2729,2455, 867,1184, 362,3371,1392,7820,7821, # 6710 +4003,4216,1770,1736,3223,2920,4499,4500,1928,2698,1459,1158,7822,3050,3372,2877, # 6726 +1292,1929,2506,2842,3701,1985,1187,2071,2014,2607,4217,7823,2566,2507,2169,3702, # 6742 +2483,3299,7824,3703,4501,7825,7826, 666,1003,3005,1022,3579,4218,7827,4502,1813, # 6758 +2253, 574,3822,1603, 295,1535, 705,3823,4219, 283, 858, 417,7828,7829,3224,4503, # 6774 +4504,3051,1220,1889,1046,2276,2456,4004,1393,1599, 689,2567, 388,4220,7830,2484, # 6790 + 802,7831,2798,3824,2060,1405,2254,7832,4505,3825,2109,1052,1345,3225,1585,7833, # 6806 + 809,7834,7835,7836, 575,2730,3477, 956,1552,1469,1144,2323,7837,2324,1560,2457, # 6822 +3580,3226,4005, 616,2207,3155,2180,2289,7838,1832,7839,3478,4506,7840,1319,3704, # 6838 +3705,1211,3581,1023,3227,1293,2799,7841,7842,7843,3826, 607,2306,3827, 762,2878, # 6854 +1439,4221,1360,7844,1485,3052,7845,4507,1038,4222,1450,2061,2638,4223,1379,4508, # 6870 +2585,7846,7847,4224,1352,1414,2325,2921,1172,7848,7849,3828,3829,7850,1797,1451, # 6886 +7851,7852,7853,7854,2922,4006,4007,2485,2346, 411,4008,4009,3582,3300,3101,4509, # 6902 +1561,2664,1452,4010,1375,7855,7856, 47,2959, 316,7857,1406,1591,2923,3156,7858, # 6918 +1025,2141,3102,3157, 354,2731, 884,2224,4225,2407, 508,3706, 726,3583, 996,2428, # 6934 +3584, 729,7859, 392,2191,1453,4011,4510,3707,7860,7861,2458,3585,2608,1675,2800, # 6950 + 919,2347,2960,2348,1270,4511,4012, 73,7862,7863, 647,7864,3228,2843,2255,1550, # 6966 +1346,3006,7865,1332, 883,3479,7866,7867,7868,7869,3301,2765,7870,1212, 831,1347, # 6982 +4226,4512,2326,3830,1863,3053, 720,3831,4513,4514,3832,7871,4227,7872,7873,4515, # 6998 +7874,7875,1798,4516,3708,2609,4517,3586,1645,2371,7876,7877,2924, 669,2208,2665, # 7014 +2429,7878,2879,7879,7880,1028,3229,7881,4228,2408,7882,2256,1353,7883,7884,4518, # 7030 +3158, 518,7885,4013,7886,4229,1960,7887,2142,4230,7888,7889,3007,2349,2350,3833, # 7046 + 516,1833,1454,4014,2699,4231,4519,2225,2610,1971,1129,3587,7890,2766,7891,2961, # 7062 +1422, 577,1470,3008,1524,3373,7892,7893, 432,4232,3054,3480,7894,2586,1455,2508, # 7078 +2226,1972,1175,7895,1020,2732,4015,3481,4520,7896,2733,7897,1743,1361,3055,3482, # 7094 +2639,4016,4233,4521,2290, 895, 924,4234,2170, 331,2243,3056, 166,1627,3057,1098, # 7110 +7898,1232,2880,2227,3374,4522, 657, 403,1196,2372, 542,3709,3375,1600,4235,3483, # 7126 +7899,4523,2767,3230, 576, 530,1362,7900,4524,2533,2666,3710,4017,7901, 842,3834, # 7142 +7902,2801,2031,1014,4018, 213,2700,3376, 665, 621,4236,7903,3711,2925,2430,7904, # 7158 +2431,3302,3588,3377,7905,4237,2534,4238,4525,3589,1682,4239,3484,1380,7906, 724, # 7174 +2277, 600,1670,7907,1337,1233,4526,3103,2244,7908,1621,4527,7909, 651,4240,7910, # 7190 +1612,4241,2611,7911,2844,7912,2734,2307,3058,7913, 716,2459,3059, 174,1255,2701, # 7206 +4019,3590, 548,1320,1398, 728,4020,1574,7914,1890,1197,3060,4021,7915,3061,3062, # 7222 +3712,3591,3713, 747,7916, 635,4242,4528,7917,7918,7919,4243,7920,7921,4529,7922, # 7238 +3378,4530,2432, 451,7923,3714,2535,2072,4244,2735,4245,4022,7924,1764,4531,7925, # 7254 +4246, 350,7926,2278,2390,2486,7927,4247,4023,2245,1434,4024, 488,4532, 458,4248, # 7270 +4025,3715, 771,1330,2391,3835,2568,3159,2159,2409,1553,2667,3160,4249,7928,2487, # 7286 +2881,2612,1720,2702,4250,3379,4533,7929,2536,4251,7930,3231,4252,2768,7931,2015, # 7302 +2736,7932,1155,1017,3716,3836,7933,3303,2308, 201,1864,4253,1430,7934,4026,7935, # 7318 +7936,7937,7938,7939,4254,1604,7940, 414,1865, 371,2587,4534,4535,3485,2016,3104, # 7334 +4536,1708, 960,4255, 887, 389,2171,1536,1663,1721,7941,2228,4027,2351,2926,1580, # 7350 +7942,7943,7944,1744,7945,2537,4537,4538,7946,4539,7947,2073,7948,7949,3592,3380, # 7366 +2882,4256,7950,4257,2640,3381,2802, 673,2703,2460, 709,3486,4028,3593,4258,7951, # 7382 +1148, 502, 634,7952,7953,1204,4540,3594,1575,4541,2613,3717,7954,3718,3105, 948, # 7398 +3232, 121,1745,3837,1110,7955,4259,3063,2509,3009,4029,3719,1151,1771,3838,1488, # 7414 +4030,1986,7956,2433,3487,7957,7958,2093,7959,4260,3839,1213,1407,2803, 531,2737, # 7430 +2538,3233,1011,1537,7960,2769,4261,3106,1061,7961,3720,3721,1866,2883,7962,2017, # 7446 + 120,4262,4263,2062,3595,3234,2309,3840,2668,3382,1954,4542,7963,7964,3488,1047, # 7462 +2704,1266,7965,1368,4543,2845, 649,3383,3841,2539,2738,1102,2846,2669,7966,7967, # 7478 +1999,7968,1111,3596,2962,7969,2488,3842,3597,2804,1854,3384,3722,7970,7971,3385, # 7494 +2410,2884,3304,3235,3598,7972,2569,7973,3599,2805,4031,1460, 856,7974,3600,7975, # 7510 +2885,2963,7976,2886,3843,7977,4264, 632,2510, 875,3844,1697,3845,2291,7978,7979, # 7526 +4544,3010,1239, 580,4545,4265,7980, 914, 936,2074,1190,4032,1039,2123,7981,7982, # 7542 +7983,3386,1473,7984,1354,4266,3846,7985,2172,3064,4033, 915,3305,4267,4268,3306, # 7558 +1605,1834,7986,2739, 398,3601,4269,3847,4034, 328,1912,2847,4035,3848,1331,4270, # 7574 +3011, 937,4271,7987,3602,4036,4037,3387,2160,4546,3388, 524, 742, 538,3065,1012, # 7590 +7988,7989,3849,2461,7990, 658,1103, 225,3850,7991,7992,4547,7993,4548,7994,3236, # 7606 +1243,7995,4038, 963,2246,4549,7996,2705,3603,3161,7997,7998,2588,2327,7999,4550, # 7622 +8000,8001,8002,3489,3307, 957,3389,2540,2032,1930,2927,2462, 870,2018,3604,1746, # 7638 +2770,2771,2434,2463,8003,3851,8004,3723,3107,3724,3490,3390,3725,8005,1179,3066, # 7654 +8006,3162,2373,4272,3726,2541,3163,3108,2740,4039,8007,3391,1556,2542,2292, 977, # 7670 +2887,2033,4040,1205,3392,8008,1765,3393,3164,2124,1271,1689, 714,4551,3491,8009, # 7686 +2328,3852, 533,4273,3605,2181, 617,8010,2464,3308,3492,2310,8011,8012,3165,8013, # 7702 +8014,3853,1987, 618, 427,2641,3493,3394,8015,8016,1244,1690,8017,2806,4274,4552, # 7718 +8018,3494,8019,8020,2279,1576, 473,3606,4275,3395, 972,8021,3607,8022,3067,8023, # 7734 +8024,4553,4554,8025,3727,4041,4042,8026, 153,4555, 356,8027,1891,2888,4276,2143, # 7750 + 408, 803,2352,8028,3854,8029,4277,1646,2570,2511,4556,4557,3855,8030,3856,4278, # 7766 +8031,2411,3396, 752,8032,8033,1961,2964,8034, 746,3012,2465,8035,4279,3728, 698, # 7782 +4558,1892,4280,3608,2543,4559,3609,3857,8036,3166,3397,8037,1823,1302,4043,2706, # 7798 +3858,1973,4281,8038,4282,3167, 823,1303,1288,1236,2848,3495,4044,3398, 774,3859, # 7814 +8039,1581,4560,1304,2849,3860,4561,8040,2435,2161,1083,3237,4283,4045,4284, 344, # 7830 +1173, 288,2311, 454,1683,8041,8042,1461,4562,4046,2589,8043,8044,4563, 985, 894, # 7846 +8045,3399,3168,8046,1913,2928,3729,1988,8047,2110,1974,8048,4047,8049,2571,1194, # 7862 + 425,8050,4564,3169,1245,3730,4285,8051,8052,2850,8053, 636,4565,1855,3861, 760, # 7878 +1799,8054,4286,2209,1508,4566,4048,1893,1684,2293,8055,8056,8057,4287,4288,2210, # 7894 + 479,8058,8059, 832,8060,4049,2489,8061,2965,2490,3731, 990,3109, 627,1814,2642, # 7910 +4289,1582,4290,2125,2111,3496,4567,8062, 799,4291,3170,8063,4568,2112,1737,3013, # 7926 +1018, 543, 754,4292,3309,1676,4569,4570,4050,8064,1489,8065,3497,8066,2614,2889, # 7942 +4051,8067,8068,2966,8069,8070,8071,8072,3171,4571,4572,2182,1722,8073,3238,3239, # 7958 +1842,3610,1715, 481, 365,1975,1856,8074,8075,1962,2491,4573,8076,2126,3611,3240, # 7974 + 433,1894,2063,2075,8077, 602,2741,8078,8079,8080,8081,8082,3014,1628,3400,8083, # 7990 +3172,4574,4052,2890,4575,2512,8084,2544,2772,8085,8086,8087,3310,4576,2891,8088, # 8006 +4577,8089,2851,4578,4579,1221,2967,4053,2513,8090,8091,8092,1867,1989,8093,8094, # 8022 +8095,1895,8096,8097,4580,1896,4054, 318,8098,2094,4055,4293,8099,8100, 485,8101, # 8038 + 938,3862, 553,2670, 116,8102,3863,3612,8103,3498,2671,2773,3401,3311,2807,8104, # 8054 +3613,2929,4056,1747,2930,2968,8105,8106, 207,8107,8108,2672,4581,2514,8109,3015, # 8070 + 890,3614,3864,8110,1877,3732,3402,8111,2183,2353,3403,1652,8112,8113,8114, 941, # 8086 +2294, 208,3499,4057,2019, 330,4294,3865,2892,2492,3733,4295,8115,8116,8117,8118, # 8102 +) + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/euctwprober.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/euctwprober.py new file mode 100644 index 0000000..35669cc --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/euctwprober.py @@ -0,0 +1,46 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import EUCTWDistributionAnalysis +from .mbcssm import EUCTW_SM_MODEL + +class EUCTWProber(MultiByteCharSetProber): + def __init__(self): + super(EUCTWProber, self).__init__() + self.coding_sm = CodingStateMachine(EUCTW_SM_MODEL) + self.distribution_analyzer = EUCTWDistributionAnalysis() + self.reset() + + @property + def charset_name(self): + return "EUC-TW" + + @property + def language(self): + return "Taiwan" diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/gb2312freq.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/gb2312freq.py new file mode 100644 index 0000000..697837b --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/gb2312freq.py @@ -0,0 +1,283 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# GB2312 most frequently used character table +# +# Char to FreqOrder table , from hz6763 + +# 512 --> 0.79 -- 0.79 +# 1024 --> 0.92 -- 0.13 +# 2048 --> 0.98 -- 0.06 +# 6768 --> 1.00 -- 0.02 +# +# Ideal Distribution Ratio = 0.79135/(1-0.79135) = 3.79 +# Random Distribution Ration = 512 / (3755 - 512) = 0.157 +# +# Typical Distribution Ratio about 25% of Ideal one, still much higher that RDR + +GB2312_TYPICAL_DISTRIBUTION_RATIO = 0.9 + +GB2312_TABLE_SIZE = 3760 + +GB2312_CHAR_TO_FREQ_ORDER = ( +1671, 749,1443,2364,3924,3807,2330,3921,1704,3463,2691,1511,1515, 572,3191,2205, +2361, 224,2558, 479,1711, 963,3162, 440,4060,1905,2966,2947,3580,2647,3961,3842, +2204, 869,4207, 970,2678,5626,2944,2956,1479,4048, 514,3595, 588,1346,2820,3409, + 249,4088,1746,1873,2047,1774, 581,1813, 358,1174,3590,1014,1561,4844,2245, 670, +1636,3112, 889,1286, 953, 556,2327,3060,1290,3141, 613, 185,3477,1367, 850,3820, +1715,2428,2642,2303,2732,3041,2562,2648,3566,3946,1349, 388,3098,2091,1360,3585, + 152,1687,1539, 738,1559, 59,1232,2925,2267,1388,1249,1741,1679,2960, 151,1566, +1125,1352,4271, 924,4296, 385,3166,4459, 310,1245,2850, 70,3285,2729,3534,3575, +2398,3298,3466,1960,2265, 217,3647, 864,1909,2084,4401,2773,1010,3269,5152, 853, +3051,3121,1244,4251,1895, 364,1499,1540,2313,1180,3655,2268, 562, 715,2417,3061, + 544, 336,3768,2380,1752,4075, 950, 280,2425,4382, 183,2759,3272, 333,4297,2155, +1688,2356,1444,1039,4540, 736,1177,3349,2443,2368,2144,2225, 565, 196,1482,3406, + 927,1335,4147, 692, 878,1311,1653,3911,3622,1378,4200,1840,2969,3149,2126,1816, +2534,1546,2393,2760, 737,2494, 13, 447, 245,2747, 38,2765,2129,2589,1079, 606, + 360, 471,3755,2890, 404, 848, 699,1785,1236, 370,2221,1023,3746,2074,2026,2023, +2388,1581,2119, 812,1141,3091,2536,1519, 804,2053, 406,1596,1090, 784, 548,4414, +1806,2264,2936,1100, 343,4114,5096, 622,3358, 743,3668,1510,1626,5020,3567,2513, +3195,4115,5627,2489,2991, 24,2065,2697,1087,2719, 48,1634, 315, 68, 985,2052, + 198,2239,1347,1107,1439, 597,2366,2172, 871,3307, 919,2487,2790,1867, 236,2570, +1413,3794, 906,3365,3381,1701,1982,1818,1524,2924,1205, 616,2586,2072,2004, 575, + 253,3099, 32,1365,1182, 197,1714,2454,1201, 554,3388,3224,2748, 756,2587, 250, +2567,1507,1517,3529,1922,2761,2337,3416,1961,1677,2452,2238,3153, 615, 911,1506, +1474,2495,1265,1906,2749,3756,3280,2161, 898,2714,1759,3450,2243,2444, 563, 26, +3286,2266,3769,3344,2707,3677, 611,1402, 531,1028,2871,4548,1375, 261,2948, 835, +1190,4134, 353, 840,2684,1900,3082,1435,2109,1207,1674, 329,1872,2781,4055,2686, +2104, 608,3318,2423,2957,2768,1108,3739,3512,3271,3985,2203,1771,3520,1418,2054, +1681,1153, 225,1627,2929, 162,2050,2511,3687,1954, 124,1859,2431,1684,3032,2894, + 585,4805,3969,2869,2704,2088,2032,2095,3656,2635,4362,2209, 256, 518,2042,2105, +3777,3657, 643,2298,1148,1779, 190, 989,3544, 414, 11,2135,2063,2979,1471, 403, +3678, 126, 770,1563, 671,2499,3216,2877, 600,1179, 307,2805,4937,1268,1297,2694, + 252,4032,1448,1494,1331,1394, 127,2256, 222,1647,1035,1481,3056,1915,1048, 873, +3651, 210, 33,1608,2516, 200,1520, 415, 102, 0,3389,1287, 817, 91,3299,2940, + 836,1814, 549,2197,1396,1669,2987,3582,2297,2848,4528,1070, 687, 20,1819, 121, +1552,1364,1461,1968,2617,3540,2824,2083, 177, 948,4938,2291, 110,4549,2066, 648, +3359,1755,2110,2114,4642,4845,1693,3937,3308,1257,1869,2123, 208,1804,3159,2992, +2531,2549,3361,2418,1350,2347,2800,2568,1291,2036,2680, 72, 842,1990, 212,1233, +1154,1586, 75,2027,3410,4900,1823,1337,2710,2676, 728,2810,1522,3026,4995, 157, + 755,1050,4022, 710, 785,1936,2194,2085,1406,2777,2400, 150,1250,4049,1206, 807, +1910, 534, 529,3309,1721,1660, 274, 39,2827, 661,2670,1578, 925,3248,3815,1094, +4278,4901,4252, 41,1150,3747,2572,2227,4501,3658,4902,3813,3357,3617,2884,2258, + 887, 538,4187,3199,1294,2439,3042,2329,2343,2497,1255, 107, 543,1527, 521,3478, +3568, 194,5062, 15, 961,3870,1241,1192,2664, 66,5215,3260,2111,1295,1127,2152, +3805,4135, 901,1164,1976, 398,1278, 530,1460, 748, 904,1054,1966,1426, 53,2909, + 509, 523,2279,1534, 536,1019, 239,1685, 460,2353, 673,1065,2401,3600,4298,2272, +1272,2363, 284,1753,3679,4064,1695, 81, 815,2677,2757,2731,1386, 859, 500,4221, +2190,2566, 757,1006,2519,2068,1166,1455, 337,2654,3203,1863,1682,1914,3025,1252, +1409,1366, 847, 714,2834,2038,3209, 964,2970,1901, 885,2553,1078,1756,3049, 301, +1572,3326, 688,2130,1996,2429,1805,1648,2930,3421,2750,3652,3088, 262,1158,1254, + 389,1641,1812, 526,1719, 923,2073,1073,1902, 468, 489,4625,1140, 857,2375,3070, +3319,2863, 380, 116,1328,2693,1161,2244, 273,1212,1884,2769,3011,1775,1142, 461, +3066,1200,2147,2212, 790, 702,2695,4222,1601,1058, 434,2338,5153,3640, 67,2360, +4099,2502, 618,3472,1329, 416,1132, 830,2782,1807,2653,3211,3510,1662, 192,2124, + 296,3979,1739,1611,3684, 23, 118, 324, 446,1239,1225, 293,2520,3814,3795,2535, +3116, 17,1074, 467,2692,2201, 387,2922, 45,1326,3055,1645,3659,2817, 958, 243, +1903,2320,1339,2825,1784,3289, 356, 576, 865,2315,2381,3377,3916,1088,3122,1713, +1655, 935, 628,4689,1034,1327, 441, 800, 720, 894,1979,2183,1528,5289,2702,1071, +4046,3572,2399,1571,3281, 79, 761,1103, 327, 134, 758,1899,1371,1615, 879, 442, + 215,2605,2579, 173,2048,2485,1057,2975,3317,1097,2253,3801,4263,1403,1650,2946, + 814,4968,3487,1548,2644,1567,1285, 2, 295,2636, 97, 946,3576, 832, 141,4257, +3273, 760,3821,3521,3156,2607, 949,1024,1733,1516,1803,1920,2125,2283,2665,3180, +1501,2064,3560,2171,1592, 803,3518,1416, 732,3897,4258,1363,1362,2458, 119,1427, + 602,1525,2608,1605,1639,3175, 694,3064, 10, 465, 76,2000,4846,4208, 444,3781, +1619,3353,2206,1273,3796, 740,2483, 320,1723,2377,3660,2619,1359,1137,1762,1724, +2345,2842,1850,1862, 912, 821,1866, 612,2625,1735,2573,3369,1093, 844, 89, 937, + 930,1424,3564,2413,2972,1004,3046,3019,2011, 711,3171,1452,4178, 428, 801,1943, + 432, 445,2811, 206,4136,1472, 730, 349, 73, 397,2802,2547, 998,1637,1167, 789, + 396,3217, 154,1218, 716,1120,1780,2819,4826,1931,3334,3762,2139,1215,2627, 552, +3664,3628,3232,1405,2383,3111,1356,2652,3577,3320,3101,1703, 640,1045,1370,1246, +4996, 371,1575,2436,1621,2210, 984,4033,1734,2638, 16,4529, 663,2755,3255,1451, +3917,2257,1253,1955,2234,1263,2951, 214,1229, 617, 485, 359,1831,1969, 473,2310, + 750,2058, 165, 80,2864,2419, 361,4344,2416,2479,1134, 796,3726,1266,2943, 860, +2715, 938, 390,2734,1313,1384, 248, 202, 877,1064,2854, 522,3907, 279,1602, 297, +2357, 395,3740, 137,2075, 944,4089,2584,1267,3802, 62,1533,2285, 178, 176, 780, +2440, 201,3707, 590, 478,1560,4354,2117,1075, 30, 74,4643,4004,1635,1441,2745, + 776,2596, 238,1077,1692,1912,2844, 605, 499,1742,3947, 241,3053, 980,1749, 936, +2640,4511,2582, 515,1543,2162,5322,2892,2993, 890,2148,1924, 665,1827,3581,1032, + 968,3163, 339,1044,1896, 270, 583,1791,1720,4367,1194,3488,3669, 43,2523,1657, + 163,2167, 290,1209,1622,3378, 550, 634,2508,2510, 695,2634,2384,2512,1476,1414, + 220,1469,2341,2138,2852,3183,2900,4939,2865,3502,1211,3680, 854,3227,1299,2976, +3172, 186,2998,1459, 443,1067,3251,1495, 321,1932,3054, 909, 753,1410,1828, 436, +2441,1119,1587,3164,2186,1258, 227, 231,1425,1890,3200,3942, 247, 959, 725,5254, +2741, 577,2158,2079, 929, 120, 174, 838,2813, 591,1115, 417,2024, 40,3240,1536, +1037, 291,4151,2354, 632,1298,2406,2500,3535,1825,1846,3451, 205,1171, 345,4238, + 18,1163, 811, 685,2208,1217, 425,1312,1508,1175,4308,2552,1033, 587,1381,3059, +2984,3482, 340,1316,4023,3972, 792,3176, 519, 777,4690, 918, 933,4130,2981,3741, + 90,3360,2911,2200,5184,4550, 609,3079,2030, 272,3379,2736, 363,3881,1130,1447, + 286, 779, 357,1169,3350,3137,1630,1220,2687,2391, 747,1277,3688,2618,2682,2601, +1156,3196,5290,4034,3102,1689,3596,3128, 874, 219,2783, 798, 508,1843,2461, 269, +1658,1776,1392,1913,2983,3287,2866,2159,2372, 829,4076, 46,4253,2873,1889,1894, + 915,1834,1631,2181,2318, 298, 664,2818,3555,2735, 954,3228,3117, 527,3511,2173, + 681,2712,3033,2247,2346,3467,1652, 155,2164,3382, 113,1994, 450, 899, 494, 994, +1237,2958,1875,2336,1926,3727, 545,1577,1550, 633,3473, 204,1305,3072,2410,1956, +2471, 707,2134, 841,2195,2196,2663,3843,1026,4940, 990,3252,4997, 368,1092, 437, +3212,3258,1933,1829, 675,2977,2893, 412, 943,3723,4644,3294,3283,2230,2373,5154, +2389,2241,2661,2323,1404,2524, 593, 787, 677,3008,1275,2059, 438,2709,2609,2240, +2269,2246,1446, 36,1568,1373,3892,1574,2301,1456,3962, 693,2276,5216,2035,1143, +2720,1919,1797,1811,2763,4137,2597,1830,1699,1488,1198,2090, 424,1694, 312,3634, +3390,4179,3335,2252,1214, 561,1059,3243,2295,2561, 975,5155,2321,2751,3772, 472, +1537,3282,3398,1047,2077,2348,2878,1323,3340,3076, 690,2906, 51, 369, 170,3541, +1060,2187,2688,3670,2541,1083,1683, 928,3918, 459, 109,4427, 599,3744,4286, 143, +2101,2730,2490, 82,1588,3036,2121, 281,1860, 477,4035,1238,2812,3020,2716,3312, +1530,2188,2055,1317, 843, 636,1808,1173,3495, 649, 181,1002, 147,3641,1159,2414, +3750,2289,2795, 813,3123,2610,1136,4368, 5,3391,4541,2174, 420, 429,1728, 754, +1228,2115,2219, 347,2223,2733, 735,1518,3003,2355,3134,1764,3948,3329,1888,2424, +1001,1234,1972,3321,3363,1672,1021,1450,1584, 226, 765, 655,2526,3404,3244,2302, +3665, 731, 594,2184, 319,1576, 621, 658,2656,4299,2099,3864,1279,2071,2598,2739, + 795,3086,3699,3908,1707,2352,2402,1382,3136,2475,1465,4847,3496,3865,1085,3004, +2591,1084, 213,2287,1963,3565,2250, 822, 793,4574,3187,1772,1789,3050, 595,1484, +1959,2770,1080,2650, 456, 422,2996, 940,3322,4328,4345,3092,2742, 965,2784, 739, +4124, 952,1358,2498,2949,2565, 332,2698,2378, 660,2260,2473,4194,3856,2919, 535, +1260,2651,1208,1428,1300,1949,1303,2942, 433,2455,2450,1251,1946, 614,1269, 641, +1306,1810,2737,3078,2912, 564,2365,1419,1415,1497,4460,2367,2185,1379,3005,1307, +3218,2175,1897,3063, 682,1157,4040,4005,1712,1160,1941,1399, 394, 402,2952,1573, +1151,2986,2404, 862, 299,2033,1489,3006, 346, 171,2886,3401,1726,2932, 168,2533, + 47,2507,1030,3735,1145,3370,1395,1318,1579,3609,4560,2857,4116,1457,2529,1965, + 504,1036,2690,2988,2405, 745,5871, 849,2397,2056,3081, 863,2359,3857,2096, 99, +1397,1769,2300,4428,1643,3455,1978,1757,3718,1440, 35,4879,3742,1296,4228,2280, + 160,5063,1599,2013, 166, 520,3479,1646,3345,3012, 490,1937,1545,1264,2182,2505, +1096,1188,1369,1436,2421,1667,2792,2460,1270,2122, 727,3167,2143, 806,1706,1012, +1800,3037, 960,2218,1882, 805, 139,2456,1139,1521, 851,1052,3093,3089, 342,2039, + 744,5097,1468,1502,1585,2087, 223, 939, 326,2140,2577, 892,2481,1623,4077, 982, +3708, 135,2131, 87,2503,3114,2326,1106, 876,1616, 547,2997,2831,2093,3441,4530, +4314, 9,3256,4229,4148, 659,1462,1986,1710,2046,2913,2231,4090,4880,5255,3392, +3274,1368,3689,4645,1477, 705,3384,3635,1068,1529,2941,1458,3782,1509, 100,1656, +2548, 718,2339, 408,1590,2780,3548,1838,4117,3719,1345,3530, 717,3442,2778,3220, +2898,1892,4590,3614,3371,2043,1998,1224,3483, 891, 635, 584,2559,3355, 733,1766, +1729,1172,3789,1891,2307, 781,2982,2271,1957,1580,5773,2633,2005,4195,3097,1535, +3213,1189,1934,5693,3262, 586,3118,1324,1598, 517,1564,2217,1868,1893,4445,3728, +2703,3139,1526,1787,1992,3882,2875,1549,1199,1056,2224,1904,2711,5098,4287, 338, +1993,3129,3489,2689,1809,2815,1997, 957,1855,3898,2550,3275,3057,1105,1319, 627, +1505,1911,1883,3526, 698,3629,3456,1833,1431, 746, 77,1261,2017,2296,1977,1885, + 125,1334,1600, 525,1798,1109,2222,1470,1945, 559,2236,1186,3443,2476,1929,1411, +2411,3135,1777,3372,2621,1841,1613,3229, 668,1430,1839,2643,2916, 195,1989,2671, +2358,1387, 629,3205,2293,5256,4439, 123,1310, 888,1879,4300,3021,3605,1003,1162, +3192,2910,2010, 140,2395,2859, 55,1082,2012,2901, 662, 419,2081,1438, 680,2774, +4654,3912,1620,1731,1625,5035,4065,2328, 512,1344, 802,5443,2163,2311,2537, 524, +3399, 98,1155,2103,1918,2606,3925,2816,1393,2465,1504,3773,2177,3963,1478,4346, + 180,1113,4655,3461,2028,1698, 833,2696,1235,1322,1594,4408,3623,3013,3225,2040, +3022, 541,2881, 607,3632,2029,1665,1219, 639,1385,1686,1099,2803,3231,1938,3188, +2858, 427, 676,2772,1168,2025, 454,3253,2486,3556, 230,1950, 580, 791,1991,1280, +1086,1974,2034, 630, 257,3338,2788,4903,1017, 86,4790, 966,2789,1995,1696,1131, + 259,3095,4188,1308, 179,1463,5257, 289,4107,1248, 42,3413,1725,2288, 896,1947, + 774,4474,4254, 604,3430,4264, 392,2514,2588, 452, 237,1408,3018, 988,4531,1970, +3034,3310, 540,2370,1562,1288,2990, 502,4765,1147, 4,1853,2708, 207, 294,2814, +4078,2902,2509, 684, 34,3105,3532,2551, 644, 709,2801,2344, 573,1727,3573,3557, +2021,1081,3100,4315,2100,3681, 199,2263,1837,2385, 146,3484,1195,2776,3949, 997, +1939,3973,1008,1091,1202,1962,1847,1149,4209,5444,1076, 493, 117,5400,2521, 972, +1490,2934,1796,4542,2374,1512,2933,2657, 413,2888,1135,2762,2314,2156,1355,2369, + 766,2007,2527,2170,3124,2491,2593,2632,4757,2437, 234,3125,3591,1898,1750,1376, +1942,3468,3138, 570,2127,2145,3276,4131, 962, 132,1445,4196, 19, 941,3624,3480, +3366,1973,1374,4461,3431,2629, 283,2415,2275, 808,2887,3620,2112,2563,1353,3610, + 955,1089,3103,1053, 96, 88,4097, 823,3808,1583, 399, 292,4091,3313, 421,1128, + 642,4006, 903,2539,1877,2082, 596, 29,4066,1790, 722,2157, 130, 995,1569, 769, +1485, 464, 513,2213, 288,1923,1101,2453,4316, 133, 486,2445, 50, 625, 487,2207, + 57, 423, 481,2962, 159,3729,1558, 491, 303, 482, 501, 240,2837, 112,3648,2392, +1783, 362, 8,3433,3422, 610,2793,3277,1390,1284,1654, 21,3823, 734, 367, 623, + 193, 287, 374,1009,1483, 816, 476, 313,2255,2340,1262,2150,2899,1146,2581, 782, +2116,1659,2018,1880, 255,3586,3314,1110,2867,2137,2564, 986,2767,5185,2006, 650, + 158, 926, 762, 881,3157,2717,2362,3587, 306,3690,3245,1542,3077,2427,1691,2478, +2118,2985,3490,2438, 539,2305, 983, 129,1754, 355,4201,2386, 827,2923, 104,1773, +2838,2771, 411,2905,3919, 376, 767, 122,1114, 828,2422,1817,3506, 266,3460,1007, +1609,4998, 945,2612,4429,2274, 726,1247,1964,2914,2199,2070,4002,4108, 657,3323, +1422, 579, 455,2764,4737,1222,2895,1670, 824,1223,1487,2525, 558, 861,3080, 598, +2659,2515,1967, 752,2583,2376,2214,4180, 977, 704,2464,4999,2622,4109,1210,2961, + 819,1541, 142,2284, 44, 418, 457,1126,3730,4347,4626,1644,1876,3671,1864, 302, +1063,5694, 624, 723,1984,3745,1314,1676,2488,1610,1449,3558,3569,2166,2098, 409, +1011,2325,3704,2306, 818,1732,1383,1824,1844,3757, 999,2705,3497,1216,1423,2683, +2426,2954,2501,2726,2229,1475,2554,5064,1971,1794,1666,2014,1343, 783, 724, 191, +2434,1354,2220,5065,1763,2752,2472,4152, 131, 175,2885,3434, 92,1466,4920,2616, +3871,3872,3866, 128,1551,1632, 669,1854,3682,4691,4125,1230, 188,2973,3290,1302, +1213, 560,3266, 917, 763,3909,3249,1760, 868,1958, 764,1782,2097, 145,2277,3774, +4462, 64,1491,3062, 971,2132,3606,2442, 221,1226,1617, 218, 323,1185,3207,3147, + 571, 619,1473,1005,1744,2281, 449,1887,2396,3685, 275, 375,3816,1743,3844,3731, + 845,1983,2350,4210,1377, 773, 967,3499,3052,3743,2725,4007,1697,1022,3943,1464, +3264,2855,2722,1952,1029,2839,2467, 84,4383,2215, 820,1391,2015,2448,3672, 377, +1948,2168, 797,2545,3536,2578,2645, 94,2874,1678, 405,1259,3071, 771, 546,1315, + 470,1243,3083, 895,2468, 981, 969,2037, 846,4181, 653,1276,2928, 14,2594, 557, +3007,2474, 156, 902,1338,1740,2574, 537,2518, 973,2282,2216,2433,1928, 138,2903, +1293,2631,1612, 646,3457, 839,2935, 111, 496,2191,2847, 589,3186, 149,3994,2060, +4031,2641,4067,3145,1870, 37,3597,2136,1025,2051,3009,3383,3549,1121,1016,3261, +1301, 251,2446,2599,2153, 872,3246, 637, 334,3705, 831, 884, 921,3065,3140,4092, +2198,1944, 246,2964, 108,2045,1152,1921,2308,1031, 203,3173,4170,1907,3890, 810, +1401,2003,1690, 506, 647,1242,2828,1761,1649,3208,2249,1589,3709,2931,5156,1708, + 498, 666,2613, 834,3817,1231, 184,2851,1124, 883,3197,2261,3710,1765,1553,2658, +1178,2639,2351, 93,1193, 942,2538,2141,4402, 235,1821, 870,1591,2192,1709,1871, +3341,1618,4126,2595,2334, 603, 651, 69, 701, 268,2662,3411,2555,1380,1606, 503, + 448, 254,2371,2646, 574,1187,2309,1770, 322,2235,1292,1801, 305, 566,1133, 229, +2067,2057, 706, 167, 483,2002,2672,3295,1820,3561,3067, 316, 378,2746,3452,1112, + 136,1981, 507,1651,2917,1117, 285,4591, 182,2580,3522,1304, 335,3303,1835,2504, +1795,1792,2248, 674,1018,2106,2449,1857,2292,2845, 976,3047,1781,2600,2727,1389, +1281, 52,3152, 153, 265,3950, 672,3485,3951,4463, 430,1183, 365, 278,2169, 27, +1407,1336,2304, 209,1340,1730,2202,1852,2403,2883, 979,1737,1062, 631,2829,2542, +3876,2592, 825,2086,2226,3048,3625, 352,1417,3724, 542, 991, 431,1351,3938,1861, +2294, 826,1361,2927,3142,3503,1738, 463,2462,2723, 582,1916,1595,2808, 400,3845, +3891,2868,3621,2254, 58,2492,1123, 910,2160,2614,1372,1603,1196,1072,3385,1700, +3267,1980, 696, 480,2430, 920, 799,1570,2920,1951,2041,4047,2540,1321,4223,2469, +3562,2228,1271,2602, 401,2833,3351,2575,5157, 907,2312,1256, 410, 263,3507,1582, + 996, 678,1849,2316,1480, 908,3545,2237, 703,2322, 667,1826,2849,1531,2604,2999, +2407,3146,2151,2630,1786,3711, 469,3542, 497,3899,2409, 858, 837,4446,3393,1274, + 786, 620,1845,2001,3311, 484, 308,3367,1204,1815,3691,2332,1532,2557,1842,2020, +2724,1927,2333,4440, 567, 22,1673,2728,4475,1987,1858,1144,1597, 101,1832,3601, + 12, 974,3783,4391, 951,1412, 1,3720, 453,4608,4041, 528,1041,1027,3230,2628, +1129, 875,1051,3291,1203,2262,1069,2860,2799,2149,2615,3278, 144,1758,3040, 31, + 475,1680, 366,2685,3184, 311,1642,4008,2466,5036,1593,1493,2809, 216,1420,1668, + 233, 304,2128,3284, 232,1429,1768,1040,2008,3407,2740,2967,2543, 242,2133, 778, +1565,2022,2620, 505,2189,2756,1098,2273, 372,1614, 708, 553,2846,2094,2278, 169, +3626,2835,4161, 228,2674,3165, 809,1454,1309, 466,1705,1095, 900,3423, 880,2667, +3751,5258,2317,3109,2571,4317,2766,1503,1342, 866,4447,1118, 63,2076, 314,1881, +1348,1061, 172, 978,3515,1747, 532, 511,3970, 6, 601, 905,2699,3300,1751, 276, +1467,3725,2668, 65,4239,2544,2779,2556,1604, 578,2451,1802, 992,2331,2624,1320, +3446, 713,1513,1013, 103,2786,2447,1661, 886,1702, 916, 654,3574,2031,1556, 751, +2178,2821,2179,1498,1538,2176, 271, 914,2251,2080,1325, 638,1953,2937,3877,2432, +2754, 95,3265,1716, 260,1227,4083, 775, 106,1357,3254, 426,1607, 555,2480, 772, +1985, 244,2546, 474, 495,1046,2611,1851,2061, 71,2089,1675,2590, 742,3758,2843, +3222,1433, 267,2180,2576,2826,2233,2092,3913,2435, 956,1745,3075, 856,2113,1116, + 451, 3,1988,2896,1398, 993,2463,1878,2049,1341,2718,2721,2870,2108, 712,2904, +4363,2753,2324, 277,2872,2349,2649, 384, 987, 435, 691,3000, 922, 164,3939, 652, +1500,1184,4153,2482,3373,2165,4848,2335,3775,3508,3154,2806,2830,1554,2102,1664, +2530,1434,2408, 893,1547,2623,3447,2832,2242,2532,3169,2856,3223,2078, 49,3770, +3469, 462, 318, 656,2259,3250,3069, 679,1629,2758, 344,1138,1104,3120,1836,1283, +3115,2154,1437,4448, 934, 759,1999, 794,2862,1038, 533,2560,1722,2342, 855,2626, +1197,1663,4476,3127, 85,4240,2528, 25,1111,1181,3673, 407,3470,4561,2679,2713, + 768,1925,2841,3986,1544,1165, 932, 373,1240,2146,1930,2673, 721,4766, 354,4333, + 391,2963, 187, 61,3364,1442,1102, 330,1940,1767, 341,3809,4118, 393,2496,2062, +2211, 105, 331, 300, 439, 913,1332, 626, 379,3304,1557, 328, 689,3952, 309,1555, + 931, 317,2517,3027, 325, 569, 686,2107,3084, 60,1042,1333,2794, 264,3177,4014, +1628, 258,3712, 7,4464,1176,1043,1778, 683, 114,1975, 78,1492, 383,1886, 510, + 386, 645,5291,2891,2069,3305,4138,3867,2939,2603,2493,1935,1066,1848,3588,1015, +1282,1289,4609, 697,1453,3044,2666,3611,1856,2412, 54, 719,1330, 568,3778,2459, +1748, 788, 492, 551,1191,1000, 488,3394,3763, 282,1799, 348,2016,1523,3155,2390, +1049, 382,2019,1788,1170, 729,2968,3523, 897,3926,2785,2938,3292, 350,2319,3238, +1718,1717,2655,3453,3143,4465, 161,2889,2980,2009,1421, 56,1908,1640,2387,2232, +1917,1874,2477,4921, 148, 83,3438, 592,4245,2882,1822,1055, 741, 115,1496,1624, + 381,1638,4592,1020, 516,3214, 458, 947,4575,1432, 211,1514,2926,1865,2142, 189, + 852,1221,1400,1486, 882,2299,4036, 351, 28,1122, 700,6479,6480,6481,6482,6483, #last 512 +) + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/gb2312prober.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/gb2312prober.py new file mode 100644 index 0000000..8446d2d --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/gb2312prober.py @@ -0,0 +1,46 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import GB2312DistributionAnalysis +from .mbcssm import GB2312_SM_MODEL + +class GB2312Prober(MultiByteCharSetProber): + def __init__(self): + super(GB2312Prober, self).__init__() + self.coding_sm = CodingStateMachine(GB2312_SM_MODEL) + self.distribution_analyzer = GB2312DistributionAnalysis() + self.reset() + + @property + def charset_name(self): + return "GB2312" + + @property + def language(self): + return "Chinese" diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/hebrewprober.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/hebrewprober.py new file mode 100644 index 0000000..b0e1bf4 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/hebrewprober.py @@ -0,0 +1,292 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Shy Shalom +# Portions created by the Initial Developer are Copyright (C) 2005 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetprober import CharSetProber +from .enums import ProbingState + +# This prober doesn't actually recognize a language or a charset. +# It is a helper prober for the use of the Hebrew model probers + +### General ideas of the Hebrew charset recognition ### +# +# Four main charsets exist in Hebrew: +# "ISO-8859-8" - Visual Hebrew +# "windows-1255" - Logical Hebrew +# "ISO-8859-8-I" - Logical Hebrew +# "x-mac-hebrew" - ?? Logical Hebrew ?? +# +# Both "ISO" charsets use a completely identical set of code points, whereas +# "windows-1255" and "x-mac-hebrew" are two different proper supersets of +# these code points. windows-1255 defines additional characters in the range +# 0x80-0x9F as some misc punctuation marks as well as some Hebrew-specific +# diacritics and additional 'Yiddish' ligature letters in the range 0xc0-0xd6. +# x-mac-hebrew defines similar additional code points but with a different +# mapping. +# +# As far as an average Hebrew text with no diacritics is concerned, all four +# charsets are identical with respect to code points. Meaning that for the +# main Hebrew alphabet, all four map the same values to all 27 Hebrew letters +# (including final letters). +# +# The dominant difference between these charsets is their directionality. +# "Visual" directionality means that the text is ordered as if the renderer is +# not aware of a BIDI rendering algorithm. The renderer sees the text and +# draws it from left to right. The text itself when ordered naturally is read +# backwards. A buffer of Visual Hebrew generally looks like so: +# "[last word of first line spelled backwards] [whole line ordered backwards +# and spelled backwards] [first word of first line spelled backwards] +# [end of line] [last word of second line] ... etc' " +# adding punctuation marks, numbers and English text to visual text is +# naturally also "visual" and from left to right. +# +# "Logical" directionality means the text is ordered "naturally" according to +# the order it is read. It is the responsibility of the renderer to display +# the text from right to left. A BIDI algorithm is used to place general +# punctuation marks, numbers and English text in the text. +# +# Texts in x-mac-hebrew are almost impossible to find on the Internet. From +# what little evidence I could find, it seems that its general directionality +# is Logical. +# +# To sum up all of the above, the Hebrew probing mechanism knows about two +# charsets: +# Visual Hebrew - "ISO-8859-8" - backwards text - Words and sentences are +# backwards while line order is natural. For charset recognition purposes +# the line order is unimportant (In fact, for this implementation, even +# word order is unimportant). +# Logical Hebrew - "windows-1255" - normal, naturally ordered text. +# +# "ISO-8859-8-I" is a subset of windows-1255 and doesn't need to be +# specifically identified. +# "x-mac-hebrew" is also identified as windows-1255. A text in x-mac-hebrew +# that contain special punctuation marks or diacritics is displayed with +# some unconverted characters showing as question marks. This problem might +# be corrected using another model prober for x-mac-hebrew. Due to the fact +# that x-mac-hebrew texts are so rare, writing another model prober isn't +# worth the effort and performance hit. +# +#### The Prober #### +# +# The prober is divided between two SBCharSetProbers and a HebrewProber, +# all of which are managed, created, fed data, inquired and deleted by the +# SBCSGroupProber. The two SBCharSetProbers identify that the text is in +# fact some kind of Hebrew, Logical or Visual. The final decision about which +# one is it is made by the HebrewProber by combining final-letter scores +# with the scores of the two SBCharSetProbers to produce a final answer. +# +# The SBCSGroupProber is responsible for stripping the original text of HTML +# tags, English characters, numbers, low-ASCII punctuation characters, spaces +# and new lines. It reduces any sequence of such characters to a single space. +# The buffer fed to each prober in the SBCS group prober is pure text in +# high-ASCII. +# The two SBCharSetProbers (model probers) share the same language model: +# Win1255Model. +# The first SBCharSetProber uses the model normally as any other +# SBCharSetProber does, to recognize windows-1255, upon which this model was +# built. The second SBCharSetProber is told to make the pair-of-letter +# lookup in the language model backwards. This in practice exactly simulates +# a visual Hebrew model using the windows-1255 logical Hebrew model. +# +# The HebrewProber is not using any language model. All it does is look for +# final-letter evidence suggesting the text is either logical Hebrew or visual +# Hebrew. Disjointed from the model probers, the results of the HebrewProber +# alone are meaningless. HebrewProber always returns 0.00 as confidence +# since it never identifies a charset by itself. Instead, the pointer to the +# HebrewProber is passed to the model probers as a helper "Name Prober". +# When the Group prober receives a positive identification from any prober, +# it asks for the name of the charset identified. If the prober queried is a +# Hebrew model prober, the model prober forwards the call to the +# HebrewProber to make the final decision. In the HebrewProber, the +# decision is made according to the final-letters scores maintained and Both +# model probers scores. The answer is returned in the form of the name of the +# charset identified, either "windows-1255" or "ISO-8859-8". + +class HebrewProber(CharSetProber): + # windows-1255 / ISO-8859-8 code points of interest + FINAL_KAF = 0xea + NORMAL_KAF = 0xeb + FINAL_MEM = 0xed + NORMAL_MEM = 0xee + FINAL_NUN = 0xef + NORMAL_NUN = 0xf0 + FINAL_PE = 0xf3 + NORMAL_PE = 0xf4 + FINAL_TSADI = 0xf5 + NORMAL_TSADI = 0xf6 + + # Minimum Visual vs Logical final letter score difference. + # If the difference is below this, don't rely solely on the final letter score + # distance. + MIN_FINAL_CHAR_DISTANCE = 5 + + # Minimum Visual vs Logical model score difference. + # If the difference is below this, don't rely at all on the model score + # distance. + MIN_MODEL_DISTANCE = 0.01 + + VISUAL_HEBREW_NAME = "ISO-8859-8" + LOGICAL_HEBREW_NAME = "windows-1255" + + def __init__(self): + super(HebrewProber, self).__init__() + self._final_char_logical_score = None + self._final_char_visual_score = None + self._prev = None + self._before_prev = None + self._logical_prober = None + self._visual_prober = None + self.reset() + + def reset(self): + self._final_char_logical_score = 0 + self._final_char_visual_score = 0 + # The two last characters seen in the previous buffer, + # mPrev and mBeforePrev are initialized to space in order to simulate + # a word delimiter at the beginning of the data + self._prev = ' ' + self._before_prev = ' ' + # These probers are owned by the group prober. + + def set_model_probers(self, logicalProber, visualProber): + self._logical_prober = logicalProber + self._visual_prober = visualProber + + def is_final(self, c): + return c in [self.FINAL_KAF, self.FINAL_MEM, self.FINAL_NUN, + self.FINAL_PE, self.FINAL_TSADI] + + def is_non_final(self, c): + # The normal Tsadi is not a good Non-Final letter due to words like + # 'lechotet' (to chat) containing an apostrophe after the tsadi. This + # apostrophe is converted to a space in FilterWithoutEnglishLetters + # causing the Non-Final tsadi to appear at an end of a word even + # though this is not the case in the original text. + # The letters Pe and Kaf rarely display a related behavior of not being + # a good Non-Final letter. Words like 'Pop', 'Winamp' and 'Mubarak' + # for example legally end with a Non-Final Pe or Kaf. However, the + # benefit of these letters as Non-Final letters outweighs the damage + # since these words are quite rare. + return c in [self.NORMAL_KAF, self.NORMAL_MEM, + self.NORMAL_NUN, self.NORMAL_PE] + + def feed(self, byte_str): + # Final letter analysis for logical-visual decision. + # Look for evidence that the received buffer is either logical Hebrew + # or visual Hebrew. + # The following cases are checked: + # 1) A word longer than 1 letter, ending with a final letter. This is + # an indication that the text is laid out "naturally" since the + # final letter really appears at the end. +1 for logical score. + # 2) A word longer than 1 letter, ending with a Non-Final letter. In + # normal Hebrew, words ending with Kaf, Mem, Nun, Pe or Tsadi, + # should not end with the Non-Final form of that letter. Exceptions + # to this rule are mentioned above in isNonFinal(). This is an + # indication that the text is laid out backwards. +1 for visual + # score + # 3) A word longer than 1 letter, starting with a final letter. Final + # letters should not appear at the beginning of a word. This is an + # indication that the text is laid out backwards. +1 for visual + # score. + # + # The visual score and logical score are accumulated throughout the + # text and are finally checked against each other in GetCharSetName(). + # No checking for final letters in the middle of words is done since + # that case is not an indication for either Logical or Visual text. + # + # We automatically filter out all 7-bit characters (replace them with + # spaces) so the word boundary detection works properly. [MAP] + + if self.state == ProbingState.NOT_ME: + # Both model probers say it's not them. No reason to continue. + return ProbingState.NOT_ME + + byte_str = self.filter_high_byte_only(byte_str) + + for cur in byte_str: + if cur == ' ': + # We stand on a space - a word just ended + if self._before_prev != ' ': + # next-to-last char was not a space so self._prev is not a + # 1 letter word + if self.is_final(self._prev): + # case (1) [-2:not space][-1:final letter][cur:space] + self._final_char_logical_score += 1 + elif self.is_non_final(self._prev): + # case (2) [-2:not space][-1:Non-Final letter][ + # cur:space] + self._final_char_visual_score += 1 + else: + # Not standing on a space + if ((self._before_prev == ' ') and + (self.is_final(self._prev)) and (cur != ' ')): + # case (3) [-2:space][-1:final letter][cur:not space] + self._final_char_visual_score += 1 + self._before_prev = self._prev + self._prev = cur + + # Forever detecting, till the end or until both model probers return + # ProbingState.NOT_ME (handled above) + return ProbingState.DETECTING + + @property + def charset_name(self): + # Make the decision: is it Logical or Visual? + # If the final letter score distance is dominant enough, rely on it. + finalsub = self._final_char_logical_score - self._final_char_visual_score + if finalsub >= self.MIN_FINAL_CHAR_DISTANCE: + return self.LOGICAL_HEBREW_NAME + if finalsub <= -self.MIN_FINAL_CHAR_DISTANCE: + return self.VISUAL_HEBREW_NAME + + # It's not dominant enough, try to rely on the model scores instead. + modelsub = (self._logical_prober.get_confidence() + - self._visual_prober.get_confidence()) + if modelsub > self.MIN_MODEL_DISTANCE: + return self.LOGICAL_HEBREW_NAME + if modelsub < -self.MIN_MODEL_DISTANCE: + return self.VISUAL_HEBREW_NAME + + # Still no good, back to final letter distance, maybe it'll save the + # day. + if finalsub < 0.0: + return self.VISUAL_HEBREW_NAME + + # (finalsub > 0 - Logical) or (don't know what to do) default to + # Logical. + return self.LOGICAL_HEBREW_NAME + + @property + def language(self): + return 'Hebrew' + + @property + def state(self): + # Remain active as long as any of the model probers are active. + if (self._logical_prober.state == ProbingState.NOT_ME) and \ + (self._visual_prober.state == ProbingState.NOT_ME): + return ProbingState.NOT_ME + return ProbingState.DETECTING diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/jisfreq.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/jisfreq.py new file mode 100644 index 0000000..83fc082 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/jisfreq.py @@ -0,0 +1,325 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# Sampling from about 20M text materials include literature and computer technology +# +# Japanese frequency table, applied to both S-JIS and EUC-JP +# They are sorted in order. + +# 128 --> 0.77094 +# 256 --> 0.85710 +# 512 --> 0.92635 +# 1024 --> 0.97130 +# 2048 --> 0.99431 +# +# Ideal Distribution Ratio = 0.92635 / (1-0.92635) = 12.58 +# Random Distribution Ration = 512 / (2965+62+83+86-512) = 0.191 +# +# Typical Distribution Ratio, 25% of IDR + +JIS_TYPICAL_DISTRIBUTION_RATIO = 3.0 + +# Char to FreqOrder table , +JIS_TABLE_SIZE = 4368 + +JIS_CHAR_TO_FREQ_ORDER = ( + 40, 1, 6, 182, 152, 180, 295,2127, 285, 381,3295,4304,3068,4606,3165,3510, # 16 +3511,1822,2785,4607,1193,2226,5070,4608, 171,2996,1247, 18, 179,5071, 856,1661, # 32 +1262,5072, 619, 127,3431,3512,3230,1899,1700, 232, 228,1294,1298, 284, 283,2041, # 48 +2042,1061,1062, 48, 49, 44, 45, 433, 434,1040,1041, 996, 787,2997,1255,4305, # 64 +2108,4609,1684,1648,5073,5074,5075,5076,5077,5078,3687,5079,4610,5080,3927,3928, # 80 +5081,3296,3432, 290,2285,1471,2187,5082,2580,2825,1303,2140,1739,1445,2691,3375, # 96 +1691,3297,4306,4307,4611, 452,3376,1182,2713,3688,3069,4308,5083,5084,5085,5086, # 112 +5087,5088,5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,5099,5100,5101,5102, # 128 +5103,5104,5105,5106,5107,5108,5109,5110,5111,5112,4097,5113,5114,5115,5116,5117, # 144 +5118,5119,5120,5121,5122,5123,5124,5125,5126,5127,5128,5129,5130,5131,5132,5133, # 160 +5134,5135,5136,5137,5138,5139,5140,5141,5142,5143,5144,5145,5146,5147,5148,5149, # 176 +5150,5151,5152,4612,5153,5154,5155,5156,5157,5158,5159,5160,5161,5162,5163,5164, # 192 +5165,5166,5167,5168,5169,5170,5171,5172,5173,5174,5175,1472, 598, 618, 820,1205, # 208 +1309,1412,1858,1307,1692,5176,5177,5178,5179,5180,5181,5182,1142,1452,1234,1172, # 224 +1875,2043,2149,1793,1382,2973, 925,2404,1067,1241, 960,1377,2935,1491, 919,1217, # 240 +1865,2030,1406,1499,2749,4098,5183,5184,5185,5186,5187,5188,2561,4099,3117,1804, # 256 +2049,3689,4309,3513,1663,5189,3166,3118,3298,1587,1561,3433,5190,3119,1625,2998, # 272 +3299,4613,1766,3690,2786,4614,5191,5192,5193,5194,2161, 26,3377, 2,3929, 20, # 288 +3691, 47,4100, 50, 17, 16, 35, 268, 27, 243, 42, 155, 24, 154, 29, 184, # 304 + 4, 91, 14, 92, 53, 396, 33, 289, 9, 37, 64, 620, 21, 39, 321, 5, # 320 + 12, 11, 52, 13, 3, 208, 138, 0, 7, 60, 526, 141, 151,1069, 181, 275, # 336 +1591, 83, 132,1475, 126, 331, 829, 15, 69, 160, 59, 22, 157, 55,1079, 312, # 352 + 109, 38, 23, 25, 10, 19, 79,5195, 61, 382,1124, 8, 30,5196,5197,5198, # 368 +5199,5200,5201,5202,5203,5204,5205,5206, 89, 62, 74, 34,2416, 112, 139, 196, # 384 + 271, 149, 84, 607, 131, 765, 46, 88, 153, 683, 76, 874, 101, 258, 57, 80, # 400 + 32, 364, 121,1508, 169,1547, 68, 235, 145,2999, 41, 360,3027, 70, 63, 31, # 416 + 43, 259, 262,1383, 99, 533, 194, 66, 93, 846, 217, 192, 56, 106, 58, 565, # 432 + 280, 272, 311, 256, 146, 82, 308, 71, 100, 128, 214, 655, 110, 261, 104,1140, # 448 + 54, 51, 36, 87, 67,3070, 185,2618,2936,2020, 28,1066,2390,2059,5207,5208, # 464 +5209,5210,5211,5212,5213,5214,5215,5216,4615,5217,5218,5219,5220,5221,5222,5223, # 480 +5224,5225,5226,5227,5228,5229,5230,5231,5232,5233,5234,5235,5236,3514,5237,5238, # 496 +5239,5240,5241,5242,5243,5244,2297,2031,4616,4310,3692,5245,3071,5246,3598,5247, # 512 +4617,3231,3515,5248,4101,4311,4618,3808,4312,4102,5249,4103,4104,3599,5250,5251, # 528 +5252,5253,5254,5255,5256,5257,5258,5259,5260,5261,5262,5263,5264,5265,5266,5267, # 544 +5268,5269,5270,5271,5272,5273,5274,5275,5276,5277,5278,5279,5280,5281,5282,5283, # 560 +5284,5285,5286,5287,5288,5289,5290,5291,5292,5293,5294,5295,5296,5297,5298,5299, # 576 +5300,5301,5302,5303,5304,5305,5306,5307,5308,5309,5310,5311,5312,5313,5314,5315, # 592 +5316,5317,5318,5319,5320,5321,5322,5323,5324,5325,5326,5327,5328,5329,5330,5331, # 608 +5332,5333,5334,5335,5336,5337,5338,5339,5340,5341,5342,5343,5344,5345,5346,5347, # 624 +5348,5349,5350,5351,5352,5353,5354,5355,5356,5357,5358,5359,5360,5361,5362,5363, # 640 +5364,5365,5366,5367,5368,5369,5370,5371,5372,5373,5374,5375,5376,5377,5378,5379, # 656 +5380,5381, 363, 642,2787,2878,2788,2789,2316,3232,2317,3434,2011, 165,1942,3930, # 672 +3931,3932,3933,5382,4619,5383,4620,5384,5385,5386,5387,5388,5389,5390,5391,5392, # 688 +5393,5394,5395,5396,5397,5398,5399,5400,5401,5402,5403,5404,5405,5406,5407,5408, # 704 +5409,5410,5411,5412,5413,5414,5415,5416,5417,5418,5419,5420,5421,5422,5423,5424, # 720 +5425,5426,5427,5428,5429,5430,5431,5432,5433,5434,5435,5436,5437,5438,5439,5440, # 736 +5441,5442,5443,5444,5445,5446,5447,5448,5449,5450,5451,5452,5453,5454,5455,5456, # 752 +5457,5458,5459,5460,5461,5462,5463,5464,5465,5466,5467,5468,5469,5470,5471,5472, # 768 +5473,5474,5475,5476,5477,5478,5479,5480,5481,5482,5483,5484,5485,5486,5487,5488, # 784 +5489,5490,5491,5492,5493,5494,5495,5496,5497,5498,5499,5500,5501,5502,5503,5504, # 800 +5505,5506,5507,5508,5509,5510,5511,5512,5513,5514,5515,5516,5517,5518,5519,5520, # 816 +5521,5522,5523,5524,5525,5526,5527,5528,5529,5530,5531,5532,5533,5534,5535,5536, # 832 +5537,5538,5539,5540,5541,5542,5543,5544,5545,5546,5547,5548,5549,5550,5551,5552, # 848 +5553,5554,5555,5556,5557,5558,5559,5560,5561,5562,5563,5564,5565,5566,5567,5568, # 864 +5569,5570,5571,5572,5573,5574,5575,5576,5577,5578,5579,5580,5581,5582,5583,5584, # 880 +5585,5586,5587,5588,5589,5590,5591,5592,5593,5594,5595,5596,5597,5598,5599,5600, # 896 +5601,5602,5603,5604,5605,5606,5607,5608,5609,5610,5611,5612,5613,5614,5615,5616, # 912 +5617,5618,5619,5620,5621,5622,5623,5624,5625,5626,5627,5628,5629,5630,5631,5632, # 928 +5633,5634,5635,5636,5637,5638,5639,5640,5641,5642,5643,5644,5645,5646,5647,5648, # 944 +5649,5650,5651,5652,5653,5654,5655,5656,5657,5658,5659,5660,5661,5662,5663,5664, # 960 +5665,5666,5667,5668,5669,5670,5671,5672,5673,5674,5675,5676,5677,5678,5679,5680, # 976 +5681,5682,5683,5684,5685,5686,5687,5688,5689,5690,5691,5692,5693,5694,5695,5696, # 992 +5697,5698,5699,5700,5701,5702,5703,5704,5705,5706,5707,5708,5709,5710,5711,5712, # 1008 +5713,5714,5715,5716,5717,5718,5719,5720,5721,5722,5723,5724,5725,5726,5727,5728, # 1024 +5729,5730,5731,5732,5733,5734,5735,5736,5737,5738,5739,5740,5741,5742,5743,5744, # 1040 +5745,5746,5747,5748,5749,5750,5751,5752,5753,5754,5755,5756,5757,5758,5759,5760, # 1056 +5761,5762,5763,5764,5765,5766,5767,5768,5769,5770,5771,5772,5773,5774,5775,5776, # 1072 +5777,5778,5779,5780,5781,5782,5783,5784,5785,5786,5787,5788,5789,5790,5791,5792, # 1088 +5793,5794,5795,5796,5797,5798,5799,5800,5801,5802,5803,5804,5805,5806,5807,5808, # 1104 +5809,5810,5811,5812,5813,5814,5815,5816,5817,5818,5819,5820,5821,5822,5823,5824, # 1120 +5825,5826,5827,5828,5829,5830,5831,5832,5833,5834,5835,5836,5837,5838,5839,5840, # 1136 +5841,5842,5843,5844,5845,5846,5847,5848,5849,5850,5851,5852,5853,5854,5855,5856, # 1152 +5857,5858,5859,5860,5861,5862,5863,5864,5865,5866,5867,5868,5869,5870,5871,5872, # 1168 +5873,5874,5875,5876,5877,5878,5879,5880,5881,5882,5883,5884,5885,5886,5887,5888, # 1184 +5889,5890,5891,5892,5893,5894,5895,5896,5897,5898,5899,5900,5901,5902,5903,5904, # 1200 +5905,5906,5907,5908,5909,5910,5911,5912,5913,5914,5915,5916,5917,5918,5919,5920, # 1216 +5921,5922,5923,5924,5925,5926,5927,5928,5929,5930,5931,5932,5933,5934,5935,5936, # 1232 +5937,5938,5939,5940,5941,5942,5943,5944,5945,5946,5947,5948,5949,5950,5951,5952, # 1248 +5953,5954,5955,5956,5957,5958,5959,5960,5961,5962,5963,5964,5965,5966,5967,5968, # 1264 +5969,5970,5971,5972,5973,5974,5975,5976,5977,5978,5979,5980,5981,5982,5983,5984, # 1280 +5985,5986,5987,5988,5989,5990,5991,5992,5993,5994,5995,5996,5997,5998,5999,6000, # 1296 +6001,6002,6003,6004,6005,6006,6007,6008,6009,6010,6011,6012,6013,6014,6015,6016, # 1312 +6017,6018,6019,6020,6021,6022,6023,6024,6025,6026,6027,6028,6029,6030,6031,6032, # 1328 +6033,6034,6035,6036,6037,6038,6039,6040,6041,6042,6043,6044,6045,6046,6047,6048, # 1344 +6049,6050,6051,6052,6053,6054,6055,6056,6057,6058,6059,6060,6061,6062,6063,6064, # 1360 +6065,6066,6067,6068,6069,6070,6071,6072,6073,6074,6075,6076,6077,6078,6079,6080, # 1376 +6081,6082,6083,6084,6085,6086,6087,6088,6089,6090,6091,6092,6093,6094,6095,6096, # 1392 +6097,6098,6099,6100,6101,6102,6103,6104,6105,6106,6107,6108,6109,6110,6111,6112, # 1408 +6113,6114,2044,2060,4621, 997,1235, 473,1186,4622, 920,3378,6115,6116, 379,1108, # 1424 +4313,2657,2735,3934,6117,3809, 636,3233, 573,1026,3693,3435,2974,3300,2298,4105, # 1440 + 854,2937,2463, 393,2581,2417, 539, 752,1280,2750,2480, 140,1161, 440, 708,1569, # 1456 + 665,2497,1746,1291,1523,3000, 164,1603, 847,1331, 537,1997, 486, 508,1693,2418, # 1472 +1970,2227, 878,1220, 299,1030, 969, 652,2751, 624,1137,3301,2619, 65,3302,2045, # 1488 +1761,1859,3120,1930,3694,3516, 663,1767, 852, 835,3695, 269, 767,2826,2339,1305, # 1504 + 896,1150, 770,1616,6118, 506,1502,2075,1012,2519, 775,2520,2975,2340,2938,4314, # 1520 +3028,2086,1224,1943,2286,6119,3072,4315,2240,1273,1987,3935,1557, 175, 597, 985, # 1536 +3517,2419,2521,1416,3029, 585, 938,1931,1007,1052,1932,1685,6120,3379,4316,4623, # 1552 + 804, 599,3121,1333,2128,2539,1159,1554,2032,3810, 687,2033,2904, 952, 675,1467, # 1568 +3436,6121,2241,1096,1786,2440,1543,1924, 980,1813,2228, 781,2692,1879, 728,1918, # 1584 +3696,4624, 548,1950,4625,1809,1088,1356,3303,2522,1944, 502, 972, 373, 513,2827, # 1600 + 586,2377,2391,1003,1976,1631,6122,2464,1084, 648,1776,4626,2141, 324, 962,2012, # 1616 +2177,2076,1384, 742,2178,1448,1173,1810, 222, 102, 301, 445, 125,2420, 662,2498, # 1632 + 277, 200,1476,1165,1068, 224,2562,1378,1446, 450,1880, 659, 791, 582,4627,2939, # 1648 +3936,1516,1274, 555,2099,3697,1020,1389,1526,3380,1762,1723,1787,2229, 412,2114, # 1664 +1900,2392,3518, 512,2597, 427,1925,2341,3122,1653,1686,2465,2499, 697, 330, 273, # 1680 + 380,2162, 951, 832, 780, 991,1301,3073, 965,2270,3519, 668,2523,2636,1286, 535, # 1696 +1407, 518, 671, 957,2658,2378, 267, 611,2197,3030,6123, 248,2299, 967,1799,2356, # 1712 + 850,1418,3437,1876,1256,1480,2828,1718,6124,6125,1755,1664,2405,6126,4628,2879, # 1728 +2829, 499,2179, 676,4629, 557,2329,2214,2090, 325,3234, 464, 811,3001, 992,2342, # 1744 +2481,1232,1469, 303,2242, 466,1070,2163, 603,1777,2091,4630,2752,4631,2714, 322, # 1760 +2659,1964,1768, 481,2188,1463,2330,2857,3600,2092,3031,2421,4632,2318,2070,1849, # 1776 +2598,4633,1302,2254,1668,1701,2422,3811,2905,3032,3123,2046,4106,1763,1694,4634, # 1792 +1604, 943,1724,1454, 917, 868,2215,1169,2940, 552,1145,1800,1228,1823,1955, 316, # 1808 +1080,2510, 361,1807,2830,4107,2660,3381,1346,1423,1134,4108,6127, 541,1263,1229, # 1824 +1148,2540, 545, 465,1833,2880,3438,1901,3074,2482, 816,3937, 713,1788,2500, 122, # 1840 +1575, 195,1451,2501,1111,6128, 859, 374,1225,2243,2483,4317, 390,1033,3439,3075, # 1856 +2524,1687, 266, 793,1440,2599, 946, 779, 802, 507, 897,1081, 528,2189,1292, 711, # 1872 +1866,1725,1167,1640, 753, 398,2661,1053, 246, 348,4318, 137,1024,3440,1600,2077, # 1888 +2129, 825,4319, 698, 238, 521, 187,2300,1157,2423,1641,1605,1464,1610,1097,2541, # 1904 +1260,1436, 759,2255,1814,2150, 705,3235, 409,2563,3304, 561,3033,2005,2564, 726, # 1920 +1956,2343,3698,4109, 949,3812,3813,3520,1669, 653,1379,2525, 881,2198, 632,2256, # 1936 +1027, 778,1074, 733,1957, 514,1481,2466, 554,2180, 702,3938,1606,1017,1398,6129, # 1952 +1380,3521, 921, 993,1313, 594, 449,1489,1617,1166, 768,1426,1360, 495,1794,3601, # 1968 +1177,3602,1170,4320,2344, 476, 425,3167,4635,3168,1424, 401,2662,1171,3382,1998, # 1984 +1089,4110, 477,3169, 474,6130,1909, 596,2831,1842, 494, 693,1051,1028,1207,3076, # 2000 + 606,2115, 727,2790,1473,1115, 743,3522, 630, 805,1532,4321,2021, 366,1057, 838, # 2016 + 684,1114,2142,4322,2050,1492,1892,1808,2271,3814,2424,1971,1447,1373,3305,1090, # 2032 +1536,3939,3523,3306,1455,2199, 336, 369,2331,1035, 584,2393, 902, 718,2600,6131, # 2048 +2753, 463,2151,1149,1611,2467, 715,1308,3124,1268, 343,1413,3236,1517,1347,2663, # 2064 +2093,3940,2022,1131,1553,2100,2941,1427,3441,2942,1323,2484,6132,1980, 872,2368, # 2080 +2441,2943, 320,2369,2116,1082, 679,1933,3941,2791,3815, 625,1143,2023, 422,2200, # 2096 +3816,6133, 730,1695, 356,2257,1626,2301,2858,2637,1627,1778, 937, 883,2906,2693, # 2112 +3002,1769,1086, 400,1063,1325,3307,2792,4111,3077, 456,2345,1046, 747,6134,1524, # 2128 + 884,1094,3383,1474,2164,1059, 974,1688,2181,2258,1047, 345,1665,1187, 358, 875, # 2144 +3170, 305, 660,3524,2190,1334,1135,3171,1540,1649,2542,1527, 927, 968,2793, 885, # 2160 +1972,1850, 482, 500,2638,1218,1109,1085,2543,1654,2034, 876, 78,2287,1482,1277, # 2176 + 861,1675,1083,1779, 724,2754, 454, 397,1132,1612,2332, 893, 672,1237, 257,2259, # 2192 +2370, 135,3384, 337,2244, 547, 352, 340, 709,2485,1400, 788,1138,2511, 540, 772, # 2208 +1682,2260,2272,2544,2013,1843,1902,4636,1999,1562,2288,4637,2201,1403,1533, 407, # 2224 + 576,3308,1254,2071, 978,3385, 170, 136,1201,3125,2664,3172,2394, 213, 912, 873, # 2240 +3603,1713,2202, 699,3604,3699, 813,3442, 493, 531,1054, 468,2907,1483, 304, 281, # 2256 +4112,1726,1252,2094, 339,2319,2130,2639, 756,1563,2944, 748, 571,2976,1588,2425, # 2272 +2715,1851,1460,2426,1528,1392,1973,3237, 288,3309, 685,3386, 296, 892,2716,2216, # 2288 +1570,2245, 722,1747,2217, 905,3238,1103,6135,1893,1441,1965, 251,1805,2371,3700, # 2304 +2601,1919,1078, 75,2182,1509,1592,1270,2640,4638,2152,6136,3310,3817, 524, 706, # 2320 +1075, 292,3818,1756,2602, 317, 98,3173,3605,3525,1844,2218,3819,2502, 814, 567, # 2336 + 385,2908,1534,6137, 534,1642,3239, 797,6138,1670,1529, 953,4323, 188,1071, 538, # 2352 + 178, 729,3240,2109,1226,1374,2000,2357,2977, 731,2468,1116,2014,2051,6139,1261, # 2368 +1593, 803,2859,2736,3443, 556, 682, 823,1541,6140,1369,2289,1706,2794, 845, 462, # 2384 +2603,2665,1361, 387, 162,2358,1740, 739,1770,1720,1304,1401,3241,1049, 627,1571, # 2400 +2427,3526,1877,3942,1852,1500, 431,1910,1503, 677, 297,2795, 286,1433,1038,1198, # 2416 +2290,1133,1596,4113,4639,2469,1510,1484,3943,6141,2442, 108, 712,4640,2372, 866, # 2432 +3701,2755,3242,1348, 834,1945,1408,3527,2395,3243,1811, 824, 994,1179,2110,1548, # 2448 +1453, 790,3003, 690,4324,4325,2832,2909,3820,1860,3821, 225,1748, 310, 346,1780, # 2464 +2470, 821,1993,2717,2796, 828, 877,3528,2860,2471,1702,2165,2910,2486,1789, 453, # 2480 + 359,2291,1676, 73,1164,1461,1127,3311, 421, 604, 314,1037, 589, 116,2487, 737, # 2496 + 837,1180, 111, 244, 735,6142,2261,1861,1362, 986, 523, 418, 581,2666,3822, 103, # 2512 + 855, 503,1414,1867,2488,1091, 657,1597, 979, 605,1316,4641,1021,2443,2078,2001, # 2528 +1209, 96, 587,2166,1032, 260,1072,2153, 173, 94, 226,3244, 819,2006,4642,4114, # 2544 +2203, 231,1744, 782, 97,2667, 786,3387, 887, 391, 442,2219,4326,1425,6143,2694, # 2560 + 633,1544,1202, 483,2015, 592,2052,1958,2472,1655, 419, 129,4327,3444,3312,1714, # 2576 +1257,3078,4328,1518,1098, 865,1310,1019,1885,1512,1734, 469,2444, 148, 773, 436, # 2592 +1815,1868,1128,1055,4329,1245,2756,3445,2154,1934,1039,4643, 579,1238, 932,2320, # 2608 + 353, 205, 801, 115,2428, 944,2321,1881, 399,2565,1211, 678, 766,3944, 335,2101, # 2624 +1459,1781,1402,3945,2737,2131,1010, 844, 981,1326,1013, 550,1816,1545,2620,1335, # 2640 +1008, 371,2881, 936,1419,1613,3529,1456,1395,2273,1834,2604,1317,2738,2503, 416, # 2656 +1643,4330, 806,1126, 229, 591,3946,1314,1981,1576,1837,1666, 347,1790, 977,3313, # 2672 + 764,2861,1853, 688,2429,1920,1462, 77, 595, 415,2002,3034, 798,1192,4115,6144, # 2688 +2978,4331,3035,2695,2582,2072,2566, 430,2430,1727, 842,1396,3947,3702, 613, 377, # 2704 + 278, 236,1417,3388,3314,3174, 757,1869, 107,3530,6145,1194, 623,2262, 207,1253, # 2720 +2167,3446,3948, 492,1117,1935, 536,1838,2757,1246,4332, 696,2095,2406,1393,1572, # 2736 +3175,1782, 583, 190, 253,1390,2230, 830,3126,3389, 934,3245,1703,1749,2979,1870, # 2752 +2545,1656,2204, 869,2346,4116,3176,1817, 496,1764,4644, 942,1504, 404,1903,1122, # 2768 +1580,3606,2945,1022, 515, 372,1735, 955,2431,3036,6146,2797,1110,2302,2798, 617, # 2784 +6147, 441, 762,1771,3447,3607,3608,1904, 840,3037, 86, 939,1385, 572,1370,2445, # 2800 +1336, 114,3703, 898, 294, 203,3315, 703,1583,2274, 429, 961,4333,1854,1951,3390, # 2816 +2373,3704,4334,1318,1381, 966,1911,2322,1006,1155, 309, 989, 458,2718,1795,1372, # 2832 +1203, 252,1689,1363,3177, 517,1936, 168,1490, 562, 193,3823,1042,4117,1835, 551, # 2848 + 470,4645, 395, 489,3448,1871,1465,2583,2641, 417,1493, 279,1295, 511,1236,1119, # 2864 + 72,1231,1982,1812,3004, 871,1564, 984,3449,1667,2696,2096,4646,2347,2833,1673, # 2880 +3609, 695,3246,2668, 807,1183,4647, 890, 388,2333,1801,1457,2911,1765,1477,1031, # 2896 +3316,3317,1278,3391,2799,2292,2526, 163,3450,4335,2669,1404,1802,6148,2323,2407, # 2912 +1584,1728,1494,1824,1269, 298, 909,3318,1034,1632, 375, 776,1683,2061, 291, 210, # 2928 +1123, 809,1249,1002,2642,3038, 206,1011,2132, 144, 975, 882,1565, 342, 667, 754, # 2944 +1442,2143,1299,2303,2062, 447, 626,2205,1221,2739,2912,1144,1214,2206,2584, 760, # 2960 +1715, 614, 950,1281,2670,2621, 810, 577,1287,2546,4648, 242,2168, 250,2643, 691, # 2976 + 123,2644, 647, 313,1029, 689,1357,2946,1650, 216, 771,1339,1306, 808,2063, 549, # 2992 + 913,1371,2913,2914,6149,1466,1092,1174,1196,1311,2605,2396,1783,1796,3079, 406, # 3008 +2671,2117,3949,4649, 487,1825,2220,6150,2915, 448,2348,1073,6151,2397,1707, 130, # 3024 + 900,1598, 329, 176,1959,2527,1620,6152,2275,4336,3319,1983,2191,3705,3610,2155, # 3040 +3706,1912,1513,1614,6153,1988, 646, 392,2304,1589,3320,3039,1826,1239,1352,1340, # 3056 +2916, 505,2567,1709,1437,2408,2547, 906,6154,2672, 384,1458,1594,1100,1329, 710, # 3072 + 423,3531,2064,2231,2622,1989,2673,1087,1882, 333, 841,3005,1296,2882,2379, 580, # 3088 +1937,1827,1293,2585, 601, 574, 249,1772,4118,2079,1120, 645, 901,1176,1690, 795, # 3104 +2207, 478,1434, 516,1190,1530, 761,2080, 930,1264, 355, 435,1552, 644,1791, 987, # 3120 + 220,1364,1163,1121,1538, 306,2169,1327,1222, 546,2645, 218, 241, 610,1704,3321, # 3136 +1984,1839,1966,2528, 451,6155,2586,3707,2568, 907,3178, 254,2947, 186,1845,4650, # 3152 + 745, 432,1757, 428,1633, 888,2246,2221,2489,3611,2118,1258,1265, 956,3127,1784, # 3168 +4337,2490, 319, 510, 119, 457,3612, 274,2035,2007,4651,1409,3128, 970,2758, 590, # 3184 +2800, 661,2247,4652,2008,3950,1420,1549,3080,3322,3951,1651,1375,2111, 485,2491, # 3200 +1429,1156,6156,2548,2183,1495, 831,1840,2529,2446, 501,1657, 307,1894,3247,1341, # 3216 + 666, 899,2156,1539,2549,1559, 886, 349,2208,3081,2305,1736,3824,2170,2759,1014, # 3232 +1913,1386, 542,1397,2948, 490, 368, 716, 362, 159, 282,2569,1129,1658,1288,1750, # 3248 +2674, 276, 649,2016, 751,1496, 658,1818,1284,1862,2209,2087,2512,3451, 622,2834, # 3264 + 376, 117,1060,2053,1208,1721,1101,1443, 247,1250,3179,1792,3952,2760,2398,3953, # 3280 +6157,2144,3708, 446,2432,1151,2570,3452,2447,2761,2835,1210,2448,3082, 424,2222, # 3296 +1251,2449,2119,2836, 504,1581,4338, 602, 817, 857,3825,2349,2306, 357,3826,1470, # 3312 +1883,2883, 255, 958, 929,2917,3248, 302,4653,1050,1271,1751,2307,1952,1430,2697, # 3328 +2719,2359, 354,3180, 777, 158,2036,4339,1659,4340,4654,2308,2949,2248,1146,2232, # 3344 +3532,2720,1696,2623,3827,6158,3129,1550,2698,1485,1297,1428, 637, 931,2721,2145, # 3360 + 914,2550,2587, 81,2450, 612, 827,2646,1242,4655,1118,2884, 472,1855,3181,3533, # 3376 +3534, 569,1353,2699,1244,1758,2588,4119,2009,2762,2171,3709,1312,1531,6159,1152, # 3392 +1938, 134,1830, 471,3710,2276,1112,1535,3323,3453,3535, 982,1337,2950, 488, 826, # 3408 + 674,1058,1628,4120,2017, 522,2399, 211, 568,1367,3454, 350, 293,1872,1139,3249, # 3424 +1399,1946,3006,1300,2360,3324, 588, 736,6160,2606, 744, 669,3536,3828,6161,1358, # 3440 + 199, 723, 848, 933, 851,1939,1505,1514,1338,1618,1831,4656,1634,3613, 443,2740, # 3456 +3829, 717,1947, 491,1914,6162,2551,1542,4121,1025,6163,1099,1223, 198,3040,2722, # 3472 + 370, 410,1905,2589, 998,1248,3182,2380, 519,1449,4122,1710, 947, 928,1153,4341, # 3488 +2277, 344,2624,1511, 615, 105, 161,1212,1076,1960,3130,2054,1926,1175,1906,2473, # 3504 + 414,1873,2801,6164,2309, 315,1319,3325, 318,2018,2146,2157, 963, 631, 223,4342, # 3520 +4343,2675, 479,3711,1197,2625,3712,2676,2361,6165,4344,4123,6166,2451,3183,1886, # 3536 +2184,1674,1330,1711,1635,1506, 799, 219,3250,3083,3954,1677,3713,3326,2081,3614, # 3552 +1652,2073,4657,1147,3041,1752, 643,1961, 147,1974,3955,6167,1716,2037, 918,3007, # 3568 +1994, 120,1537, 118, 609,3184,4345, 740,3455,1219, 332,1615,3830,6168,1621,2980, # 3584 +1582, 783, 212, 553,2350,3714,1349,2433,2082,4124, 889,6169,2310,1275,1410, 973, # 3600 + 166,1320,3456,1797,1215,3185,2885,1846,2590,2763,4658, 629, 822,3008, 763, 940, # 3616 +1990,2862, 439,2409,1566,1240,1622, 926,1282,1907,2764, 654,2210,1607, 327,1130, # 3632 +3956,1678,1623,6170,2434,2192, 686, 608,3831,3715, 903,3957,3042,6171,2741,1522, # 3648 +1915,1105,1555,2552,1359, 323,3251,4346,3457, 738,1354,2553,2311,2334,1828,2003, # 3664 +3832,1753,2351,1227,6172,1887,4125,1478,6173,2410,1874,1712,1847, 520,1204,2607, # 3680 + 264,4659, 836,2677,2102, 600,4660,3833,2278,3084,6174,4347,3615,1342, 640, 532, # 3696 + 543,2608,1888,2400,2591,1009,4348,1497, 341,1737,3616,2723,1394, 529,3252,1321, # 3712 + 983,4661,1515,2120, 971,2592, 924, 287,1662,3186,4349,2700,4350,1519, 908,1948, # 3728 +2452, 156, 796,1629,1486,2223,2055, 694,4126,1259,1036,3392,1213,2249,2742,1889, # 3744 +1230,3958,1015, 910, 408, 559,3617,4662, 746, 725, 935,4663,3959,3009,1289, 563, # 3760 + 867,4664,3960,1567,2981,2038,2626, 988,2263,2381,4351, 143,2374, 704,1895,6175, # 3776 +1188,3716,2088, 673,3085,2362,4352, 484,1608,1921,2765,2918, 215, 904,3618,3537, # 3792 + 894, 509, 976,3043,2701,3961,4353,2837,2982, 498,6176,6177,1102,3538,1332,3393, # 3808 +1487,1636,1637, 233, 245,3962, 383, 650, 995,3044, 460,1520,1206,2352, 749,3327, # 3824 + 530, 700, 389,1438,1560,1773,3963,2264, 719,2951,2724,3834, 870,1832,1644,1000, # 3840 + 839,2474,3717, 197,1630,3394, 365,2886,3964,1285,2133, 734, 922, 818,1106, 732, # 3856 + 480,2083,1774,3458, 923,2279,1350, 221,3086, 85,2233,2234,3835,1585,3010,2147, # 3872 +1387,1705,2382,1619,2475, 133, 239,2802,1991,1016,2084,2383, 411,2838,1113, 651, # 3888 +1985,1160,3328, 990,1863,3087,1048,1276,2647, 265,2627,1599,3253,2056, 150, 638, # 3904 +2019, 656, 853, 326,1479, 680,1439,4354,1001,1759, 413,3459,3395,2492,1431, 459, # 3920 +4355,1125,3329,2265,1953,1450,2065,2863, 849, 351,2678,3131,3254,3255,1104,1577, # 3936 + 227,1351,1645,2453,2193,1421,2887, 812,2121, 634, 95,2435, 201,2312,4665,1646, # 3952 +1671,2743,1601,2554,2702,2648,2280,1315,1366,2089,3132,1573,3718,3965,1729,1189, # 3968 + 328,2679,1077,1940,1136, 558,1283, 964,1195, 621,2074,1199,1743,3460,3619,1896, # 3984 +1916,1890,3836,2952,1154,2112,1064, 862, 378,3011,2066,2113,2803,1568,2839,6178, # 4000 +3088,2919,1941,1660,2004,1992,2194, 142, 707,1590,1708,1624,1922,1023,1836,1233, # 4016 +1004,2313, 789, 741,3620,6179,1609,2411,1200,4127,3719,3720,4666,2057,3721, 593, # 4032 +2840, 367,2920,1878,6180,3461,1521, 628,1168, 692,2211,2649, 300, 720,2067,2571, # 4048 +2953,3396, 959,2504,3966,3539,3462,1977, 701,6181, 954,1043, 800, 681, 183,3722, # 4064 +1803,1730,3540,4128,2103, 815,2314, 174, 467, 230,2454,1093,2134, 755,3541,3397, # 4080 +1141,1162,6182,1738,2039, 270,3256,2513,1005,1647,2185,3837, 858,1679,1897,1719, # 4096 +2954,2324,1806, 402, 670, 167,4129,1498,2158,2104, 750,6183, 915, 189,1680,1551, # 4112 + 455,4356,1501,2455, 405,1095,2955, 338,1586,1266,1819, 570, 641,1324, 237,1556, # 4128 +2650,1388,3723,6184,1368,2384,1343,1978,3089,2436, 879,3724, 792,1191, 758,3012, # 4144 +1411,2135,1322,4357, 240,4667,1848,3725,1574,6185, 420,3045,1546,1391, 714,4358, # 4160 +1967, 941,1864, 863, 664, 426, 560,1731,2680,1785,2864,1949,2363, 403,3330,1415, # 4176 +1279,2136,1697,2335, 204, 721,2097,3838, 90,6186,2085,2505, 191,3967, 124,2148, # 4192 +1376,1798,1178,1107,1898,1405, 860,4359,1243,1272,2375,2983,1558,2456,1638, 113, # 4208 +3621, 578,1923,2609, 880, 386,4130, 784,2186,2266,1422,2956,2172,1722, 497, 263, # 4224 +2514,1267,2412,2610, 177,2703,3542, 774,1927,1344, 616,1432,1595,1018, 172,4360, # 4240 +2325, 911,4361, 438,1468,3622, 794,3968,2024,2173,1681,1829,2957, 945, 895,3090, # 4256 + 575,2212,2476, 475,2401,2681, 785,2744,1745,2293,2555,1975,3133,2865, 394,4668, # 4272 +3839, 635,4131, 639, 202,1507,2195,2766,1345,1435,2572,3726,1908,1184,1181,2457, # 4288 +3727,3134,4362, 843,2611, 437, 916,4669, 234, 769,1884,3046,3047,3623, 833,6187, # 4304 +1639,2250,2402,1355,1185,2010,2047, 999, 525,1732,1290,1488,2612, 948,1578,3728, # 4320 +2413,2477,1216,2725,2159, 334,3840,1328,3624,2921,1525,4132, 564,1056, 891,4363, # 4336 +1444,1698,2385,2251,3729,1365,2281,2235,1717,6188, 864,3841,2515, 444, 527,2767, # 4352 +2922,3625, 544, 461,6189, 566, 209,2437,3398,2098,1065,2068,3331,3626,3257,2137, # 4368 #last 512 +) + + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/jpcntx.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/jpcntx.py new file mode 100644 index 0000000..20044e4 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/jpcntx.py @@ -0,0 +1,233 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + + +# This is hiragana 2-char sequence table, the number in each cell represents its frequency category +jp2CharContext = ( +(0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1), +(2,4,0,4,0,3,0,4,0,3,4,4,4,2,4,3,3,4,3,2,3,3,4,2,3,3,3,2,4,1,4,3,3,1,5,4,3,4,3,4,3,5,3,0,3,5,4,2,0,3,1,0,3,3,0,3,3,0,1,1,0,4,3,0,3,3,0,4,0,2,0,3,5,5,5,5,4,0,4,1,0,3,4), +(0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2), +(0,4,0,5,0,5,0,4,0,4,5,4,4,3,5,3,5,1,5,3,4,3,4,4,3,4,3,3,4,3,5,4,4,3,5,5,3,5,5,5,3,5,5,3,4,5,5,3,1,3,2,0,3,4,0,4,2,0,4,2,1,5,3,2,3,5,0,4,0,2,0,5,4,4,5,4,5,0,4,0,0,4,4), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +(0,3,0,4,0,3,0,3,0,4,5,4,3,3,3,3,4,3,5,4,4,3,5,4,4,3,4,3,4,4,4,4,5,3,4,4,3,4,5,5,4,5,5,1,4,5,4,3,0,3,3,1,3,3,0,4,4,0,3,3,1,5,3,3,3,5,0,4,0,3,0,4,4,3,4,3,3,0,4,1,1,3,4), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +(0,4,0,3,0,3,0,4,0,3,4,4,3,2,2,1,2,1,3,1,3,3,3,3,3,4,3,1,3,3,5,3,3,0,4,3,0,5,4,3,3,5,4,4,3,4,4,5,0,1,2,0,1,2,0,2,2,0,1,0,0,5,2,2,1,4,0,3,0,1,0,4,4,3,5,4,3,0,2,1,0,4,3), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +(0,3,0,5,0,4,0,2,1,4,4,2,4,1,4,2,4,2,4,3,3,3,4,3,3,3,3,1,4,2,3,3,3,1,4,4,1,1,1,4,3,3,2,0,2,4,3,2,0,3,3,0,3,1,1,0,0,0,3,3,0,4,2,2,3,4,0,4,0,3,0,4,4,5,3,4,4,0,3,0,0,1,4), +(1,4,0,4,0,4,0,4,0,3,5,4,4,3,4,3,5,4,3,3,4,3,5,4,4,4,4,3,4,2,4,3,3,1,5,4,3,2,4,5,4,5,5,4,4,5,4,4,0,3,2,2,3,3,0,4,3,1,3,2,1,4,3,3,4,5,0,3,0,2,0,4,5,5,4,5,4,0,4,0,0,5,4), +(0,5,0,5,0,4,0,3,0,4,4,3,4,3,3,3,4,0,4,4,4,3,4,3,4,3,3,1,4,2,4,3,4,0,5,4,1,4,5,4,4,5,3,2,4,3,4,3,2,4,1,3,3,3,2,3,2,0,4,3,3,4,3,3,3,4,0,4,0,3,0,4,5,4,4,4,3,0,4,1,0,1,3), +(0,3,1,4,0,3,0,2,0,3,4,4,3,1,4,2,3,3,4,3,4,3,4,3,4,4,3,2,3,1,5,4,4,1,4,4,3,5,4,4,3,5,5,4,3,4,4,3,1,2,3,1,2,2,0,3,2,0,3,1,0,5,3,3,3,4,3,3,3,3,4,4,4,4,5,4,2,0,3,3,2,4,3), +(0,2,0,3,0,1,0,1,0,0,3,2,0,0,2,0,1,0,2,1,3,3,3,1,2,3,1,0,1,0,4,2,1,1,3,3,0,4,3,3,1,4,3,3,0,3,3,2,0,0,0,0,1,0,0,2,0,0,0,0,0,4,1,0,2,3,2,2,2,1,3,3,3,4,4,3,2,0,3,1,0,3,3), +(0,4,0,4,0,3,0,3,0,4,4,4,3,3,3,3,3,3,4,3,4,2,4,3,4,3,3,2,4,3,4,5,4,1,4,5,3,5,4,5,3,5,4,0,3,5,5,3,1,3,3,2,2,3,0,3,4,1,3,3,2,4,3,3,3,4,0,4,0,3,0,4,5,4,4,5,3,0,4,1,0,3,4), +(0,2,0,3,0,3,0,0,0,2,2,2,1,0,1,0,0,0,3,0,3,0,3,0,1,3,1,0,3,1,3,3,3,1,3,3,3,0,1,3,1,3,4,0,0,3,1,1,0,3,2,0,0,0,0,1,3,0,1,0,0,3,3,2,0,3,0,0,0,0,0,3,4,3,4,3,3,0,3,0,0,2,3), +(2,3,0,3,0,2,0,1,0,3,3,4,3,1,3,1,1,1,3,1,4,3,4,3,3,3,0,0,3,1,5,4,3,1,4,3,2,5,5,4,4,4,4,3,3,4,4,4,0,2,1,1,3,2,0,1,2,0,0,1,0,4,1,3,3,3,0,3,0,1,0,4,4,4,5,5,3,0,2,0,0,4,4), +(0,2,0,1,0,3,1,3,0,2,3,3,3,0,3,1,0,0,3,0,3,2,3,1,3,2,1,1,0,0,4,2,1,0,2,3,1,4,3,2,0,4,4,3,1,3,1,3,0,1,0,0,1,0,0,0,1,0,0,0,0,4,1,1,1,2,0,3,0,0,0,3,4,2,4,3,2,0,1,0,0,3,3), +(0,1,0,4,0,5,0,4,0,2,4,4,2,3,3,2,3,3,5,3,3,3,4,3,4,2,3,0,4,3,3,3,4,1,4,3,2,1,5,5,3,4,5,1,3,5,4,2,0,3,3,0,1,3,0,4,2,0,1,3,1,4,3,3,3,3,0,3,0,1,0,3,4,4,4,5,5,0,3,0,1,4,5), +(0,2,0,3,0,3,0,0,0,2,3,1,3,0,4,0,1,1,3,0,3,4,3,2,3,1,0,3,3,2,3,1,3,0,2,3,0,2,1,4,1,2,2,0,0,3,3,0,0,2,0,0,0,1,0,0,0,0,2,2,0,3,2,1,3,3,0,2,0,2,0,0,3,3,1,2,4,0,3,0,2,2,3), +(2,4,0,5,0,4,0,4,0,2,4,4,4,3,4,3,3,3,1,2,4,3,4,3,4,4,5,0,3,3,3,3,2,0,4,3,1,4,3,4,1,4,4,3,3,4,4,3,1,2,3,0,4,2,0,4,1,0,3,3,0,4,3,3,3,4,0,4,0,2,0,3,5,3,4,5,2,0,3,0,0,4,5), +(0,3,0,4,0,1,0,1,0,1,3,2,2,1,3,0,3,0,2,0,2,0,3,0,2,0,0,0,1,0,1,1,0,0,3,1,0,0,0,4,0,3,1,0,2,1,3,0,0,0,0,0,0,3,0,0,0,0,0,0,0,4,2,2,3,1,0,3,0,0,0,1,4,4,4,3,0,0,4,0,0,1,4), +(1,4,1,5,0,3,0,3,0,4,5,4,4,3,5,3,3,4,4,3,4,1,3,3,3,3,2,1,4,1,5,4,3,1,4,4,3,5,4,4,3,5,4,3,3,4,4,4,0,3,3,1,2,3,0,3,1,0,3,3,0,5,4,4,4,4,4,4,3,3,5,4,4,3,3,5,4,0,3,2,0,4,4), +(0,2,0,3,0,1,0,0,0,1,3,3,3,2,4,1,3,0,3,1,3,0,2,2,1,1,0,0,2,0,4,3,1,0,4,3,0,4,4,4,1,4,3,1,1,3,3,1,0,2,0,0,1,3,0,0,0,0,2,0,0,4,3,2,4,3,5,4,3,3,3,4,3,3,4,3,3,0,2,1,0,3,3), +(0,2,0,4,0,3,0,2,0,2,5,5,3,4,4,4,4,1,4,3,3,0,4,3,4,3,1,3,3,2,4,3,0,3,4,3,0,3,4,4,2,4,4,0,4,5,3,3,2,2,1,1,1,2,0,1,5,0,3,3,2,4,3,3,3,4,0,3,0,2,0,4,4,3,5,5,0,0,3,0,2,3,3), +(0,3,0,4,0,3,0,1,0,3,4,3,3,1,3,3,3,0,3,1,3,0,4,3,3,1,1,0,3,0,3,3,0,0,4,4,0,1,5,4,3,3,5,0,3,3,4,3,0,2,0,1,1,1,0,1,3,0,1,2,1,3,3,2,3,3,0,3,0,1,0,1,3,3,4,4,1,0,1,2,2,1,3), +(0,1,0,4,0,4,0,3,0,1,3,3,3,2,3,1,1,0,3,0,3,3,4,3,2,4,2,0,1,0,4,3,2,0,4,3,0,5,3,3,2,4,4,4,3,3,3,4,0,1,3,0,0,1,0,0,1,0,0,0,0,4,2,3,3,3,0,3,0,0,0,4,4,4,5,3,2,0,3,3,0,3,5), +(0,2,0,3,0,0,0,3,0,1,3,0,2,0,0,0,1,0,3,1,1,3,3,0,0,3,0,0,3,0,2,3,1,0,3,1,0,3,3,2,0,4,2,2,0,2,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,2,1,2,0,1,0,1,0,0,0,1,3,1,2,0,0,0,1,0,0,1,4), +(0,3,0,3,0,5,0,1,0,2,4,3,1,3,3,2,1,1,5,2,1,0,5,1,2,0,0,0,3,3,2,2,3,2,4,3,0,0,3,3,1,3,3,0,2,5,3,4,0,3,3,0,1,2,0,2,2,0,3,2,0,2,2,3,3,3,0,2,0,1,0,3,4,4,2,5,4,0,3,0,0,3,5), +(0,3,0,3,0,3,0,1,0,3,3,3,3,0,3,0,2,0,2,1,1,0,2,0,1,0,0,0,2,1,0,0,1,0,3,2,0,0,3,3,1,2,3,1,0,3,3,0,0,1,0,0,0,0,0,2,0,0,0,0,0,2,3,1,2,3,0,3,0,1,0,3,2,1,0,4,3,0,1,1,0,3,3), +(0,4,0,5,0,3,0,3,0,4,5,5,4,3,5,3,4,3,5,3,3,2,5,3,4,4,4,3,4,3,4,5,5,3,4,4,3,4,4,5,4,4,4,3,4,5,5,4,2,3,4,2,3,4,0,3,3,1,4,3,2,4,3,3,5,5,0,3,0,3,0,5,5,5,5,4,4,0,4,0,1,4,4), +(0,4,0,4,0,3,0,3,0,3,5,4,4,2,3,2,5,1,3,2,5,1,4,2,3,2,3,3,4,3,3,3,3,2,5,4,1,3,3,5,3,4,4,0,4,4,3,1,1,3,1,0,2,3,0,2,3,0,3,0,0,4,3,1,3,4,0,3,0,2,0,4,4,4,3,4,5,0,4,0,0,3,4), +(0,3,0,3,0,3,1,2,0,3,4,4,3,3,3,0,2,2,4,3,3,1,3,3,3,1,1,0,3,1,4,3,2,3,4,4,2,4,4,4,3,4,4,3,2,4,4,3,1,3,3,1,3,3,0,4,1,0,2,2,1,4,3,2,3,3,5,4,3,3,5,4,4,3,3,0,4,0,3,2,2,4,4), +(0,2,0,1,0,0,0,0,0,1,2,1,3,0,0,0,0,0,2,0,1,2,1,0,0,1,0,0,0,0,3,0,0,1,0,1,1,3,1,0,0,0,1,1,0,1,1,0,0,0,0,0,2,0,0,0,0,0,0,0,0,1,1,2,2,0,3,4,0,0,0,1,1,0,0,1,0,0,0,0,0,1,1), +(0,1,0,0,0,1,0,0,0,0,4,0,4,1,4,0,3,0,4,0,3,0,4,0,3,0,3,0,4,1,5,1,4,0,0,3,0,5,0,5,2,0,1,0,0,0,2,1,4,0,1,3,0,0,3,0,0,3,1,1,4,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0), +(1,4,0,5,0,3,0,2,0,3,5,4,4,3,4,3,5,3,4,3,3,0,4,3,3,3,3,3,3,2,4,4,3,1,3,4,4,5,4,4,3,4,4,1,3,5,4,3,3,3,1,2,2,3,3,1,3,1,3,3,3,5,3,3,4,5,0,3,0,3,0,3,4,3,4,4,3,0,3,0,2,4,3), +(0,1,0,4,0,0,0,0,0,1,4,0,4,1,4,2,4,0,3,0,1,0,1,0,0,0,0,0,2,0,3,1,1,1,0,3,0,0,0,1,2,1,0,0,1,1,1,1,0,1,0,0,0,1,0,0,3,0,0,0,0,3,2,0,2,2,0,1,0,0,0,2,3,2,3,3,0,0,0,0,2,1,0), +(0,5,1,5,0,3,0,3,0,5,4,4,5,1,5,3,3,0,4,3,4,3,5,3,4,3,3,2,4,3,4,3,3,0,3,3,1,4,4,3,4,4,4,3,4,5,5,3,2,3,1,1,3,3,1,3,1,1,3,3,2,4,5,3,3,5,0,4,0,3,0,4,4,3,5,3,3,0,3,4,0,4,3), +(0,5,0,5,0,3,0,2,0,4,4,3,5,2,4,3,3,3,4,4,4,3,5,3,5,3,3,1,4,0,4,3,3,0,3,3,0,4,4,4,4,5,4,3,3,5,5,3,2,3,1,2,3,2,0,1,0,0,3,2,2,4,4,3,1,5,0,4,0,3,0,4,3,1,3,2,1,0,3,3,0,3,3), +(0,4,0,5,0,5,0,4,0,4,5,5,5,3,4,3,3,2,5,4,4,3,5,3,5,3,4,0,4,3,4,4,3,2,4,4,3,4,5,4,4,5,5,0,3,5,5,4,1,3,3,2,3,3,1,3,1,0,4,3,1,4,4,3,4,5,0,4,0,2,0,4,3,4,4,3,3,0,4,0,0,5,5), +(0,4,0,4,0,5,0,1,1,3,3,4,4,3,4,1,3,0,5,1,3,0,3,1,3,1,1,0,3,0,3,3,4,0,4,3,0,4,4,4,3,4,4,0,3,5,4,1,0,3,0,0,2,3,0,3,1,0,3,1,0,3,2,1,3,5,0,3,0,1,0,3,2,3,3,4,4,0,2,2,0,4,4), +(2,4,0,5,0,4,0,3,0,4,5,5,4,3,5,3,5,3,5,3,5,2,5,3,4,3,3,4,3,4,5,3,2,1,5,4,3,2,3,4,5,3,4,1,2,5,4,3,0,3,3,0,3,2,0,2,3,0,4,1,0,3,4,3,3,5,0,3,0,1,0,4,5,5,5,4,3,0,4,2,0,3,5), +(0,5,0,4,0,4,0,2,0,5,4,3,4,3,4,3,3,3,4,3,4,2,5,3,5,3,4,1,4,3,4,4,4,0,3,5,0,4,4,4,4,5,3,1,3,4,5,3,3,3,3,3,3,3,0,2,2,0,3,3,2,4,3,3,3,5,3,4,1,3,3,5,3,2,0,0,0,0,4,3,1,3,3), +(0,1,0,3,0,3,0,1,0,1,3,3,3,2,3,3,3,0,3,0,0,0,3,1,3,0,0,0,2,2,2,3,0,0,3,2,0,1,2,4,1,3,3,0,0,3,3,3,0,1,0,0,2,1,0,0,3,0,3,1,0,3,0,0,1,3,0,2,0,1,0,3,3,1,3,3,0,0,1,1,0,3,3), +(0,2,0,3,0,2,1,4,0,2,2,3,1,1,3,1,1,0,2,0,3,1,2,3,1,3,0,0,1,0,4,3,2,3,3,3,1,4,2,3,3,3,3,1,0,3,1,4,0,1,1,0,1,2,0,1,1,0,1,1,0,3,1,3,2,2,0,1,0,0,0,2,3,3,3,1,0,0,0,0,0,2,3), +(0,5,0,4,0,5,0,2,0,4,5,5,3,3,4,3,3,1,5,4,4,2,4,4,4,3,4,2,4,3,5,5,4,3,3,4,3,3,5,5,4,5,5,1,3,4,5,3,1,4,3,1,3,3,0,3,3,1,4,3,1,4,5,3,3,5,0,4,0,3,0,5,3,3,1,4,3,0,4,0,1,5,3), +(0,5,0,5,0,4,0,2,0,4,4,3,4,3,3,3,3,3,5,4,4,4,4,4,4,5,3,3,5,2,4,4,4,3,4,4,3,3,4,4,5,5,3,3,4,3,4,3,3,4,3,3,3,3,1,2,2,1,4,3,3,5,4,4,3,4,0,4,0,3,0,4,4,4,4,4,1,0,4,2,0,2,4), +(0,4,0,4,0,3,0,1,0,3,5,2,3,0,3,0,2,1,4,2,3,3,4,1,4,3,3,2,4,1,3,3,3,0,3,3,0,0,3,3,3,5,3,3,3,3,3,2,0,2,0,0,2,0,0,2,0,0,1,0,0,3,1,2,2,3,0,3,0,2,0,4,4,3,3,4,1,0,3,0,0,2,4), +(0,0,0,4,0,0,0,0,0,0,1,0,1,0,2,0,0,0,0,0,1,0,2,0,1,0,0,0,0,0,3,1,3,0,3,2,0,0,0,1,0,3,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,4,0,2,0,0,0,0,0,0,2), +(0,2,1,3,0,2,0,2,0,3,3,3,3,1,3,1,3,3,3,3,3,3,4,2,2,1,2,1,4,0,4,3,1,3,3,3,2,4,3,5,4,3,3,3,3,3,3,3,0,1,3,0,2,0,0,1,0,0,1,0,0,4,2,0,2,3,0,3,3,0,3,3,4,2,3,1,4,0,1,2,0,2,3), +(0,3,0,3,0,1,0,3,0,2,3,3,3,0,3,1,2,0,3,3,2,3,3,2,3,2,3,1,3,0,4,3,2,0,3,3,1,4,3,3,2,3,4,3,1,3,3,1,1,0,1,1,0,1,0,1,0,1,0,0,0,4,1,1,0,3,0,3,1,0,2,3,3,3,3,3,1,0,0,2,0,3,3), +(0,0,0,0,0,0,0,0,0,0,3,0,2,0,3,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,3,0,3,0,3,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,2,0,2,3,0,0,0,0,0,0,0,0,3), +(0,2,0,3,1,3,0,3,0,2,3,3,3,1,3,1,3,1,3,1,3,3,3,1,3,0,2,3,1,1,4,3,3,2,3,3,1,2,2,4,1,3,3,0,1,4,2,3,0,1,3,0,3,0,0,1,3,0,2,0,0,3,3,2,1,3,0,3,0,2,0,3,4,4,4,3,1,0,3,0,0,3,3), +(0,2,0,1,0,2,0,0,0,1,3,2,2,1,3,0,1,1,3,0,3,2,3,1,2,0,2,0,1,1,3,3,3,0,3,3,1,1,2,3,2,3,3,1,2,3,2,0,0,1,0,0,0,0,0,0,3,0,1,0,0,2,1,2,1,3,0,3,0,0,0,3,4,4,4,3,2,0,2,0,0,2,4), +(0,0,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,2,2,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,3,1,0,0,0,0,0,0,0,3), +(0,3,0,3,0,2,0,3,0,3,3,3,2,3,2,2,2,0,3,1,3,3,3,2,3,3,0,0,3,0,3,2,2,0,2,3,1,4,3,4,3,3,2,3,1,5,4,4,0,3,1,2,1,3,0,3,1,1,2,0,2,3,1,3,1,3,0,3,0,1,0,3,3,4,4,2,1,0,2,1,0,2,4), +(0,1,0,3,0,1,0,2,0,1,4,2,5,1,4,0,2,0,2,1,3,1,4,0,2,1,0,0,2,1,4,1,1,0,3,3,0,5,1,3,2,3,3,1,0,3,2,3,0,1,0,0,0,0,0,0,1,0,0,0,0,4,0,1,0,3,0,2,0,1,0,3,3,3,4,3,3,0,0,0,0,2,3), +(0,0,0,1,0,0,0,0,0,0,2,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,0,0,1,0,0,0,0,0,3), +(0,1,0,3,0,4,0,3,0,2,4,3,1,0,3,2,2,1,3,1,2,2,3,1,1,1,2,1,3,0,1,2,0,1,3,2,1,3,0,5,5,1,0,0,1,3,2,1,0,3,0,0,1,0,0,0,0,0,3,4,0,1,1,1,3,2,0,2,0,1,0,2,3,3,1,2,3,0,1,0,1,0,4), +(0,0,0,1,0,3,0,3,0,2,2,1,0,0,4,0,3,0,3,1,3,0,3,0,3,0,1,0,3,0,3,1,3,0,3,3,0,0,1,2,1,1,1,0,1,2,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,2,2,1,2,0,0,2,0,0,0,0,2,3,3,3,3,0,0,0,0,1,4), +(0,0,0,3,0,3,0,0,0,0,3,1,1,0,3,0,1,0,2,0,1,0,0,0,0,0,0,0,1,0,3,0,2,0,2,3,0,0,2,2,3,1,2,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,2,0,0,0,0,2,3), +(2,4,0,5,0,5,0,4,0,3,4,3,3,3,4,3,3,3,4,3,4,4,5,4,5,5,5,2,3,0,5,5,4,1,5,4,3,1,5,4,3,4,4,3,3,4,3,3,0,3,2,0,2,3,0,3,0,0,3,3,0,5,3,2,3,3,0,3,0,3,0,3,4,5,4,5,3,0,4,3,0,3,4), +(0,3,0,3,0,3,0,3,0,3,3,4,3,2,3,2,3,0,4,3,3,3,3,3,3,3,3,0,3,2,4,3,3,1,3,4,3,4,4,4,3,4,4,3,2,4,4,1,0,2,0,0,1,1,0,2,0,0,3,1,0,5,3,2,1,3,0,3,0,1,2,4,3,2,4,3,3,0,3,2,0,4,4), +(0,3,0,3,0,1,0,0,0,1,4,3,3,2,3,1,3,1,4,2,3,2,4,2,3,4,3,0,2,2,3,3,3,0,3,3,3,0,3,4,1,3,3,0,3,4,3,3,0,1,1,0,1,0,0,0,4,0,3,0,0,3,1,2,1,3,0,4,0,1,0,4,3,3,4,3,3,0,2,0,0,3,3), +(0,3,0,4,0,1,0,3,0,3,4,3,3,0,3,3,3,1,3,1,3,3,4,3,3,3,0,0,3,1,5,3,3,1,3,3,2,5,4,3,3,4,5,3,2,5,3,4,0,1,0,0,0,0,0,2,0,0,1,1,0,4,2,2,1,3,0,3,0,2,0,4,4,3,5,3,2,0,1,1,0,3,4), +(0,5,0,4,0,5,0,2,0,4,4,3,3,2,3,3,3,1,4,3,4,1,5,3,4,3,4,0,4,2,4,3,4,1,5,4,0,4,4,4,4,5,4,1,3,5,4,2,1,4,1,1,3,2,0,3,1,0,3,2,1,4,3,3,3,4,0,4,0,3,0,4,4,4,3,3,3,0,4,2,0,3,4), +(1,4,0,4,0,3,0,1,0,3,3,3,1,1,3,3,2,2,3,3,1,0,3,2,2,1,2,0,3,1,2,1,2,0,3,2,0,2,2,3,3,4,3,0,3,3,1,2,0,1,1,3,1,2,0,0,3,0,1,1,0,3,2,2,3,3,0,3,0,0,0,2,3,3,4,3,3,0,1,0,0,1,4), +(0,4,0,4,0,4,0,0,0,3,4,4,3,1,4,2,3,2,3,3,3,1,4,3,4,0,3,0,4,2,3,3,2,2,5,4,2,1,3,4,3,4,3,1,3,3,4,2,0,2,1,0,3,3,0,0,2,0,3,1,0,4,4,3,4,3,0,4,0,1,0,2,4,4,4,4,4,0,3,2,0,3,3), +(0,0,0,1,0,4,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,3,2,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,2), +(0,2,0,3,0,4,0,4,0,1,3,3,3,0,4,0,2,1,2,1,1,1,2,0,3,1,1,0,1,0,3,1,0,0,3,3,2,0,1,1,0,0,0,0,0,1,0,2,0,2,2,0,3,1,0,0,1,0,1,1,0,1,2,0,3,0,0,0,0,1,0,0,3,3,4,3,1,0,1,0,3,0,2), +(0,0,0,3,0,5,0,0,0,0,1,0,2,0,3,1,0,1,3,0,0,0,2,0,0,0,1,0,0,0,1,1,0,0,4,0,0,0,2,3,0,1,4,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,1,0,0,0,0,0,0,0,2,0,0,3,0,0,0,0,0,3), +(0,2,0,5,0,5,0,1,0,2,4,3,3,2,5,1,3,2,3,3,3,0,4,1,2,0,3,0,4,0,2,2,1,1,5,3,0,0,1,4,2,3,2,0,3,3,3,2,0,2,4,1,1,2,0,1,1,0,3,1,0,1,3,1,2,3,0,2,0,0,0,1,3,5,4,4,4,0,3,0,0,1,3), +(0,4,0,5,0,4,0,4,0,4,5,4,3,3,4,3,3,3,4,3,4,4,5,3,4,5,4,2,4,2,3,4,3,1,4,4,1,3,5,4,4,5,5,4,4,5,5,5,2,3,3,1,4,3,1,3,3,0,3,3,1,4,3,4,4,4,0,3,0,4,0,3,3,4,4,5,0,0,4,3,0,4,5), +(0,4,0,4,0,3,0,3,0,3,4,4,4,3,3,2,4,3,4,3,4,3,5,3,4,3,2,1,4,2,4,4,3,1,3,4,2,4,5,5,3,4,5,4,1,5,4,3,0,3,2,2,3,2,1,3,1,0,3,3,3,5,3,3,3,5,4,4,2,3,3,4,3,3,3,2,1,0,3,2,1,4,3), +(0,4,0,5,0,4,0,3,0,3,5,5,3,2,4,3,4,0,5,4,4,1,4,4,4,3,3,3,4,3,5,5,2,3,3,4,1,2,5,5,3,5,5,2,3,5,5,4,0,3,2,0,3,3,1,1,5,1,4,1,0,4,3,2,3,5,0,4,0,3,0,5,4,3,4,3,0,0,4,1,0,4,4), +(1,3,0,4,0,2,0,2,0,2,5,5,3,3,3,3,3,0,4,2,3,4,4,4,3,4,0,0,3,4,5,4,3,3,3,3,2,5,5,4,5,5,5,4,3,5,5,5,1,3,1,0,1,0,0,3,2,0,4,2,0,5,2,3,2,4,1,3,0,3,0,4,5,4,5,4,3,0,4,2,0,5,4), +(0,3,0,4,0,5,0,3,0,3,4,4,3,2,3,2,3,3,3,3,3,2,4,3,3,2,2,0,3,3,3,3,3,1,3,3,3,0,4,4,3,4,4,1,1,4,4,2,0,3,1,0,1,1,0,4,1,0,2,3,1,3,3,1,3,4,0,3,0,1,0,3,1,3,0,0,1,0,2,0,0,4,4), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +(0,3,0,3,0,2,0,3,0,1,5,4,3,3,3,1,4,2,1,2,3,4,4,2,4,4,5,0,3,1,4,3,4,0,4,3,3,3,2,3,2,5,3,4,3,2,2,3,0,0,3,0,2,1,0,1,2,0,0,0,0,2,1,1,3,1,0,2,0,4,0,3,4,4,4,5,2,0,2,0,0,1,3), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,0,0,1,1,0,0,0,4,2,1,1,0,1,0,3,2,0,0,3,1,1,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,1,0,0,0,2,0,0,0,1,4,0,4,2,1,0,0,0,0,0,1), +(0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,3,1,0,0,0,2,0,2,1,0,0,1,2,1,0,1,1,0,0,3,0,0,0,0,0,0,0,0,0,0,0,1,3,1,0,0,0,0,0,1,0,0,2,1,0,0,0,0,0,0,0,0,2), +(0,4,0,4,0,4,0,3,0,4,4,3,4,2,4,3,2,0,4,4,4,3,5,3,5,3,3,2,4,2,4,3,4,3,1,4,0,2,3,4,4,4,3,3,3,4,4,4,3,4,1,3,4,3,2,1,2,1,3,3,3,4,4,3,3,5,0,4,0,3,0,4,3,3,3,2,1,0,3,0,0,3,3), +(0,4,0,3,0,3,0,3,0,3,5,5,3,3,3,3,4,3,4,3,3,3,4,4,4,3,3,3,3,4,3,5,3,3,1,3,2,4,5,5,5,5,4,3,4,5,5,3,2,2,3,3,3,3,2,3,3,1,2,3,2,4,3,3,3,4,0,4,0,2,0,4,3,2,2,1,2,0,3,0,0,4,1), +) + +class JapaneseContextAnalysis(object): + NUM_OF_CATEGORY = 6 + DONT_KNOW = -1 + ENOUGH_REL_THRESHOLD = 100 + MAX_REL_THRESHOLD = 1000 + MINIMUM_DATA_THRESHOLD = 4 + + def __init__(self): + self._total_rel = None + self._rel_sample = None + self._need_to_skip_char_num = None + self._last_char_order = None + self._done = None + self.reset() + + def reset(self): + self._total_rel = 0 # total sequence received + # category counters, each integer counts sequence in its category + self._rel_sample = [0] * self.NUM_OF_CATEGORY + # if last byte in current buffer is not the last byte of a character, + # we need to know how many bytes to skip in next buffer + self._need_to_skip_char_num = 0 + self._last_char_order = -1 # The order of previous char + # If this flag is set to True, detection is done and conclusion has + # been made + self._done = False + + def feed(self, byte_str, num_bytes): + if self._done: + return + + # The buffer we got is byte oriented, and a character may span in more than one + # buffers. In case the last one or two byte in last buffer is not + # complete, we record how many byte needed to complete that character + # and skip these bytes here. We can choose to record those bytes as + # well and analyse the character once it is complete, but since a + # character will not make much difference, by simply skipping + # this character will simply our logic and improve performance. + i = self._need_to_skip_char_num + while i < num_bytes: + order, char_len = self.get_order(byte_str[i:i + 2]) + i += char_len + if i > num_bytes: + self._need_to_skip_char_num = i - num_bytes + self._last_char_order = -1 + else: + if (order != -1) and (self._last_char_order != -1): + self._total_rel += 1 + if self._total_rel > self.MAX_REL_THRESHOLD: + self._done = True + break + self._rel_sample[jp2CharContext[self._last_char_order][order]] += 1 + self._last_char_order = order + + def got_enough_data(self): + return self._total_rel > self.ENOUGH_REL_THRESHOLD + + def get_confidence(self): + # This is just one way to calculate confidence. It works well for me. + if self._total_rel > self.MINIMUM_DATA_THRESHOLD: + return (self._total_rel - self._rel_sample[0]) / self._total_rel + else: + return self.DONT_KNOW + + def get_order(self, byte_str): + return -1, 1 + +class SJISContextAnalysis(JapaneseContextAnalysis): + def __init__(self): + super(SJISContextAnalysis, self).__init__() + self._charset_name = "SHIFT_JIS" + + @property + def charset_name(self): + return self._charset_name + + def get_order(self, byte_str): + if not byte_str: + return -1, 1 + # find out current char's byte length + first_char = byte_str[0] + if (0x81 <= first_char <= 0x9F) or (0xE0 <= first_char <= 0xFC): + char_len = 2 + if (first_char == 0x87) or (0xFA <= first_char <= 0xFC): + self._charset_name = "CP932" + else: + char_len = 1 + + # return its order if it is hiragana + if len(byte_str) > 1: + second_char = byte_str[1] + if (first_char == 202) and (0x9F <= second_char <= 0xF1): + return second_char - 0x9F, char_len + + return -1, char_len + +class EUCJPContextAnalysis(JapaneseContextAnalysis): + def get_order(self, byte_str): + if not byte_str: + return -1, 1 + # find out current char's byte length + first_char = byte_str[0] + if (first_char == 0x8E) or (0xA1 <= first_char <= 0xFE): + char_len = 2 + elif first_char == 0x8F: + char_len = 3 + else: + char_len = 1 + + # return its order if it is hiragana + if len(byte_str) > 1: + second_char = byte_str[1] + if (first_char == 0xA4) and (0xA1 <= second_char <= 0xF3): + return second_char - 0xA1, char_len + + return -1, char_len + + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langbulgarianmodel.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langbulgarianmodel.py new file mode 100644 index 0000000..2aa4fb2 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langbulgarianmodel.py @@ -0,0 +1,228 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Character Mapping Table: +# this table is modified base on win1251BulgarianCharToOrderMap, so +# only number <64 is sure valid + +Latin5_BulgarianCharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 77, 90, 99,100, 72,109,107,101, 79,185, 81,102, 76, 94, 82, # 40 +110,186,108, 91, 74,119, 84, 96,111,187,115,253,253,253,253,253, # 50 +253, 65, 69, 70, 66, 63, 68,112,103, 92,194,104, 95, 86, 87, 71, # 60 +116,195, 85, 93, 97,113,196,197,198,199,200,253,253,253,253,253, # 70 +194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209, # 80 +210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225, # 90 + 81,226,227,228,229,230,105,231,232,233,234,235,236, 45,237,238, # a0 + 31, 32, 35, 43, 37, 44, 55, 47, 40, 59, 33, 46, 38, 36, 41, 30, # b0 + 39, 28, 34, 51, 48, 49, 53, 50, 54, 57, 61,239, 67,240, 60, 56, # c0 + 1, 18, 9, 20, 11, 3, 23, 15, 2, 26, 12, 10, 14, 6, 4, 13, # d0 + 7, 8, 5, 19, 29, 25, 22, 21, 27, 24, 17, 75, 52,241, 42, 16, # e0 + 62,242,243,244, 58,245, 98,246,247,248,249,250,251, 91,252,253, # f0 +) + +win1251BulgarianCharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 77, 90, 99,100, 72,109,107,101, 79,185, 81,102, 76, 94, 82, # 40 +110,186,108, 91, 74,119, 84, 96,111,187,115,253,253,253,253,253, # 50 +253, 65, 69, 70, 66, 63, 68,112,103, 92,194,104, 95, 86, 87, 71, # 60 +116,195, 85, 93, 97,113,196,197,198,199,200,253,253,253,253,253, # 70 +206,207,208,209,210,211,212,213,120,214,215,216,217,218,219,220, # 80 +221, 78, 64, 83,121, 98,117,105,222,223,224,225,226,227,228,229, # 90 + 88,230,231,232,233,122, 89,106,234,235,236,237,238, 45,239,240, # a0 + 73, 80,118,114,241,242,243,244,245, 62, 58,246,247,248,249,250, # b0 + 31, 32, 35, 43, 37, 44, 55, 47, 40, 59, 33, 46, 38, 36, 41, 30, # c0 + 39, 28, 34, 51, 48, 49, 53, 50, 54, 57, 61,251, 67,252, 60, 56, # d0 + 1, 18, 9, 20, 11, 3, 23, 15, 2, 26, 12, 10, 14, 6, 4, 13, # e0 + 7, 8, 5, 19, 29, 25, 22, 21, 27, 24, 17, 75, 52,253, 42, 16, # f0 +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 96.9392% +# first 1024 sequences:3.0618% +# rest sequences: 0.2992% +# negative sequences: 0.0020% +BulgarianLangModel = ( +0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,2,3,3,3,3,3, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,3,2,2,3,2,2,1,2,2, +3,1,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,3,3,3,3,3,3,3,3,0,3,0,1, +0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,2,3,3,3,3,3,3,3,3,0,3,1,0, +0,1,0,0,0,0,0,0,0,0,1,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,2,3,3,3,3,3,3,3,3,0,3,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,1,3,2,3,3,3,3,3,3,3,3,0,3,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,2,3,2,2,1,3,3,3,3,2,2,2,1,1,2,0,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,2,3,2,2,3,3,1,1,2,3,3,2,3,3,3,3,2,1,2,0,2,0,3,0,0, +0,0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,1,3,3,3,3,3,2,3,2,3,3,3,3,3,2,3,3,1,3,0,3,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,1,3,3,2,3,3,3,1,3,3,2,3,2,2,2,0,0,2,0,2,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,0,3,3,3,2,2,3,3,3,1,2,2,3,2,1,1,2,0,2,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,2,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,2,3,3,1,2,3,2,2,2,3,3,3,3,3,2,2,3,1,2,0,2,1,2,0,0, +0,0,0,0,0,0,0,0,0,0,3,0,0,1,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,1,3,3,3,3,3,2,3,3,3,2,3,3,2,3,2,2,2,3,1,2,0,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,3,3,1,1,1,2,2,1,3,1,3,2,2,3,0,0,1,0,1,0,1,0,0, +0,0,0,1,0,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,2,2,3,2,2,3,1,2,1,1,1,2,3,1,3,1,2,2,0,1,1,1,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,1,3,2,2,3,3,1,2,3,1,1,3,3,3,3,1,2,2,1,1,1,0,2,0,2,0,1, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,2,2,3,3,3,2,2,1,1,2,0,2,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,0,1,2,1,3,3,2,3,3,3,3,3,2,3,2,1,0,3,1,2,1,2,1,2,3,2,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,1,2,3,3,3,3,3,3,3,3,3,3,3,3,0,0,3,1,3,3,2,3,3,2,2,2,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,0,3,3,3,3,3,2,1,1,2,1,3,3,0,3,1,1,1,1,3,2,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,2,2,2,3,3,3,3,3,3,3,3,3,3,3,1,1,3,1,3,3,2,3,2,2,2,3,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,2,3,3,2,2,3,2,1,1,1,1,1,3,1,3,1,1,0,0,0,1,0,0,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,2,3,2,0,3,2,0,3,0,2,0,0,2,1,3,1,0,0,1,0,0,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,2,1,1,1,1,2,1,1,2,1,1,1,2,2,1,2,1,1,1,0,1,1,0,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,2,1,3,1,1,2,1,3,2,1,1,0,1,2,3,2,1,1,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,2,2,1,0,1,0,0,1,0,0,0,2,1,0,3,0,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,2,3,2,3,3,1,3,2,1,1,1,2,1,1,2,1,3,0,1,0,0,0,1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,2,2,3,3,2,3,2,2,2,3,1,2,2,1,1,2,1,1,2,2,0,1,1,0,1,0,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,1,3,1,0,2,2,1,3,2,1,0,0,2,0,2,0,1,0,0,0,0,0,0,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,3,1,2,0,2,3,1,2,3,2,0,1,3,1,2,1,1,1,0,0,1,0,0,2,2,2,3, +2,2,2,2,1,2,1,1,2,2,1,1,2,0,1,1,1,0,0,1,1,0,0,1,1,0,0,0,1,1,0,1, +3,3,3,3,3,2,1,2,2,1,2,0,2,0,1,0,1,2,1,2,1,1,0,0,0,1,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1, +3,3,2,3,3,1,1,3,1,0,3,2,1,0,0,0,1,2,0,2,0,1,0,0,0,1,0,1,2,1,2,2, +1,1,1,1,1,1,1,2,2,2,1,1,1,1,1,1,1,0,1,2,1,1,1,0,0,0,0,0,1,1,0,0, +3,1,0,1,0,2,3,2,2,2,3,2,2,2,2,2,1,0,2,1,2,1,1,1,0,1,2,1,2,2,2,1, +1,1,2,2,2,2,1,2,1,1,0,1,2,1,2,2,2,1,1,1,0,1,1,1,1,2,0,1,0,0,0,0, +2,3,2,3,3,0,0,2,1,0,2,1,0,0,0,0,2,3,0,2,0,0,0,0,0,1,0,0,2,0,1,2, +2,1,2,1,2,2,1,1,1,2,1,1,1,0,1,2,2,1,1,1,1,1,0,1,1,1,0,0,1,2,0,0, +3,3,2,2,3,0,2,3,1,1,2,0,0,0,1,0,0,2,0,2,0,0,0,1,0,1,0,1,2,0,2,2, +1,1,1,1,2,1,0,1,2,2,2,1,1,1,1,1,1,1,0,1,1,1,0,0,0,0,0,0,1,1,0,0, +2,3,2,3,3,0,0,3,0,1,1,0,1,0,0,0,2,2,1,2,0,0,0,0,0,0,0,0,2,0,1,2, +2,2,1,1,1,1,1,2,2,2,1,0,2,0,1,0,1,0,0,1,0,1,0,0,1,0,0,0,0,1,0,0, +3,3,3,3,2,2,2,2,2,0,2,1,1,1,1,2,1,2,1,1,0,2,0,1,0,1,0,0,2,0,1,2, +1,1,1,1,1,1,1,2,2,1,1,0,2,0,1,0,2,0,0,1,1,1,0,0,2,0,0,0,1,1,0,0, +2,3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,2,0,0,1,1,0,0,0,0,0,0,1,2,0,1,2, +2,2,2,1,1,2,1,1,2,2,2,1,2,0,1,1,1,1,1,1,0,1,1,1,1,0,0,1,1,1,0,0, +2,3,3,3,3,0,2,2,0,2,1,0,0,0,1,1,1,2,0,2,0,0,0,3,0,0,0,0,2,0,2,2, +1,1,1,2,1,2,1,1,2,2,2,1,2,0,1,1,1,0,1,1,1,1,0,2,1,0,0,0,1,1,0,0, +2,3,3,3,3,0,2,1,0,0,2,0,0,0,0,0,1,2,0,2,0,0,0,0,0,0,0,0,2,0,1,2, +1,1,1,2,1,1,1,1,2,2,2,0,1,0,1,1,1,0,0,1,1,1,0,0,1,0,0,0,0,1,0,0, +3,3,2,2,3,0,1,0,1,0,0,0,0,0,0,0,1,1,0,3,0,0,0,0,0,0,0,0,1,0,2,2, +1,1,1,1,1,2,1,1,2,2,1,2,2,1,0,1,1,1,1,1,0,1,0,0,1,0,0,0,1,1,0,0, +3,1,0,1,0,2,2,2,2,3,2,1,1,1,2,3,0,0,1,0,2,1,1,0,1,1,1,1,2,1,1,1, +1,2,2,1,2,1,2,2,1,1,0,1,2,1,2,2,1,1,1,0,0,1,1,1,2,1,0,1,0,0,0,0, +2,1,0,1,0,3,1,2,2,2,2,1,2,2,1,1,1,0,2,1,2,2,1,1,2,1,1,0,2,1,1,1, +1,2,2,2,2,2,2,2,1,2,0,1,1,0,2,1,1,1,1,1,0,0,1,1,1,1,0,1,0,0,0,0, +2,1,1,1,1,2,2,2,2,1,2,2,2,1,2,2,1,1,2,1,2,3,2,2,1,1,1,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,3,2,0,1,2,0,1,2,1,1,0,1,0,1,2,1,2,0,0,0,1,1,0,0,0,1,0,0,2, +1,1,0,0,1,1,0,1,1,1,1,0,2,0,1,1,1,0,0,1,1,0,0,0,0,1,0,0,0,1,0,0, +2,0,0,0,0,1,2,2,2,2,2,2,2,1,2,1,1,1,1,1,1,1,0,1,1,1,1,1,2,1,1,1, +1,2,2,2,2,1,1,2,1,2,1,1,1,0,2,1,2,1,1,1,0,2,1,1,1,1,0,1,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0, +1,1,0,1,0,1,1,1,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,3,2,0,0,0,0,1,0,0,0,0,0,0,1,1,0,2,0,0,0,0,0,0,0,0,1,0,1,2, +1,1,1,1,1,1,0,0,2,2,2,2,2,0,1,1,0,1,1,1,1,1,0,0,1,0,0,0,1,1,0,1, +2,3,1,2,1,0,1,1,0,2,2,2,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,1,0,1,2, +1,1,1,1,2,1,1,1,1,1,1,1,1,0,1,1,0,1,0,1,0,1,0,0,1,0,0,0,0,1,0,0, +2,2,2,2,2,0,0,2,0,0,2,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,2,0,2,2, +1,1,1,1,1,0,0,1,2,1,1,0,1,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,0,2,0,1,1,0,0,0,1,0,0,2,0,2,0,0,0,0,0,0,0,0,0,0,1,1, +0,0,0,1,1,1,1,1,1,1,1,1,1,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,3,2,0,0,1,0,0,1,0,0,0,0,0,0,1,0,2,0,0,0,1,0,0,0,0,0,0,0,2, +1,1,0,0,1,0,0,0,1,1,0,0,1,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +2,1,2,2,2,1,2,1,2,2,1,1,2,1,1,1,0,1,1,1,1,2,0,1,0,1,1,1,1,0,1,1, +1,1,2,1,1,1,1,1,1,0,0,1,2,1,1,1,1,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0, +1,0,0,1,3,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,1,0,0,1,0,2,0,0,0,0,0,1,1,1,0,1,0,0,0,0,0,0,0,0,2,0,0,1, +0,2,0,1,0,0,1,1,2,0,1,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,1,1,0,2,1,0,1,1,1,0,0,1,0,2,0,1,0,0,0,0,0,0,0,0,0,1, +0,1,0,0,1,0,0,0,1,1,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,2,0,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1, +0,1,0,1,1,1,0,0,1,1,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +2,0,1,0,0,1,2,1,1,1,1,1,1,2,2,1,0,0,1,0,1,0,0,0,0,1,1,1,1,0,0,0, +1,1,2,1,1,1,1,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,1,2,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1, +0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0, +0,1,1,0,1,1,1,0,0,1,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0, +1,0,1,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,1,0,2,0,0,2,0,1,0,0,1,0,0,1, +1,1,0,0,1,1,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0, +1,1,1,1,1,1,1,2,0,0,0,0,0,0,2,1,0,1,1,0,0,1,1,1,0,1,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1,1,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +) + +Latin5BulgarianModel = { + 'char_to_order_map': Latin5_BulgarianCharToOrderMap, + 'precedence_matrix': BulgarianLangModel, + 'typical_positive_ratio': 0.969392, + 'keep_english_letter': False, + 'charset_name': "ISO-8859-5", + 'language': 'Bulgairan', +} + +Win1251BulgarianModel = { + 'char_to_order_map': win1251BulgarianCharToOrderMap, + 'precedence_matrix': BulgarianLangModel, + 'typical_positive_ratio': 0.969392, + 'keep_english_letter': False, + 'charset_name': "windows-1251", + 'language': 'Bulgarian', +} diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langcyrillicmodel.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langcyrillicmodel.py new file mode 100644 index 0000000..e5f9a1f --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langcyrillicmodel.py @@ -0,0 +1,333 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# KOI8-R language model +# Character Mapping Table: +KOI8R_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, # 80 +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, # 90 +223,224,225, 68,226,227,228,229,230,231,232,233,234,235,236,237, # a0 +238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253, # b0 + 27, 3, 21, 28, 13, 2, 39, 19, 26, 4, 23, 11, 8, 12, 5, 1, # c0 + 15, 16, 9, 7, 6, 14, 24, 10, 17, 18, 20, 25, 30, 29, 22, 54, # d0 + 59, 37, 44, 58, 41, 48, 53, 46, 55, 42, 60, 36, 49, 38, 31, 34, # e0 + 35, 43, 45, 32, 40, 52, 56, 33, 61, 62, 51, 57, 47, 63, 50, 70, # f0 +) + +win1251_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, +239,240,241,242,243,244,245,246, 68,247,248,249,250,251,252,253, + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16, +) + +latin5_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16, +239, 68,240,241,242,243,244,245,246,247,248,249,250,251,252,255, +) + +macCyrillic_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, +239,240,241,242,243,244,245,246,247,248,249,250,251,252, 68, 16, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27,255, +) + +IBM855_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 +191,192,193,194, 68,195,196,197,198,199,200,201,202,203,204,205, +206,207,208,209,210,211,212,213,214,215,216,217, 27, 59, 54, 70, + 3, 37, 21, 44, 28, 58, 13, 41, 2, 48, 39, 53, 19, 46,218,219, +220,221,222,223,224, 26, 55, 4, 42,225,226,227,228, 23, 60,229, +230,231,232,233,234,235, 11, 36,236,237,238,239,240,241,242,243, + 8, 49, 12, 38, 5, 31, 1, 34, 15,244,245,246,247, 35, 16,248, + 43, 9, 45, 7, 32, 6, 40, 14, 52, 24, 56, 10, 33, 17, 61,249, +250, 18, 62, 20, 51, 25, 57, 30, 47, 29, 63, 22, 50,251,252,255, +) + +IBM866_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,142,143,144,145,146,147,148,149,150,151,152, 74,153, 75,154, # 40 +155,156,157,158,159,160,161,162,163,164,165,253,253,253,253,253, # 50 +253, 71,172, 66,173, 65,174, 76,175, 64,176,177, 77, 72,178, 69, # 60 + 67,179, 78, 73,180,181, 79,182,183,184,185,253,253,253,253,253, # 70 + 37, 44, 33, 46, 41, 48, 56, 51, 42, 60, 36, 49, 38, 31, 34, 35, + 45, 32, 40, 52, 53, 55, 58, 50, 57, 63, 70, 62, 61, 47, 59, 43, + 3, 21, 10, 19, 13, 2, 24, 20, 4, 23, 11, 8, 12, 5, 1, 15, +191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206, +207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222, +223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238, + 9, 7, 6, 14, 39, 26, 28, 22, 25, 29, 54, 18, 17, 30, 27, 16, +239, 68,240,241,242,243,244,245,246,247,248,249,250,251,252,255, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 97.6601% +# first 1024 sequences: 2.3389% +# rest sequences: 0.1237% +# negative sequences: 0.0009% +RussianLangModel = ( +0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,1,3,3,3,3,1,3,3,3,2,3,2,3,3, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,3,2,2,2,2,2,0,0,2, +3,3,3,2,3,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,3,2,3,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,2,2,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,2,3,3,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,0,0,3,3,3,3,3,3,3,3,3,3,3,2,1, +0,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,0,0,3,3,3,3,3,3,3,3,3,3,3,2,1, +0,0,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,2,2,2,3,1,3,3,1,3,3,3,3,2,2,3,0,2,2,2,3,3,2,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,3,3,3,2,2,3,2,3,3,3,2,1,2,2,0,1,2,2,2,2,2,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,3,0,2,2,3,3,2,1,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,1,2,3,2,2,3,2,3,3,3,3,2,2,3,0,3,2,2,3,1,1,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,2,2,3,3,3,3,3,2,3,3,3,3,2,2,2,0,3,3,3,2,2,2,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,2,3,2,3,3,3,3,3,3,2,3,2,2,0,1,3,2,1,2,2,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,2,1,1,3,0,1,1,1,1,2,1,1,0,2,2,2,1,2,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,2,2,2,2,1,3,2,3,2,3,2,1,2,2,0,1,1,2,1,2,1,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,2,2,3,2,3,3,3,2,2,2,2,0,2,2,2,2,3,1,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,2,3,2,2,3,3,3,3,3,3,3,3,3,1,3,2,0,0,3,3,3,3,2,3,3,3,3,2,3,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,3,2,2,3,3,0,2,1,0,3,2,3,2,3,0,0,1,2,0,0,1,0,1,2,1,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,3,0,2,3,3,3,3,2,3,3,3,3,1,2,2,0,0,2,3,2,2,2,3,2,3,2,2,3,0,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,0,2,3,2,3,0,1,2,3,3,2,0,2,3,0,0,2,3,2,2,0,1,3,1,3,2,2,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,3,0,2,3,3,3,3,3,3,3,3,2,1,3,2,0,0,2,2,3,3,3,2,3,3,0,2,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,2,3,3,2,2,2,3,3,0,0,1,1,1,1,1,2,0,0,1,1,1,1,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,2,3,3,3,3,3,3,3,0,3,2,3,3,2,3,2,0,2,1,0,1,1,0,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,3,2,2,2,2,3,1,3,2,3,1,1,2,1,0,2,2,2,2,1,3,1,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +2,2,3,3,3,3,3,1,2,2,1,3,1,0,3,0,0,3,0,0,0,1,1,0,1,2,1,0,0,0,0,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,2,1,1,3,3,3,2,2,1,2,2,3,1,1,2,0,0,2,2,1,3,0,0,2,1,1,2,1,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,3,3,3,1,2,2,2,1,2,1,3,3,1,1,2,1,2,1,2,2,0,2,0,0,1,1,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,3,2,1,3,2,2,3,2,0,3,2,0,3,0,1,0,1,1,0,0,1,1,1,1,0,1,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,2,3,3,3,2,2,2,3,3,1,2,1,2,1,0,1,0,1,1,0,1,0,0,2,1,1,1,0,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +3,1,1,2,1,2,3,3,2,2,1,2,2,3,0,2,1,0,0,2,2,3,2,1,2,2,2,2,2,3,1,0, +0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,1,1,0,1,1,2,2,1,1,3,0,0,1,3,1,1,1,0,0,0,1,0,1,1,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,3,3,3,2,0,0,0,2,1,0,1,0,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,1,0,0,2,3,2,2,2,1,2,2,2,1,2,1,0,0,1,1,1,0,2,0,1,1,1,0,0,1,1, +1,0,0,0,0,0,1,2,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,3,0,0,0,0,1,0,0,0,0,3,0,1,2,1,0,0,0,0,0,0,0,1,1,0,0,1,1, +1,0,1,0,1,2,0,0,1,1,2,1,0,1,1,1,1,0,1,1,1,1,0,1,0,0,1,0,0,1,1,0, +2,2,3,2,2,2,3,1,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,0,1,0,1,1,1,0,2,1, +1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1,0,1,1,0, +3,3,3,2,2,2,2,3,2,2,1,1,2,2,2,2,1,1,3,1,2,1,2,0,0,1,1,0,1,0,2,1, +1,1,1,1,1,2,1,0,1,1,1,1,0,1,0,0,1,1,0,0,1,0,1,0,0,1,0,0,0,1,1,0, +2,0,0,1,0,3,2,2,2,2,1,2,1,2,1,2,0,0,0,2,1,2,2,1,1,2,2,0,1,1,0,2, +1,1,1,1,1,0,1,1,1,2,1,1,1,2,1,0,1,2,1,1,1,1,0,1,1,1,0,0,1,0,0,1, +1,3,2,2,2,1,1,1,2,3,0,0,0,0,2,0,2,2,1,0,0,0,0,0,0,1,0,0,0,0,1,1, +1,0,1,1,0,1,0,1,1,0,1,1,0,2,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0, +2,3,2,3,2,1,2,2,2,2,1,0,0,0,2,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,2,1, +1,1,2,1,0,2,0,0,1,0,1,0,0,1,0,0,1,1,0,1,1,0,0,0,0,0,1,0,0,0,0,0, +3,0,0,1,0,2,2,2,3,2,2,2,2,2,2,2,0,0,0,2,1,2,1,1,1,2,2,0,0,0,1,2, +1,1,1,1,1,0,1,2,1,1,1,1,1,1,1,0,1,1,1,1,1,1,0,1,1,1,1,1,1,0,0,1, +2,3,2,3,3,2,0,1,1,1,0,0,1,0,2,0,1,1,3,1,0,0,0,0,0,0,0,1,0,0,2,1, +1,1,1,1,1,1,1,0,1,0,1,1,1,1,0,1,1,1,0,0,1,1,0,1,0,0,0,0,0,0,1,0, +2,3,3,3,3,1,2,2,2,2,0,1,1,0,2,1,1,1,2,1,0,1,1,0,0,1,0,1,0,0,2,0, +0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,3,3,2,0,0,1,1,2,2,1,0,0,2,0,1,1,3,0,0,1,0,0,0,0,0,1,0,1,2,1, +1,1,2,0,1,1,1,0,1,0,1,1,0,1,0,1,1,1,1,0,1,0,0,0,0,0,0,1,0,1,1,0, +1,3,2,3,2,1,0,0,2,2,2,0,1,0,2,0,1,1,1,0,1,0,0,0,3,0,1,1,0,0,2,1, +1,1,1,0,1,1,0,0,0,0,1,1,0,1,0,0,2,1,1,0,1,0,0,0,1,0,1,0,0,1,1,0, +3,1,2,1,1,2,2,2,2,2,2,1,2,2,1,1,0,0,0,2,2,2,0,0,0,1,2,1,0,1,0,1, +2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,2,1,1,1,0,1,0,1,1,0,1,1,1,0,0,1, +3,0,0,0,0,2,0,1,1,1,1,1,1,1,0,1,0,0,0,1,1,1,0,1,0,1,1,0,0,1,0,1, +1,1,0,0,1,0,0,0,1,0,1,1,0,0,1,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,1, +1,3,3,2,2,0,0,0,2,2,0,0,0,1,2,0,1,1,2,0,0,0,0,0,0,0,0,1,0,0,2,1, +0,1,1,0,0,1,1,0,0,0,1,1,0,1,1,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0, +2,3,2,3,2,0,0,0,0,1,1,0,0,0,2,0,2,0,2,0,0,0,0,0,1,0,0,1,0,0,1,1, +1,1,2,0,1,2,1,0,1,1,2,1,1,1,1,1,2,1,1,0,1,0,0,1,1,1,1,1,0,1,1,0, +1,3,2,2,2,1,0,0,2,2,1,0,1,2,2,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,1,1, +0,0,1,1,0,1,1,0,0,1,1,0,1,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,0,2,3,1,2,2,2,2,2,2,1,1,0,0,0,1,0,1,0,2,1,1,1,0,0,0,0,1, +1,1,0,1,1,0,1,1,1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0, +2,0,2,0,0,1,0,3,2,1,2,1,2,2,0,1,0,0,0,2,1,0,0,2,1,1,1,1,0,2,0,2, +2,1,1,1,1,1,1,1,1,1,1,1,1,2,1,0,1,1,1,1,0,0,0,1,1,1,1,0,1,0,0,1, +1,2,2,2,2,1,0,0,1,0,0,0,0,0,2,0,1,1,1,1,0,0,0,0,1,0,1,2,0,0,2,0, +1,0,1,1,1,2,1,0,1,0,1,1,0,0,1,0,1,1,1,0,1,0,0,0,1,0,0,1,0,1,1,0, +2,1,2,2,2,0,3,0,1,1,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +0,0,0,1,1,1,0,0,1,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0, +1,2,2,3,2,2,0,0,1,1,2,0,1,2,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1, +0,1,1,0,0,1,1,0,0,1,1,0,0,1,1,0,1,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0, +2,2,1,1,2,1,2,2,2,2,2,1,2,2,0,1,0,0,0,1,2,2,2,1,2,1,1,1,1,1,2,1, +1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,1,1,1,0,0,0,0,1,1,1,0,1,1,0,0,1, +1,2,2,2,2,0,1,0,2,2,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0, +0,0,1,0,0,1,0,0,0,0,1,0,1,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,0,0,2,2,2,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1, +0,1,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,2,0,0,0,0,1,0,0,1,1,2,0,0,0,0,1,0,1,0,0,1,0,0,2,0,0,0,1, +0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0, +1,2,2,2,1,1,2,0,2,1,1,1,1,0,2,2,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,1, +0,0,1,0,1,1,0,0,0,0,1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +1,0,2,1,2,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0, +0,0,1,0,1,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0, +1,0,0,0,0,2,0,1,2,1,0,1,1,1,0,1,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,1, +0,0,0,0,0,1,0,0,1,1,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1, +2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +1,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +1,1,1,0,1,0,1,0,0,1,1,1,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +1,1,0,1,1,0,1,0,1,0,0,0,0,1,1,0,1,1,0,0,0,0,0,1,0,1,1,0,1,0,0,0, +0,1,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, +) + +Koi8rModel = { + 'char_to_order_map': KOI8R_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "KOI8-R", + 'language': 'Russian', +} + +Win1251CyrillicModel = { + 'char_to_order_map': win1251_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "windows-1251", + 'language': 'Russian', +} + +Latin5CyrillicModel = { + 'char_to_order_map': latin5_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "ISO-8859-5", + 'language': 'Russian', +} + +MacCyrillicModel = { + 'char_to_order_map': macCyrillic_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "MacCyrillic", + 'language': 'Russian', +} + +Ibm866Model = { + 'char_to_order_map': IBM866_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "IBM866", + 'language': 'Russian', +} + +Ibm855Model = { + 'char_to_order_map': IBM855_char_to_order_map, + 'precedence_matrix': RussianLangModel, + 'typical_positive_ratio': 0.976601, + 'keep_english_letter': False, + 'charset_name': "IBM855", + 'language': 'Russian', +} diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langgreekmodel.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langgreekmodel.py new file mode 100644 index 0000000..5332221 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langgreekmodel.py @@ -0,0 +1,225 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Character Mapping Table: +Latin7_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 82,100,104, 94, 98,101,116,102,111,187,117, 92, 88,113, 85, # 40 + 79,118,105, 83, 67,114,119, 95, 99,109,188,253,253,253,253,253, # 50 +253, 72, 70, 80, 81, 60, 96, 93, 89, 68,120, 97, 77, 86, 69, 55, # 60 + 78,115, 65, 66, 58, 76,106,103, 87,107,112,253,253,253,253,253, # 70 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 80 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 90 +253,233, 90,253,253,253,253,253,253,253,253,253,253, 74,253,253, # a0 +253,253,253,253,247,248, 61, 36, 46, 71, 73,253, 54,253,108,123, # b0 +110, 31, 51, 43, 41, 34, 91, 40, 52, 47, 44, 53, 38, 49, 59, 39, # c0 + 35, 48,250, 37, 33, 45, 56, 50, 84, 57,120,121, 17, 18, 22, 15, # d0 +124, 1, 29, 20, 21, 3, 32, 13, 25, 5, 11, 16, 10, 6, 30, 4, # e0 + 9, 8, 14, 7, 2, 12, 28, 23, 42, 24, 64, 75, 19, 26, 27,253, # f0 +) + +win1253_char_to_order_map = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 82,100,104, 94, 98,101,116,102,111,187,117, 92, 88,113, 85, # 40 + 79,118,105, 83, 67,114,119, 95, 99,109,188,253,253,253,253,253, # 50 +253, 72, 70, 80, 81, 60, 96, 93, 89, 68,120, 97, 77, 86, 69, 55, # 60 + 78,115, 65, 66, 58, 76,106,103, 87,107,112,253,253,253,253,253, # 70 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 80 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 90 +253,233, 61,253,253,253,253,253,253,253,253,253,253, 74,253,253, # a0 +253,253,253,253,247,253,253, 36, 46, 71, 73,253, 54,253,108,123, # b0 +110, 31, 51, 43, 41, 34, 91, 40, 52, 47, 44, 53, 38, 49, 59, 39, # c0 + 35, 48,250, 37, 33, 45, 56, 50, 84, 57,120,121, 17, 18, 22, 15, # d0 +124, 1, 29, 20, 21, 3, 32, 13, 25, 5, 11, 16, 10, 6, 30, 4, # e0 + 9, 8, 14, 7, 2, 12, 28, 23, 42, 24, 64, 75, 19, 26, 27,253, # f0 +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 98.2851% +# first 1024 sequences:1.7001% +# rest sequences: 0.0359% +# negative sequences: 0.0148% +GreekLangModel = ( +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,2,2,3,3,3,3,3,3,3,3,1,3,3,3,0,2,2,3,3,0,3,0,3,2,0,3,3,3,0, +3,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,0,3,3,0,3,2,3,3,0,3,2,3,3,3,0,0,3,0,3,0,3,3,2,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, +0,2,3,2,2,3,3,3,3,3,3,3,3,0,3,3,3,3,0,2,3,3,0,3,3,3,3,2,3,3,3,0, +2,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,0,2,1,3,3,3,3,2,3,3,2,3,3,2,0, +0,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,0,3,3,3,3,3,3,0,3,3,0,3,3,3,3,3,3,3,3,3,3,0,3,2,3,3,0, +2,0,1,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,3,0,0,0,0,3,3,0,3,1,3,3,3,0,3,3,0,3,3,3,3,0,0,0,0, +2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,0,3,0,3,3,3,3,3,0,3,2,2,2,3,0,2,3,3,3,3,3,2,3,3,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,3,2,2,2,3,3,3,3,0,3,1,3,3,3,3,2,3,3,3,3,3,3,3,2,2,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,0,3,0,0,0,3,3,2,3,3,3,3,3,0,0,3,2,3,0,2,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,3,0,0,3,3,0,2,3,0,3,0,3,3,3,0,0,3,0,3,0,2,2,3,3,0,0, +0,0,1,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,0,3,2,3,3,3,3,0,3,3,3,3,3,0,3,3,2,3,2,3,3,2,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,2,3,2,3,3,3,3,3,3,0,2,3,2,3,2,2,2,3,2,3,3,2,3,0,2,2,2,3,0, +2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,0,3,3,3,2,3,3,0,0,3,0,3,0,0,0,3,2,0,3,0,3,0,0,2,0,2,0, +0,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,0,3,3,3,3,3,3,0,3,3,0,3,0,0,0,3,3,0,3,3,3,0,0,1,2,3,0, +3,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,2,0,0,3,2,2,3,3,0,3,3,3,3,3,2,1,3,0,3,2,3,3,2,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,3,0,2,3,3,3,3,3,3,0,0,3,0,3,0,0,0,3,3,0,3,2,3,0,0,3,3,3,0, +3,0,0,0,2,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,0,3,3,3,3,3,3,0,0,3,0,3,0,0,0,3,2,0,3,2,3,0,0,3,2,3,0, +2,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,1,2,2,3,3,3,3,3,3,0,2,3,0,3,0,0,0,3,3,0,3,0,2,0,0,2,3,1,0, +2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,3,0,3,0,3,3,2,3,0,3,3,3,3,3,3,0,3,3,3,0,2,3,0,0,3,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,0,0,3,0,0,0,3,3,0,3,0,2,3,3,0,0,3,0,3,0,3,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,0,3,3,3,3,3,3,0,0,3,0,2,0,0,0,3,3,0,3,0,3,0,0,2,0,2,0, +0,0,0,0,1,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,3,0,3,0,2,0,3,2,0,3,2,3,2,3,0,0,3,2,3,2,3,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,2,3,3,3,3,3,0,0,0,3,0,2,1,0,0,3,2,2,2,0,3,0,0,2,2,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,2,0,3,0,3,0,3,3,0,2,1,2,3,3,0,0,3,0,3,0,3,3,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,3,3,3,0,3,3,3,3,3,3,0,2,3,0,3,0,0,0,2,1,0,2,2,3,0,0,2,2,2,0, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,3,0,0,2,3,3,3,2,3,0,0,1,3,0,2,0,0,0,0,3,0,1,0,2,0,0,1,1,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,3,1,0,3,0,0,0,3,2,0,3,2,3,3,3,0,0,3,0,3,2,2,2,1,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,3,3,3,0,0,3,0,0,0,0,2,0,2,3,3,2,2,2,2,3,0,2,0,2,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,3,3,3,2,0,0,0,0,0,0,2,3,0,2,0,2,3,2,0,0,3,0,3,0,3,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,3,2,3,3,2,2,3,0,2,0,3,0,0,0,2,0,0,0,0,1,2,0,2,0,2,0, +0,2,0,2,0,2,2,0,0,1,0,2,2,2,0,2,2,2,0,2,2,2,0,0,2,0,0,1,0,0,0,0, +0,2,0,3,3,2,0,0,0,0,0,0,1,3,0,2,0,2,2,2,0,0,2,0,3,0,0,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,0,2,3,2,0,2,2,0,2,0,2,2,0,2,0,2,2,2,0,0,0,0,0,0,2,3,0,0,0,2, +0,1,2,0,0,0,0,2,2,0,0,0,2,1,0,2,2,0,0,0,0,0,0,1,0,2,0,0,0,0,0,0, +0,0,2,1,0,2,3,2,2,3,2,3,2,0,0,3,3,3,0,0,3,2,0,0,0,1,1,0,2,0,2,2, +0,2,0,2,0,2,2,0,0,2,0,2,2,2,0,2,2,2,2,0,0,2,0,0,0,2,0,1,0,0,0,0, +0,3,0,3,3,2,2,0,3,0,0,0,2,2,0,2,2,2,1,2,0,0,1,2,2,0,0,3,0,0,0,2, +0,1,2,0,0,0,1,2,0,0,0,0,0,0,0,2,2,0,1,0,0,2,0,0,0,2,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,3,3,2,2,0,0,0,2,0,2,3,3,0,2,0,0,0,0,0,0,2,2,2,0,2,2,0,2,0,2, +0,2,2,0,0,2,2,2,2,1,0,0,2,2,0,2,0,0,2,0,0,0,0,0,0,2,0,0,0,0,0,0, +0,2,0,3,2,3,0,0,0,3,0,0,2,2,0,2,0,2,2,2,0,0,2,0,0,0,0,0,0,0,0,2, +0,0,2,2,0,0,2,2,2,0,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,0,0,3,2,0,2,2,2,2,2,0,0,0,2,0,0,0,0,2,0,1,0,0,2,0,1,0,0,0, +0,2,2,2,0,2,2,0,1,2,0,2,2,2,0,2,2,2,2,1,2,2,0,0,2,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,2,0,2,0,2,2,0,0,0,0,1,2,1,0,0,2,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,3,2,3,0,0,2,0,0,0,2,2,0,2,0,0,0,1,0,0,2,0,2,0,2,2,0,0,0,0, +0,0,2,0,0,0,0,2,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0, +0,2,2,3,2,2,0,0,0,0,0,0,1,3,0,2,0,2,2,0,0,0,1,0,2,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,0,2,0,3,2,0,2,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +0,0,2,0,0,0,0,1,1,0,0,2,1,2,0,2,2,0,1,0,0,1,0,0,0,2,0,0,0,0,0,0, +0,3,0,2,2,2,0,0,2,0,0,0,2,0,0,0,2,3,0,2,0,0,0,0,0,0,2,2,0,0,0,2, +0,1,2,0,0,0,1,2,2,1,0,0,0,2,0,0,2,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,1,2,0,2,2,0,2,0,0,2,0,0,0,0,1,2,1,0,2,1,0,0,0,0,0,0,0,0,0,0, +0,0,2,0,0,0,3,1,2,2,0,2,0,0,0,0,2,0,0,0,2,0,0,3,0,0,0,0,2,2,2,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,1,0,2,0,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0,2, +0,2,2,0,0,2,2,2,2,2,0,1,2,0,0,0,2,2,0,1,0,2,0,0,2,2,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,3,0,0,2,0,0,0,0,0,0,0,0,2,0,2,0,0,0,0,2, +0,1,2,0,0,0,0,2,2,1,0,1,0,1,0,2,2,2,1,0,0,0,0,0,0,1,0,0,0,0,0,0, +0,2,0,1,2,0,0,0,0,0,0,0,0,0,0,2,0,0,2,2,0,0,0,0,1,0,0,0,0,0,0,2, +0,2,2,0,0,0,0,2,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0,0, +0,2,2,2,2,0,0,0,3,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,2,0,0,0,0,0,0,1, +0,0,2,0,0,0,0,1,2,0,0,0,0,0,0,2,2,1,1,0,0,0,0,0,0,1,0,0,0,0,0,0, +0,2,0,2,2,2,0,0,2,0,0,0,0,0,0,0,2,2,2,0,0,0,2,0,0,0,0,0,0,0,0,2, +0,0,1,0,0,0,0,2,1,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +0,3,0,2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,2,0,0,0,0,0,0,0,2,0,0,0,0,2, +0,0,2,0,0,0,0,2,2,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2,0,2,2,1,0,0,0,0,0,0,2,0,0,2,0,2,2,2,0,0,0,0,0,0,2,0,0,0,0,2, +0,0,2,0,0,2,0,2,2,0,0,0,0,2,0,2,0,0,0,0,0,2,0,0,0,2,0,0,0,0,0,0, +0,0,3,0,0,0,2,2,0,2,2,0,0,0,0,0,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0,0,0,0, +0,2,2,2,2,2,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1, +0,0,0,0,0,0,0,2,1,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,2,2,0,0,0,0,0,2,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,2,0,0,0,2,0,0,0,0,0,1,0,0,0,0,2,2,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,2,0,0,0, +0,2,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,2,0,2,0,0,0, +0,0,0,0,0,0,0,0,2,1,0,0,0,0,0,0,2,0,0,0,1,2,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +) + +Latin7GreekModel = { + 'char_to_order_map': Latin7_char_to_order_map, + 'precedence_matrix': GreekLangModel, + 'typical_positive_ratio': 0.982851, + 'keep_english_letter': False, + 'charset_name': "ISO-8859-7", + 'language': 'Greek', +} + +Win1253GreekModel = { + 'char_to_order_map': win1253_char_to_order_map, + 'precedence_matrix': GreekLangModel, + 'typical_positive_ratio': 0.982851, + 'keep_english_letter': False, + 'charset_name': "windows-1253", + 'language': 'Greek', +} diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langhebrewmodel.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langhebrewmodel.py new file mode 100644 index 0000000..58f4c87 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langhebrewmodel.py @@ -0,0 +1,200 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Simon Montagu +# Portions created by the Initial Developer are Copyright (C) 2005 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# Shoshannah Forbes - original C code (?) +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Windows-1255 language model +# Character Mapping Table: +WIN1255_CHAR_TO_ORDER_MAP = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 69, 91, 79, 80, 92, 89, 97, 90, 68,111,112, 82, 73, 95, 85, # 40 + 78,121, 86, 71, 67,102,107, 84,114,103,115,253,253,253,253,253, # 50 +253, 50, 74, 60, 61, 42, 76, 70, 64, 53,105, 93, 56, 65, 54, 49, # 60 + 66,110, 51, 43, 44, 63, 81, 77, 98, 75,108,253,253,253,253,253, # 70 +124,202,203,204,205, 40, 58,206,207,208,209,210,211,212,213,214, +215, 83, 52, 47, 46, 72, 32, 94,216,113,217,109,218,219,220,221, + 34,116,222,118,100,223,224,117,119,104,125,225,226, 87, 99,227, +106,122,123,228, 55,229,230,101,231,232,120,233, 48, 39, 57,234, + 30, 59, 41, 88, 33, 37, 36, 31, 29, 35,235, 62, 28,236,126,237, +238, 38, 45,239,240,241,242,243,127,244,245,246,247,248,249,250, + 9, 8, 20, 16, 3, 2, 24, 14, 22, 1, 25, 15, 4, 11, 6, 23, + 12, 19, 13, 26, 18, 27, 21, 17, 7, 10, 5,251,252,128, 96,253, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 98.4004% +# first 1024 sequences: 1.5981% +# rest sequences: 0.087% +# negative sequences: 0.0015% +HEBREW_LANG_MODEL = ( +0,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,2,3,2,1,2,0,1,0,0, +3,0,3,1,0,0,1,3,2,0,1,1,2,0,2,2,2,1,1,1,1,2,1,1,1,2,0,0,2,2,0,1, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2, +1,2,1,2,1,2,0,0,2,0,0,0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2, +1,2,1,3,1,1,0,0,2,0,0,0,1,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,0,1,2,2,1,3, +1,2,1,1,2,2,0,0,2,2,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,1,0,1,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,2,2,2,2,3,2, +1,2,1,2,2,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,2,3,2,2,3,2,2,2,1,2,2,2,2, +1,2,1,1,2,2,0,1,2,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,0,2,2,2,2,2, +0,2,0,2,2,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,0,2,2,2, +0,2,1,2,2,2,0,0,2,1,0,0,0,0,1,0,1,0,0,0,0,0,0,2,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,2,1,2,3,2,2,2, +1,2,1,2,2,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,3,3,1,0,2,0,2, +0,2,1,2,2,2,0,0,1,2,0,0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,2,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,2,3,2,2,3,2,1,2,1,1,1, +0,1,1,1,1,1,3,0,1,0,0,0,0,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,0,1,0,0,1,0,0,0,0, +0,0,1,0,0,0,0,0,2,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2, +0,2,0,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,2,1,2,3,3,2,3,3,3,3,2,3,2,1,2,0,2,1,2, +0,2,0,2,2,2,0,0,1,2,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,1,2,2,3,3,2,3,2,3,2,2,3,1,2,2,0,2,2,2, +0,2,1,2,2,2,0,0,1,2,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3,2,2,2,3,3,3,3,1,3,2,2,2, +0,2,0,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,2,3,3,3,2,3,2,2,2,1,2,2,0,2,2,2,2, +0,2,0,2,2,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,1,3,2,3,3,2,3,3,2,2,1,2,2,2,2,2,2, +0,2,1,2,1,2,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,2,3,3,2,3,3,3,3,2,3,2,3,3,3,3,3,2,2,2,2,2,2,2,1, +0,2,0,1,2,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,2,1,2,3,3,3,3,3,3,3,2,3,2,3,2,1,2,3,0,2,1,2,2, +0,2,1,1,2,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,2,0, +3,3,3,3,3,3,3,3,3,2,3,3,3,3,2,1,3,1,2,2,2,1,2,3,3,1,2,1,2,2,2,2, +0,1,1,1,1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,0,2,3,3,3,1,3,3,3,1,2,2,2,2,1,1,2,2,2,2,2,2, +0,2,0,1,1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,3,3,2,2,3,3,3,2,1,2,3,2,3,2,2,2,2,1,2,1,1,1,2,2, +0,2,1,1,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,1,0,0,0,0,0, +1,0,1,0,0,0,0,0,2,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,2,3,3,2,3,1,2,2,2,2,3,2,3,1,1,2,2,1,2,2,1,1,0,2,2,2,2, +0,1,0,1,2,2,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0, +3,0,0,1,1,0,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,2,0, +0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,1,0,1,0,1,1,0,1,1,0,0,0,1,1,0,1,1,1,0,0,0,0,0,0,1,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +3,2,2,1,2,2,2,2,2,2,2,1,2,2,1,2,2,1,1,1,1,1,1,1,1,2,1,1,0,3,3,3, +0,3,0,2,2,2,2,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +2,2,2,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,2,1,2,2,2,1,1,1,2,0,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,2,2,2,2,2,2,0,2,2,0,0,0,0,0,0, +0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,1,2,1,0,2,1,0, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +0,3,1,1,2,2,2,2,2,1,2,2,2,1,1,2,2,2,2,2,2,2,1,2,2,1,0,1,1,1,1,0, +0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,2,1,1,1,1,2,1,1,2,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0, +0,0,2,0,0,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,1,1,0,0,0,0,0,0,1,0,0, +2,1,1,2,2,2,2,2,2,2,2,2,2,2,1,2,2,2,2,2,1,2,1,2,1,1,1,1,0,0,0,0, +0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,2,1,2,2,2,2,2,2,2,2,2,2,1,2,1,2,1,1,2,1,1,1,2,1,2,1,2,0,1,0,1, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,3,1,2,2,2,1,2,2,2,2,2,2,2,2,1,2,1,1,1,1,1,1,2,1,2,1,1,0,1,0,1, +0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,2, +0,2,0,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,1,1,1,1,1,1,0,1,1,0,1,0,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,2,0,1,1,1,0,1,0,0,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0, +0,1,1,1,2,1,2,2,2,0,2,0,2,0,1,1,2,1,1,1,1,2,1,0,1,1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,1,0,0,0,0,0,1,0,1,2,2,0,1,0,0,1,1,2,2,1,2,0,2,0,0,0,1,2,0,1, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,2,0,2,1,2,0,2,0,0,1,1,1,1,1,1,0,1,0,0,0,1,0,0,1, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,0,0,0,0,0,1,0,2,1,1,0,1,0,0,1,1,1,2,2,0,0,1,0,0,0,1,0,0,1, +1,1,2,1,0,1,1,1,0,1,0,1,1,1,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,2,2,1, +0,2,0,1,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,1,0,0,1,0,1,1,1,1,0,0,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,1,1,1,1,1,1,1,2,1,0,1,1,1,1,1,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,1,1,0,1,0,0,0,1,1,0,1, +2,0,1,0,1,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,1,0,1,0,0,1,1,2,1,1,2,0,1,0,0,0,1,1,0,1, +1,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,2,0,1,0,0,0,0,2,1,1,2,0,2,0,0,0,1,1,0,1, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,2,1,1,0,1,0,0,2,2,1,2,1,1,0,1,0,0,0,1,1,0,1, +2,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,2,2,0,0,0,0,0,1,1,0,1,0,0,1,0,0,0,0,1,0,1, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,2,2,0,0,0,0,2,1,1,1,0,2,1,1,0,0,0,2,1,0,1, +1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,2,0,1,0,0,1,1,0,2,1,1,0,1,0,0,0,1,1,0,1, +2,2,1,1,1,0,1,1,0,1,1,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,2,1,1,0,1,0,0,1,1,0,1,2,1,0,2,0,0,0,1,1,0,1, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0, +0,1,0,0,2,0,2,1,1,0,1,0,1,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1,0,1,1,2,0,1,0,0,1,1,1,0,1,0,0,1,0,0,0,1,0,0,1, +1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,0,0,0,0,0,1,0,1,1,0,0,1,0,0,2,1,1,1,1,1,0,1,0,0,0,0,1,0,1, +0,1,1,1,2,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1,2,1,0,0,0,0,0,1,1,1,1,1,0,1,0,0,0,1,1,0,0, +) + +Win1255HebrewModel = { + 'char_to_order_map': WIN1255_CHAR_TO_ORDER_MAP, + 'precedence_matrix': HEBREW_LANG_MODEL, + 'typical_positive_ratio': 0.984004, + 'keep_english_letter': False, + 'charset_name': "windows-1255", + 'language': 'Hebrew', +} diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langhungarianmodel.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langhungarianmodel.py new file mode 100644 index 0000000..bb7c095 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langhungarianmodel.py @@ -0,0 +1,225 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Character Mapping Table: +Latin2_HungarianCharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 28, 40, 54, 45, 32, 50, 49, 38, 39, 53, 36, 41, 34, 35, 47, + 46, 71, 43, 33, 37, 57, 48, 64, 68, 55, 52,253,253,253,253,253, +253, 2, 18, 26, 17, 1, 27, 12, 20, 9, 22, 7, 6, 13, 4, 8, + 23, 67, 10, 5, 3, 21, 19, 65, 62, 16, 11,253,253,253,253,253, +159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174, +175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190, +191,192,193,194,195,196,197, 75,198,199,200,201,202,203,204,205, + 79,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220, +221, 51, 81,222, 78,223,224,225,226, 44,227,228,229, 61,230,231, +232,233,234, 58,235, 66, 59,236,237,238, 60, 69, 63,239,240,241, + 82, 14, 74,242, 70, 80,243, 72,244, 15, 83, 77, 84, 30, 76, 85, +245,246,247, 25, 73, 42, 24,248,249,250, 31, 56, 29,251,252,253, +) + +win1250HungarianCharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253, 28, 40, 54, 45, 32, 50, 49, 38, 39, 53, 36, 41, 34, 35, 47, + 46, 72, 43, 33, 37, 57, 48, 64, 68, 55, 52,253,253,253,253,253, +253, 2, 18, 26, 17, 1, 27, 12, 20, 9, 22, 7, 6, 13, 4, 8, + 23, 67, 10, 5, 3, 21, 19, 65, 62, 16, 11,253,253,253,253,253, +161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176, +177,178,179,180, 78,181, 69,182,183,184,185,186,187,188,189,190, +191,192,193,194,195,196,197, 76,198,199,200,201,202,203,204,205, + 81,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220, +221, 51, 83,222, 80,223,224,225,226, 44,227,228,229, 61,230,231, +232,233,234, 58,235, 66, 59,236,237,238, 60, 70, 63,239,240,241, + 84, 14, 75,242, 71, 82,243, 73,244, 15, 85, 79, 86, 30, 77, 87, +245,246,247, 25, 74, 42, 24,248,249,250, 31, 56, 29,251,252,253, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 94.7368% +# first 1024 sequences:5.2623% +# rest sequences: 0.8894% +# negative sequences: 0.0009% +HungarianLangModel = ( +0,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,1,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, +3,3,3,3,3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,2,2,3,3,1,1,2,2,2,2,2,1,2, +3,2,2,3,3,3,3,3,2,3,3,3,3,3,3,1,2,3,3,3,3,2,3,3,1,1,3,3,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0, +3,2,1,3,3,3,3,3,2,3,3,3,3,3,1,1,2,3,3,3,3,3,3,3,1,1,3,2,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,1,1,2,3,3,3,1,3,3,3,3,3,1,3,3,2,2,0,3,2,3, +0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,3,3,3,2,3,3,2,3,3,3,3,3,2,3,3,2,2,3,2,3,2,0,3,2,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,3,3,3,3,2,3,3,3,1,2,3,2,2,3,1,2,3,3,2,2,0,3,3,3, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,2,2,3,3,3,3,3,3,2,3,3,3,3,2,3,3,3,3,0,2,3,2, +0,0,0,1,1,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,1,1,1,3,3,2,1,3,2,2,3,2,1,3,2,2,1,0,3,3,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,2,2,3,3,3,3,3,1,2,3,3,3,3,1,2,1,3,3,3,3,2,2,3,1,1,3,2,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,2,2,3,3,3,3,3,2,1,3,3,3,3,3,2,2,1,3,3,3,0,1,1,2, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,2,3,3,3,2,3,3,2,3,3,3,2,0,3,2,3, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,1,0, +3,3,3,3,3,3,2,3,3,3,2,3,2,3,3,3,1,3,2,2,2,3,1,1,3,3,1,1,0,3,3,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,2,3,3,3,2,3,2,3,3,3,2,3,3,3,3,3,1,2,3,2,2,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,2,2,2,3,1,3,3,2,2,1,3,3,3,1,1,3,1,2,3,2,3,2,2,2,1,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, +3,1,1,3,3,3,3,3,1,2,3,3,3,3,1,2,1,3,3,3,2,2,3,2,1,0,3,2,0,1,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,3,3,3,3,3,1,2,3,3,3,3,1,1,0,3,3,3,3,0,2,3,0,0,2,1,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,2,2,3,3,2,2,2,2,3,3,0,1,2,3,2,3,2,2,3,2,1,2,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, +3,3,3,3,3,3,1,2,3,3,3,2,1,2,3,3,2,2,2,3,2,3,3,1,3,3,1,1,0,2,3,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,1,2,2,2,2,3,3,3,1,1,1,3,3,1,1,3,1,1,3,2,1,2,3,1,1,0,2,2,2, +0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,2,1,2,1,1,3,3,1,1,1,1,3,3,1,1,2,2,1,2,1,1,2,2,1,1,0,2,2,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,1,1,2,1,1,3,3,1,0,1,1,3,3,2,0,1,1,2,3,1,0,2,2,1,0,0,1,3,2, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,2,1,3,3,3,3,3,1,2,3,2,3,3,2,1,1,3,2,3,2,1,2,2,0,1,2,1,0,0,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,3,3,2,2,2,2,3,1,2,2,1,1,3,3,0,3,2,1,2,3,2,1,3,3,1,1,0,2,1,3, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,3,3,2,2,2,3,2,3,3,3,2,1,1,3,3,1,1,1,2,2,3,2,3,2,2,2,1,0,2,2,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +1,0,0,3,3,3,3,3,0,0,3,3,2,3,0,0,0,2,3,3,1,0,1,2,0,0,1,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,2,3,3,3,3,3,1,2,3,3,2,2,1,1,0,3,3,2,2,1,2,2,1,0,2,2,0,1,1,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,2,2,1,3,1,2,3,3,2,2,1,1,2,2,1,1,1,1,3,2,1,1,1,1,2,1,0,1,2,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +2,3,3,1,1,1,1,1,3,3,3,0,1,1,3,3,1,1,1,1,1,2,2,0,3,1,1,2,0,2,1,1, +0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, +3,1,0,1,2,1,2,2,0,1,2,3,1,2,0,0,0,2,1,1,1,1,1,2,0,0,1,1,0,0,0,0, +1,2,1,2,2,2,1,2,1,2,0,2,0,2,2,1,1,2,1,1,2,1,1,1,0,1,0,0,0,1,1,0, +1,1,1,2,3,2,3,3,0,1,2,2,3,1,0,1,0,2,1,2,2,0,1,1,0,0,1,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,3,3,2,2,1,0,0,3,2,3,2,0,0,0,1,1,3,0,0,1,1,0,0,2,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,2,2,3,3,1,0,1,3,2,3,1,1,1,0,1,1,1,1,1,3,1,0,0,2,2,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,1,1,2,2,2,1,0,1,2,3,3,2,0,0,0,2,1,1,1,2,1,1,1,0,1,1,1,0,0,0, +1,2,2,2,2,2,1,1,1,2,0,2,1,1,1,1,1,2,1,1,1,1,1,1,0,1,1,1,0,0,1,1, +3,2,2,1,0,0,1,1,2,2,0,3,0,1,2,1,1,0,0,1,1,1,0,1,1,1,1,0,2,1,1,1, +2,2,1,1,1,2,1,2,1,1,1,1,1,1,1,2,1,1,1,2,3,1,1,1,1,1,1,1,1,1,0,1, +2,3,3,0,1,0,0,0,3,3,1,0,0,1,2,2,1,0,0,0,0,2,0,0,1,1,1,0,2,1,1,1, +2,1,1,1,1,1,1,2,1,1,0,1,1,0,1,1,1,0,1,2,1,1,0,1,1,1,1,1,1,1,0,1, +2,3,3,0,1,0,0,0,2,2,0,0,0,0,1,2,2,0,0,0,0,1,0,0,1,1,0,0,2,0,1,0, +2,1,1,1,1,2,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,2,0,1,1,1,1,1,0,1, +3,2,2,0,1,0,1,0,2,3,2,0,0,1,2,2,1,0,0,1,1,1,0,0,2,1,0,1,2,2,1,1, +2,1,1,1,1,1,1,2,1,1,1,1,1,1,0,2,1,0,1,1,0,1,1,1,0,1,1,2,1,1,0,1, +2,2,2,0,0,1,0,0,2,2,1,1,0,0,2,1,1,0,0,0,1,2,0,0,2,1,0,0,2,1,1,1, +2,1,1,1,1,2,1,2,1,1,1,2,2,1,1,2,1,1,1,2,1,1,1,1,1,1,1,1,1,1,0,1, +1,2,3,0,0,0,1,0,3,2,1,0,0,1,2,1,1,0,0,0,0,2,1,0,1,1,0,0,2,1,2,1, +1,1,0,0,0,1,0,1,1,1,1,1,2,0,0,1,0,0,0,2,0,0,1,1,1,1,1,1,1,1,0,1, +3,0,0,2,1,2,2,1,0,0,2,1,2,2,0,0,0,2,1,1,1,0,1,1,0,0,1,1,2,0,0,0, +1,2,1,2,2,1,1,2,1,2,0,1,1,1,1,1,1,1,1,1,2,1,1,0,0,1,1,1,1,0,0,1, +1,3,2,0,0,0,1,0,2,2,2,0,0,0,2,2,1,0,0,0,0,3,1,1,1,1,0,0,2,1,1,1, +2,1,0,1,1,1,0,1,1,1,1,1,1,1,0,2,1,0,0,1,0,1,1,0,1,1,1,1,1,1,0,1, +2,3,2,0,0,0,1,0,2,2,0,0,0,0,2,1,1,0,0,0,0,2,1,0,1,1,0,0,2,1,1,0, +2,1,1,1,1,2,1,2,1,2,0,1,1,1,0,2,1,1,1,2,1,1,1,1,0,1,1,1,1,1,0,1, +3,1,1,2,2,2,3,2,1,1,2,2,1,1,0,1,0,2,2,1,1,1,1,1,0,0,1,1,0,1,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,0,0,0,0,0,2,2,0,0,0,0,2,2,1,0,0,0,1,1,0,0,1,2,0,0,2,1,1,1, +2,2,1,1,1,2,1,2,1,1,0,1,1,1,1,2,1,1,1,2,1,1,1,1,0,1,2,1,1,1,0,1, +1,0,0,1,2,3,2,1,0,0,2,0,1,1,0,0,0,1,1,1,1,0,1,1,0,0,1,0,0,0,0,0, +1,2,1,2,1,2,1,1,1,2,0,2,1,1,1,0,1,2,0,0,1,1,1,0,0,0,0,0,0,0,0,0, +2,3,2,0,0,0,0,0,1,1,2,1,0,0,1,1,1,0,0,0,0,2,0,0,1,1,0,0,2,1,1,1, +2,1,1,1,1,1,1,2,1,0,1,1,1,1,0,2,1,1,1,1,1,1,0,1,0,1,1,1,1,1,0,1, +1,2,2,0,1,1,1,0,2,2,2,0,0,0,3,2,1,0,0,0,1,1,0,0,1,1,0,1,1,1,0,0, +1,1,0,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,2,1,1,1,0,0,1,1,1,0,1,0,1, +2,1,0,2,1,1,2,2,1,1,2,1,1,1,0,0,0,1,1,0,1,1,1,1,0,0,1,1,1,0,0,0, +1,2,2,2,2,2,1,1,1,2,0,2,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,0,0,0,1,0, +1,2,3,0,0,0,1,0,2,2,0,0,0,0,2,2,0,0,0,0,0,1,0,0,1,0,0,0,2,0,1,0, +2,1,1,1,1,1,0,2,0,0,0,1,2,1,1,1,1,0,1,2,0,1,0,1,0,1,1,1,0,1,0,1, +2,2,2,0,0,0,1,0,2,1,2,0,0,0,1,1,2,0,0,0,0,1,0,0,1,1,0,0,2,1,0,1, +2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,0,1,1,1,1,1,0,1, +1,2,2,0,0,0,1,0,2,2,2,0,0,0,1,1,0,0,0,0,0,1,1,0,2,0,0,1,1,1,0,1, +1,0,1,1,1,1,1,1,0,1,1,1,1,0,0,1,0,0,1,1,0,1,0,1,1,1,1,1,0,0,0,1, +1,0,0,1,0,1,2,1,0,0,1,1,1,2,0,0,0,1,1,0,1,0,1,1,0,0,1,0,0,0,0,0, +0,2,1,2,1,1,1,1,1,2,0,2,0,1,1,0,1,2,1,0,1,1,1,0,0,0,0,0,0,1,0,0, +2,1,1,0,1,2,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,1,0,0,1,0,0,0,2,1,0,1, +2,2,1,1,1,1,1,2,1,1,0,1,1,1,1,2,1,1,1,2,1,1,0,1,0,1,1,1,1,1,0,1, +1,2,2,0,0,0,0,0,1,1,0,0,0,0,2,1,0,0,0,0,0,2,0,0,2,2,0,0,2,0,0,1, +2,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,0,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1, +1,1,2,0,0,3,1,0,2,1,1,1,0,0,1,1,1,0,0,0,1,1,0,0,0,1,0,0,1,0,1,0, +1,2,1,0,1,1,1,2,1,1,0,1,1,1,1,1,0,0,0,1,1,1,1,1,0,1,0,0,0,1,0,0, +2,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,2,0,0,0, +2,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,2,1,1,0,0,1,1,1,1,1,0,1, +2,1,1,1,2,1,1,1,0,1,1,2,1,0,0,0,0,1,1,1,1,0,1,0,0,0,0,1,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,0,1,1,1,1,1,0,0,1,1,2,1,0,0,0,1,1,0,0,0,1,1,0,0,1,0,1,0,0,0, +1,2,1,1,1,1,1,1,1,1,0,1,0,1,1,1,1,1,1,0,1,1,1,0,0,0,0,0,0,1,0,0, +2,0,0,0,1,1,1,1,0,0,1,1,0,0,0,0,0,1,1,1,2,0,0,1,0,0,1,0,1,0,0,0, +0,1,1,1,1,1,1,1,1,2,0,1,1,1,1,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,1,1,0,0,2,1,0,1,0,0,0,1,0,1,0,0,0,0,0,0,1,0,0,0,0,0, +0,1,1,1,1,1,1,0,1,1,0,1,0,1,1,0,1,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,0,0,0,0,1,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +0,1,1,1,1,1,0,0,1,1,0,1,0,1,0,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0, +0,0,0,1,0,0,0,0,0,0,1,1,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,1,1,1,0,1,0,0,1,1,0,1,0,1,1,0,1,1,1,0,1,1,1,0,0,0,0,0,0,0,0,0, +2,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,0,0,1,0,0,1,0,1,0,1,1,1,0,0,1,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,0,1,1,1,1,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, +0,1,1,1,1,1,1,0,1,1,0,1,0,1,0,0,1,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0, +) + +Latin2HungarianModel = { + 'char_to_order_map': Latin2_HungarianCharToOrderMap, + 'precedence_matrix': HungarianLangModel, + 'typical_positive_ratio': 0.947368, + 'keep_english_letter': True, + 'charset_name': "ISO-8859-2", + 'language': 'Hungarian', +} + +Win1250HungarianModel = { + 'char_to_order_map': win1250HungarianCharToOrderMap, + 'precedence_matrix': HungarianLangModel, + 'typical_positive_ratio': 0.947368, + 'keep_english_letter': True, + 'charset_name': "windows-1250", + 'language': 'Hungarian', +} diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langthaimodel.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langthaimodel.py new file mode 100644 index 0000000..15f94c2 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langthaimodel.py @@ -0,0 +1,199 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# The following result for thai was collected from a limited sample (1M). + +# Character Mapping Table: +TIS620CharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,254,255,255,254,255,255, # 00 +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, # 10 +253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253, # 20 +252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253, # 30 +253,182,106,107,100,183,184,185,101, 94,186,187,108,109,110,111, # 40 +188,189,190, 89, 95,112,113,191,192,193,194,253,253,253,253,253, # 50 +253, 64, 72, 73,114, 74,115,116,102, 81,201,117, 90,103, 78, 82, # 60 + 96,202, 91, 79, 84,104,105, 97, 98, 92,203,253,253,253,253,253, # 70 +209,210,211,212,213, 88,214,215,216,217,218,219,220,118,221,222, +223,224, 99, 85, 83,225,226,227,228,229,230,231,232,233,234,235, +236, 5, 30,237, 24,238, 75, 8, 26, 52, 34, 51,119, 47, 58, 57, + 49, 53, 55, 43, 20, 19, 44, 14, 48, 3, 17, 25, 39, 62, 31, 54, + 45, 9, 16, 2, 61, 15,239, 12, 42, 46, 18, 21, 76, 4, 66, 63, + 22, 10, 1, 36, 23, 13, 40, 27, 32, 35, 86,240,241,242,243,244, + 11, 28, 41, 29, 33,245, 50, 37, 6, 7, 67, 77, 38, 93,246,247, + 68, 56, 59, 65, 69, 60, 70, 80, 71, 87,248,249,250,251,252,253, +) + +# Model Table: +# total sequences: 100% +# first 512 sequences: 92.6386% +# first 1024 sequences:7.3177% +# rest sequences: 1.0230% +# negative sequences: 0.0436% +ThaiLangModel = ( +0,1,3,3,3,3,0,0,3,3,0,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3,3,0,3,3,3,3, +0,3,3,0,0,0,1,3,0,3,3,2,3,3,0,1,2,3,3,3,3,0,2,0,2,0,0,3,2,1,2,2, +3,0,3,3,2,3,0,0,3,3,0,3,3,0,3,3,3,3,3,3,3,3,3,0,3,2,3,0,2,2,2,3, +0,2,3,0,0,0,0,1,0,1,2,3,1,1,3,2,2,0,1,1,0,0,1,0,0,0,0,0,0,0,1,1, +3,3,3,2,3,3,3,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,3,3,2,3,2,3,3,2,2,2, +3,1,2,3,0,3,3,2,2,1,2,3,3,1,2,0,1,3,0,1,0,0,1,0,0,0,0,0,0,0,1,1, +3,3,2,2,3,3,3,3,1,2,3,3,3,3,3,2,2,2,2,3,3,2,2,3,3,2,2,3,2,3,2,2, +3,3,1,2,3,1,2,2,3,3,1,0,2,1,0,0,3,1,2,1,0,0,1,0,0,0,0,0,0,1,0,1, +3,3,3,3,3,3,2,2,3,3,3,3,2,3,2,2,3,3,2,2,3,2,2,2,2,1,1,3,1,2,1,1, +3,2,1,0,2,1,0,1,0,1,1,0,1,1,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0, +3,3,3,2,3,2,3,3,2,2,3,2,3,3,2,3,1,1,2,3,2,2,2,3,2,2,2,2,2,1,2,1, +2,2,1,1,3,3,2,1,0,1,2,2,0,1,3,0,0,0,1,1,0,0,0,0,0,2,3,0,0,2,1,1, +3,3,2,3,3,2,0,0,3,3,0,3,3,0,2,2,3,1,2,2,1,1,1,0,2,2,2,0,2,2,1,1, +0,2,1,0,2,0,0,2,0,1,0,0,1,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0, +3,3,2,3,3,2,0,0,3,3,0,2,3,0,2,1,2,2,2,2,1,2,0,0,2,2,2,0,2,2,1,1, +0,2,1,0,2,0,0,2,0,1,1,0,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0, +3,3,2,3,2,3,2,0,2,2,1,3,2,1,3,2,1,2,3,2,2,3,0,2,3,2,2,1,2,2,2,2, +1,2,2,0,0,0,0,2,0,1,2,0,1,1,1,0,1,0,3,1,1,0,0,0,0,0,0,0,0,0,1,0, +3,3,2,3,3,2,3,2,2,2,3,2,2,3,2,2,1,2,3,2,2,3,1,3,2,2,2,3,2,2,2,3, +3,2,1,3,0,1,1,1,0,2,1,1,1,1,1,0,1,0,1,1,0,0,0,0,0,0,0,0,0,2,0,0, +1,0,0,3,0,3,3,3,3,3,0,0,3,0,2,2,3,3,3,3,3,0,0,0,1,1,3,0,0,0,0,2, +0,0,1,0,0,0,0,0,0,0,2,3,0,0,0,3,0,2,0,0,0,0,0,3,0,0,0,0,0,0,0,0, +2,0,3,3,3,3,0,0,2,3,0,0,3,0,3,3,2,3,3,3,3,3,0,0,3,3,3,0,0,0,3,3, +0,0,3,0,0,0,0,2,0,0,2,1,1,3,0,0,1,0,0,2,3,0,1,0,0,0,0,0,0,0,1,0, +3,3,3,3,2,3,3,3,3,3,3,3,1,2,1,3,3,2,2,1,2,2,2,3,1,1,2,0,2,1,2,1, +2,2,1,0,0,0,1,1,0,1,0,1,1,0,0,0,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0, +3,0,2,1,2,3,3,3,0,2,0,2,2,0,2,1,3,2,2,1,2,1,0,0,2,2,1,0,2,1,2,2, +0,1,1,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,1,3,3,1,1,3,0,2,3,1,1,3,2,1,1,2,0,2,2,3,2,1,1,1,1,1,2, +3,0,0,1,3,1,2,1,2,0,3,0,0,0,1,0,3,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0, +3,3,1,1,3,2,3,3,3,1,3,2,1,3,2,1,3,2,2,2,2,1,3,3,1,2,1,3,1,2,3,0, +2,1,1,3,2,2,2,1,2,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2, +3,3,2,3,2,3,3,2,3,2,3,2,3,3,2,1,0,3,2,2,2,1,2,2,2,1,2,2,1,2,1,1, +2,2,2,3,0,1,3,1,1,1,1,0,1,1,0,2,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,3,2,2,1,1,3,2,3,2,3,2,0,3,2,2,1,2,0,2,2,2,1,2,2,2,2,1, +3,2,1,2,2,1,0,2,0,1,0,0,1,1,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,1, +3,3,3,3,3,2,3,1,2,3,3,2,2,3,0,1,1,2,0,3,3,2,2,3,0,1,1,3,0,0,0,0, +3,1,0,3,3,0,2,0,2,1,0,0,3,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,2,3,2,3,3,0,1,3,1,1,2,1,2,1,1,3,1,1,0,2,3,1,1,1,1,1,1,1,1, +3,1,1,2,2,2,2,1,1,1,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,2,2,1,1,2,1,3,3,2,3,2,2,3,2,2,3,1,2,2,1,2,0,3,2,1,2,2,2,2,2,1, +3,2,1,2,2,2,1,1,1,1,0,0,1,1,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,1,3,3,0,2,1,0,3,2,0,0,3,1,0,1,1,0,1,0,0,0,0,0,1, +1,0,0,1,0,3,2,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,2,2,2,3,0,0,1,3,0,3,2,0,3,2,2,3,3,3,3,3,1,0,2,2,2,0,2,2,1,2, +0,2,3,0,0,0,0,1,0,1,0,0,1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +3,0,2,3,1,3,3,2,3,3,0,3,3,0,3,2,2,3,2,3,3,3,0,0,2,2,3,0,1,1,1,3, +0,0,3,0,0,0,2,2,0,1,3,0,1,2,2,2,3,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1, +3,2,3,3,2,0,3,3,2,2,3,1,3,2,1,3,2,0,1,2,2,0,2,3,2,1,0,3,0,0,0,0, +3,0,0,2,3,1,3,0,0,3,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,1,3,2,2,2,1,2,0,1,3,1,1,3,1,3,0,0,2,1,1,1,1,2,1,1,1,0,2,1,0,1, +1,2,0,0,0,3,1,1,0,0,0,0,1,0,1,0,0,1,0,1,0,0,0,0,0,3,1,0,0,0,1,0, +3,3,3,3,2,2,2,2,2,1,3,1,1,1,2,0,1,1,2,1,2,1,3,2,0,0,3,1,1,1,1,1, +3,1,0,2,3,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,2,3,0,3,3,0,2,0,0,0,0,0,0,0,3,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,2,3,1,3,0,0,1,2,0,0,2,0,3,3,2,3,3,3,2,3,0,0,2,2,2,0,0,0,2,2, +0,0,1,0,0,0,0,3,0,0,0,0,2,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +0,0,0,3,0,2,0,0,0,0,0,0,0,0,0,0,1,2,3,1,3,3,0,0,1,0,3,0,0,0,0,0, +0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,1,2,3,1,2,3,1,0,3,0,2,2,1,0,2,1,1,2,0,1,0,0,1,1,1,1,0,1,0,0, +1,0,0,0,0,1,1,0,3,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,2,1,0,1,1,1,3,1,2,2,2,2,2,2,1,1,1,1,0,3,1,0,1,3,1,1,1,1, +1,1,0,2,0,1,3,1,1,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1, +3,0,2,2,1,3,3,2,3,3,0,1,1,0,2,2,1,2,1,3,3,1,0,0,3,2,0,0,0,0,2,1, +0,1,0,0,0,0,1,2,0,1,1,3,1,1,2,2,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0, +0,0,3,0,0,1,0,0,0,3,0,0,3,0,3,1,0,1,1,1,3,2,0,0,0,3,0,0,0,0,2,0, +0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0, +3,3,1,3,2,1,3,3,1,2,2,0,1,2,1,0,1,2,0,0,0,0,0,3,0,0,0,3,0,0,0,0, +3,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,1,2,0,3,3,3,2,2,0,1,1,0,1,3,0,0,0,2,2,0,0,0,0,3,1,0,1,0,0,0, +0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,2,3,1,2,0,0,2,1,0,3,1,0,1,2,0,1,1,1,1,3,0,0,3,1,1,0,2,2,1,1, +0,2,0,0,0,0,0,1,0,1,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,3,1,2,0,0,2,2,0,1,2,0,1,0,1,3,1,2,1,0,0,0,2,0,3,0,0,0,1,0, +0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,1,1,2,2,0,0,0,2,0,2,1,0,1,1,0,1,1,1,2,1,0,0,1,1,1,0,2,1,1,1, +0,1,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,0,1, +0,0,0,2,0,1,3,1,1,1,1,0,0,0,0,3,2,0,1,0,0,0,1,2,0,0,0,1,0,0,0,0, +0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,0,2,3,2,2,0,0,0,1,0,0,0,0,2,3,2,1,2,2,3,0,0,0,2,3,1,0,0,0,1,1, +0,0,1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0, +3,3,2,2,0,1,0,0,0,0,2,0,2,0,1,0,0,0,1,1,0,0,0,2,1,0,1,0,1,1,0,0, +0,1,0,2,0,0,1,0,3,0,1,0,0,0,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,1,0,0,1,0,0,0,0,0,1,1,2,0,0,0,0,1,0,0,1,3,1,0,0,0,0,1,1,0,0, +0,1,0,0,0,0,3,0,0,0,0,0,0,3,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0, +3,3,1,1,1,1,2,3,0,0,2,1,1,1,1,1,0,2,1,1,0,0,0,2,1,0,1,2,1,1,0,1, +2,1,0,3,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,3,1,0,0,0,0,0,0,0,3,0,0,0,3,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1, +0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,2,0,0,0,0,0,0,1,2,1,0,1,1,0,2,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,2,0,0,0,1,3,0,1,0,0,0,2,0,0,0,0,0,0,0,1,2,0,0,0,0,0, +3,3,0,0,1,1,2,0,0,1,2,1,0,1,1,1,0,1,1,0,0,2,1,1,0,1,0,0,1,1,1,0, +0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,1,0,0,0,0,1,0,0,0,0,3,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,3,0,0,1,1,0,0,0,2,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1,1,0,1,2,0,1,2,0,0,1,1,0,2,0,1,0,0,1,0,0,0,0,1,0,0,0,2,0,0,0,0, +1,0,0,1,0,1,1,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,1,0,0,0,0,0,0,0,1,1,0,1,1,0,2,1,3,0,0,0,0,1,1,0,0,0,0,0,0,0,3, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,1,0,1,0,0,2,0,0,2,0,0,1,1,2,0,0,1,1,0,0,0,1,0,0,0,1,1,0,0,0, +1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0, +1,0,0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1,1,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,2,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,3,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,1,0,0,0,0, +1,0,0,0,0,0,0,0,0,1,0,0,0,0,2,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,1,0,0,2,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +) + +TIS620ThaiModel = { + 'char_to_order_map': TIS620CharToOrderMap, + 'precedence_matrix': ThaiLangModel, + 'typical_positive_ratio': 0.926386, + 'keep_english_letter': False, + 'charset_name': "TIS-620", + 'language': 'Thai', +} diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langturkishmodel.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langturkishmodel.py new file mode 100644 index 0000000..a427a45 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/langturkishmodel.py @@ -0,0 +1,193 @@ +# -*- coding: utf-8 -*- +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Özgür Baskın - Turkish Language Model +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# 255: Control characters that usually does not exist in any text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 + +# Character Mapping Table: +Latin5_TurkishCharToOrderMap = ( +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, +255, 23, 37, 47, 39, 29, 52, 36, 45, 53, 60, 16, 49, 20, 46, 42, + 48, 69, 44, 35, 31, 51, 38, 62, 65, 43, 56,255,255,255,255,255, +255, 1, 21, 28, 12, 2, 18, 27, 25, 3, 24, 10, 5, 13, 4, 15, + 26, 64, 7, 8, 9, 14, 32, 57, 58, 11, 22,255,255,255,255,255, +180,179,178,177,176,175,174,173,172,171,170,169,168,167,166,165, +164,163,162,161,160,159,101,158,157,156,155,154,153,152,151,106, +150,149,148,147,146,145,144,100,143,142,141,140,139,138,137,136, + 94, 80, 93,135,105,134,133, 63,132,131,130,129,128,127,126,125, +124,104, 73, 99, 79, 85,123, 54,122, 98, 92,121,120, 91,103,119, + 68,118,117, 97,116,115, 50, 90,114,113,112,111, 55, 41, 40, 86, + 89, 70, 59, 78, 71, 82, 88, 33, 77, 66, 84, 83,110, 75, 61, 96, + 30, 67,109, 74, 87,102, 34, 95, 81,108, 76, 72, 17, 6, 19,107, +) + +TurkishLangModel = ( +3,2,3,3,3,1,3,3,3,3,3,3,3,3,2,1,1,3,3,1,3,3,0,3,3,3,3,3,0,3,1,3, +3,2,1,0,0,1,1,0,0,0,1,0,0,1,1,1,1,0,0,0,0,0,0,0,2,2,0,0,1,0,0,1, +3,2,2,3,3,0,3,3,3,3,3,3,3,2,3,1,0,3,3,1,3,3,0,3,3,3,3,3,0,3,0,3, +3,1,1,0,1,0,1,0,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,2,2,0,0,0,1,0,1, +3,3,2,3,3,0,3,3,3,3,3,3,3,2,3,1,1,3,3,0,3,3,1,2,3,3,3,3,0,3,0,3, +3,1,1,0,0,0,1,0,0,0,0,1,1,0,1,2,1,0,0,0,1,0,0,0,0,2,0,0,0,0,0,1, +3,3,3,3,3,3,2,3,3,3,3,3,3,3,3,1,3,3,2,0,3,2,1,2,2,1,3,3,0,0,0,2, +2,2,0,1,0,0,1,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,1,0,0,1, +3,3,3,2,3,3,1,2,3,3,3,3,3,3,3,1,3,2,1,0,3,2,0,1,2,3,3,2,1,0,0,2, +2,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,2,0,2,0,0,0, +1,0,1,3,3,1,3,3,3,3,3,3,3,1,2,0,0,2,3,0,2,3,0,0,2,2,2,3,0,3,0,1, +2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,3,0,3,2,0,2,3,2,3,3,1,0,0,2, +3,2,0,0,1,0,0,0,0,0,0,2,0,0,1,0,0,0,0,0,0,0,0,0,1,1,1,0,2,0,0,1, +3,3,3,2,3,3,2,3,3,3,3,2,3,3,3,0,3,3,0,0,2,1,0,0,2,3,2,2,0,0,0,2, +2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1,0,1,0,2,0,0,1, +3,3,3,2,3,3,3,3,3,3,3,2,3,3,3,0,3,2,0,1,3,2,1,1,3,2,3,2,1,0,0,2, +2,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0, +3,3,3,2,3,3,3,3,3,3,3,2,3,3,3,0,3,2,2,0,2,3,0,0,2,2,2,2,0,0,0,2, +3,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,0,1,0,0,0, +3,3,3,3,3,3,3,2,2,2,2,3,2,3,3,0,3,3,1,1,2,2,0,0,2,2,3,2,0,0,1,3, +0,3,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,1, +3,3,3,2,3,3,3,2,1,2,2,3,2,3,3,0,3,2,0,0,1,1,0,1,1,2,1,2,0,0,0,1, +0,3,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,1,0,0,0, +3,3,3,2,3,3,2,3,2,2,2,3,3,3,3,1,3,1,1,0,3,2,1,1,3,3,2,3,1,0,0,1, +1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,2,0,0,1, +3,2,2,3,3,0,3,3,3,3,3,3,3,2,2,1,0,3,3,1,3,3,0,1,3,3,2,3,0,3,0,3, +2,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0, +2,2,2,3,3,0,3,3,3,3,3,3,3,3,3,0,0,3,2,0,3,3,0,3,2,3,3,3,0,3,1,3, +2,0,0,0,0,0,0,0,0,0,0,1,0,1,2,0,1,0,0,0,0,0,0,0,2,2,0,0,1,0,0,1, +3,3,3,1,2,3,3,1,0,0,1,0,0,3,3,2,3,0,0,2,0,0,2,0,2,0,0,0,2,0,2,0, +0,3,1,0,1,0,0,0,2,2,1,0,1,1,2,1,2,2,2,0,2,1,1,0,0,0,2,0,0,0,0,0, +1,2,1,3,3,0,3,3,3,3,3,2,3,0,0,0,0,2,3,0,2,3,1,0,2,3,1,3,0,3,0,2, +3,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,1,3,3,2,2,3,2,2,0,1,2,3,0,1,2,1,0,1,0,0,0,1,0,2,2,0,0,0,1, +1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,1,0,0,0, +3,3,3,1,3,3,1,1,3,3,1,1,3,3,1,0,2,1,2,0,2,1,0,0,1,1,2,1,0,0,0,2, +2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,1,0,2,1,3,0,0,2,0,0,3,3,0,3,0,0,1,0,1,2,0,0,1,1,2,2,0,1,0, +0,1,2,1,1,0,1,0,1,1,1,1,1,0,1,1,1,2,2,1,2,0,1,0,0,0,0,0,0,1,0,0, +3,3,3,2,3,2,3,3,0,2,2,2,3,3,3,0,3,0,0,0,2,2,0,1,2,1,1,1,0,0,0,1, +0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0, +3,3,3,3,3,3,2,1,2,2,3,3,3,3,2,0,2,0,0,0,2,2,0,0,2,1,3,3,0,0,1,1, +1,1,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0, +1,1,2,3,3,0,3,3,3,3,3,3,2,2,0,2,0,2,3,2,3,2,2,2,2,2,2,2,1,3,2,3, +2,0,2,1,2,2,2,2,1,1,2,2,1,2,2,1,2,0,0,2,1,1,0,2,1,0,0,1,0,0,0,1, +2,3,3,1,1,1,0,1,1,1,2,3,2,1,1,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0, +0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,2,2,2,3,2,3,2,2,1,3,3,3,0,2,1,2,0,2,1,0,0,1,1,1,1,1,0,0,1, +2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,2,0,1,0,0,0, +3,3,3,2,3,3,3,3,3,2,3,1,2,3,3,1,2,0,0,0,0,0,0,0,3,2,1,1,0,0,0,0, +2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0, +3,3,3,2,2,3,3,2,1,1,1,1,1,3,3,0,3,1,0,0,1,1,0,0,3,1,2,1,0,0,0,0, +0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0, +3,3,3,2,2,3,2,2,2,3,2,1,1,3,3,0,3,0,0,0,0,1,0,0,3,1,1,2,0,0,0,1, +1,0,0,1,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1, +1,1,1,3,3,0,3,3,3,3,3,2,2,2,1,2,0,2,1,2,2,1,1,0,1,2,2,2,2,2,2,2, +0,0,2,1,2,1,2,1,0,1,1,3,1,2,1,1,2,0,0,2,0,1,0,1,0,1,0,0,0,1,0,1, +3,3,3,1,3,3,3,0,1,1,0,2,2,3,1,0,3,0,0,0,1,0,0,0,1,0,0,1,0,1,0,0, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,2,0,0,2,2,1,0,0,1,0,0,3,3,1,3,0,0,1,1,0,2,0,3,0,0,0,2,0,1,1, +0,1,2,0,1,2,2,0,2,2,2,2,1,0,2,1,1,0,2,0,2,1,2,0,0,0,0,0,0,0,0,0, +3,3,3,1,3,2,3,2,0,2,2,2,1,3,2,0,2,1,2,0,1,2,0,0,1,0,2,2,0,0,0,2, +1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,0,0,0, +3,3,3,0,3,3,1,1,2,3,1,0,3,2,3,0,3,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0, +1,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,3,3,0,3,3,2,3,3,2,2,0,0,0,0,1,2,0,1,3,0,0,0,3,1,1,0,3,0,2, +2,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,1,2,2,1,0,3,1,1,1,1,3,3,2,3,0,0,1,0,1,2,0,2,2,0,2,2,0,2,1, +0,2,2,1,1,1,1,0,2,1,1,0,1,1,1,1,2,1,2,1,2,0,1,0,1,0,0,0,0,0,0,0, +3,3,3,0,1,1,3,0,0,1,1,0,0,2,2,0,3,0,0,1,1,0,1,0,0,0,0,0,2,0,0,0, +0,3,1,0,1,0,1,0,2,0,0,1,0,1,0,1,1,1,2,1,1,0,2,0,0,0,0,0,0,0,0,0, +3,3,3,0,2,0,2,0,1,1,1,0,0,3,3,0,2,0,0,1,0,0,2,1,1,0,1,0,1,0,1,0, +0,2,0,1,2,0,2,0,2,1,1,0,1,0,2,1,1,0,2,1,1,0,1,0,0,0,1,1,0,0,0,0, +3,2,3,0,1,0,0,0,0,0,0,0,0,1,2,0,1,0,0,1,0,0,1,0,0,0,0,0,2,0,0,0, +0,0,1,1,0,0,1,0,1,0,0,1,0,0,0,2,1,0,1,0,2,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,0,0,2,3,0,0,1,0,1,0,2,3,2,3,0,0,1,3,0,2,1,0,0,0,0,2,0,1,0, +0,2,1,0,0,1,1,0,2,1,0,0,1,0,0,1,1,0,1,1,2,0,1,0,0,0,0,1,0,0,0,0, +3,2,2,0,0,1,1,0,0,0,0,0,0,3,1,1,1,0,0,0,0,0,1,0,0,0,0,0,2,0,1,0, +0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,3,3,0,2,3,2,2,1,2,2,1,1,2,0,1,3,2,2,2,0,0,2,2,0,0,0,1,2,1, +3,0,2,1,1,0,1,1,1,0,1,2,2,2,1,1,2,0,0,0,0,1,0,1,1,0,0,0,0,0,0,0, +0,1,1,2,3,0,3,3,3,2,2,2,2,1,0,1,0,1,0,1,2,2,0,0,2,2,1,3,1,1,2,1, +0,0,1,1,2,0,1,1,0,0,1,2,0,2,1,1,2,0,0,1,0,0,0,1,0,1,0,1,0,0,0,0, +3,3,2,0,0,3,1,0,0,0,0,0,0,3,2,1,2,0,0,1,0,0,2,0,0,0,0,0,2,0,1,0, +0,2,1,1,0,0,1,0,1,2,0,0,1,1,0,0,2,1,1,1,1,0,2,0,0,0,0,0,0,0,0,0, +3,3,2,0,0,1,0,0,0,0,1,0,0,3,3,2,2,0,0,1,0,0,2,0,1,0,0,0,2,0,1,0, +0,0,1,1,0,0,2,0,2,1,0,0,1,1,2,1,2,0,2,1,2,1,1,1,0,0,1,1,0,0,0,0, +3,3,2,0,0,2,2,0,0,0,1,1,0,2,2,1,3,1,0,1,0,1,2,0,0,0,0,0,1,0,1,0, +0,1,1,0,0,0,0,0,1,0,0,1,0,0,0,1,1,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,2,0,0,0,1,0,0,1,0,0,2,3,1,2,0,0,1,0,0,2,0,0,0,1,0,2,0,2,0, +0,1,1,2,2,1,2,0,2,1,1,0,0,1,1,0,1,1,1,1,2,1,1,0,0,0,0,0,0,0,0,0, +3,3,3,0,2,1,2,1,0,0,1,1,0,3,3,1,2,0,0,1,0,0,2,0,2,0,1,1,2,0,0,0, +0,0,1,1,1,1,2,0,1,1,0,1,1,1,1,0,0,0,1,1,1,0,1,0,0,0,1,0,0,0,0,0, +3,3,3,0,2,2,3,2,0,0,1,0,0,2,3,1,0,0,0,0,0,0,2,0,2,0,0,0,2,0,0,0, +0,1,1,0,0,0,1,0,0,1,0,1,1,0,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0, +3,2,3,0,0,0,0,0,0,0,1,0,0,2,2,2,2,0,0,1,0,0,2,0,0,0,0,0,2,0,1,0, +0,0,2,1,1,0,1,0,2,1,1,0,0,1,1,2,1,0,2,0,2,0,1,0,0,0,2,0,0,0,0,0, +0,0,0,2,2,0,2,1,1,1,1,2,2,0,0,1,0,1,0,0,1,3,0,0,0,0,1,0,0,2,1,0, +0,0,1,0,1,0,0,0,0,0,2,1,0,1,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0, +2,0,0,2,3,0,2,3,1,2,2,0,2,0,0,2,0,2,1,1,1,2,1,0,0,1,2,1,1,2,1,0, +1,0,2,0,1,0,1,1,0,0,2,2,1,2,1,1,2,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0, +3,3,3,0,2,1,2,0,0,0,1,0,0,3,2,0,1,0,0,1,0,0,2,0,0,0,1,2,1,0,1,0, +0,0,0,0,1,0,1,0,0,1,0,0,0,0,1,0,1,0,1,1,1,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,2,2,0,2,2,1,1,0,1,1,1,1,1,0,0,1,2,1,1,1,0,1,0,0,0,1,1,1,1, +0,0,2,1,0,1,1,1,0,1,1,2,1,2,1,1,2,0,1,1,2,1,0,2,0,0,0,0,0,0,0,0, +3,2,2,0,0,2,0,0,0,0,0,0,0,2,2,0,2,0,0,1,0,0,2,0,0,0,0,0,2,0,0,0, +0,2,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,3,2,0,2,2,0,1,1,0,1,0,0,1,0,0,0,1,0,1,0,0,0,0,0,1,0,0,0,0, +2,0,1,0,1,0,1,1,0,0,1,2,0,1,0,1,1,0,0,1,0,1,0,2,0,0,0,0,0,0,0,0, +2,2,2,0,1,1,0,0,0,1,0,0,0,1,2,0,1,0,0,1,0,0,1,0,0,0,0,1,2,0,1,0, +0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,1,0,1,0,2,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,2,1,0,1,1,1,0,0,0,0,1,2,0,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0, +1,1,2,0,1,0,0,0,1,0,1,0,0,0,1,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,2,0,0,0,0,0,1, +0,0,1,2,2,0,2,1,2,1,1,2,2,0,0,0,0,1,0,0,1,1,0,0,2,0,0,0,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0, +2,2,2,0,0,0,1,0,0,0,0,0,0,2,2,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0, +0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,1,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +2,2,2,0,1,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1,0,0,0,0,0,0,0,0,0,0,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +) + +Latin5TurkishModel = { + 'char_to_order_map': Latin5_TurkishCharToOrderMap, + 'precedence_matrix': TurkishLangModel, + 'typical_positive_ratio': 0.970290, + 'keep_english_letter': True, + 'charset_name': "ISO-8859-9", + 'language': 'Turkish', +} diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/latin1prober.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/latin1prober.py new file mode 100644 index 0000000..7d1e8c2 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/latin1prober.py @@ -0,0 +1,145 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetprober import CharSetProber +from .enums import ProbingState + +FREQ_CAT_NUM = 4 + +UDF = 0 # undefined +OTH = 1 # other +ASC = 2 # ascii capital letter +ASS = 3 # ascii small letter +ACV = 4 # accent capital vowel +ACO = 5 # accent capital other +ASV = 6 # accent small vowel +ASO = 7 # accent small other +CLASS_NUM = 8 # total classes + +Latin1_CharToClass = ( + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 00 - 07 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 08 - 0F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 10 - 17 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 18 - 1F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 20 - 27 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 28 - 2F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 30 - 37 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 38 - 3F + OTH, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 40 - 47 + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 48 - 4F + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 50 - 57 + ASC, ASC, ASC, OTH, OTH, OTH, OTH, OTH, # 58 - 5F + OTH, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 60 - 67 + ASS, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 68 - 6F + ASS, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 70 - 77 + ASS, ASS, ASS, OTH, OTH, OTH, OTH, OTH, # 78 - 7F + OTH, UDF, OTH, ASO, OTH, OTH, OTH, OTH, # 80 - 87 + OTH, OTH, ACO, OTH, ACO, UDF, ACO, UDF, # 88 - 8F + UDF, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 90 - 97 + OTH, OTH, ASO, OTH, ASO, UDF, ASO, ACO, # 98 - 9F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # A0 - A7 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # A8 - AF + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # B0 - B7 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # B8 - BF + ACV, ACV, ACV, ACV, ACV, ACV, ACO, ACO, # C0 - C7 + ACV, ACV, ACV, ACV, ACV, ACV, ACV, ACV, # C8 - CF + ACO, ACO, ACV, ACV, ACV, ACV, ACV, OTH, # D0 - D7 + ACV, ACV, ACV, ACV, ACV, ACO, ACO, ACO, # D8 - DF + ASV, ASV, ASV, ASV, ASV, ASV, ASO, ASO, # E0 - E7 + ASV, ASV, ASV, ASV, ASV, ASV, ASV, ASV, # E8 - EF + ASO, ASO, ASV, ASV, ASV, ASV, ASV, OTH, # F0 - F7 + ASV, ASV, ASV, ASV, ASV, ASO, ASO, ASO, # F8 - FF +) + +# 0 : illegal +# 1 : very unlikely +# 2 : normal +# 3 : very likely +Latin1ClassModel = ( +# UDF OTH ASC ASS ACV ACO ASV ASO + 0, 0, 0, 0, 0, 0, 0, 0, # UDF + 0, 3, 3, 3, 3, 3, 3, 3, # OTH + 0, 3, 3, 3, 3, 3, 3, 3, # ASC + 0, 3, 3, 3, 1, 1, 3, 3, # ASS + 0, 3, 3, 3, 1, 2, 1, 2, # ACV + 0, 3, 3, 3, 3, 3, 3, 3, # ACO + 0, 3, 1, 3, 1, 1, 1, 3, # ASV + 0, 3, 1, 3, 1, 1, 3, 3, # ASO +) + + +class Latin1Prober(CharSetProber): + def __init__(self): + super(Latin1Prober, self).__init__() + self._last_char_class = None + self._freq_counter = None + self.reset() + + def reset(self): + self._last_char_class = OTH + self._freq_counter = [0] * FREQ_CAT_NUM + CharSetProber.reset(self) + + @property + def charset_name(self): + return "ISO-8859-1" + + @property + def language(self): + return "" + + def feed(self, byte_str): + byte_str = self.filter_with_english_letters(byte_str) + for c in byte_str: + char_class = Latin1_CharToClass[c] + freq = Latin1ClassModel[(self._last_char_class * CLASS_NUM) + + char_class] + if freq == 0: + self._state = ProbingState.NOT_ME + break + self._freq_counter[freq] += 1 + self._last_char_class = char_class + + return self.state + + def get_confidence(self): + if self.state == ProbingState.NOT_ME: + return 0.01 + + total = sum(self._freq_counter) + if total < 0.01: + confidence = 0.0 + else: + confidence = ((self._freq_counter[3] - self._freq_counter[1] * 20.0) + / total) + if confidence < 0.0: + confidence = 0.0 + # lower the confidence of latin1 so that other more accurate + # detector can take priority. + confidence = confidence * 0.73 + return confidence diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/mbcharsetprober.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/mbcharsetprober.py new file mode 100644 index 0000000..6256ecf --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/mbcharsetprober.py @@ -0,0 +1,91 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# Proofpoint, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetprober import CharSetProber +from .enums import ProbingState, MachineState + + +class MultiByteCharSetProber(CharSetProber): + """ + MultiByteCharSetProber + """ + + def __init__(self, lang_filter=None): + super(MultiByteCharSetProber, self).__init__(lang_filter=lang_filter) + self.distribution_analyzer = None + self.coding_sm = None + self._last_char = [0, 0] + + def reset(self): + super(MultiByteCharSetProber, self).reset() + if self.coding_sm: + self.coding_sm.reset() + if self.distribution_analyzer: + self.distribution_analyzer.reset() + self._last_char = [0, 0] + + @property + def charset_name(self): + raise NotImplementedError + + @property + def language(self): + raise NotImplementedError + + def feed(self, byte_str): + for i in range(len(byte_str)): + coding_state = self.coding_sm.next_state(byte_str[i]) + if coding_state == MachineState.ERROR: + self.logger.debug('%s %s prober hit error at byte %s', + self.charset_name, self.language, i) + self._state = ProbingState.NOT_ME + break + elif coding_state == MachineState.ITS_ME: + self._state = ProbingState.FOUND_IT + break + elif coding_state == MachineState.START: + char_len = self.coding_sm.get_current_charlen() + if i == 0: + self._last_char[1] = byte_str[0] + self.distribution_analyzer.feed(self._last_char, char_len) + else: + self.distribution_analyzer.feed(byte_str[i - 1:i + 1], + char_len) + + self._last_char[0] = byte_str[-1] + + if self.state == ProbingState.DETECTING: + if (self.distribution_analyzer.got_enough_data() and + (self.get_confidence() > self.SHORTCUT_THRESHOLD)): + self._state = ProbingState.FOUND_IT + + return self.state + + def get_confidence(self): + return self.distribution_analyzer.get_confidence() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/mbcsgroupprober.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/mbcsgroupprober.py new file mode 100644 index 0000000..530abe7 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/mbcsgroupprober.py @@ -0,0 +1,54 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# Proofpoint, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetgroupprober import CharSetGroupProber +from .utf8prober import UTF8Prober +from .sjisprober import SJISProber +from .eucjpprober import EUCJPProber +from .gb2312prober import GB2312Prober +from .euckrprober import EUCKRProber +from .cp949prober import CP949Prober +from .big5prober import Big5Prober +from .euctwprober import EUCTWProber + + +class MBCSGroupProber(CharSetGroupProber): + def __init__(self, lang_filter=None): + super(MBCSGroupProber, self).__init__(lang_filter=lang_filter) + self.probers = [ + UTF8Prober(), + SJISProber(), + EUCJPProber(), + GB2312Prober(), + EUCKRProber(), + CP949Prober(), + Big5Prober(), + EUCTWProber() + ] + self.reset() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/mbcssm.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/mbcssm.py new file mode 100644 index 0000000..8360d0f --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/mbcssm.py @@ -0,0 +1,572 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .enums import MachineState + +# BIG5 + +BIG5_CLS = ( + 1,1,1,1,1,1,1,1, # 00 - 07 #allow 0x00 as legal value + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,1, # 78 - 7f + 4,4,4,4,4,4,4,4, # 80 - 87 + 4,4,4,4,4,4,4,4, # 88 - 8f + 4,4,4,4,4,4,4,4, # 90 - 97 + 4,4,4,4,4,4,4,4, # 98 - 9f + 4,3,3,3,3,3,3,3, # a0 - a7 + 3,3,3,3,3,3,3,3, # a8 - af + 3,3,3,3,3,3,3,3, # b0 - b7 + 3,3,3,3,3,3,3,3, # b8 - bf + 3,3,3,3,3,3,3,3, # c0 - c7 + 3,3,3,3,3,3,3,3, # c8 - cf + 3,3,3,3,3,3,3,3, # d0 - d7 + 3,3,3,3,3,3,3,3, # d8 - df + 3,3,3,3,3,3,3,3, # e0 - e7 + 3,3,3,3,3,3,3,3, # e8 - ef + 3,3,3,3,3,3,3,3, # f0 - f7 + 3,3,3,3,3,3,3,0 # f8 - ff +) + +BIG5_ST = ( + MachineState.ERROR,MachineState.START,MachineState.START, 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,#08-0f + MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START#10-17 +) + +BIG5_CHAR_LEN_TABLE = (0, 1, 1, 2, 0) + +BIG5_SM_MODEL = {'class_table': BIG5_CLS, + 'class_factor': 5, + 'state_table': BIG5_ST, + 'char_len_table': BIG5_CHAR_LEN_TABLE, + 'name': 'Big5'} + +# CP949 + +CP949_CLS = ( + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,0,0, # 00 - 0f + 1,1,1,1,1,1,1,1, 1,1,1,0,1,1,1,1, # 10 - 1f + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, # 20 - 2f + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, # 30 - 3f + 1,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4, # 40 - 4f + 4,4,5,5,5,5,5,5, 5,5,5,1,1,1,1,1, # 50 - 5f + 1,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5, # 60 - 6f + 5,5,5,5,5,5,5,5, 5,5,5,1,1,1,1,1, # 70 - 7f + 0,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6, # 80 - 8f + 6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6, # 90 - 9f + 6,7,7,7,7,7,7,7, 7,7,7,7,7,8,8,8, # a0 - af + 7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7, # b0 - bf + 7,7,7,7,7,7,9,2, 2,3,2,2,2,2,2,2, # c0 - cf + 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, # d0 - df + 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, # e0 - ef + 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,0, # f0 - ff +) + +CP949_ST = ( +#cls= 0 1 2 3 4 5 6 7 8 9 # previous state = + MachineState.ERROR,MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START, 4, 5,MachineState.ERROR, 6, # MachineState.START + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, # MachineState.ERROR + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME, # MachineState.ITS_ME + MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START, # 3 + MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START, # 4 + MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START, # 5 + MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START, # 6 +) + +CP949_CHAR_LEN_TABLE = (0, 1, 2, 0, 1, 1, 2, 2, 0, 2) + +CP949_SM_MODEL = {'class_table': CP949_CLS, + 'class_factor': 10, + 'state_table': CP949_ST, + 'char_len_table': CP949_CHAR_LEN_TABLE, + 'name': 'CP949'} + +# EUC-JP + +EUCJP_CLS = ( + 4,4,4,4,4,4,4,4, # 00 - 07 + 4,4,4,4,4,4,5,5, # 08 - 0f + 4,4,4,4,4,4,4,4, # 10 - 17 + 4,4,4,5,4,4,4,4, # 18 - 1f + 4,4,4,4,4,4,4,4, # 20 - 27 + 4,4,4,4,4,4,4,4, # 28 - 2f + 4,4,4,4,4,4,4,4, # 30 - 37 + 4,4,4,4,4,4,4,4, # 38 - 3f + 4,4,4,4,4,4,4,4, # 40 - 47 + 4,4,4,4,4,4,4,4, # 48 - 4f + 4,4,4,4,4,4,4,4, # 50 - 57 + 4,4,4,4,4,4,4,4, # 58 - 5f + 4,4,4,4,4,4,4,4, # 60 - 67 + 4,4,4,4,4,4,4,4, # 68 - 6f + 4,4,4,4,4,4,4,4, # 70 - 77 + 4,4,4,4,4,4,4,4, # 78 - 7f + 5,5,5,5,5,5,5,5, # 80 - 87 + 5,5,5,5,5,5,1,3, # 88 - 8f + 5,5,5,5,5,5,5,5, # 90 - 97 + 5,5,5,5,5,5,5,5, # 98 - 9f + 5,2,2,2,2,2,2,2, # a0 - a7 + 2,2,2,2,2,2,2,2, # a8 - af + 2,2,2,2,2,2,2,2, # b0 - b7 + 2,2,2,2,2,2,2,2, # b8 - bf + 2,2,2,2,2,2,2,2, # c0 - c7 + 2,2,2,2,2,2,2,2, # c8 - cf + 2,2,2,2,2,2,2,2, # d0 - d7 + 2,2,2,2,2,2,2,2, # d8 - df + 0,0,0,0,0,0,0,0, # e0 - e7 + 0,0,0,0,0,0,0,0, # e8 - ef + 0,0,0,0,0,0,0,0, # f0 - f7 + 0,0,0,0,0,0,0,5 # f8 - ff +) + +EUCJP_ST = ( + 3, 4, 3, 5,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.START,MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#10-17 + MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 3,MachineState.ERROR,#18-1f + 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START#20-27 +) + +EUCJP_CHAR_LEN_TABLE = (2, 2, 2, 3, 1, 0) + +EUCJP_SM_MODEL = {'class_table': EUCJP_CLS, + 'class_factor': 6, + 'state_table': EUCJP_ST, + 'char_len_table': EUCJP_CHAR_LEN_TABLE, + 'name': 'EUC-JP'} + +# EUC-KR + +EUCKR_CLS = ( + 1,1,1,1,1,1,1,1, # 00 - 07 + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 1,1,1,1,1,1,1,1, # 40 - 47 + 1,1,1,1,1,1,1,1, # 48 - 4f + 1,1,1,1,1,1,1,1, # 50 - 57 + 1,1,1,1,1,1,1,1, # 58 - 5f + 1,1,1,1,1,1,1,1, # 60 - 67 + 1,1,1,1,1,1,1,1, # 68 - 6f + 1,1,1,1,1,1,1,1, # 70 - 77 + 1,1,1,1,1,1,1,1, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,0,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,2,2,2,2,2,2,2, # a0 - a7 + 2,2,2,2,2,3,3,3, # a8 - af + 2,2,2,2,2,2,2,2, # b0 - b7 + 2,2,2,2,2,2,2,2, # b8 - bf + 2,2,2,2,2,2,2,2, # c0 - c7 + 2,3,2,2,2,2,2,2, # c8 - cf + 2,2,2,2,2,2,2,2, # d0 - d7 + 2,2,2,2,2,2,2,2, # d8 - df + 2,2,2,2,2,2,2,2, # e0 - e7 + 2,2,2,2,2,2,2,2, # e8 - ef + 2,2,2,2,2,2,2,2, # f0 - f7 + 2,2,2,2,2,2,2,0 # f8 - ff +) + +EUCKR_ST = ( + MachineState.ERROR,MachineState.START, 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START #08-0f +) + +EUCKR_CHAR_LEN_TABLE = (0, 1, 2, 0) + +EUCKR_SM_MODEL = {'class_table': EUCKR_CLS, + 'class_factor': 4, + 'state_table': EUCKR_ST, + 'char_len_table': EUCKR_CHAR_LEN_TABLE, + 'name': 'EUC-KR'} + +# EUC-TW + +EUCTW_CLS = ( + 2,2,2,2,2,2,2,2, # 00 - 07 + 2,2,2,2,2,2,0,0, # 08 - 0f + 2,2,2,2,2,2,2,2, # 10 - 17 + 2,2,2,0,2,2,2,2, # 18 - 1f + 2,2,2,2,2,2,2,2, # 20 - 27 + 2,2,2,2,2,2,2,2, # 28 - 2f + 2,2,2,2,2,2,2,2, # 30 - 37 + 2,2,2,2,2,2,2,2, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,2, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,6,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,3,4,4,4,4,4,4, # a0 - a7 + 5,5,1,1,1,1,1,1, # a8 - af + 1,1,1,1,1,1,1,1, # b0 - b7 + 1,1,1,1,1,1,1,1, # b8 - bf + 1,1,3,1,3,3,3,3, # c0 - c7 + 3,3,3,3,3,3,3,3, # c8 - cf + 3,3,3,3,3,3,3,3, # d0 - d7 + 3,3,3,3,3,3,3,3, # d8 - df + 3,3,3,3,3,3,3,3, # e0 - e7 + 3,3,3,3,3,3,3,3, # e8 - ef + 3,3,3,3,3,3,3,3, # f0 - f7 + 3,3,3,3,3,3,3,0 # f8 - ff +) + +EUCTW_ST = ( + MachineState.ERROR,MachineState.ERROR,MachineState.START, 3, 3, 3, 4,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.START,MachineState.ERROR,#10-17 + MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#18-1f + 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.START,MachineState.START,#20-27 + MachineState.START,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START #28-2f +) + +EUCTW_CHAR_LEN_TABLE = (0, 0, 1, 2, 2, 2, 3) + +EUCTW_SM_MODEL = {'class_table': EUCTW_CLS, + 'class_factor': 7, + 'state_table': EUCTW_ST, + 'char_len_table': EUCTW_CHAR_LEN_TABLE, + 'name': 'x-euc-tw'} + +# GB2312 + +GB2312_CLS = ( + 1,1,1,1,1,1,1,1, # 00 - 07 + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 3,3,3,3,3,3,3,3, # 30 - 37 + 3,3,1,1,1,1,1,1, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,4, # 78 - 7f + 5,6,6,6,6,6,6,6, # 80 - 87 + 6,6,6,6,6,6,6,6, # 88 - 8f + 6,6,6,6,6,6,6,6, # 90 - 97 + 6,6,6,6,6,6,6,6, # 98 - 9f + 6,6,6,6,6,6,6,6, # a0 - a7 + 6,6,6,6,6,6,6,6, # a8 - af + 6,6,6,6,6,6,6,6, # b0 - b7 + 6,6,6,6,6,6,6,6, # b8 - bf + 6,6,6,6,6,6,6,6, # c0 - c7 + 6,6,6,6,6,6,6,6, # c8 - cf + 6,6,6,6,6,6,6,6, # d0 - d7 + 6,6,6,6,6,6,6,6, # d8 - df + 6,6,6,6,6,6,6,6, # e0 - e7 + 6,6,6,6,6,6,6,6, # e8 - ef + 6,6,6,6,6,6,6,6, # f0 - f7 + 6,6,6,6,6,6,6,0 # f8 - ff +) + +GB2312_ST = ( + MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START, 3,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,#10-17 + 4,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#18-1f + MachineState.ERROR,MachineState.ERROR, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,#20-27 + MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START #28-2f +) + +# To be accurate, the length of class 6 can be either 2 or 4. +# But it is not necessary to discriminate between the two since +# it is used for frequency analysis only, and we are validating +# each code range there as well. So it is safe to set it to be +# 2 here. +GB2312_CHAR_LEN_TABLE = (0, 1, 1, 1, 1, 1, 2) + +GB2312_SM_MODEL = {'class_table': GB2312_CLS, + 'class_factor': 7, + 'state_table': GB2312_ST, + 'char_len_table': GB2312_CHAR_LEN_TABLE, + 'name': 'GB2312'} + +# Shift_JIS + +SJIS_CLS = ( + 1,1,1,1,1,1,1,1, # 00 - 07 + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,1, # 78 - 7f + 3,3,3,3,3,2,2,3, # 80 - 87 + 3,3,3,3,3,3,3,3, # 88 - 8f + 3,3,3,3,3,3,3,3, # 90 - 97 + 3,3,3,3,3,3,3,3, # 98 - 9f + #0xa0 is illegal in sjis encoding, but some pages does + #contain such byte. We need to be more error forgiven. + 2,2,2,2,2,2,2,2, # a0 - a7 + 2,2,2,2,2,2,2,2, # a8 - af + 2,2,2,2,2,2,2,2, # b0 - b7 + 2,2,2,2,2,2,2,2, # b8 - bf + 2,2,2,2,2,2,2,2, # c0 - c7 + 2,2,2,2,2,2,2,2, # c8 - cf + 2,2,2,2,2,2,2,2, # d0 - d7 + 2,2,2,2,2,2,2,2, # d8 - df + 3,3,3,3,3,3,3,3, # e0 - e7 + 3,3,3,3,3,4,4,4, # e8 - ef + 3,3,3,3,3,3,3,3, # f0 - f7 + 3,3,3,3,3,0,0,0) # f8 - ff + + +SJIS_ST = ( + MachineState.ERROR,MachineState.START,MachineState.START, 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START #10-17 +) + +SJIS_CHAR_LEN_TABLE = (0, 1, 1, 2, 0, 0) + +SJIS_SM_MODEL = {'class_table': SJIS_CLS, + 'class_factor': 6, + 'state_table': SJIS_ST, + 'char_len_table': SJIS_CHAR_LEN_TABLE, + 'name': 'Shift_JIS'} + +# UCS2-BE + +UCS2BE_CLS = ( + 0,0,0,0,0,0,0,0, # 00 - 07 + 0,0,1,0,0,2,0,0, # 08 - 0f + 0,0,0,0,0,0,0,0, # 10 - 17 + 0,0,0,3,0,0,0,0, # 18 - 1f + 0,0,0,0,0,0,0,0, # 20 - 27 + 0,3,3,3,3,3,0,0, # 28 - 2f + 0,0,0,0,0,0,0,0, # 30 - 37 + 0,0,0,0,0,0,0,0, # 38 - 3f + 0,0,0,0,0,0,0,0, # 40 - 47 + 0,0,0,0,0,0,0,0, # 48 - 4f + 0,0,0,0,0,0,0,0, # 50 - 57 + 0,0,0,0,0,0,0,0, # 58 - 5f + 0,0,0,0,0,0,0,0, # 60 - 67 + 0,0,0,0,0,0,0,0, # 68 - 6f + 0,0,0,0,0,0,0,0, # 70 - 77 + 0,0,0,0,0,0,0,0, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,0,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,0,0,0,0,0,0,0, # a0 - a7 + 0,0,0,0,0,0,0,0, # a8 - af + 0,0,0,0,0,0,0,0, # b0 - b7 + 0,0,0,0,0,0,0,0, # b8 - bf + 0,0,0,0,0,0,0,0, # c0 - c7 + 0,0,0,0,0,0,0,0, # c8 - cf + 0,0,0,0,0,0,0,0, # d0 - d7 + 0,0,0,0,0,0,0,0, # d8 - df + 0,0,0,0,0,0,0,0, # e0 - e7 + 0,0,0,0,0,0,0,0, # e8 - ef + 0,0,0,0,0,0,0,0, # f0 - f7 + 0,0,0,0,0,0,4,5 # f8 - ff +) + +UCS2BE_ST = ( + 5, 7, 7,MachineState.ERROR, 4, 3,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME, 6, 6, 6, 6,MachineState.ERROR,MachineState.ERROR,#10-17 + 6, 6, 6, 6, 6,MachineState.ITS_ME, 6, 6,#18-1f + 6, 6, 6, 6, 5, 7, 7,MachineState.ERROR,#20-27 + 5, 8, 6, 6,MachineState.ERROR, 6, 6, 6,#28-2f + 6, 6, 6, 6,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START #30-37 +) + +UCS2BE_CHAR_LEN_TABLE = (2, 2, 2, 0, 2, 2) + +UCS2BE_SM_MODEL = {'class_table': UCS2BE_CLS, + 'class_factor': 6, + 'state_table': UCS2BE_ST, + 'char_len_table': UCS2BE_CHAR_LEN_TABLE, + 'name': 'UTF-16BE'} + +# UCS2-LE + +UCS2LE_CLS = ( + 0,0,0,0,0,0,0,0, # 00 - 07 + 0,0,1,0,0,2,0,0, # 08 - 0f + 0,0,0,0,0,0,0,0, # 10 - 17 + 0,0,0,3,0,0,0,0, # 18 - 1f + 0,0,0,0,0,0,0,0, # 20 - 27 + 0,3,3,3,3,3,0,0, # 28 - 2f + 0,0,0,0,0,0,0,0, # 30 - 37 + 0,0,0,0,0,0,0,0, # 38 - 3f + 0,0,0,0,0,0,0,0, # 40 - 47 + 0,0,0,0,0,0,0,0, # 48 - 4f + 0,0,0,0,0,0,0,0, # 50 - 57 + 0,0,0,0,0,0,0,0, # 58 - 5f + 0,0,0,0,0,0,0,0, # 60 - 67 + 0,0,0,0,0,0,0,0, # 68 - 6f + 0,0,0,0,0,0,0,0, # 70 - 77 + 0,0,0,0,0,0,0,0, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,0,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,0,0,0,0,0,0,0, # a0 - a7 + 0,0,0,0,0,0,0,0, # a8 - af + 0,0,0,0,0,0,0,0, # b0 - b7 + 0,0,0,0,0,0,0,0, # b8 - bf + 0,0,0,0,0,0,0,0, # c0 - c7 + 0,0,0,0,0,0,0,0, # c8 - cf + 0,0,0,0,0,0,0,0, # d0 - d7 + 0,0,0,0,0,0,0,0, # d8 - df + 0,0,0,0,0,0,0,0, # e0 - e7 + 0,0,0,0,0,0,0,0, # e8 - ef + 0,0,0,0,0,0,0,0, # f0 - f7 + 0,0,0,0,0,0,4,5 # f8 - ff +) + +UCS2LE_ST = ( + 6, 6, 7, 6, 4, 3,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME, 5, 5, 5,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,#10-17 + 5, 5, 5,MachineState.ERROR, 5,MachineState.ERROR, 6, 6,#18-1f + 7, 6, 8, 8, 5, 5, 5,MachineState.ERROR,#20-27 + 5, 5, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 5, 5,#28-2f + 5, 5, 5,MachineState.ERROR, 5,MachineState.ERROR,MachineState.START,MachineState.START #30-37 +) + +UCS2LE_CHAR_LEN_TABLE = (2, 2, 2, 2, 2, 2) + +UCS2LE_SM_MODEL = {'class_table': UCS2LE_CLS, + 'class_factor': 6, + 'state_table': UCS2LE_ST, + 'char_len_table': UCS2LE_CHAR_LEN_TABLE, + 'name': 'UTF-16LE'} + +# UTF-8 + +UTF8_CLS = ( + 1,1,1,1,1,1,1,1, # 00 - 07 #allow 0x00 as a legal value + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 1,1,1,1,1,1,1,1, # 40 - 47 + 1,1,1,1,1,1,1,1, # 48 - 4f + 1,1,1,1,1,1,1,1, # 50 - 57 + 1,1,1,1,1,1,1,1, # 58 - 5f + 1,1,1,1,1,1,1,1, # 60 - 67 + 1,1,1,1,1,1,1,1, # 68 - 6f + 1,1,1,1,1,1,1,1, # 70 - 77 + 1,1,1,1,1,1,1,1, # 78 - 7f + 2,2,2,2,3,3,3,3, # 80 - 87 + 4,4,4,4,4,4,4,4, # 88 - 8f + 4,4,4,4,4,4,4,4, # 90 - 97 + 4,4,4,4,4,4,4,4, # 98 - 9f + 5,5,5,5,5,5,5,5, # a0 - a7 + 5,5,5,5,5,5,5,5, # a8 - af + 5,5,5,5,5,5,5,5, # b0 - b7 + 5,5,5,5,5,5,5,5, # b8 - bf + 0,0,6,6,6,6,6,6, # c0 - c7 + 6,6,6,6,6,6,6,6, # c8 - cf + 6,6,6,6,6,6,6,6, # d0 - d7 + 6,6,6,6,6,6,6,6, # d8 - df + 7,8,8,8,8,8,8,8, # e0 - e7 + 8,8,8,8,8,9,8,8, # e8 - ef + 10,11,11,11,11,11,11,11, # f0 - f7 + 12,13,13,13,14,15,0,0 # f8 - ff +) + +UTF8_ST = ( + MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 12, 10,#00-07 + 9, 11, 8, 7, 6, 5, 4, 3,#08-0f + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#10-17 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#18-1f + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#20-27 + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#28-2f + MachineState.ERROR,MachineState.ERROR, 5, 5, 5, 5,MachineState.ERROR,MachineState.ERROR,#30-37 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#38-3f + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 5, 5, 5,MachineState.ERROR,MachineState.ERROR,#40-47 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#48-4f + MachineState.ERROR,MachineState.ERROR, 7, 7, 7, 7,MachineState.ERROR,MachineState.ERROR,#50-57 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#58-5f + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 7, 7,MachineState.ERROR,MachineState.ERROR,#60-67 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#68-6f + MachineState.ERROR,MachineState.ERROR, 9, 9, 9, 9,MachineState.ERROR,MachineState.ERROR,#70-77 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#78-7f + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 9,MachineState.ERROR,MachineState.ERROR,#80-87 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#88-8f + MachineState.ERROR,MachineState.ERROR, 12, 12, 12, 12,MachineState.ERROR,MachineState.ERROR,#90-97 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#98-9f + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 12,MachineState.ERROR,MachineState.ERROR,#a0-a7 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#a8-af + MachineState.ERROR,MachineState.ERROR, 12, 12, 12,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#b0-b7 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#b8-bf + MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,#c0-c7 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR #c8-cf +) + +UTF8_CHAR_LEN_TABLE = (0, 1, 0, 0, 0, 0, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6) + +UTF8_SM_MODEL = {'class_table': UTF8_CLS, + 'class_factor': 16, + 'state_table': UTF8_ST, + 'char_len_table': UTF8_CHAR_LEN_TABLE, + 'name': 'UTF-8'} diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/sbcharsetprober.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/sbcharsetprober.py new file mode 100644 index 0000000..0adb51d --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/sbcharsetprober.py @@ -0,0 +1,132 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetprober import CharSetProber +from .enums import CharacterCategory, ProbingState, SequenceLikelihood + + +class SingleByteCharSetProber(CharSetProber): + SAMPLE_SIZE = 64 + SB_ENOUGH_REL_THRESHOLD = 1024 # 0.25 * SAMPLE_SIZE^2 + POSITIVE_SHORTCUT_THRESHOLD = 0.95 + NEGATIVE_SHORTCUT_THRESHOLD = 0.05 + + def __init__(self, model, reversed=False, name_prober=None): + super(SingleByteCharSetProber, self).__init__() + self._model = model + # TRUE if we need to reverse every pair in the model lookup + self._reversed = reversed + # Optional auxiliary prober for name decision + self._name_prober = name_prober + self._last_order = None + self._seq_counters = None + self._total_seqs = None + self._total_char = None + self._freq_char = None + self.reset() + + def reset(self): + super(SingleByteCharSetProber, self).reset() + # char order of last character + self._last_order = 255 + self._seq_counters = [0] * SequenceLikelihood.get_num_categories() + self._total_seqs = 0 + self._total_char = 0 + # characters that fall in our sampling range + self._freq_char = 0 + + @property + def charset_name(self): + if self._name_prober: + return self._name_prober.charset_name + else: + return self._model['charset_name'] + + @property + def language(self): + if self._name_prober: + return self._name_prober.language + else: + return self._model.get('language') + + def feed(self, byte_str): + if not self._model['keep_english_letter']: + byte_str = self.filter_international_words(byte_str) + if not byte_str: + return self.state + char_to_order_map = self._model['char_to_order_map'] + for i, c in enumerate(byte_str): + # XXX: Order is in range 1-64, so one would think we want 0-63 here, + # but that leads to 27 more test failures than before. + order = char_to_order_map[c] + # XXX: This was SYMBOL_CAT_ORDER before, with a value of 250, but + # CharacterCategory.SYMBOL is actually 253, so we use CONTROL + # to make it closer to the original intent. The only difference + # is whether or not we count digits and control characters for + # _total_char purposes. + if order < CharacterCategory.CONTROL: + self._total_char += 1 + if order < self.SAMPLE_SIZE: + self._freq_char += 1 + if self._last_order < self.SAMPLE_SIZE: + self._total_seqs += 1 + if not self._reversed: + i = (self._last_order * self.SAMPLE_SIZE) + order + model = self._model['precedence_matrix'][i] + else: # reverse the order of the letters in the lookup + i = (order * self.SAMPLE_SIZE) + self._last_order + model = self._model['precedence_matrix'][i] + self._seq_counters[model] += 1 + self._last_order = order + + charset_name = self._model['charset_name'] + if self.state == ProbingState.DETECTING: + if self._total_seqs > self.SB_ENOUGH_REL_THRESHOLD: + confidence = self.get_confidence() + if confidence > self.POSITIVE_SHORTCUT_THRESHOLD: + self.logger.debug('%s confidence = %s, we have a winner', + charset_name, confidence) + self._state = ProbingState.FOUND_IT + elif confidence < self.NEGATIVE_SHORTCUT_THRESHOLD: + self.logger.debug('%s confidence = %s, below negative ' + 'shortcut threshhold %s', charset_name, + confidence, + self.NEGATIVE_SHORTCUT_THRESHOLD) + self._state = ProbingState.NOT_ME + + return self.state + + def get_confidence(self): + r = 0.01 + if self._total_seqs > 0: + r = ((1.0 * self._seq_counters[SequenceLikelihood.POSITIVE]) / + self._total_seqs / self._model['typical_positive_ratio']) + r = r * self._freq_char / self._total_char + if r >= 1.0: + r = 0.99 + return r diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/sbcsgroupprober.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/sbcsgroupprober.py new file mode 100644 index 0000000..98e95dc --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/sbcsgroupprober.py @@ -0,0 +1,73 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetgroupprober import CharSetGroupProber +from .sbcharsetprober import SingleByteCharSetProber +from .langcyrillicmodel import (Win1251CyrillicModel, Koi8rModel, + Latin5CyrillicModel, MacCyrillicModel, + Ibm866Model, Ibm855Model) +from .langgreekmodel import Latin7GreekModel, Win1253GreekModel +from .langbulgarianmodel import Latin5BulgarianModel, Win1251BulgarianModel +# from .langhungarianmodel import Latin2HungarianModel, Win1250HungarianModel +from .langthaimodel import TIS620ThaiModel +from .langhebrewmodel import Win1255HebrewModel +from .hebrewprober import HebrewProber +from .langturkishmodel import Latin5TurkishModel + + +class SBCSGroupProber(CharSetGroupProber): + def __init__(self): + super(SBCSGroupProber, self).__init__() + self.probers = [ + SingleByteCharSetProber(Win1251CyrillicModel), + SingleByteCharSetProber(Koi8rModel), + SingleByteCharSetProber(Latin5CyrillicModel), + SingleByteCharSetProber(MacCyrillicModel), + SingleByteCharSetProber(Ibm866Model), + SingleByteCharSetProber(Ibm855Model), + SingleByteCharSetProber(Latin7GreekModel), + SingleByteCharSetProber(Win1253GreekModel), + SingleByteCharSetProber(Latin5BulgarianModel), + SingleByteCharSetProber(Win1251BulgarianModel), + # TODO: Restore Hungarian encodings (iso-8859-2 and windows-1250) + # after we retrain model. + # SingleByteCharSetProber(Latin2HungarianModel), + # SingleByteCharSetProber(Win1250HungarianModel), + SingleByteCharSetProber(TIS620ThaiModel), + SingleByteCharSetProber(Latin5TurkishModel), + ] + hebrew_prober = HebrewProber() + logical_hebrew_prober = SingleByteCharSetProber(Win1255HebrewModel, + False, hebrew_prober) + visual_hebrew_prober = SingleByteCharSetProber(Win1255HebrewModel, True, + hebrew_prober) + hebrew_prober.set_model_probers(logical_hebrew_prober, visual_hebrew_prober) + self.probers.extend([hebrew_prober, logical_hebrew_prober, + visual_hebrew_prober]) + + self.reset() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/sjisprober.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/sjisprober.py new file mode 100644 index 0000000..9e29623 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/sjisprober.py @@ -0,0 +1,92 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import SJISDistributionAnalysis +from .jpcntx import SJISContextAnalysis +from .mbcssm import SJIS_SM_MODEL +from .enums import ProbingState, MachineState + + +class SJISProber(MultiByteCharSetProber): + def __init__(self): + super(SJISProber, self).__init__() + self.coding_sm = CodingStateMachine(SJIS_SM_MODEL) + self.distribution_analyzer = SJISDistributionAnalysis() + self.context_analyzer = SJISContextAnalysis() + self.reset() + + def reset(self): + super(SJISProber, self).reset() + self.context_analyzer.reset() + + @property + def charset_name(self): + return self.context_analyzer.charset_name + + @property + def language(self): + return "Japanese" + + def feed(self, byte_str): + for i in range(len(byte_str)): + coding_state = self.coding_sm.next_state(byte_str[i]) + if coding_state == MachineState.ERROR: + self.logger.debug('%s %s prober hit error at byte %s', + self.charset_name, self.language, i) + self._state = ProbingState.NOT_ME + break + elif coding_state == MachineState.ITS_ME: + self._state = ProbingState.FOUND_IT + break + elif coding_state == MachineState.START: + char_len = self.coding_sm.get_current_charlen() + if i == 0: + self._last_char[1] = byte_str[0] + self.context_analyzer.feed(self._last_char[2 - char_len:], + char_len) + self.distribution_analyzer.feed(self._last_char, char_len) + else: + self.context_analyzer.feed(byte_str[i + 1 - char_len:i + 3 + - char_len], char_len) + self.distribution_analyzer.feed(byte_str[i - 1:i + 1], + char_len) + + self._last_char[0] = byte_str[-1] + + if self.state == ProbingState.DETECTING: + if (self.context_analyzer.got_enough_data() and + (self.get_confidence() > self.SHORTCUT_THRESHOLD)): + self._state = ProbingState.FOUND_IT + + return self.state + + def get_confidence(self): + context_conf = self.context_analyzer.get_confidence() + distrib_conf = self.distribution_analyzer.get_confidence() + return max(context_conf, distrib_conf) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/universaldetector.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/universaldetector.py new file mode 100644 index 0000000..7b4e92d --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/universaldetector.py @@ -0,0 +1,286 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### +""" +Module containing the UniversalDetector detector class, which is the primary +class a user of ``chardet`` should use. + +:author: Mark Pilgrim (initial port to Python) +:author: Shy Shalom (original C code) +:author: Dan Blanchard (major refactoring for 3.0) +:author: Ian Cordasco +""" + + +import codecs +import logging +import re + +from .charsetgroupprober import CharSetGroupProber +from .enums import InputState, LanguageFilter, ProbingState +from .escprober import EscCharSetProber +from .latin1prober import Latin1Prober +from .mbcsgroupprober import MBCSGroupProber +from .sbcsgroupprober import SBCSGroupProber + + +class UniversalDetector(object): + """ + The ``UniversalDetector`` class underlies the ``chardet.detect`` function + and coordinates all of the different charset probers. + + To get a ``dict`` containing an encoding and its confidence, you can simply + run: + + .. code:: + + u = UniversalDetector() + u.feed(some_bytes) + u.close() + detected = u.result + + """ + + MINIMUM_THRESHOLD = 0.20 + HIGH_BYTE_DETECTOR = re.compile(b'[\x80-\xFF]') + ESC_DETECTOR = re.compile(b'(\033|~{)') + WIN_BYTE_DETECTOR = re.compile(b'[\x80-\x9F]') + ISO_WIN_MAP = {'iso-8859-1': 'Windows-1252', + 'iso-8859-2': 'Windows-1250', + 'iso-8859-5': 'Windows-1251', + 'iso-8859-6': 'Windows-1256', + 'iso-8859-7': 'Windows-1253', + 'iso-8859-8': 'Windows-1255', + 'iso-8859-9': 'Windows-1254', + 'iso-8859-13': 'Windows-1257'} + + def __init__(self, lang_filter=LanguageFilter.ALL): + self._esc_charset_prober = None + self._charset_probers = [] + self.result = None + self.done = None + self._got_data = None + self._input_state = None + self._last_char = None + self.lang_filter = lang_filter + self.logger = logging.getLogger(__name__) + self._has_win_bytes = None + self.reset() + + def reset(self): + """ + Reset the UniversalDetector and all of its probers back to their + initial states. This is called by ``__init__``, so you only need to + call this directly in between analyses of different documents. + """ + self.result = {'encoding': None, 'confidence': 0.0, 'language': None} + self.done = False + self._got_data = False + self._has_win_bytes = False + self._input_state = InputState.PURE_ASCII + self._last_char = b'' + if self._esc_charset_prober: + self._esc_charset_prober.reset() + for prober in self._charset_probers: + prober.reset() + + def feed(self, byte_str): + """ + Takes a chunk of a document and feeds it through all of the relevant + charset probers. + + After calling ``feed``, you can check the value of the ``done`` + attribute to see if you need to continue feeding the + ``UniversalDetector`` more data, or if it has made a prediction + (in the ``result`` attribute). + + .. note:: + You should always call ``close`` when you're done feeding in your + document if ``done`` is not already ``True``. + """ + if self.done: + return + + if not len(byte_str): + return + + if not isinstance(byte_str, bytearray): + byte_str = bytearray(byte_str) + + # First check for known BOMs, since these are guaranteed to be correct + if not self._got_data: + # If the data starts with BOM, we know it is UTF + if byte_str.startswith(codecs.BOM_UTF8): + # EF BB BF UTF-8 with BOM + self.result = {'encoding': "UTF-8-SIG", + 'confidence': 1.0, + 'language': ''} + elif byte_str.startswith((codecs.BOM_UTF32_LE, + codecs.BOM_UTF32_BE)): + # FF FE 00 00 UTF-32, little-endian BOM + # 00 00 FE FF UTF-32, big-endian BOM + self.result = {'encoding': "UTF-32", + 'confidence': 1.0, + 'language': ''} + elif byte_str.startswith(b'\xFE\xFF\x00\x00'): + # FE FF 00 00 UCS-4, unusual octet order BOM (3412) + self.result = {'encoding': "X-ISO-10646-UCS-4-3412", + 'confidence': 1.0, + 'language': ''} + elif byte_str.startswith(b'\x00\x00\xFF\xFE'): + # 00 00 FF FE UCS-4, unusual octet order BOM (2143) + self.result = {'encoding': "X-ISO-10646-UCS-4-2143", + 'confidence': 1.0, + 'language': ''} + elif byte_str.startswith((codecs.BOM_LE, codecs.BOM_BE)): + # FF FE UTF-16, little endian BOM + # FE FF UTF-16, big endian BOM + self.result = {'encoding': "UTF-16", + 'confidence': 1.0, + 'language': ''} + + self._got_data = True + if self.result['encoding'] is not None: + self.done = True + return + + # If none of those matched and we've only see ASCII so far, check + # for high bytes and escape sequences + if self._input_state == InputState.PURE_ASCII: + if self.HIGH_BYTE_DETECTOR.search(byte_str): + self._input_state = InputState.HIGH_BYTE + elif self._input_state == InputState.PURE_ASCII and \ + self.ESC_DETECTOR.search(self._last_char + byte_str): + self._input_state = InputState.ESC_ASCII + + self._last_char = byte_str[-1:] + + # If we've seen escape sequences, use the EscCharSetProber, which + # uses a simple state machine to check for known escape sequences in + # HZ and ISO-2022 encodings, since those are the only encodings that + # use such sequences. + if self._input_state == InputState.ESC_ASCII: + if not self._esc_charset_prober: + self._esc_charset_prober = EscCharSetProber(self.lang_filter) + if self._esc_charset_prober.feed(byte_str) == ProbingState.FOUND_IT: + self.result = {'encoding': + self._esc_charset_prober.charset_name, + 'confidence': + self._esc_charset_prober.get_confidence(), + 'language': + self._esc_charset_prober.language} + self.done = True + # If we've seen high bytes (i.e., those with values greater than 127), + # we need to do more complicated checks using all our multi-byte and + # single-byte probers that are left. The single-byte probers + # use character bigram distributions to determine the encoding, whereas + # the multi-byte probers use a combination of character unigram and + # bigram distributions. + elif self._input_state == InputState.HIGH_BYTE: + if not self._charset_probers: + self._charset_probers = [MBCSGroupProber(self.lang_filter)] + # If we're checking non-CJK encodings, use single-byte prober + if self.lang_filter & LanguageFilter.NON_CJK: + self._charset_probers.append(SBCSGroupProber()) + self._charset_probers.append(Latin1Prober()) + for prober in self._charset_probers: + if prober.feed(byte_str) == ProbingState.FOUND_IT: + self.result = {'encoding': prober.charset_name, + 'confidence': prober.get_confidence(), + 'language': prober.language} + self.done = True + break + if self.WIN_BYTE_DETECTOR.search(byte_str): + self._has_win_bytes = True + + def close(self): + """ + Stop analyzing the current document and come up with a final + prediction. + + :returns: The ``result`` attribute, a ``dict`` with the keys + `encoding`, `confidence`, and `language`. + """ + # Don't bother with checks if we're already done + if self.done: + return self.result + self.done = True + + if not self._got_data: + self.logger.debug('no data received!') + + # Default to ASCII if it is all we've seen so far + elif self._input_state == InputState.PURE_ASCII: + self.result = {'encoding': 'ascii', + 'confidence': 1.0, + 'language': ''} + + # If we have seen non-ASCII, return the best that met MINIMUM_THRESHOLD + elif self._input_state == InputState.HIGH_BYTE: + prober_confidence = None + max_prober_confidence = 0.0 + max_prober = None + for prober in self._charset_probers: + if not prober: + continue + prober_confidence = prober.get_confidence() + if prober_confidence > max_prober_confidence: + max_prober_confidence = prober_confidence + max_prober = prober + if max_prober and (max_prober_confidence > self.MINIMUM_THRESHOLD): + charset_name = max_prober.charset_name + lower_charset_name = max_prober.charset_name.lower() + confidence = max_prober.get_confidence() + # Use Windows encoding name instead of ISO-8859 if we saw any + # extra Windows-specific bytes + if lower_charset_name.startswith('iso-8859'): + if self._has_win_bytes: + charset_name = self.ISO_WIN_MAP.get(lower_charset_name, + charset_name) + self.result = {'encoding': charset_name, + 'confidence': confidence, + 'language': max_prober.language} + + # Log all prober confidences if none met MINIMUM_THRESHOLD + if self.logger.getEffectiveLevel() == logging.DEBUG: + if self.result['encoding'] is None: + self.logger.debug('no probers hit minimum threshold') + for group_prober in self._charset_probers: + if not group_prober: + continue + if isinstance(group_prober, CharSetGroupProber): + for prober in group_prober.probers: + self.logger.debug('%s %s confidence = %s', + prober.charset_name, + prober.language, + prober.get_confidence()) + else: + self.logger.debug('%s %s confidence = %s', + prober.charset_name, + prober.language, + prober.get_confidence()) + return self.result diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/utf8prober.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/utf8prober.py new file mode 100644 index 0000000..6c3196c --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/utf8prober.py @@ -0,0 +1,82 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetprober import CharSetProber +from .enums import ProbingState, MachineState +from .codingstatemachine import CodingStateMachine +from .mbcssm import UTF8_SM_MODEL + + + +class UTF8Prober(CharSetProber): + ONE_CHAR_PROB = 0.5 + + def __init__(self): + super(UTF8Prober, self).__init__() + self.coding_sm = CodingStateMachine(UTF8_SM_MODEL) + self._num_mb_chars = None + self.reset() + + def reset(self): + super(UTF8Prober, self).reset() + self.coding_sm.reset() + self._num_mb_chars = 0 + + @property + def charset_name(self): + return "utf-8" + + @property + def language(self): + return "" + + def feed(self, byte_str): + for c in byte_str: + coding_state = self.coding_sm.next_state(c) + if coding_state == MachineState.ERROR: + self._state = ProbingState.NOT_ME + break + elif coding_state == MachineState.ITS_ME: + self._state = ProbingState.FOUND_IT + break + elif coding_state == MachineState.START: + if self.coding_sm.get_current_charlen() >= 2: + self._num_mb_chars += 1 + + if self.state == ProbingState.DETECTING: + if self.get_confidence() > self.SHORTCUT_THRESHOLD: + self._state = ProbingState.FOUND_IT + + return self.state + + def get_confidence(self): + unlike = 0.99 + if self._num_mb_chars < 6: + unlike *= self.ONE_CHAR_PROB ** self._num_mb_chars + return 1.0 - unlike + else: + return unlike diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/version.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/version.py new file mode 100644 index 0000000..bb2a34a --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/chardet/version.py @@ -0,0 +1,9 @@ +""" +This module exists only to simplify retrieving the version number of chardet +from within setup.py and from chardet subpackages. + +:author: Dan Blanchard (dan.blanchard@gmail.com) +""" + +__version__ = "3.0.4" +VERSION = __version__.split('.') diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click-7.1.2.dist-info/INSTALLER b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click-7.1.2.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click-7.1.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click-7.1.2.dist-info/LICENSE.rst b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click-7.1.2.dist-info/LICENSE.rst new file mode 100644 index 0000000..d12a849 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click-7.1.2.dist-info/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2014 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click-7.1.2.dist-info/METADATA b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click-7.1.2.dist-info/METADATA new file mode 100644 index 0000000..00d6974 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click-7.1.2.dist-info/METADATA @@ -0,0 +1,102 @@ +Metadata-Version: 2.1 +Name: click +Version: 7.1.2 +Summary: Composable command line interface toolkit +Home-page: https://palletsprojects.com/p/click/ +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Documentation, https://click.palletsprojects.com/ +Project-URL: Code, https://github.com/pallets/click +Project-URL: Issue tracker, https://github.com/pallets/click/issues +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 3 +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* + +\$ click\_ +========== + +Click is a Python package for creating beautiful command line interfaces +in a composable way with as little code as necessary. It's the "Command +Line Interface Creation Kit". It's highly configurable but comes with +sensible defaults out of the box. + +It aims to make the process of writing command line tools quick and fun +while also preventing any frustration caused by the inability to +implement an intended CLI API. + +Click in three points: + +- Arbitrary nesting of commands +- Automatic help page generation +- Supports lazy loading of subcommands at runtime + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + $ pip install -U click + +.. _pip: https://pip.pypa.io/en/stable/quickstart/ + + +A Simple Example +---------------- + +.. code-block:: python + + import click + + @click.command() + @click.option("--count", default=1, help="Number of greetings.") + @click.option("--name", prompt="Your name", help="The person to greet.") + def hello(count, name): + """Simple program that greets NAME for a total of COUNT times.""" + for _ in range(count): + click.echo(f"Hello, {name}!") + + if __name__ == '__main__': + hello() + +.. code-block:: text + + $ python hello.py --count=3 + Your name: Click + Hello, Click! + Hello, Click! + Hello, Click! + + +Donate +------ + +The Pallets organization develops and supports Click and other popular +packages. In order to grow the community of contributors and users, and +allow the maintainers to devote more time to the projects, `please +donate today`_. + +.. _please donate today: https://palletsprojects.com/donate + + +Links +----- + +- Website: https://palletsprojects.com/p/click/ +- Documentation: https://click.palletsprojects.com/ +- Releases: https://pypi.org/project/click/ +- Code: https://github.com/pallets/click +- Issue tracker: https://github.com/pallets/click/issues +- Test status: https://dev.azure.com/pallets/click/_build +- Official chat: https://discord.gg/t6rrQZH + + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click-7.1.2.dist-info/RECORD b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click-7.1.2.dist-info/RECORD new file mode 100644 index 0000000..8fc797d --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click-7.1.2.dist-info/RECORD @@ -0,0 +1,40 @@ +click-7.1.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +click-7.1.2.dist-info/LICENSE.rst,sha256=morRBqOU6FO_4h9C9OctWSgZoigF2ZG18ydQKSkrZY0,1475 +click-7.1.2.dist-info/METADATA,sha256=LrRgakZKV7Yg3qJqX_plu2WhFW81MzP3EqQmZhHIO8M,2868 +click-7.1.2.dist-info/RECORD,, +click-7.1.2.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110 +click-7.1.2.dist-info/top_level.txt,sha256=J1ZQogalYS4pphY_lPECoNMfw0HzTSrZglC4Yfwo4xA,6 +click/__init__.py,sha256=FkyGDQ-cbiQxP_lxgUspyFYS48f2S_pTcfKPz-d_RMo,2463 +click/__pycache__/__init__.cpython-38.pyc,, +click/__pycache__/_bashcomplete.cpython-38.pyc,, +click/__pycache__/_compat.cpython-38.pyc,, +click/__pycache__/_termui_impl.cpython-38.pyc,, +click/__pycache__/_textwrap.cpython-38.pyc,, +click/__pycache__/_unicodefun.cpython-38.pyc,, +click/__pycache__/_winconsole.cpython-38.pyc,, +click/__pycache__/core.cpython-38.pyc,, +click/__pycache__/decorators.cpython-38.pyc,, +click/__pycache__/exceptions.cpython-38.pyc,, +click/__pycache__/formatting.cpython-38.pyc,, +click/__pycache__/globals.cpython-38.pyc,, +click/__pycache__/parser.cpython-38.pyc,, +click/__pycache__/termui.cpython-38.pyc,, +click/__pycache__/testing.cpython-38.pyc,, +click/__pycache__/types.cpython-38.pyc,, +click/__pycache__/utils.cpython-38.pyc,, +click/_bashcomplete.py,sha256=9J98IHQYmCAr2Jup6TDshUr5FJEen-AoQCZR0K5nKxQ,12309 +click/_compat.py,sha256=AoMaYnZ-3pwtNXuHtlb6_UXsayoG0QZiHKIRy2VFezc,24169 +click/_termui_impl.py,sha256=yNktUMAdjYOU1HMkq915jR3zgAzUNtGSQqSTSSMn3eQ,20702 +click/_textwrap.py,sha256=ajCzkzFly5tjm9foQ5N9_MOeaYJMBjAltuFa69n4iXY,1197 +click/_unicodefun.py,sha256=apLSNEBZgUsQNPMUv072zJ1swqnm0dYVT5TqcIWTt6w,4201 +click/_winconsole.py,sha256=6YDu6Rq1Wxx4w9uinBMK2LHvP83aerZM9GQurlk3QDo,10010 +click/core.py,sha256=V6DJzastGhrC6WTDwV9MSLwcJUdX2Uf1ypmgkjBdn_Y,77650 +click/decorators.py,sha256=3TvEO_BkaHl7k6Eh1G5eC7JK4LKPdpFqH9JP0QDyTlM,11215 +click/exceptions.py,sha256=3pQAyyMFzx5A3eV0Y27WtDTyGogZRbrC6_o5DjjKBbw,8118 +click/formatting.py,sha256=Wb4gqFEpWaKPgAbOvnkCl8p-bEZx5KpM5ZSByhlnJNk,9281 +click/globals.py,sha256=ht7u2kUGI08pAarB4e4yC8Lkkxy6gJfRZyzxEj8EbWQ,1501 +click/parser.py,sha256=mFK-k58JtPpqO0AC36WAr0t5UfzEw1mvgVSyn7WCe9M,15691 +click/termui.py,sha256=G7QBEKIepRIGLvNdGwBTYiEtSImRxvTO_AglVpyHH2s,23998 +click/testing.py,sha256=EUEsDUqNXFgCLhZ0ZFOROpaVDA5I_rijwnNPE6qICgA,12854 +click/types.py,sha256=wuubik4VqgqAw5dvbYFkDt-zSAx97y9TQXuXcVaRyQA,25045 +click/utils.py,sha256=4VEcJ7iEHwjnFuzEuRtkT99o5VG3zqSD7Q2CVzv13WU,15940 diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click-7.1.2.dist-info/WHEEL b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click-7.1.2.dist-info/WHEEL new file mode 100644 index 0000000..ef99c6c --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click-7.1.2.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.34.2) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click-7.1.2.dist-info/top_level.txt b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click-7.1.2.dist-info/top_level.txt new file mode 100644 index 0000000..dca9a90 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click-7.1.2.dist-info/top_level.txt @@ -0,0 +1 @@ +click diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/__init__.py new file mode 100644 index 0000000..2b6008f --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/__init__.py @@ -0,0 +1,79 @@ +""" +Click is a simple Python module inspired by the stdlib optparse to make +writing command line scripts fun. Unlike other modules, it's based +around a simple API that does not come with too much magic and is +composable. +""" +from .core import Argument +from .core import BaseCommand +from .core import Command +from .core import CommandCollection +from .core import Context +from .core import Group +from .core import MultiCommand +from .core import Option +from .core import Parameter +from .decorators import argument +from .decorators import command +from .decorators import confirmation_option +from .decorators import group +from .decorators import help_option +from .decorators import make_pass_decorator +from .decorators import option +from .decorators import pass_context +from .decorators import pass_obj +from .decorators import password_option +from .decorators import version_option +from .exceptions import Abort +from .exceptions import BadArgumentUsage +from .exceptions import BadOptionUsage +from .exceptions import BadParameter +from .exceptions import ClickException +from .exceptions import FileError +from .exceptions import MissingParameter +from .exceptions import NoSuchOption +from .exceptions import UsageError +from .formatting import HelpFormatter +from .formatting import wrap_text +from .globals import get_current_context +from .parser import OptionParser +from .termui import clear +from .termui import confirm +from .termui import echo_via_pager +from .termui import edit +from .termui import get_terminal_size +from .termui import getchar +from .termui import launch +from .termui import pause +from .termui import progressbar +from .termui import prompt +from .termui import secho +from .termui import style +from .termui import unstyle +from .types import BOOL +from .types import Choice +from .types import DateTime +from .types import File +from .types import FLOAT +from .types import FloatRange +from .types import INT +from .types import IntRange +from .types import ParamType +from .types import Path +from .types import STRING +from .types import Tuple +from .types import UNPROCESSED +from .types import UUID +from .utils import echo +from .utils import format_filename +from .utils import get_app_dir +from .utils import get_binary_stream +from .utils import get_os_args +from .utils import get_text_stream +from .utils import open_file + +# Controls if click should emit the warning about the use of unicode +# literals. +disable_unicode_literals_warning = False + +__version__ = "7.1.2" diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/_bashcomplete.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/_bashcomplete.py new file mode 100644 index 0000000..8bca244 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/_bashcomplete.py @@ -0,0 +1,375 @@ +import copy +import os +import re + +from .core import Argument +from .core import MultiCommand +from .core import Option +from .parser import split_arg_string +from .types import Choice +from .utils import echo + +try: + from collections import abc +except ImportError: + import collections as abc + +WORDBREAK = "=" + +# Note, only BASH version 4.4 and later have the nosort option. +COMPLETION_SCRIPT_BASH = """ +%(complete_func)s() { + local IFS=$'\n' + COMPREPLY=( $( env COMP_WORDS="${COMP_WORDS[*]}" \\ + COMP_CWORD=$COMP_CWORD \\ + %(autocomplete_var)s=complete $1 ) ) + return 0 +} + +%(complete_func)setup() { + local COMPLETION_OPTIONS="" + local BASH_VERSION_ARR=(${BASH_VERSION//./ }) + # Only BASH version 4.4 and later have the nosort option. + if [ ${BASH_VERSION_ARR[0]} -gt 4 ] || ([ ${BASH_VERSION_ARR[0]} -eq 4 ] \ +&& [ ${BASH_VERSION_ARR[1]} -ge 4 ]); then + COMPLETION_OPTIONS="-o nosort" + fi + + complete $COMPLETION_OPTIONS -F %(complete_func)s %(script_names)s +} + +%(complete_func)setup +""" + +COMPLETION_SCRIPT_ZSH = """ +#compdef %(script_names)s + +%(complete_func)s() { + local -a completions + local -a completions_with_descriptions + local -a response + (( ! $+commands[%(script_names)s] )) && return 1 + + response=("${(@f)$( env COMP_WORDS=\"${words[*]}\" \\ + COMP_CWORD=$((CURRENT-1)) \\ + %(autocomplete_var)s=\"complete_zsh\" \\ + %(script_names)s )}") + + for key descr in ${(kv)response}; do + if [[ "$descr" == "_" ]]; then + completions+=("$key") + else + completions_with_descriptions+=("$key":"$descr") + fi + done + + if [ -n "$completions_with_descriptions" ]; then + _describe -V unsorted completions_with_descriptions -U + fi + + if [ -n "$completions" ]; then + compadd -U -V unsorted -a completions + fi + compstate[insert]="automenu" +} + +compdef %(complete_func)s %(script_names)s +""" + +COMPLETION_SCRIPT_FISH = ( + "complete --no-files --command %(script_names)s --arguments" + ' "(env %(autocomplete_var)s=complete_fish' + " COMP_WORDS=(commandline -cp) COMP_CWORD=(commandline -t)" + ' %(script_names)s)"' +) + +_completion_scripts = { + "bash": COMPLETION_SCRIPT_BASH, + "zsh": COMPLETION_SCRIPT_ZSH, + "fish": COMPLETION_SCRIPT_FISH, +} + +_invalid_ident_char_re = re.compile(r"[^a-zA-Z0-9_]") + + +def get_completion_script(prog_name, complete_var, shell): + cf_name = _invalid_ident_char_re.sub("", prog_name.replace("-", "_")) + script = _completion_scripts.get(shell, COMPLETION_SCRIPT_BASH) + return ( + script + % { + "complete_func": "_{}_completion".format(cf_name), + "script_names": prog_name, + "autocomplete_var": complete_var, + } + ).strip() + ";" + + +def resolve_ctx(cli, prog_name, args): + """Parse into a hierarchy of contexts. Contexts are connected + through the parent variable. + + :param cli: command definition + :param prog_name: the program that is running + :param args: full list of args + :return: the final context/command parsed + """ + ctx = cli.make_context(prog_name, args, resilient_parsing=True) + args = ctx.protected_args + ctx.args + while args: + if isinstance(ctx.command, MultiCommand): + if not ctx.command.chain: + cmd_name, cmd, args = ctx.command.resolve_command(ctx, args) + if cmd is None: + return ctx + ctx = cmd.make_context( + cmd_name, args, parent=ctx, resilient_parsing=True + ) + args = ctx.protected_args + ctx.args + else: + # Walk chained subcommand contexts saving the last one. + while args: + cmd_name, cmd, args = ctx.command.resolve_command(ctx, args) + if cmd is None: + return ctx + sub_ctx = cmd.make_context( + cmd_name, + args, + parent=ctx, + allow_extra_args=True, + allow_interspersed_args=False, + resilient_parsing=True, + ) + args = sub_ctx.args + ctx = sub_ctx + args = sub_ctx.protected_args + sub_ctx.args + else: + break + return ctx + + +def start_of_option(param_str): + """ + :param param_str: param_str to check + :return: whether or not this is the start of an option declaration + (i.e. starts "-" or "--") + """ + return param_str and param_str[:1] == "-" + + +def is_incomplete_option(all_args, cmd_param): + """ + :param all_args: the full original list of args supplied + :param cmd_param: the current command paramter + :return: whether or not the last option declaration (i.e. starts + "-" or "--") is incomplete and corresponds to this cmd_param. In + other words whether this cmd_param option can still accept + values + """ + if not isinstance(cmd_param, Option): + return False + if cmd_param.is_flag: + return False + last_option = None + for index, arg_str in enumerate( + reversed([arg for arg in all_args if arg != WORDBREAK]) + ): + if index + 1 > cmd_param.nargs: + break + if start_of_option(arg_str): + last_option = arg_str + + return True if last_option and last_option in cmd_param.opts else False + + +def is_incomplete_argument(current_params, cmd_param): + """ + :param current_params: the current params and values for this + argument as already entered + :param cmd_param: the current command parameter + :return: whether or not the last argument is incomplete and + corresponds to this cmd_param. In other words whether or not the + this cmd_param argument can still accept values + """ + if not isinstance(cmd_param, Argument): + return False + current_param_values = current_params[cmd_param.name] + if current_param_values is None: + return True + if cmd_param.nargs == -1: + return True + if ( + isinstance(current_param_values, abc.Iterable) + and cmd_param.nargs > 1 + and len(current_param_values) < cmd_param.nargs + ): + return True + return False + + +def get_user_autocompletions(ctx, args, incomplete, cmd_param): + """ + :param ctx: context associated with the parsed command + :param args: full list of args + :param incomplete: the incomplete text to autocomplete + :param cmd_param: command definition + :return: all the possible user-specified completions for the param + """ + results = [] + if isinstance(cmd_param.type, Choice): + # Choices don't support descriptions. + results = [ + (c, None) for c in cmd_param.type.choices if str(c).startswith(incomplete) + ] + elif cmd_param.autocompletion is not None: + dynamic_completions = cmd_param.autocompletion( + ctx=ctx, args=args, incomplete=incomplete + ) + results = [ + c if isinstance(c, tuple) else (c, None) for c in dynamic_completions + ] + return results + + +def get_visible_commands_starting_with(ctx, starts_with): + """ + :param ctx: context associated with the parsed command + :starts_with: string that visible commands must start with. + :return: all visible (not hidden) commands that start with starts_with. + """ + for c in ctx.command.list_commands(ctx): + if c.startswith(starts_with): + command = ctx.command.get_command(ctx, c) + if not command.hidden: + yield command + + +def add_subcommand_completions(ctx, incomplete, completions_out): + # Add subcommand completions. + if isinstance(ctx.command, MultiCommand): + completions_out.extend( + [ + (c.name, c.get_short_help_str()) + for c in get_visible_commands_starting_with(ctx, incomplete) + ] + ) + + # Walk up the context list and add any other completion + # possibilities from chained commands + while ctx.parent is not None: + ctx = ctx.parent + if isinstance(ctx.command, MultiCommand) and ctx.command.chain: + remaining_commands = [ + c + for c in get_visible_commands_starting_with(ctx, incomplete) + if c.name not in ctx.protected_args + ] + completions_out.extend( + [(c.name, c.get_short_help_str()) for c in remaining_commands] + ) + + +def get_choices(cli, prog_name, args, incomplete): + """ + :param cli: command definition + :param prog_name: the program that is running + :param args: full list of args + :param incomplete: the incomplete text to autocomplete + :return: all the possible completions for the incomplete + """ + all_args = copy.deepcopy(args) + + ctx = resolve_ctx(cli, prog_name, args) + if ctx is None: + return [] + + has_double_dash = "--" in all_args + + # In newer versions of bash long opts with '='s are partitioned, but + # it's easier to parse without the '=' + if start_of_option(incomplete) and WORDBREAK in incomplete: + partition_incomplete = incomplete.partition(WORDBREAK) + all_args.append(partition_incomplete[0]) + incomplete = partition_incomplete[2] + elif incomplete == WORDBREAK: + incomplete = "" + + completions = [] + if not has_double_dash and start_of_option(incomplete): + # completions for partial options + for param in ctx.command.params: + if isinstance(param, Option) and not param.hidden: + param_opts = [ + param_opt + for param_opt in param.opts + param.secondary_opts + if param_opt not in all_args or param.multiple + ] + completions.extend( + [(o, param.help) for o in param_opts if o.startswith(incomplete)] + ) + return completions + # completion for option values from user supplied values + for param in ctx.command.params: + if is_incomplete_option(all_args, param): + return get_user_autocompletions(ctx, all_args, incomplete, param) + # completion for argument values from user supplied values + for param in ctx.command.params: + if is_incomplete_argument(ctx.params, param): + return get_user_autocompletions(ctx, all_args, incomplete, param) + + add_subcommand_completions(ctx, incomplete, completions) + # Sort before returning so that proper ordering can be enforced in custom types. + return sorted(completions) + + +def do_complete(cli, prog_name, include_descriptions): + cwords = split_arg_string(os.environ["COMP_WORDS"]) + cword = int(os.environ["COMP_CWORD"]) + args = cwords[1:cword] + try: + incomplete = cwords[cword] + except IndexError: + incomplete = "" + + for item in get_choices(cli, prog_name, args, incomplete): + echo(item[0]) + if include_descriptions: + # ZSH has trouble dealing with empty array parameters when + # returned from commands, use '_' to indicate no description + # is present. + echo(item[1] if item[1] else "_") + + return True + + +def do_complete_fish(cli, prog_name): + cwords = split_arg_string(os.environ["COMP_WORDS"]) + incomplete = os.environ["COMP_CWORD"] + args = cwords[1:] + + for item in get_choices(cli, prog_name, args, incomplete): + if item[1]: + echo("{arg}\t{desc}".format(arg=item[0], desc=item[1])) + else: + echo(item[0]) + + return True + + +def bashcomplete(cli, prog_name, complete_var, complete_instr): + if "_" in complete_instr: + command, shell = complete_instr.split("_", 1) + else: + command = complete_instr + shell = "bash" + + if command == "source": + echo(get_completion_script(prog_name, complete_var, shell)) + return True + elif command == "complete": + if shell == "fish": + return do_complete_fish(cli, prog_name) + elif shell in {"bash", "zsh"}: + return do_complete(cli, prog_name, shell == "zsh") + + return False diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/_compat.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/_compat.py new file mode 100644 index 0000000..60cb115 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/_compat.py @@ -0,0 +1,786 @@ +# flake8: noqa +import codecs +import io +import os +import re +import sys +from weakref import WeakKeyDictionary + +PY2 = sys.version_info[0] == 2 +CYGWIN = sys.platform.startswith("cygwin") +MSYS2 = sys.platform.startswith("win") and ("GCC" in sys.version) +# Determine local App Engine environment, per Google's own suggestion +APP_ENGINE = "APPENGINE_RUNTIME" in os.environ and "Development/" in os.environ.get( + "SERVER_SOFTWARE", "" +) +WIN = sys.platform.startswith("win") and not APP_ENGINE and not MSYS2 +DEFAULT_COLUMNS = 80 + + +_ansi_re = re.compile(r"\033\[[;?0-9]*[a-zA-Z]") + + +def get_filesystem_encoding(): + return sys.getfilesystemencoding() or sys.getdefaultencoding() + + +def _make_text_stream( + stream, encoding, errors, force_readable=False, force_writable=False +): + if encoding is None: + encoding = get_best_encoding(stream) + if errors is None: + errors = "replace" + return _NonClosingTextIOWrapper( + stream, + encoding, + errors, + line_buffering=True, + force_readable=force_readable, + force_writable=force_writable, + ) + + +def is_ascii_encoding(encoding): + """Checks if a given encoding is ascii.""" + try: + return codecs.lookup(encoding).name == "ascii" + except LookupError: + return False + + +def get_best_encoding(stream): + """Returns the default stream encoding if not found.""" + rv = getattr(stream, "encoding", None) or sys.getdefaultencoding() + if is_ascii_encoding(rv): + return "utf-8" + return rv + + +class _NonClosingTextIOWrapper(io.TextIOWrapper): + def __init__( + self, + stream, + encoding, + errors, + force_readable=False, + force_writable=False, + **extra + ): + self._stream = stream = _FixupStream(stream, force_readable, force_writable) + io.TextIOWrapper.__init__(self, stream, encoding, errors, **extra) + + # The io module is a place where the Python 3 text behavior + # was forced upon Python 2, so we need to unbreak + # it to look like Python 2. + if PY2: + + def write(self, x): + if isinstance(x, str) or is_bytes(x): + try: + self.flush() + except Exception: + pass + return self.buffer.write(str(x)) + return io.TextIOWrapper.write(self, x) + + def writelines(self, lines): + for line in lines: + self.write(line) + + def __del__(self): + try: + self.detach() + except Exception: + pass + + def isatty(self): + # https://bitbucket.org/pypy/pypy/issue/1803 + return self._stream.isatty() + + +class _FixupStream(object): + """The new io interface needs more from streams than streams + traditionally implement. As such, this fix-up code is necessary in + some circumstances. + + The forcing of readable and writable flags are there because some tools + put badly patched objects on sys (one such offender are certain version + of jupyter notebook). + """ + + def __init__(self, stream, force_readable=False, force_writable=False): + self._stream = stream + self._force_readable = force_readable + self._force_writable = force_writable + + def __getattr__(self, name): + return getattr(self._stream, name) + + def read1(self, size): + f = getattr(self._stream, "read1", None) + if f is not None: + return f(size) + # We only dispatch to readline instead of read in Python 2 as we + # do not want cause problems with the different implementation + # of line buffering. + if PY2: + return self._stream.readline(size) + return self._stream.read(size) + + def readable(self): + if self._force_readable: + return True + x = getattr(self._stream, "readable", None) + if x is not None: + return x() + try: + self._stream.read(0) + except Exception: + return False + return True + + def writable(self): + if self._force_writable: + return True + x = getattr(self._stream, "writable", None) + if x is not None: + return x() + try: + self._stream.write("") + except Exception: + try: + self._stream.write(b"") + except Exception: + return False + return True + + def seekable(self): + x = getattr(self._stream, "seekable", None) + if x is not None: + return x() + try: + self._stream.seek(self._stream.tell()) + except Exception: + return False + return True + + +if PY2: + text_type = unicode + raw_input = raw_input + string_types = (str, unicode) + int_types = (int, long) + iteritems = lambda x: x.iteritems() + range_type = xrange + + def is_bytes(x): + return isinstance(x, (buffer, bytearray)) + + _identifier_re = re.compile(r"^[a-zA-Z_][a-zA-Z0-9_]*$") + + # For Windows, we need to force stdout/stdin/stderr to binary if it's + # fetched for that. This obviously is not the most correct way to do + # it as it changes global state. Unfortunately, there does not seem to + # be a clear better way to do it as just reopening the file in binary + # mode does not change anything. + # + # An option would be to do what Python 3 does and to open the file as + # binary only, patch it back to the system, and then use a wrapper + # stream that converts newlines. It's not quite clear what's the + # correct option here. + # + # This code also lives in _winconsole for the fallback to the console + # emulation stream. + # + # There are also Windows environments where the `msvcrt` module is not + # available (which is why we use try-catch instead of the WIN variable + # here), such as the Google App Engine development server on Windows. In + # those cases there is just nothing we can do. + def set_binary_mode(f): + return f + + try: + import msvcrt + except ImportError: + pass + else: + + def set_binary_mode(f): + try: + fileno = f.fileno() + except Exception: + pass + else: + msvcrt.setmode(fileno, os.O_BINARY) + return f + + try: + import fcntl + except ImportError: + pass + else: + + def set_binary_mode(f): + try: + fileno = f.fileno() + except Exception: + pass + else: + flags = fcntl.fcntl(fileno, fcntl.F_GETFL) + fcntl.fcntl(fileno, fcntl.F_SETFL, flags & ~os.O_NONBLOCK) + return f + + def isidentifier(x): + return _identifier_re.search(x) is not None + + def get_binary_stdin(): + return set_binary_mode(sys.stdin) + + def get_binary_stdout(): + _wrap_std_stream("stdout") + return set_binary_mode(sys.stdout) + + def get_binary_stderr(): + _wrap_std_stream("stderr") + return set_binary_mode(sys.stderr) + + def get_text_stdin(encoding=None, errors=None): + rv = _get_windows_console_stream(sys.stdin, encoding, errors) + if rv is not None: + return rv + return _make_text_stream(sys.stdin, encoding, errors, force_readable=True) + + def get_text_stdout(encoding=None, errors=None): + _wrap_std_stream("stdout") + rv = _get_windows_console_stream(sys.stdout, encoding, errors) + if rv is not None: + return rv + return _make_text_stream(sys.stdout, encoding, errors, force_writable=True) + + def get_text_stderr(encoding=None, errors=None): + _wrap_std_stream("stderr") + rv = _get_windows_console_stream(sys.stderr, encoding, errors) + if rv is not None: + return rv + return _make_text_stream(sys.stderr, encoding, errors, force_writable=True) + + def filename_to_ui(value): + if isinstance(value, bytes): + value = value.decode(get_filesystem_encoding(), "replace") + return value + + +else: + import io + + text_type = str + raw_input = input + string_types = (str,) + int_types = (int,) + range_type = range + isidentifier = lambda x: x.isidentifier() + iteritems = lambda x: iter(x.items()) + + def is_bytes(x): + return isinstance(x, (bytes, memoryview, bytearray)) + + def _is_binary_reader(stream, default=False): + try: + return isinstance(stream.read(0), bytes) + except Exception: + return default + # This happens in some cases where the stream was already + # closed. In this case, we assume the default. + + def _is_binary_writer(stream, default=False): + try: + stream.write(b"") + except Exception: + try: + stream.write("") + return False + except Exception: + pass + return default + return True + + def _find_binary_reader(stream): + # We need to figure out if the given stream is already binary. + # This can happen because the official docs recommend detaching + # the streams to get binary streams. Some code might do this, so + # we need to deal with this case explicitly. + if _is_binary_reader(stream, False): + return stream + + buf = getattr(stream, "buffer", None) + + # Same situation here; this time we assume that the buffer is + # actually binary in case it's closed. + if buf is not None and _is_binary_reader(buf, True): + return buf + + def _find_binary_writer(stream): + # We need to figure out if the given stream is already binary. + # This can happen because the official docs recommend detatching + # the streams to get binary streams. Some code might do this, so + # we need to deal with this case explicitly. + if _is_binary_writer(stream, False): + return stream + + buf = getattr(stream, "buffer", None) + + # Same situation here; this time we assume that the buffer is + # actually binary in case it's closed. + if buf is not None and _is_binary_writer(buf, True): + return buf + + def _stream_is_misconfigured(stream): + """A stream is misconfigured if its encoding is ASCII.""" + # If the stream does not have an encoding set, we assume it's set + # to ASCII. This appears to happen in certain unittest + # environments. It's not quite clear what the correct behavior is + # but this at least will force Click to recover somehow. + return is_ascii_encoding(getattr(stream, "encoding", None) or "ascii") + + def _is_compat_stream_attr(stream, attr, value): + """A stream attribute is compatible if it is equal to the + desired value or the desired value is unset and the attribute + has a value. + """ + stream_value = getattr(stream, attr, None) + return stream_value == value or (value is None and stream_value is not None) + + def _is_compatible_text_stream(stream, encoding, errors): + """Check if a stream's encoding and errors attributes are + compatible with the desired values. + """ + return _is_compat_stream_attr( + stream, "encoding", encoding + ) and _is_compat_stream_attr(stream, "errors", errors) + + def _force_correct_text_stream( + text_stream, + encoding, + errors, + is_binary, + find_binary, + force_readable=False, + force_writable=False, + ): + if is_binary(text_stream, False): + binary_reader = text_stream + else: + # If the stream looks compatible, and won't default to a + # misconfigured ascii encoding, return it as-is. + if _is_compatible_text_stream(text_stream, encoding, errors) and not ( + encoding is None and _stream_is_misconfigured(text_stream) + ): + return text_stream + + # Otherwise, get the underlying binary reader. + binary_reader = find_binary(text_stream) + + # If that's not possible, silently use the original reader + # and get mojibake instead of exceptions. + if binary_reader is None: + return text_stream + + # Default errors to replace instead of strict in order to get + # something that works. + if errors is None: + errors = "replace" + + # Wrap the binary stream in a text stream with the correct + # encoding parameters. + return _make_text_stream( + binary_reader, + encoding, + errors, + force_readable=force_readable, + force_writable=force_writable, + ) + + def _force_correct_text_reader(text_reader, encoding, errors, force_readable=False): + return _force_correct_text_stream( + text_reader, + encoding, + errors, + _is_binary_reader, + _find_binary_reader, + force_readable=force_readable, + ) + + def _force_correct_text_writer(text_writer, encoding, errors, force_writable=False): + return _force_correct_text_stream( + text_writer, + encoding, + errors, + _is_binary_writer, + _find_binary_writer, + force_writable=force_writable, + ) + + def get_binary_stdin(): + reader = _find_binary_reader(sys.stdin) + if reader is None: + raise RuntimeError("Was not able to determine binary stream for sys.stdin.") + return reader + + def get_binary_stdout(): + writer = _find_binary_writer(sys.stdout) + if writer is None: + raise RuntimeError( + "Was not able to determine binary stream for sys.stdout." + ) + return writer + + def get_binary_stderr(): + writer = _find_binary_writer(sys.stderr) + if writer is None: + raise RuntimeError( + "Was not able to determine binary stream for sys.stderr." + ) + return writer + + def get_text_stdin(encoding=None, errors=None): + rv = _get_windows_console_stream(sys.stdin, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_reader( + sys.stdin, encoding, errors, force_readable=True + ) + + def get_text_stdout(encoding=None, errors=None): + rv = _get_windows_console_stream(sys.stdout, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_writer( + sys.stdout, encoding, errors, force_writable=True + ) + + def get_text_stderr(encoding=None, errors=None): + rv = _get_windows_console_stream(sys.stderr, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_writer( + sys.stderr, encoding, errors, force_writable=True + ) + + def filename_to_ui(value): + if isinstance(value, bytes): + value = value.decode(get_filesystem_encoding(), "replace") + else: + value = value.encode("utf-8", "surrogateescape").decode("utf-8", "replace") + return value + + +def get_streerror(e, default=None): + if hasattr(e, "strerror"): + msg = e.strerror + else: + if default is not None: + msg = default + else: + msg = str(e) + if isinstance(msg, bytes): + msg = msg.decode("utf-8", "replace") + return msg + + +def _wrap_io_open(file, mode, encoding, errors): + """On Python 2, :func:`io.open` returns a text file wrapper that + requires passing ``unicode`` to ``write``. Need to open the file in + binary mode then wrap it in a subclass that can write ``str`` and + ``unicode``. + + Also handles not passing ``encoding`` and ``errors`` in binary mode. + """ + binary = "b" in mode + + if binary: + kwargs = {} + else: + kwargs = {"encoding": encoding, "errors": errors} + + if not PY2 or binary: + return io.open(file, mode, **kwargs) + + f = io.open(file, "{}b".format(mode.replace("t", ""))) + return _make_text_stream(f, **kwargs) + + +def open_stream(filename, mode="r", encoding=None, errors="strict", atomic=False): + binary = "b" in mode + + # Standard streams first. These are simple because they don't need + # special handling for the atomic flag. It's entirely ignored. + if filename == "-": + if any(m in mode for m in ["w", "a", "x"]): + if binary: + return get_binary_stdout(), False + return get_text_stdout(encoding=encoding, errors=errors), False + if binary: + return get_binary_stdin(), False + return get_text_stdin(encoding=encoding, errors=errors), False + + # Non-atomic writes directly go out through the regular open functions. + if not atomic: + return _wrap_io_open(filename, mode, encoding, errors), True + + # Some usability stuff for atomic writes + if "a" in mode: + raise ValueError( + "Appending to an existing file is not supported, because that" + " would involve an expensive `copy`-operation to a temporary" + " file. Open the file in normal `w`-mode and copy explicitly" + " if that's what you're after." + ) + if "x" in mode: + raise ValueError("Use the `overwrite`-parameter instead.") + if "w" not in mode: + raise ValueError("Atomic writes only make sense with `w`-mode.") + + # Atomic writes are more complicated. They work by opening a file + # as a proxy in the same folder and then using the fdopen + # functionality to wrap it in a Python file. Then we wrap it in an + # atomic file that moves the file over on close. + import errno + import random + + try: + perm = os.stat(filename).st_mode + except OSError: + perm = None + + flags = os.O_RDWR | os.O_CREAT | os.O_EXCL + + if binary: + flags |= getattr(os, "O_BINARY", 0) + + while True: + tmp_filename = os.path.join( + os.path.dirname(filename), + ".__atomic-write{:08x}".format(random.randrange(1 << 32)), + ) + try: + fd = os.open(tmp_filename, flags, 0o666 if perm is None else perm) + break + except OSError as e: + if e.errno == errno.EEXIST or ( + os.name == "nt" + and e.errno == errno.EACCES + and os.path.isdir(e.filename) + and os.access(e.filename, os.W_OK) + ): + continue + raise + + if perm is not None: + os.chmod(tmp_filename, perm) # in case perm includes bits in umask + + f = _wrap_io_open(fd, mode, encoding, errors) + return _AtomicFile(f, tmp_filename, os.path.realpath(filename)), True + + +# Used in a destructor call, needs extra protection from interpreter cleanup. +if hasattr(os, "replace"): + _replace = os.replace + _can_replace = True +else: + _replace = os.rename + _can_replace = not WIN + + +class _AtomicFile(object): + def __init__(self, f, tmp_filename, real_filename): + self._f = f + self._tmp_filename = tmp_filename + self._real_filename = real_filename + self.closed = False + + @property + def name(self): + return self._real_filename + + def close(self, delete=False): + if self.closed: + return + self._f.close() + if not _can_replace: + try: + os.remove(self._real_filename) + except OSError: + pass + _replace(self._tmp_filename, self._real_filename) + self.closed = True + + def __getattr__(self, name): + return getattr(self._f, name) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, tb): + self.close(delete=exc_type is not None) + + def __repr__(self): + return repr(self._f) + + +auto_wrap_for_ansi = None +colorama = None +get_winterm_size = None + + +def strip_ansi(value): + return _ansi_re.sub("", value) + + +def _is_jupyter_kernel_output(stream): + if WIN: + # TODO: Couldn't test on Windows, should't try to support until + # someone tests the details wrt colorama. + return + + while isinstance(stream, (_FixupStream, _NonClosingTextIOWrapper)): + stream = stream._stream + + return stream.__class__.__module__.startswith("ipykernel.") + + +def should_strip_ansi(stream=None, color=None): + if color is None: + if stream is None: + stream = sys.stdin + return not isatty(stream) and not _is_jupyter_kernel_output(stream) + return not color + + +# If we're on Windows, we provide transparent integration through +# colorama. This will make ANSI colors through the echo function +# work automatically. +if WIN: + # Windows has a smaller terminal + DEFAULT_COLUMNS = 79 + + from ._winconsole import _get_windows_console_stream, _wrap_std_stream + + def _get_argv_encoding(): + import locale + + return locale.getpreferredencoding() + + if PY2: + + def raw_input(prompt=""): + sys.stderr.flush() + if prompt: + stdout = _default_text_stdout() + stdout.write(prompt) + stdin = _default_text_stdin() + return stdin.readline().rstrip("\r\n") + + try: + import colorama + except ImportError: + pass + else: + _ansi_stream_wrappers = WeakKeyDictionary() + + def auto_wrap_for_ansi(stream, color=None): + """This function wraps a stream so that calls through colorama + are issued to the win32 console API to recolor on demand. It + also ensures to reset the colors if a write call is interrupted + to not destroy the console afterwards. + """ + try: + cached = _ansi_stream_wrappers.get(stream) + except Exception: + cached = None + if cached is not None: + return cached + strip = should_strip_ansi(stream, color) + ansi_wrapper = colorama.AnsiToWin32(stream, strip=strip) + rv = ansi_wrapper.stream + _write = rv.write + + def _safe_write(s): + try: + return _write(s) + except: + ansi_wrapper.reset_all() + raise + + rv.write = _safe_write + try: + _ansi_stream_wrappers[stream] = rv + except Exception: + pass + return rv + + def get_winterm_size(): + win = colorama.win32.GetConsoleScreenBufferInfo( + colorama.win32.STDOUT + ).srWindow + return win.Right - win.Left, win.Bottom - win.Top + + +else: + + def _get_argv_encoding(): + return getattr(sys.stdin, "encoding", None) or get_filesystem_encoding() + + _get_windows_console_stream = lambda *x: None + _wrap_std_stream = lambda *x: None + + +def term_len(x): + return len(strip_ansi(x)) + + +def isatty(stream): + try: + return stream.isatty() + except Exception: + return False + + +def _make_cached_stream_func(src_func, wrapper_func): + cache = WeakKeyDictionary() + + def func(): + stream = src_func() + try: + rv = cache.get(stream) + except Exception: + rv = None + if rv is not None: + return rv + rv = wrapper_func() + try: + stream = src_func() # In case wrapper_func() modified the stream + cache[stream] = rv + except Exception: + pass + return rv + + return func + + +_default_text_stdin = _make_cached_stream_func(lambda: sys.stdin, get_text_stdin) +_default_text_stdout = _make_cached_stream_func(lambda: sys.stdout, get_text_stdout) +_default_text_stderr = _make_cached_stream_func(lambda: sys.stderr, get_text_stderr) + + +binary_streams = { + "stdin": get_binary_stdin, + "stdout": get_binary_stdout, + "stderr": get_binary_stderr, +} + +text_streams = { + "stdin": get_text_stdin, + "stdout": get_text_stdout, + "stderr": get_text_stderr, +} diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/_termui_impl.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/_termui_impl.py new file mode 100644 index 0000000..88bec37 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/_termui_impl.py @@ -0,0 +1,657 @@ +# -*- coding: utf-8 -*- +""" +This module contains implementations for the termui module. To keep the +import time of Click down, some infrequently used functionality is +placed in this module and only imported as needed. +""" +import contextlib +import math +import os +import sys +import time + +from ._compat import _default_text_stdout +from ._compat import CYGWIN +from ._compat import get_best_encoding +from ._compat import int_types +from ._compat import isatty +from ._compat import open_stream +from ._compat import range_type +from ._compat import strip_ansi +from ._compat import term_len +from ._compat import WIN +from .exceptions import ClickException +from .utils import echo + +if os.name == "nt": + BEFORE_BAR = "\r" + AFTER_BAR = "\n" +else: + BEFORE_BAR = "\r\033[?25l" + AFTER_BAR = "\033[?25h\n" + + +def _length_hint(obj): + """Returns the length hint of an object.""" + try: + return len(obj) + except (AttributeError, TypeError): + try: + get_hint = type(obj).__length_hint__ + except AttributeError: + return None + try: + hint = get_hint(obj) + except TypeError: + return None + if hint is NotImplemented or not isinstance(hint, int_types) or hint < 0: + return None + return hint + + +class ProgressBar(object): + def __init__( + self, + iterable, + length=None, + fill_char="#", + empty_char=" ", + bar_template="%(bar)s", + info_sep=" ", + show_eta=True, + show_percent=None, + show_pos=False, + item_show_func=None, + label=None, + file=None, + color=None, + width=30, + ): + self.fill_char = fill_char + self.empty_char = empty_char + self.bar_template = bar_template + self.info_sep = info_sep + self.show_eta = show_eta + self.show_percent = show_percent + self.show_pos = show_pos + self.item_show_func = item_show_func + self.label = label or "" + if file is None: + file = _default_text_stdout() + self.file = file + self.color = color + self.width = width + self.autowidth = width == 0 + + if length is None: + length = _length_hint(iterable) + if iterable is None: + if length is None: + raise TypeError("iterable or length is required") + iterable = range_type(length) + self.iter = iter(iterable) + self.length = length + self.length_known = length is not None + self.pos = 0 + self.avg = [] + self.start = self.last_eta = time.time() + self.eta_known = False + self.finished = False + self.max_width = None + self.entered = False + self.current_item = None + self.is_hidden = not isatty(self.file) + self._last_line = None + self.short_limit = 0.5 + + def __enter__(self): + self.entered = True + self.render_progress() + return self + + def __exit__(self, exc_type, exc_value, tb): + self.render_finish() + + def __iter__(self): + if not self.entered: + raise RuntimeError("You need to use progress bars in a with block.") + self.render_progress() + return self.generator() + + def __next__(self): + # Iteration is defined in terms of a generator function, + # returned by iter(self); use that to define next(). This works + # because `self.iter` is an iterable consumed by that generator, + # so it is re-entry safe. Calling `next(self.generator())` + # twice works and does "what you want". + return next(iter(self)) + + # Python 2 compat + next = __next__ + + def is_fast(self): + return time.time() - self.start <= self.short_limit + + def render_finish(self): + if self.is_hidden or self.is_fast(): + return + self.file.write(AFTER_BAR) + self.file.flush() + + @property + def pct(self): + if self.finished: + return 1.0 + return min(self.pos / (float(self.length) or 1), 1.0) + + @property + def time_per_iteration(self): + if not self.avg: + return 0.0 + return sum(self.avg) / float(len(self.avg)) + + @property + def eta(self): + if self.length_known and not self.finished: + return self.time_per_iteration * (self.length - self.pos) + return 0.0 + + def format_eta(self): + if self.eta_known: + t = int(self.eta) + seconds = t % 60 + t //= 60 + minutes = t % 60 + t //= 60 + hours = t % 24 + t //= 24 + if t > 0: + return "{}d {:02}:{:02}:{:02}".format(t, hours, minutes, seconds) + else: + return "{:02}:{:02}:{:02}".format(hours, minutes, seconds) + return "" + + def format_pos(self): + pos = str(self.pos) + if self.length_known: + pos += "/{}".format(self.length) + return pos + + def format_pct(self): + return "{: 4}%".format(int(self.pct * 100))[1:] + + def format_bar(self): + if self.length_known: + bar_length = int(self.pct * self.width) + bar = self.fill_char * bar_length + bar += self.empty_char * (self.width - bar_length) + elif self.finished: + bar = self.fill_char * self.width + else: + bar = list(self.empty_char * (self.width or 1)) + if self.time_per_iteration != 0: + bar[ + int( + (math.cos(self.pos * self.time_per_iteration) / 2.0 + 0.5) + * self.width + ) + ] = self.fill_char + bar = "".join(bar) + return bar + + def format_progress_line(self): + show_percent = self.show_percent + + info_bits = [] + if self.length_known and show_percent is None: + show_percent = not self.show_pos + + if self.show_pos: + info_bits.append(self.format_pos()) + if show_percent: + info_bits.append(self.format_pct()) + if self.show_eta and self.eta_known and not self.finished: + info_bits.append(self.format_eta()) + if self.item_show_func is not None: + item_info = self.item_show_func(self.current_item) + if item_info is not None: + info_bits.append(item_info) + + return ( + self.bar_template + % { + "label": self.label, + "bar": self.format_bar(), + "info": self.info_sep.join(info_bits), + } + ).rstrip() + + def render_progress(self): + from .termui import get_terminal_size + + if self.is_hidden: + return + + buf = [] + # Update width in case the terminal has been resized + if self.autowidth: + old_width = self.width + self.width = 0 + clutter_length = term_len(self.format_progress_line()) + new_width = max(0, get_terminal_size()[0] - clutter_length) + if new_width < old_width: + buf.append(BEFORE_BAR) + buf.append(" " * self.max_width) + self.max_width = new_width + self.width = new_width + + clear_width = self.width + if self.max_width is not None: + clear_width = self.max_width + + buf.append(BEFORE_BAR) + line = self.format_progress_line() + line_len = term_len(line) + if self.max_width is None or self.max_width < line_len: + self.max_width = line_len + + buf.append(line) + buf.append(" " * (clear_width - line_len)) + line = "".join(buf) + # Render the line only if it changed. + + if line != self._last_line and not self.is_fast(): + self._last_line = line + echo(line, file=self.file, color=self.color, nl=False) + self.file.flush() + + def make_step(self, n_steps): + self.pos += n_steps + if self.length_known and self.pos >= self.length: + self.finished = True + + if (time.time() - self.last_eta) < 1.0: + return + + self.last_eta = time.time() + + # self.avg is a rolling list of length <= 7 of steps where steps are + # defined as time elapsed divided by the total progress through + # self.length. + if self.pos: + step = (time.time() - self.start) / self.pos + else: + step = time.time() - self.start + + self.avg = self.avg[-6:] + [step] + + self.eta_known = self.length_known + + def update(self, n_steps): + self.make_step(n_steps) + self.render_progress() + + def finish(self): + self.eta_known = 0 + self.current_item = None + self.finished = True + + def generator(self): + """Return a generator which yields the items added to the bar + during construction, and updates the progress bar *after* the + yielded block returns. + """ + # WARNING: the iterator interface for `ProgressBar` relies on + # this and only works because this is a simple generator which + # doesn't create or manage additional state. If this function + # changes, the impact should be evaluated both against + # `iter(bar)` and `next(bar)`. `next()` in particular may call + # `self.generator()` repeatedly, and this must remain safe in + # order for that interface to work. + if not self.entered: + raise RuntimeError("You need to use progress bars in a with block.") + + if self.is_hidden: + for rv in self.iter: + yield rv + else: + for rv in self.iter: + self.current_item = rv + yield rv + self.update(1) + self.finish() + self.render_progress() + + +def pager(generator, color=None): + """Decide what method to use for paging through text.""" + stdout = _default_text_stdout() + if not isatty(sys.stdin) or not isatty(stdout): + return _nullpager(stdout, generator, color) + pager_cmd = (os.environ.get("PAGER", None) or "").strip() + if pager_cmd: + if WIN: + return _tempfilepager(generator, pager_cmd, color) + return _pipepager(generator, pager_cmd, color) + if os.environ.get("TERM") in ("dumb", "emacs"): + return _nullpager(stdout, generator, color) + if WIN or sys.platform.startswith("os2"): + return _tempfilepager(generator, "more <", color) + if hasattr(os, "system") and os.system("(less) 2>/dev/null") == 0: + return _pipepager(generator, "less", color) + + import tempfile + + fd, filename = tempfile.mkstemp() + os.close(fd) + try: + if hasattr(os, "system") and os.system('more "{}"'.format(filename)) == 0: + return _pipepager(generator, "more", color) + return _nullpager(stdout, generator, color) + finally: + os.unlink(filename) + + +def _pipepager(generator, cmd, color): + """Page through text by feeding it to another program. Invoking a + pager through this might support colors. + """ + import subprocess + + env = dict(os.environ) + + # If we're piping to less we might support colors under the + # condition that + cmd_detail = cmd.rsplit("/", 1)[-1].split() + if color is None and cmd_detail[0] == "less": + less_flags = "{}{}".format(os.environ.get("LESS", ""), " ".join(cmd_detail[1:])) + if not less_flags: + env["LESS"] = "-R" + color = True + elif "r" in less_flags or "R" in less_flags: + color = True + + c = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, env=env) + encoding = get_best_encoding(c.stdin) + try: + for text in generator: + if not color: + text = strip_ansi(text) + + c.stdin.write(text.encode(encoding, "replace")) + except (IOError, KeyboardInterrupt): + pass + else: + c.stdin.close() + + # Less doesn't respect ^C, but catches it for its own UI purposes (aborting + # search or other commands inside less). + # + # That means when the user hits ^C, the parent process (click) terminates, + # but less is still alive, paging the output and messing up the terminal. + # + # If the user wants to make the pager exit on ^C, they should set + # `LESS='-K'`. It's not our decision to make. + while True: + try: + c.wait() + except KeyboardInterrupt: + pass + else: + break + + +def _tempfilepager(generator, cmd, color): + """Page through text by invoking a program on a temporary file.""" + import tempfile + + filename = tempfile.mktemp() + # TODO: This never terminates if the passed generator never terminates. + text = "".join(generator) + if not color: + text = strip_ansi(text) + encoding = get_best_encoding(sys.stdout) + with open_stream(filename, "wb")[0] as f: + f.write(text.encode(encoding)) + try: + os.system('{} "{}"'.format(cmd, filename)) + finally: + os.unlink(filename) + + +def _nullpager(stream, generator, color): + """Simply print unformatted text. This is the ultimate fallback.""" + for text in generator: + if not color: + text = strip_ansi(text) + stream.write(text) + + +class Editor(object): + def __init__(self, editor=None, env=None, require_save=True, extension=".txt"): + self.editor = editor + self.env = env + self.require_save = require_save + self.extension = extension + + def get_editor(self): + if self.editor is not None: + return self.editor + for key in "VISUAL", "EDITOR": + rv = os.environ.get(key) + if rv: + return rv + if WIN: + return "notepad" + for editor in "sensible-editor", "vim", "nano": + if os.system("which {} >/dev/null 2>&1".format(editor)) == 0: + return editor + return "vi" + + def edit_file(self, filename): + import subprocess + + editor = self.get_editor() + if self.env: + environ = os.environ.copy() + environ.update(self.env) + else: + environ = None + try: + c = subprocess.Popen( + '{} "{}"'.format(editor, filename), env=environ, shell=True, + ) + exit_code = c.wait() + if exit_code != 0: + raise ClickException("{}: Editing failed!".format(editor)) + except OSError as e: + raise ClickException("{}: Editing failed: {}".format(editor, e)) + + def edit(self, text): + import tempfile + + text = text or "" + if text and not text.endswith("\n"): + text += "\n" + + fd, name = tempfile.mkstemp(prefix="editor-", suffix=self.extension) + try: + if WIN: + encoding = "utf-8-sig" + text = text.replace("\n", "\r\n") + else: + encoding = "utf-8" + text = text.encode(encoding) + + f = os.fdopen(fd, "wb") + f.write(text) + f.close() + timestamp = os.path.getmtime(name) + + self.edit_file(name) + + if self.require_save and os.path.getmtime(name) == timestamp: + return None + + f = open(name, "rb") + try: + rv = f.read() + finally: + f.close() + return rv.decode("utf-8-sig").replace("\r\n", "\n") + finally: + os.unlink(name) + + +def open_url(url, wait=False, locate=False): + import subprocess + + def _unquote_file(url): + try: + import urllib + except ImportError: + import urllib + if url.startswith("file://"): + url = urllib.unquote(url[7:]) + return url + + if sys.platform == "darwin": + args = ["open"] + if wait: + args.append("-W") + if locate: + args.append("-R") + args.append(_unquote_file(url)) + null = open("/dev/null", "w") + try: + return subprocess.Popen(args, stderr=null).wait() + finally: + null.close() + elif WIN: + if locate: + url = _unquote_file(url) + args = 'explorer /select,"{}"'.format(_unquote_file(url.replace('"', ""))) + else: + args = 'start {} "" "{}"'.format( + "/WAIT" if wait else "", url.replace('"', "") + ) + return os.system(args) + elif CYGWIN: + if locate: + url = _unquote_file(url) + args = 'cygstart "{}"'.format(os.path.dirname(url).replace('"', "")) + else: + args = 'cygstart {} "{}"'.format("-w" if wait else "", url.replace('"', "")) + return os.system(args) + + try: + if locate: + url = os.path.dirname(_unquote_file(url)) or "." + else: + url = _unquote_file(url) + c = subprocess.Popen(["xdg-open", url]) + if wait: + return c.wait() + return 0 + except OSError: + if url.startswith(("http://", "https://")) and not locate and not wait: + import webbrowser + + webbrowser.open(url) + return 0 + return 1 + + +def _translate_ch_to_exc(ch): + if ch == u"\x03": + raise KeyboardInterrupt() + if ch == u"\x04" and not WIN: # Unix-like, Ctrl+D + raise EOFError() + if ch == u"\x1a" and WIN: # Windows, Ctrl+Z + raise EOFError() + + +if WIN: + import msvcrt + + @contextlib.contextmanager + def raw_terminal(): + yield + + def getchar(echo): + # The function `getch` will return a bytes object corresponding to + # the pressed character. Since Windows 10 build 1803, it will also + # return \x00 when called a second time after pressing a regular key. + # + # `getwch` does not share this probably-bugged behavior. Moreover, it + # returns a Unicode object by default, which is what we want. + # + # Either of these functions will return \x00 or \xe0 to indicate + # a special key, and you need to call the same function again to get + # the "rest" of the code. The fun part is that \u00e0 is + # "latin small letter a with grave", so if you type that on a French + # keyboard, you _also_ get a \xe0. + # E.g., consider the Up arrow. This returns \xe0 and then \x48. The + # resulting Unicode string reads as "a with grave" + "capital H". + # This is indistinguishable from when the user actually types + # "a with grave" and then "capital H". + # + # When \xe0 is returned, we assume it's part of a special-key sequence + # and call `getwch` again, but that means that when the user types + # the \u00e0 character, `getchar` doesn't return until a second + # character is typed. + # The alternative is returning immediately, but that would mess up + # cross-platform handling of arrow keys and others that start with + # \xe0. Another option is using `getch`, but then we can't reliably + # read non-ASCII characters, because return values of `getch` are + # limited to the current 8-bit codepage. + # + # Anyway, Click doesn't claim to do this Right(tm), and using `getwch` + # is doing the right thing in more situations than with `getch`. + if echo: + func = msvcrt.getwche + else: + func = msvcrt.getwch + + rv = func() + if rv in (u"\x00", u"\xe0"): + # \x00 and \xe0 are control characters that indicate special key, + # see above. + rv += func() + _translate_ch_to_exc(rv) + return rv + + +else: + import tty + import termios + + @contextlib.contextmanager + def raw_terminal(): + if not isatty(sys.stdin): + f = open("/dev/tty") + fd = f.fileno() + else: + fd = sys.stdin.fileno() + f = None + try: + old_settings = termios.tcgetattr(fd) + try: + tty.setraw(fd) + yield fd + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + sys.stdout.flush() + if f is not None: + f.close() + except termios.error: + pass + + def getchar(echo): + with raw_terminal() as fd: + ch = os.read(fd, 32) + ch = ch.decode(get_best_encoding(sys.stdin), "replace") + if echo and isatty(sys.stdout): + sys.stdout.write(ch) + _translate_ch_to_exc(ch) + return ch diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/_textwrap.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/_textwrap.py new file mode 100644 index 0000000..6959087 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/_textwrap.py @@ -0,0 +1,37 @@ +import textwrap +from contextlib import contextmanager + + +class TextWrapper(textwrap.TextWrapper): + def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width): + space_left = max(width - cur_len, 1) + + if self.break_long_words: + last = reversed_chunks[-1] + cut = last[:space_left] + res = last[space_left:] + cur_line.append(cut) + reversed_chunks[-1] = res + elif not cur_line: + cur_line.append(reversed_chunks.pop()) + + @contextmanager + def extra_indent(self, indent): + old_initial_indent = self.initial_indent + old_subsequent_indent = self.subsequent_indent + self.initial_indent += indent + self.subsequent_indent += indent + try: + yield + finally: + self.initial_indent = old_initial_indent + self.subsequent_indent = old_subsequent_indent + + def indent_only(self, text): + rv = [] + for idx, line in enumerate(text.splitlines()): + indent = self.initial_indent + if idx > 0: + indent = self.subsequent_indent + rv.append(indent + line) + return "\n".join(rv) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/_unicodefun.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/_unicodefun.py new file mode 100644 index 0000000..781c365 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/_unicodefun.py @@ -0,0 +1,131 @@ +import codecs +import os +import sys + +from ._compat import PY2 + + +def _find_unicode_literals_frame(): + import __future__ + + if not hasattr(sys, "_getframe"): # not all Python implementations have it + return 0 + frm = sys._getframe(1) + idx = 1 + while frm is not None: + if frm.f_globals.get("__name__", "").startswith("click."): + frm = frm.f_back + idx += 1 + elif frm.f_code.co_flags & __future__.unicode_literals.compiler_flag: + return idx + else: + break + return 0 + + +def _check_for_unicode_literals(): + if not __debug__: + return + + from . import disable_unicode_literals_warning + + if not PY2 or disable_unicode_literals_warning: + return + bad_frame = _find_unicode_literals_frame() + if bad_frame <= 0: + return + from warnings import warn + + warn( + Warning( + "Click detected the use of the unicode_literals __future__" + " import. This is heavily discouraged because it can" + " introduce subtle bugs in your code. You should instead" + ' use explicit u"" literals for your unicode strings. For' + " more information see" + " https://click.palletsprojects.com/python3/" + ), + stacklevel=bad_frame, + ) + + +def _verify_python3_env(): + """Ensures that the environment is good for unicode on Python 3.""" + if PY2: + return + try: + import locale + + fs_enc = codecs.lookup(locale.getpreferredencoding()).name + except Exception: + fs_enc = "ascii" + if fs_enc != "ascii": + return + + extra = "" + if os.name == "posix": + import subprocess + + try: + rv = subprocess.Popen( + ["locale", "-a"], stdout=subprocess.PIPE, stderr=subprocess.PIPE + ).communicate()[0] + except OSError: + rv = b"" + good_locales = set() + has_c_utf8 = False + + # Make sure we're operating on text here. + if isinstance(rv, bytes): + rv = rv.decode("ascii", "replace") + + for line in rv.splitlines(): + locale = line.strip() + if locale.lower().endswith((".utf-8", ".utf8")): + good_locales.add(locale) + if locale.lower() in ("c.utf8", "c.utf-8"): + has_c_utf8 = True + + extra += "\n\n" + if not good_locales: + extra += ( + "Additional information: on this system no suitable" + " UTF-8 locales were discovered. This most likely" + " requires resolving by reconfiguring the locale" + " system." + ) + elif has_c_utf8: + extra += ( + "This system supports the C.UTF-8 locale which is" + " recommended. You might be able to resolve your issue" + " by exporting the following environment variables:\n\n" + " export LC_ALL=C.UTF-8\n" + " export LANG=C.UTF-8" + ) + else: + extra += ( + "This system lists a couple of UTF-8 supporting locales" + " that you can pick from. The following suitable" + " locales were discovered: {}".format(", ".join(sorted(good_locales))) + ) + + bad_locale = None + for locale in os.environ.get("LC_ALL"), os.environ.get("LANG"): + if locale and locale.lower().endswith((".utf-8", ".utf8")): + bad_locale = locale + if locale is not None: + break + if bad_locale is not None: + extra += ( + "\n\nClick discovered that you exported a UTF-8 locale" + " but the locale system could not pick up from it" + " because it does not exist. The exported locale is" + " '{}' but it is not supported".format(bad_locale) + ) + + raise RuntimeError( + "Click will abort further execution because Python 3 was" + " configured to use ASCII as encoding for the environment." + " Consult https://click.palletsprojects.com/python3/ for" + " mitigation steps.{}".format(extra) + ) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/_winconsole.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/_winconsole.py new file mode 100644 index 0000000..b6c4274 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/_winconsole.py @@ -0,0 +1,370 @@ +# -*- coding: utf-8 -*- +# This module is based on the excellent work by Adam Bartoš who +# provided a lot of what went into the implementation here in +# the discussion to issue1602 in the Python bug tracker. +# +# There are some general differences in regards to how this works +# compared to the original patches as we do not need to patch +# the entire interpreter but just work in our little world of +# echo and prmopt. +import ctypes +import io +import os +import sys +import time +import zlib +from ctypes import byref +from ctypes import c_char +from ctypes import c_char_p +from ctypes import c_int +from ctypes import c_ssize_t +from ctypes import c_ulong +from ctypes import c_void_p +from ctypes import POINTER +from ctypes import py_object +from ctypes import windll +from ctypes import WinError +from ctypes import WINFUNCTYPE +from ctypes.wintypes import DWORD +from ctypes.wintypes import HANDLE +from ctypes.wintypes import LPCWSTR +from ctypes.wintypes import LPWSTR + +import msvcrt + +from ._compat import _NonClosingTextIOWrapper +from ._compat import PY2 +from ._compat import text_type + +try: + from ctypes import pythonapi + + PyObject_GetBuffer = pythonapi.PyObject_GetBuffer + PyBuffer_Release = pythonapi.PyBuffer_Release +except ImportError: + pythonapi = None + + +c_ssize_p = POINTER(c_ssize_t) + +kernel32 = windll.kernel32 +GetStdHandle = kernel32.GetStdHandle +ReadConsoleW = kernel32.ReadConsoleW +WriteConsoleW = kernel32.WriteConsoleW +GetConsoleMode = kernel32.GetConsoleMode +GetLastError = kernel32.GetLastError +GetCommandLineW = WINFUNCTYPE(LPWSTR)(("GetCommandLineW", windll.kernel32)) +CommandLineToArgvW = WINFUNCTYPE(POINTER(LPWSTR), LPCWSTR, POINTER(c_int))( + ("CommandLineToArgvW", windll.shell32) +) +LocalFree = WINFUNCTYPE(ctypes.c_void_p, ctypes.c_void_p)( + ("LocalFree", windll.kernel32) +) + + +STDIN_HANDLE = GetStdHandle(-10) +STDOUT_HANDLE = GetStdHandle(-11) +STDERR_HANDLE = GetStdHandle(-12) + + +PyBUF_SIMPLE = 0 +PyBUF_WRITABLE = 1 + +ERROR_SUCCESS = 0 +ERROR_NOT_ENOUGH_MEMORY = 8 +ERROR_OPERATION_ABORTED = 995 + +STDIN_FILENO = 0 +STDOUT_FILENO = 1 +STDERR_FILENO = 2 + +EOF = b"\x1a" +MAX_BYTES_WRITTEN = 32767 + + +class Py_buffer(ctypes.Structure): + _fields_ = [ + ("buf", c_void_p), + ("obj", py_object), + ("len", c_ssize_t), + ("itemsize", c_ssize_t), + ("readonly", c_int), + ("ndim", c_int), + ("format", c_char_p), + ("shape", c_ssize_p), + ("strides", c_ssize_p), + ("suboffsets", c_ssize_p), + ("internal", c_void_p), + ] + + if PY2: + _fields_.insert(-1, ("smalltable", c_ssize_t * 2)) + + +# On PyPy we cannot get buffers so our ability to operate here is +# serverly limited. +if pythonapi is None: + get_buffer = None +else: + + def get_buffer(obj, writable=False): + buf = Py_buffer() + flags = PyBUF_WRITABLE if writable else PyBUF_SIMPLE + PyObject_GetBuffer(py_object(obj), byref(buf), flags) + try: + buffer_type = c_char * buf.len + return buffer_type.from_address(buf.buf) + finally: + PyBuffer_Release(byref(buf)) + + +class _WindowsConsoleRawIOBase(io.RawIOBase): + def __init__(self, handle): + self.handle = handle + + def isatty(self): + io.RawIOBase.isatty(self) + return True + + +class _WindowsConsoleReader(_WindowsConsoleRawIOBase): + def readable(self): + return True + + def readinto(self, b): + bytes_to_be_read = len(b) + if not bytes_to_be_read: + return 0 + elif bytes_to_be_read % 2: + raise ValueError( + "cannot read odd number of bytes from UTF-16-LE encoded console" + ) + + buffer = get_buffer(b, writable=True) + code_units_to_be_read = bytes_to_be_read // 2 + code_units_read = c_ulong() + + rv = ReadConsoleW( + HANDLE(self.handle), + buffer, + code_units_to_be_read, + byref(code_units_read), + None, + ) + if GetLastError() == ERROR_OPERATION_ABORTED: + # wait for KeyboardInterrupt + time.sleep(0.1) + if not rv: + raise OSError("Windows error: {}".format(GetLastError())) + + if buffer[0] == EOF: + return 0 + return 2 * code_units_read.value + + +class _WindowsConsoleWriter(_WindowsConsoleRawIOBase): + def writable(self): + return True + + @staticmethod + def _get_error_message(errno): + if errno == ERROR_SUCCESS: + return "ERROR_SUCCESS" + elif errno == ERROR_NOT_ENOUGH_MEMORY: + return "ERROR_NOT_ENOUGH_MEMORY" + return "Windows error {}".format(errno) + + def write(self, b): + bytes_to_be_written = len(b) + buf = get_buffer(b) + code_units_to_be_written = min(bytes_to_be_written, MAX_BYTES_WRITTEN) // 2 + code_units_written = c_ulong() + + WriteConsoleW( + HANDLE(self.handle), + buf, + code_units_to_be_written, + byref(code_units_written), + None, + ) + bytes_written = 2 * code_units_written.value + + if bytes_written == 0 and bytes_to_be_written > 0: + raise OSError(self._get_error_message(GetLastError())) + return bytes_written + + +class ConsoleStream(object): + def __init__(self, text_stream, byte_stream): + self._text_stream = text_stream + self.buffer = byte_stream + + @property + def name(self): + return self.buffer.name + + def write(self, x): + if isinstance(x, text_type): + return self._text_stream.write(x) + try: + self.flush() + except Exception: + pass + return self.buffer.write(x) + + def writelines(self, lines): + for line in lines: + self.write(line) + + def __getattr__(self, name): + return getattr(self._text_stream, name) + + def isatty(self): + return self.buffer.isatty() + + def __repr__(self): + return "".format( + self.name, self.encoding + ) + + +class WindowsChunkedWriter(object): + """ + Wraps a stream (such as stdout), acting as a transparent proxy for all + attribute access apart from method 'write()' which we wrap to write in + limited chunks due to a Windows limitation on binary console streams. + """ + + def __init__(self, wrapped): + # double-underscore everything to prevent clashes with names of + # attributes on the wrapped stream object. + self.__wrapped = wrapped + + def __getattr__(self, name): + return getattr(self.__wrapped, name) + + def write(self, text): + total_to_write = len(text) + written = 0 + + while written < total_to_write: + to_write = min(total_to_write - written, MAX_BYTES_WRITTEN) + self.__wrapped.write(text[written : written + to_write]) + written += to_write + + +_wrapped_std_streams = set() + + +def _wrap_std_stream(name): + # Python 2 & Windows 7 and below + if ( + PY2 + and sys.getwindowsversion()[:2] <= (6, 1) + and name not in _wrapped_std_streams + ): + setattr(sys, name, WindowsChunkedWriter(getattr(sys, name))) + _wrapped_std_streams.add(name) + + +def _get_text_stdin(buffer_stream): + text_stream = _NonClosingTextIOWrapper( + io.BufferedReader(_WindowsConsoleReader(STDIN_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return ConsoleStream(text_stream, buffer_stream) + + +def _get_text_stdout(buffer_stream): + text_stream = _NonClosingTextIOWrapper( + io.BufferedWriter(_WindowsConsoleWriter(STDOUT_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return ConsoleStream(text_stream, buffer_stream) + + +def _get_text_stderr(buffer_stream): + text_stream = _NonClosingTextIOWrapper( + io.BufferedWriter(_WindowsConsoleWriter(STDERR_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return ConsoleStream(text_stream, buffer_stream) + + +if PY2: + + def _hash_py_argv(): + return zlib.crc32("\x00".join(sys.argv[1:])) + + _initial_argv_hash = _hash_py_argv() + + def _get_windows_argv(): + argc = c_int(0) + argv_unicode = CommandLineToArgvW(GetCommandLineW(), byref(argc)) + if not argv_unicode: + raise WinError() + try: + argv = [argv_unicode[i] for i in range(0, argc.value)] + finally: + LocalFree(argv_unicode) + del argv_unicode + + if not hasattr(sys, "frozen"): + argv = argv[1:] + while len(argv) > 0: + arg = argv[0] + if not arg.startswith("-") or arg == "-": + break + argv = argv[1:] + if arg.startswith(("-c", "-m")): + break + + return argv[1:] + + +_stream_factories = { + 0: _get_text_stdin, + 1: _get_text_stdout, + 2: _get_text_stderr, +} + + +def _is_console(f): + if not hasattr(f, "fileno"): + return False + + try: + fileno = f.fileno() + except OSError: + return False + + handle = msvcrt.get_osfhandle(fileno) + return bool(GetConsoleMode(handle, byref(DWORD()))) + + +def _get_windows_console_stream(f, encoding, errors): + if ( + get_buffer is not None + and encoding in ("utf-16-le", None) + and errors in ("strict", None) + and _is_console(f) + ): + func = _stream_factories.get(f.fileno()) + if func is not None: + if not PY2: + f = getattr(f, "buffer", None) + if f is None: + return None + else: + # If we are on Python 2 we need to set the stream that we + # deal with to binary mode as otherwise the exercise if a + # bit moot. The same problems apply as for + # get_binary_stdin and friends from _compat. + msvcrt.setmode(f.fileno(), os.O_BINARY) + return func(f) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/core.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/core.py new file mode 100644 index 0000000..f58bf26 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/core.py @@ -0,0 +1,2030 @@ +import errno +import inspect +import os +import sys +from contextlib import contextmanager +from functools import update_wrapper +from itertools import repeat + +from ._compat import isidentifier +from ._compat import iteritems +from ._compat import PY2 +from ._compat import string_types +from ._unicodefun import _check_for_unicode_literals +from ._unicodefun import _verify_python3_env +from .exceptions import Abort +from .exceptions import BadParameter +from .exceptions import ClickException +from .exceptions import Exit +from .exceptions import MissingParameter +from .exceptions import UsageError +from .formatting import HelpFormatter +from .formatting import join_options +from .globals import pop_context +from .globals import push_context +from .parser import OptionParser +from .parser import split_opt +from .termui import confirm +from .termui import prompt +from .termui import style +from .types import BOOL +from .types import convert_type +from .types import IntRange +from .utils import echo +from .utils import get_os_args +from .utils import make_default_short_help +from .utils import make_str +from .utils import PacifyFlushWrapper + +_missing = object() + +SUBCOMMAND_METAVAR = "COMMAND [ARGS]..." +SUBCOMMANDS_METAVAR = "COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]..." + +DEPRECATED_HELP_NOTICE = " (DEPRECATED)" +DEPRECATED_INVOKE_NOTICE = "DeprecationWarning: The command %(name)s is deprecated." + + +def _maybe_show_deprecated_notice(cmd): + if cmd.deprecated: + echo(style(DEPRECATED_INVOKE_NOTICE % {"name": cmd.name}, fg="red"), err=True) + + +def fast_exit(code): + """Exit without garbage collection, this speeds up exit by about 10ms for + things like bash completion. + """ + sys.stdout.flush() + sys.stderr.flush() + os._exit(code) + + +def _bashcomplete(cmd, prog_name, complete_var=None): + """Internal handler for the bash completion support.""" + if complete_var is None: + complete_var = "_{}_COMPLETE".format(prog_name.replace("-", "_").upper()) + complete_instr = os.environ.get(complete_var) + if not complete_instr: + return + + from ._bashcomplete import bashcomplete + + if bashcomplete(cmd, prog_name, complete_var, complete_instr): + fast_exit(1) + + +def _check_multicommand(base_command, cmd_name, cmd, register=False): + if not base_command.chain or not isinstance(cmd, MultiCommand): + return + if register: + hint = ( + "It is not possible to add multi commands as children to" + " another multi command that is in chain mode." + ) + else: + hint = ( + "Found a multi command as subcommand to a multi command" + " that is in chain mode. This is not supported." + ) + raise RuntimeError( + "{}. Command '{}' is set to chain and '{}' was added as" + " subcommand but it in itself is a multi command. ('{}' is a {}" + " within a chained {} named '{}').".format( + hint, + base_command.name, + cmd_name, + cmd_name, + cmd.__class__.__name__, + base_command.__class__.__name__, + base_command.name, + ) + ) + + +def batch(iterable, batch_size): + return list(zip(*repeat(iter(iterable), batch_size))) + + +def invoke_param_callback(callback, ctx, param, value): + code = getattr(callback, "__code__", None) + args = getattr(code, "co_argcount", 3) + + if args < 3: + from warnings import warn + + warn( + "Parameter callbacks take 3 args, (ctx, param, value). The" + " 2-arg style is deprecated and will be removed in 8.0.".format(callback), + DeprecationWarning, + stacklevel=3, + ) + return callback(ctx, value) + + return callback(ctx, param, value) + + +@contextmanager +def augment_usage_errors(ctx, param=None): + """Context manager that attaches extra information to exceptions.""" + try: + yield + except BadParameter as e: + if e.ctx is None: + e.ctx = ctx + if param is not None and e.param is None: + e.param = param + raise + except UsageError as e: + if e.ctx is None: + e.ctx = ctx + raise + + +def iter_params_for_processing(invocation_order, declaration_order): + """Given a sequence of parameters in the order as should be considered + for processing and an iterable of parameters that exist, this returns + a list in the correct order as they should be processed. + """ + + def sort_key(item): + try: + idx = invocation_order.index(item) + except ValueError: + idx = float("inf") + return (not item.is_eager, idx) + + return sorted(declaration_order, key=sort_key) + + +class Context(object): + """The context is a special internal object that holds state relevant + for the script execution at every single level. It's normally invisible + to commands unless they opt-in to getting access to it. + + The context is useful as it can pass internal objects around and can + control special execution features such as reading data from + environment variables. + + A context can be used as context manager in which case it will call + :meth:`close` on teardown. + + .. versionadded:: 2.0 + Added the `resilient_parsing`, `help_option_names`, + `token_normalize_func` parameters. + + .. versionadded:: 3.0 + Added the `allow_extra_args` and `allow_interspersed_args` + parameters. + + .. versionadded:: 4.0 + Added the `color`, `ignore_unknown_options`, and + `max_content_width` parameters. + + .. versionadded:: 7.1 + Added the `show_default` parameter. + + :param command: the command class for this context. + :param parent: the parent context. + :param info_name: the info name for this invocation. Generally this + is the most descriptive name for the script or + command. For the toplevel script it is usually + the name of the script, for commands below it it's + the name of the script. + :param obj: an arbitrary object of user data. + :param auto_envvar_prefix: the prefix to use for automatic environment + variables. If this is `None` then reading + from environment variables is disabled. This + does not affect manually set environment + variables which are always read. + :param default_map: a dictionary (like object) with default values + for parameters. + :param terminal_width: the width of the terminal. The default is + inherit from parent context. If no context + defines the terminal width then auto + detection will be applied. + :param max_content_width: the maximum width for content rendered by + Click (this currently only affects help + pages). This defaults to 80 characters if + not overridden. In other words: even if the + terminal is larger than that, Click will not + format things wider than 80 characters by + default. In addition to that, formatters might + add some safety mapping on the right. + :param resilient_parsing: if this flag is enabled then Click will + parse without any interactivity or callback + invocation. Default values will also be + ignored. This is useful for implementing + things such as completion support. + :param allow_extra_args: if this is set to `True` then extra arguments + at the end will not raise an error and will be + kept on the context. The default is to inherit + from the command. + :param allow_interspersed_args: if this is set to `False` then options + and arguments cannot be mixed. The + default is to inherit from the command. + :param ignore_unknown_options: instructs click to ignore options it does + not know and keeps them for later + processing. + :param help_option_names: optionally a list of strings that define how + the default help parameter is named. The + default is ``['--help']``. + :param token_normalize_func: an optional function that is used to + normalize tokens (options, choices, + etc.). This for instance can be used to + implement case insensitive behavior. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. This is only needed if ANSI + codes are used in texts that Click prints which is by + default not the case. This for instance would affect + help output. + :param show_default: if True, shows defaults for all options. + Even if an option is later created with show_default=False, + this command-level setting overrides it. + """ + + def __init__( + self, + command, + parent=None, + info_name=None, + obj=None, + auto_envvar_prefix=None, + default_map=None, + terminal_width=None, + max_content_width=None, + resilient_parsing=False, + allow_extra_args=None, + allow_interspersed_args=None, + ignore_unknown_options=None, + help_option_names=None, + token_normalize_func=None, + color=None, + show_default=None, + ): + #: the parent context or `None` if none exists. + self.parent = parent + #: the :class:`Command` for this context. + self.command = command + #: the descriptive information name + self.info_name = info_name + #: the parsed parameters except if the value is hidden in which + #: case it's not remembered. + self.params = {} + #: the leftover arguments. + self.args = [] + #: protected arguments. These are arguments that are prepended + #: to `args` when certain parsing scenarios are encountered but + #: must be never propagated to another arguments. This is used + #: to implement nested parsing. + self.protected_args = [] + if obj is None and parent is not None: + obj = parent.obj + #: the user object stored. + self.obj = obj + self._meta = getattr(parent, "meta", {}) + + #: A dictionary (-like object) with defaults for parameters. + if ( + default_map is None + and parent is not None + and parent.default_map is not None + ): + default_map = parent.default_map.get(info_name) + self.default_map = default_map + + #: This flag indicates if a subcommand is going to be executed. A + #: group callback can use this information to figure out if it's + #: being executed directly or because the execution flow passes + #: onwards to a subcommand. By default it's None, but it can be + #: the name of the subcommand to execute. + #: + #: If chaining is enabled this will be set to ``'*'`` in case + #: any commands are executed. It is however not possible to + #: figure out which ones. If you require this knowledge you + #: should use a :func:`resultcallback`. + self.invoked_subcommand = None + + if terminal_width is None and parent is not None: + terminal_width = parent.terminal_width + #: The width of the terminal (None is autodetection). + self.terminal_width = terminal_width + + if max_content_width is None and parent is not None: + max_content_width = parent.max_content_width + #: The maximum width of formatted content (None implies a sensible + #: default which is 80 for most things). + self.max_content_width = max_content_width + + if allow_extra_args is None: + allow_extra_args = command.allow_extra_args + #: Indicates if the context allows extra args or if it should + #: fail on parsing. + #: + #: .. versionadded:: 3.0 + self.allow_extra_args = allow_extra_args + + if allow_interspersed_args is None: + allow_interspersed_args = command.allow_interspersed_args + #: Indicates if the context allows mixing of arguments and + #: options or not. + #: + #: .. versionadded:: 3.0 + self.allow_interspersed_args = allow_interspersed_args + + if ignore_unknown_options is None: + ignore_unknown_options = command.ignore_unknown_options + #: Instructs click to ignore options that a command does not + #: understand and will store it on the context for later + #: processing. This is primarily useful for situations where you + #: want to call into external programs. Generally this pattern is + #: strongly discouraged because it's not possibly to losslessly + #: forward all arguments. + #: + #: .. versionadded:: 4.0 + self.ignore_unknown_options = ignore_unknown_options + + if help_option_names is None: + if parent is not None: + help_option_names = parent.help_option_names + else: + help_option_names = ["--help"] + + #: The names for the help options. + self.help_option_names = help_option_names + + if token_normalize_func is None and parent is not None: + token_normalize_func = parent.token_normalize_func + + #: An optional normalization function for tokens. This is + #: options, choices, commands etc. + self.token_normalize_func = token_normalize_func + + #: Indicates if resilient parsing is enabled. In that case Click + #: will do its best to not cause any failures and default values + #: will be ignored. Useful for completion. + self.resilient_parsing = resilient_parsing + + # If there is no envvar prefix yet, but the parent has one and + # the command on this level has a name, we can expand the envvar + # prefix automatically. + if auto_envvar_prefix is None: + if ( + parent is not None + and parent.auto_envvar_prefix is not None + and self.info_name is not None + ): + auto_envvar_prefix = "{}_{}".format( + parent.auto_envvar_prefix, self.info_name.upper() + ) + else: + auto_envvar_prefix = auto_envvar_prefix.upper() + if auto_envvar_prefix is not None: + auto_envvar_prefix = auto_envvar_prefix.replace("-", "_") + self.auto_envvar_prefix = auto_envvar_prefix + + if color is None and parent is not None: + color = parent.color + + #: Controls if styling output is wanted or not. + self.color = color + + self.show_default = show_default + + self._close_callbacks = [] + self._depth = 0 + + def __enter__(self): + self._depth += 1 + push_context(self) + return self + + def __exit__(self, exc_type, exc_value, tb): + self._depth -= 1 + if self._depth == 0: + self.close() + pop_context() + + @contextmanager + def scope(self, cleanup=True): + """This helper method can be used with the context object to promote + it to the current thread local (see :func:`get_current_context`). + The default behavior of this is to invoke the cleanup functions which + can be disabled by setting `cleanup` to `False`. The cleanup + functions are typically used for things such as closing file handles. + + If the cleanup is intended the context object can also be directly + used as a context manager. + + Example usage:: + + with ctx.scope(): + assert get_current_context() is ctx + + This is equivalent:: + + with ctx: + assert get_current_context() is ctx + + .. versionadded:: 5.0 + + :param cleanup: controls if the cleanup functions should be run or + not. The default is to run these functions. In + some situations the context only wants to be + temporarily pushed in which case this can be disabled. + Nested pushes automatically defer the cleanup. + """ + if not cleanup: + self._depth += 1 + try: + with self as rv: + yield rv + finally: + if not cleanup: + self._depth -= 1 + + @property + def meta(self): + """This is a dictionary which is shared with all the contexts + that are nested. It exists so that click utilities can store some + state here if they need to. It is however the responsibility of + that code to manage this dictionary well. + + The keys are supposed to be unique dotted strings. For instance + module paths are a good choice for it. What is stored in there is + irrelevant for the operation of click. However what is important is + that code that places data here adheres to the general semantics of + the system. + + Example usage:: + + LANG_KEY = f'{__name__}.lang' + + def set_language(value): + ctx = get_current_context() + ctx.meta[LANG_KEY] = value + + def get_language(): + return get_current_context().meta.get(LANG_KEY, 'en_US') + + .. versionadded:: 5.0 + """ + return self._meta + + def make_formatter(self): + """Creates the formatter for the help and usage output.""" + return HelpFormatter( + width=self.terminal_width, max_width=self.max_content_width + ) + + def call_on_close(self, f): + """This decorator remembers a function as callback that should be + executed when the context tears down. This is most useful to bind + resource handling to the script execution. For instance, file objects + opened by the :class:`File` type will register their close callbacks + here. + + :param f: the function to execute on teardown. + """ + self._close_callbacks.append(f) + return f + + def close(self): + """Invokes all close callbacks.""" + for cb in self._close_callbacks: + cb() + self._close_callbacks = [] + + @property + def command_path(self): + """The computed command path. This is used for the ``usage`` + information on the help page. It's automatically created by + combining the info names of the chain of contexts to the root. + """ + rv = "" + if self.info_name is not None: + rv = self.info_name + if self.parent is not None: + rv = "{} {}".format(self.parent.command_path, rv) + return rv.lstrip() + + def find_root(self): + """Finds the outermost context.""" + node = self + while node.parent is not None: + node = node.parent + return node + + def find_object(self, object_type): + """Finds the closest object of a given type.""" + node = self + while node is not None: + if isinstance(node.obj, object_type): + return node.obj + node = node.parent + + def ensure_object(self, object_type): + """Like :meth:`find_object` but sets the innermost object to a + new instance of `object_type` if it does not exist. + """ + rv = self.find_object(object_type) + if rv is None: + self.obj = rv = object_type() + return rv + + def lookup_default(self, name): + """Looks up the default for a parameter name. This by default + looks into the :attr:`default_map` if available. + """ + if self.default_map is not None: + rv = self.default_map.get(name) + if callable(rv): + rv = rv() + return rv + + def fail(self, message): + """Aborts the execution of the program with a specific error + message. + + :param message: the error message to fail with. + """ + raise UsageError(message, self) + + def abort(self): + """Aborts the script.""" + raise Abort() + + def exit(self, code=0): + """Exits the application with a given exit code.""" + raise Exit(code) + + def get_usage(self): + """Helper method to get formatted usage string for the current + context and command. + """ + return self.command.get_usage(self) + + def get_help(self): + """Helper method to get formatted help page for the current + context and command. + """ + return self.command.get_help(self) + + def invoke(*args, **kwargs): # noqa: B902 + """Invokes a command callback in exactly the way it expects. There + are two ways to invoke this method: + + 1. the first argument can be a callback and all other arguments and + keyword arguments are forwarded directly to the function. + 2. the first argument is a click command object. In that case all + arguments are forwarded as well but proper click parameters + (options and click arguments) must be keyword arguments and Click + will fill in defaults. + + Note that before Click 3.2 keyword arguments were not properly filled + in against the intention of this code and no context was created. For + more information about this change and why it was done in a bugfix + release see :ref:`upgrade-to-3.2`. + """ + self, callback = args[:2] + ctx = self + + # It's also possible to invoke another command which might or + # might not have a callback. In that case we also fill + # in defaults and make a new context for this command. + if isinstance(callback, Command): + other_cmd = callback + callback = other_cmd.callback + ctx = Context(other_cmd, info_name=other_cmd.name, parent=self) + if callback is None: + raise TypeError( + "The given command does not have a callback that can be invoked." + ) + + for param in other_cmd.params: + if param.name not in kwargs and param.expose_value: + kwargs[param.name] = param.get_default(ctx) + + args = args[2:] + with augment_usage_errors(self): + with ctx: + return callback(*args, **kwargs) + + def forward(*args, **kwargs): # noqa: B902 + """Similar to :meth:`invoke` but fills in default keyword + arguments from the current context if the other command expects + it. This cannot invoke callbacks directly, only other commands. + """ + self, cmd = args[:2] + + # It's also possible to invoke another command which might or + # might not have a callback. + if not isinstance(cmd, Command): + raise TypeError("Callback is not a command.") + + for param in self.params: + if param not in kwargs: + kwargs[param] = self.params[param] + + return self.invoke(cmd, **kwargs) + + +class BaseCommand(object): + """The base command implements the minimal API contract of commands. + Most code will never use this as it does not implement a lot of useful + functionality but it can act as the direct subclass of alternative + parsing methods that do not depend on the Click parser. + + For instance, this can be used to bridge Click and other systems like + argparse or docopt. + + Because base commands do not implement a lot of the API that other + parts of Click take for granted, they are not supported for all + operations. For instance, they cannot be used with the decorators + usually and they have no built-in callback system. + + .. versionchanged:: 2.0 + Added the `context_settings` parameter. + + :param name: the name of the command to use unless a group overrides it. + :param context_settings: an optional dictionary with defaults that are + passed to the context object. + """ + + #: the default for the :attr:`Context.allow_extra_args` flag. + allow_extra_args = False + #: the default for the :attr:`Context.allow_interspersed_args` flag. + allow_interspersed_args = True + #: the default for the :attr:`Context.ignore_unknown_options` flag. + ignore_unknown_options = False + + def __init__(self, name, context_settings=None): + #: the name the command thinks it has. Upon registering a command + #: on a :class:`Group` the group will default the command name + #: with this information. You should instead use the + #: :class:`Context`\'s :attr:`~Context.info_name` attribute. + self.name = name + if context_settings is None: + context_settings = {} + #: an optional dictionary with defaults passed to the context. + self.context_settings = context_settings + + def __repr__(self): + return "<{} {}>".format(self.__class__.__name__, self.name) + + def get_usage(self, ctx): + raise NotImplementedError("Base commands cannot get usage") + + def get_help(self, ctx): + raise NotImplementedError("Base commands cannot get help") + + def make_context(self, info_name, args, parent=None, **extra): + """This function when given an info name and arguments will kick + off the parsing and create a new :class:`Context`. It does not + invoke the actual command callback though. + + :param info_name: the info name for this invokation. Generally this + is the most descriptive name for the script or + command. For the toplevel script it's usually + the name of the script, for commands below it it's + the name of the script. + :param args: the arguments to parse as list of strings. + :param parent: the parent context if available. + :param extra: extra keyword arguments forwarded to the context + constructor. + """ + for key, value in iteritems(self.context_settings): + if key not in extra: + extra[key] = value + ctx = Context(self, info_name=info_name, parent=parent, **extra) + with ctx.scope(cleanup=False): + self.parse_args(ctx, args) + return ctx + + def parse_args(self, ctx, args): + """Given a context and a list of arguments this creates the parser + and parses the arguments, then modifies the context as necessary. + This is automatically invoked by :meth:`make_context`. + """ + raise NotImplementedError("Base commands do not know how to parse arguments.") + + def invoke(self, ctx): + """Given a context, this invokes the command. The default + implementation is raising a not implemented error. + """ + raise NotImplementedError("Base commands are not invokable by default") + + def main( + self, + args=None, + prog_name=None, + complete_var=None, + standalone_mode=True, + **extra + ): + """This is the way to invoke a script with all the bells and + whistles as a command line application. This will always terminate + the application after a call. If this is not wanted, ``SystemExit`` + needs to be caught. + + This method is also available by directly calling the instance of + a :class:`Command`. + + .. versionadded:: 3.0 + Added the `standalone_mode` flag to control the standalone mode. + + :param args: the arguments that should be used for parsing. If not + provided, ``sys.argv[1:]`` is used. + :param prog_name: the program name that should be used. By default + the program name is constructed by taking the file + name from ``sys.argv[0]``. + :param complete_var: the environment variable that controls the + bash completion support. The default is + ``"__COMPLETE"`` with prog_name in + uppercase. + :param standalone_mode: the default behavior is to invoke the script + in standalone mode. Click will then + handle exceptions and convert them into + error messages and the function will never + return but shut down the interpreter. If + this is set to `False` they will be + propagated to the caller and the return + value of this function is the return value + of :meth:`invoke`. + :param extra: extra keyword arguments are forwarded to the context + constructor. See :class:`Context` for more information. + """ + # If we are in Python 3, we will verify that the environment is + # sane at this point or reject further execution to avoid a + # broken script. + if not PY2: + _verify_python3_env() + else: + _check_for_unicode_literals() + + if args is None: + args = get_os_args() + else: + args = list(args) + + if prog_name is None: + prog_name = make_str( + os.path.basename(sys.argv[0] if sys.argv else __file__) + ) + + # Hook for the Bash completion. This only activates if the Bash + # completion is actually enabled, otherwise this is quite a fast + # noop. + _bashcomplete(self, prog_name, complete_var) + + try: + try: + with self.make_context(prog_name, args, **extra) as ctx: + rv = self.invoke(ctx) + if not standalone_mode: + return rv + # it's not safe to `ctx.exit(rv)` here! + # note that `rv` may actually contain data like "1" which + # has obvious effects + # more subtle case: `rv=[None, None]` can come out of + # chained commands which all returned `None` -- so it's not + # even always obvious that `rv` indicates success/failure + # by its truthiness/falsiness + ctx.exit() + except (EOFError, KeyboardInterrupt): + echo(file=sys.stderr) + raise Abort() + except ClickException as e: + if not standalone_mode: + raise + e.show() + sys.exit(e.exit_code) + except IOError as e: + if e.errno == errno.EPIPE: + sys.stdout = PacifyFlushWrapper(sys.stdout) + sys.stderr = PacifyFlushWrapper(sys.stderr) + sys.exit(1) + else: + raise + except Exit as e: + if standalone_mode: + sys.exit(e.exit_code) + else: + # in non-standalone mode, return the exit code + # note that this is only reached if `self.invoke` above raises + # an Exit explicitly -- thus bypassing the check there which + # would return its result + # the results of non-standalone execution may therefore be + # somewhat ambiguous: if there are codepaths which lead to + # `ctx.exit(1)` and to `return 1`, the caller won't be able to + # tell the difference between the two + return e.exit_code + except Abort: + if not standalone_mode: + raise + echo("Aborted!", file=sys.stderr) + sys.exit(1) + + def __call__(self, *args, **kwargs): + """Alias for :meth:`main`.""" + return self.main(*args, **kwargs) + + +class Command(BaseCommand): + """Commands are the basic building block of command line interfaces in + Click. A basic command handles command line parsing and might dispatch + more parsing to commands nested below it. + + .. versionchanged:: 2.0 + Added the `context_settings` parameter. + .. versionchanged:: 7.1 + Added the `no_args_is_help` parameter. + + :param name: the name of the command to use unless a group overrides it. + :param context_settings: an optional dictionary with defaults that are + passed to the context object. + :param callback: the callback to invoke. This is optional. + :param params: the parameters to register with this command. This can + be either :class:`Option` or :class:`Argument` objects. + :param help: the help string to use for this command. + :param epilog: like the help string but it's printed at the end of the + help page after everything else. + :param short_help: the short help to use for this command. This is + shown on the command listing of the parent command. + :param add_help_option: by default each command registers a ``--help`` + option. This can be disabled by this parameter. + :param no_args_is_help: this controls what happens if no arguments are + provided. This option is disabled by default. + If enabled this will add ``--help`` as argument + if no arguments are passed + :param hidden: hide this command from help outputs. + + :param deprecated: issues a message indicating that + the command is deprecated. + """ + + def __init__( + self, + name, + context_settings=None, + callback=None, + params=None, + help=None, + epilog=None, + short_help=None, + options_metavar="[OPTIONS]", + add_help_option=True, + no_args_is_help=False, + hidden=False, + deprecated=False, + ): + BaseCommand.__init__(self, name, context_settings) + #: the callback to execute when the command fires. This might be + #: `None` in which case nothing happens. + self.callback = callback + #: the list of parameters for this command in the order they + #: should show up in the help page and execute. Eager parameters + #: will automatically be handled before non eager ones. + self.params = params or [] + # if a form feed (page break) is found in the help text, truncate help + # text to the content preceding the first form feed + if help and "\f" in help: + help = help.split("\f", 1)[0] + self.help = help + self.epilog = epilog + self.options_metavar = options_metavar + self.short_help = short_help + self.add_help_option = add_help_option + self.no_args_is_help = no_args_is_help + self.hidden = hidden + self.deprecated = deprecated + + def get_usage(self, ctx): + """Formats the usage line into a string and returns it. + + Calls :meth:`format_usage` internally. + """ + formatter = ctx.make_formatter() + self.format_usage(ctx, formatter) + return formatter.getvalue().rstrip("\n") + + def get_params(self, ctx): + rv = self.params + help_option = self.get_help_option(ctx) + if help_option is not None: + rv = rv + [help_option] + return rv + + def format_usage(self, ctx, formatter): + """Writes the usage line into the formatter. + + This is a low-level method called by :meth:`get_usage`. + """ + pieces = self.collect_usage_pieces(ctx) + formatter.write_usage(ctx.command_path, " ".join(pieces)) + + def collect_usage_pieces(self, ctx): + """Returns all the pieces that go into the usage line and returns + it as a list of strings. + """ + rv = [self.options_metavar] + for param in self.get_params(ctx): + rv.extend(param.get_usage_pieces(ctx)) + return rv + + def get_help_option_names(self, ctx): + """Returns the names for the help option.""" + all_names = set(ctx.help_option_names) + for param in self.params: + all_names.difference_update(param.opts) + all_names.difference_update(param.secondary_opts) + return all_names + + def get_help_option(self, ctx): + """Returns the help option object.""" + help_options = self.get_help_option_names(ctx) + if not help_options or not self.add_help_option: + return + + def show_help(ctx, param, value): + if value and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + return Option( + help_options, + is_flag=True, + is_eager=True, + expose_value=False, + callback=show_help, + help="Show this message and exit.", + ) + + def make_parser(self, ctx): + """Creates the underlying option parser for this command.""" + parser = OptionParser(ctx) + for param in self.get_params(ctx): + param.add_to_parser(parser, ctx) + return parser + + def get_help(self, ctx): + """Formats the help into a string and returns it. + + Calls :meth:`format_help` internally. + """ + formatter = ctx.make_formatter() + self.format_help(ctx, formatter) + return formatter.getvalue().rstrip("\n") + + def get_short_help_str(self, limit=45): + """Gets short help for the command or makes it by shortening the + long help string. + """ + return ( + self.short_help + or self.help + and make_default_short_help(self.help, limit) + or "" + ) + + def format_help(self, ctx, formatter): + """Writes the help into the formatter if it exists. + + This is a low-level method called by :meth:`get_help`. + + This calls the following methods: + + - :meth:`format_usage` + - :meth:`format_help_text` + - :meth:`format_options` + - :meth:`format_epilog` + """ + self.format_usage(ctx, formatter) + self.format_help_text(ctx, formatter) + self.format_options(ctx, formatter) + self.format_epilog(ctx, formatter) + + def format_help_text(self, ctx, formatter): + """Writes the help text to the formatter if it exists.""" + if self.help: + formatter.write_paragraph() + with formatter.indentation(): + help_text = self.help + if self.deprecated: + help_text += DEPRECATED_HELP_NOTICE + formatter.write_text(help_text) + elif self.deprecated: + formatter.write_paragraph() + with formatter.indentation(): + formatter.write_text(DEPRECATED_HELP_NOTICE) + + def format_options(self, ctx, formatter): + """Writes all the options into the formatter if they exist.""" + opts = [] + for param in self.get_params(ctx): + rv = param.get_help_record(ctx) + if rv is not None: + opts.append(rv) + + if opts: + with formatter.section("Options"): + formatter.write_dl(opts) + + def format_epilog(self, ctx, formatter): + """Writes the epilog into the formatter if it exists.""" + if self.epilog: + formatter.write_paragraph() + with formatter.indentation(): + formatter.write_text(self.epilog) + + def parse_args(self, ctx, args): + if not args and self.no_args_is_help and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + parser = self.make_parser(ctx) + opts, args, param_order = parser.parse_args(args=args) + + for param in iter_params_for_processing(param_order, self.get_params(ctx)): + value, args = param.handle_parse_result(ctx, opts, args) + + if args and not ctx.allow_extra_args and not ctx.resilient_parsing: + ctx.fail( + "Got unexpected extra argument{} ({})".format( + "s" if len(args) != 1 else "", " ".join(map(make_str, args)) + ) + ) + + ctx.args = args + return args + + def invoke(self, ctx): + """Given a context, this invokes the attached callback (if it exists) + in the right way. + """ + _maybe_show_deprecated_notice(self) + if self.callback is not None: + return ctx.invoke(self.callback, **ctx.params) + + +class MultiCommand(Command): + """A multi command is the basic implementation of a command that + dispatches to subcommands. The most common version is the + :class:`Group`. + + :param invoke_without_command: this controls how the multi command itself + is invoked. By default it's only invoked + if a subcommand is provided. + :param no_args_is_help: this controls what happens if no arguments are + provided. This option is enabled by default if + `invoke_without_command` is disabled or disabled + if it's enabled. If enabled this will add + ``--help`` as argument if no arguments are + passed. + :param subcommand_metavar: the string that is used in the documentation + to indicate the subcommand place. + :param chain: if this is set to `True` chaining of multiple subcommands + is enabled. This restricts the form of commands in that + they cannot have optional arguments but it allows + multiple commands to be chained together. + :param result_callback: the result callback to attach to this multi + command. + """ + + allow_extra_args = True + allow_interspersed_args = False + + def __init__( + self, + name=None, + invoke_without_command=False, + no_args_is_help=None, + subcommand_metavar=None, + chain=False, + result_callback=None, + **attrs + ): + Command.__init__(self, name, **attrs) + if no_args_is_help is None: + no_args_is_help = not invoke_without_command + self.no_args_is_help = no_args_is_help + self.invoke_without_command = invoke_without_command + if subcommand_metavar is None: + if chain: + subcommand_metavar = SUBCOMMANDS_METAVAR + else: + subcommand_metavar = SUBCOMMAND_METAVAR + self.subcommand_metavar = subcommand_metavar + self.chain = chain + #: The result callback that is stored. This can be set or + #: overridden with the :func:`resultcallback` decorator. + self.result_callback = result_callback + + if self.chain: + for param in self.params: + if isinstance(param, Argument) and not param.required: + raise RuntimeError( + "Multi commands in chain mode cannot have" + " optional arguments." + ) + + def collect_usage_pieces(self, ctx): + rv = Command.collect_usage_pieces(self, ctx) + rv.append(self.subcommand_metavar) + return rv + + def format_options(self, ctx, formatter): + Command.format_options(self, ctx, formatter) + self.format_commands(ctx, formatter) + + def resultcallback(self, replace=False): + """Adds a result callback to the chain command. By default if a + result callback is already registered this will chain them but + this can be disabled with the `replace` parameter. The result + callback is invoked with the return value of the subcommand + (or the list of return values from all subcommands if chaining + is enabled) as well as the parameters as they would be passed + to the main callback. + + Example:: + + @click.group() + @click.option('-i', '--input', default=23) + def cli(input): + return 42 + + @cli.resultcallback() + def process_result(result, input): + return result + input + + .. versionadded:: 3.0 + + :param replace: if set to `True` an already existing result + callback will be removed. + """ + + def decorator(f): + old_callback = self.result_callback + if old_callback is None or replace: + self.result_callback = f + return f + + def function(__value, *args, **kwargs): + return f(old_callback(__value, *args, **kwargs), *args, **kwargs) + + self.result_callback = rv = update_wrapper(function, f) + return rv + + return decorator + + def format_commands(self, ctx, formatter): + """Extra format methods for multi methods that adds all the commands + after the options. + """ + commands = [] + for subcommand in self.list_commands(ctx): + cmd = self.get_command(ctx, subcommand) + # What is this, the tool lied about a command. Ignore it + if cmd is None: + continue + if cmd.hidden: + continue + + commands.append((subcommand, cmd)) + + # allow for 3 times the default spacing + if len(commands): + limit = formatter.width - 6 - max(len(cmd[0]) for cmd in commands) + + rows = [] + for subcommand, cmd in commands: + help = cmd.get_short_help_str(limit) + rows.append((subcommand, help)) + + if rows: + with formatter.section("Commands"): + formatter.write_dl(rows) + + def parse_args(self, ctx, args): + if not args and self.no_args_is_help and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + rest = Command.parse_args(self, ctx, args) + if self.chain: + ctx.protected_args = rest + ctx.args = [] + elif rest: + ctx.protected_args, ctx.args = rest[:1], rest[1:] + + return ctx.args + + def invoke(self, ctx): + def _process_result(value): + if self.result_callback is not None: + value = ctx.invoke(self.result_callback, value, **ctx.params) + return value + + if not ctx.protected_args: + # If we are invoked without command the chain flag controls + # how this happens. If we are not in chain mode, the return + # value here is the return value of the command. + # If however we are in chain mode, the return value is the + # return value of the result processor invoked with an empty + # list (which means that no subcommand actually was executed). + if self.invoke_without_command: + if not self.chain: + return Command.invoke(self, ctx) + with ctx: + Command.invoke(self, ctx) + return _process_result([]) + ctx.fail("Missing command.") + + # Fetch args back out + args = ctx.protected_args + ctx.args + ctx.args = [] + ctx.protected_args = [] + + # If we're not in chain mode, we only allow the invocation of a + # single command but we also inform the current context about the + # name of the command to invoke. + if not self.chain: + # Make sure the context is entered so we do not clean up + # resources until the result processor has worked. + with ctx: + cmd_name, cmd, args = self.resolve_command(ctx, args) + ctx.invoked_subcommand = cmd_name + Command.invoke(self, ctx) + sub_ctx = cmd.make_context(cmd_name, args, parent=ctx) + with sub_ctx: + return _process_result(sub_ctx.command.invoke(sub_ctx)) + + # In chain mode we create the contexts step by step, but after the + # base command has been invoked. Because at that point we do not + # know the subcommands yet, the invoked subcommand attribute is + # set to ``*`` to inform the command that subcommands are executed + # but nothing else. + with ctx: + ctx.invoked_subcommand = "*" if args else None + Command.invoke(self, ctx) + + # Otherwise we make every single context and invoke them in a + # chain. In that case the return value to the result processor + # is the list of all invoked subcommand's results. + contexts = [] + while args: + cmd_name, cmd, args = self.resolve_command(ctx, args) + sub_ctx = cmd.make_context( + cmd_name, + args, + parent=ctx, + allow_extra_args=True, + allow_interspersed_args=False, + ) + contexts.append(sub_ctx) + args, sub_ctx.args = sub_ctx.args, [] + + rv = [] + for sub_ctx in contexts: + with sub_ctx: + rv.append(sub_ctx.command.invoke(sub_ctx)) + return _process_result(rv) + + def resolve_command(self, ctx, args): + cmd_name = make_str(args[0]) + original_cmd_name = cmd_name + + # Get the command + cmd = self.get_command(ctx, cmd_name) + + # If we can't find the command but there is a normalization + # function available, we try with that one. + if cmd is None and ctx.token_normalize_func is not None: + cmd_name = ctx.token_normalize_func(cmd_name) + cmd = self.get_command(ctx, cmd_name) + + # If we don't find the command we want to show an error message + # to the user that it was not provided. However, there is + # something else we should do: if the first argument looks like + # an option we want to kick off parsing again for arguments to + # resolve things like --help which now should go to the main + # place. + if cmd is None and not ctx.resilient_parsing: + if split_opt(cmd_name)[0]: + self.parse_args(ctx, ctx.args) + ctx.fail("No such command '{}'.".format(original_cmd_name)) + + return cmd_name, cmd, args[1:] + + def get_command(self, ctx, cmd_name): + """Given a context and a command name, this returns a + :class:`Command` object if it exists or returns `None`. + """ + raise NotImplementedError() + + def list_commands(self, ctx): + """Returns a list of subcommand names in the order they should + appear. + """ + return [] + + +class Group(MultiCommand): + """A group allows a command to have subcommands attached. This is the + most common way to implement nesting in Click. + + :param commands: a dictionary of commands. + """ + + def __init__(self, name=None, commands=None, **attrs): + MultiCommand.__init__(self, name, **attrs) + #: the registered subcommands by their exported names. + self.commands = commands or {} + + def add_command(self, cmd, name=None): + """Registers another :class:`Command` with this group. If the name + is not provided, the name of the command is used. + """ + name = name or cmd.name + if name is None: + raise TypeError("Command has no name.") + _check_multicommand(self, name, cmd, register=True) + self.commands[name] = cmd + + def command(self, *args, **kwargs): + """A shortcut decorator for declaring and attaching a command to + the group. This takes the same arguments as :func:`command` but + immediately registers the created command with this instance by + calling into :meth:`add_command`. + """ + from .decorators import command + + def decorator(f): + cmd = command(*args, **kwargs)(f) + self.add_command(cmd) + return cmd + + return decorator + + def group(self, *args, **kwargs): + """A shortcut decorator for declaring and attaching a group to + the group. This takes the same arguments as :func:`group` but + immediately registers the created command with this instance by + calling into :meth:`add_command`. + """ + from .decorators import group + + def decorator(f): + cmd = group(*args, **kwargs)(f) + self.add_command(cmd) + return cmd + + return decorator + + def get_command(self, ctx, cmd_name): + return self.commands.get(cmd_name) + + def list_commands(self, ctx): + return sorted(self.commands) + + +class CommandCollection(MultiCommand): + """A command collection is a multi command that merges multiple multi + commands together into one. This is a straightforward implementation + that accepts a list of different multi commands as sources and + provides all the commands for each of them. + """ + + def __init__(self, name=None, sources=None, **attrs): + MultiCommand.__init__(self, name, **attrs) + #: The list of registered multi commands. + self.sources = sources or [] + + def add_source(self, multi_cmd): + """Adds a new multi command to the chain dispatcher.""" + self.sources.append(multi_cmd) + + def get_command(self, ctx, cmd_name): + for source in self.sources: + rv = source.get_command(ctx, cmd_name) + if rv is not None: + if self.chain: + _check_multicommand(self, cmd_name, rv) + return rv + + def list_commands(self, ctx): + rv = set() + for source in self.sources: + rv.update(source.list_commands(ctx)) + return sorted(rv) + + +class Parameter(object): + r"""A parameter to a command comes in two versions: they are either + :class:`Option`\s or :class:`Argument`\s. Other subclasses are currently + not supported by design as some of the internals for parsing are + intentionally not finalized. + + Some settings are supported by both options and arguments. + + :param param_decls: the parameter declarations for this option or + argument. This is a list of flags or argument + names. + :param type: the type that should be used. Either a :class:`ParamType` + or a Python type. The later is converted into the former + automatically if supported. + :param required: controls if this is optional or not. + :param default: the default value if omitted. This can also be a callable, + in which case it's invoked when the default is needed + without any arguments. + :param callback: a callback that should be executed after the parameter + was matched. This is called as ``fn(ctx, param, + value)`` and needs to return the value. + :param nargs: the number of arguments to match. If not ``1`` the return + value is a tuple instead of single value. The default for + nargs is ``1`` (except if the type is a tuple, then it's + the arity of the tuple). + :param metavar: how the value is represented in the help page. + :param expose_value: if this is `True` then the value is passed onwards + to the command callback and stored on the context, + otherwise it's skipped. + :param is_eager: eager values are processed before non eager ones. This + should not be set for arguments or it will inverse the + order of processing. + :param envvar: a string or list of strings that are environment variables + that should be checked. + + .. versionchanged:: 7.1 + Empty environment variables are ignored rather than taking the + empty string value. This makes it possible for scripts to clear + variables if they can't unset them. + + .. versionchanged:: 2.0 + Changed signature for parameter callback to also be passed the + parameter. The old callback format will still work, but it will + raise a warning to give you a chance to migrate the code easier. + """ + param_type_name = "parameter" + + def __init__( + self, + param_decls=None, + type=None, + required=False, + default=None, + callback=None, + nargs=None, + metavar=None, + expose_value=True, + is_eager=False, + envvar=None, + autocompletion=None, + ): + self.name, self.opts, self.secondary_opts = self._parse_decls( + param_decls or (), expose_value + ) + + self.type = convert_type(type, default) + + # Default nargs to what the type tells us if we have that + # information available. + if nargs is None: + if self.type.is_composite: + nargs = self.type.arity + else: + nargs = 1 + + self.required = required + self.callback = callback + self.nargs = nargs + self.multiple = False + self.expose_value = expose_value + self.default = default + self.is_eager = is_eager + self.metavar = metavar + self.envvar = envvar + self.autocompletion = autocompletion + + def __repr__(self): + return "<{} {}>".format(self.__class__.__name__, self.name) + + @property + def human_readable_name(self): + """Returns the human readable name of this parameter. This is the + same as the name for options, but the metavar for arguments. + """ + return self.name + + def make_metavar(self): + if self.metavar is not None: + return self.metavar + metavar = self.type.get_metavar(self) + if metavar is None: + metavar = self.type.name.upper() + if self.nargs != 1: + metavar += "..." + return metavar + + def get_default(self, ctx): + """Given a context variable this calculates the default value.""" + # Otherwise go with the regular default. + if callable(self.default): + rv = self.default() + else: + rv = self.default + return self.type_cast_value(ctx, rv) + + def add_to_parser(self, parser, ctx): + pass + + def consume_value(self, ctx, opts): + value = opts.get(self.name) + if value is None: + value = self.value_from_envvar(ctx) + if value is None: + value = ctx.lookup_default(self.name) + return value + + def type_cast_value(self, ctx, value): + """Given a value this runs it properly through the type system. + This automatically handles things like `nargs` and `multiple` as + well as composite types. + """ + if self.type.is_composite: + if self.nargs <= 1: + raise TypeError( + "Attempted to invoke composite type but nargs has" + " been set to {}. This is not supported; nargs" + " needs to be set to a fixed value > 1.".format(self.nargs) + ) + if self.multiple: + return tuple(self.type(x or (), self, ctx) for x in value or ()) + return self.type(value or (), self, ctx) + + def _convert(value, level): + if level == 0: + return self.type(value, self, ctx) + return tuple(_convert(x, level - 1) for x in value or ()) + + return _convert(value, (self.nargs != 1) + bool(self.multiple)) + + def process_value(self, ctx, value): + """Given a value and context this runs the logic to convert the + value as necessary. + """ + # If the value we were given is None we do nothing. This way + # code that calls this can easily figure out if something was + # not provided. Otherwise it would be converted into an empty + # tuple for multiple invocations which is inconvenient. + if value is not None: + return self.type_cast_value(ctx, value) + + def value_is_missing(self, value): + if value is None: + return True + if (self.nargs != 1 or self.multiple) and value == (): + return True + return False + + def full_process_value(self, ctx, value): + value = self.process_value(ctx, value) + + if value is None and not ctx.resilient_parsing: + value = self.get_default(ctx) + + if self.required and self.value_is_missing(value): + raise MissingParameter(ctx=ctx, param=self) + + return value + + def resolve_envvar_value(self, ctx): + if self.envvar is None: + return + if isinstance(self.envvar, (tuple, list)): + for envvar in self.envvar: + rv = os.environ.get(envvar) + if rv is not None: + return rv + else: + rv = os.environ.get(self.envvar) + + if rv != "": + return rv + + def value_from_envvar(self, ctx): + rv = self.resolve_envvar_value(ctx) + if rv is not None and self.nargs != 1: + rv = self.type.split_envvar_value(rv) + return rv + + def handle_parse_result(self, ctx, opts, args): + with augment_usage_errors(ctx, param=self): + value = self.consume_value(ctx, opts) + try: + value = self.full_process_value(ctx, value) + except Exception: + if not ctx.resilient_parsing: + raise + value = None + if self.callback is not None: + try: + value = invoke_param_callback(self.callback, ctx, self, value) + except Exception: + if not ctx.resilient_parsing: + raise + + if self.expose_value: + ctx.params[self.name] = value + return value, args + + def get_help_record(self, ctx): + pass + + def get_usage_pieces(self, ctx): + return [] + + def get_error_hint(self, ctx): + """Get a stringified version of the param for use in error messages to + indicate which param caused the error. + """ + hint_list = self.opts or [self.human_readable_name] + return " / ".join(repr(x) for x in hint_list) + + +class Option(Parameter): + """Options are usually optional values on the command line and + have some extra features that arguments don't have. + + All other parameters are passed onwards to the parameter constructor. + + :param show_default: controls if the default value should be shown on the + help page. Normally, defaults are not shown. If this + value is a string, it shows the string instead of the + value. This is particularly useful for dynamic options. + :param show_envvar: controls if an environment variable should be shown on + the help page. Normally, environment variables + are not shown. + :param prompt: if set to `True` or a non empty string then the user will be + prompted for input. If set to `True` the prompt will be the + option name capitalized. + :param confirmation_prompt: if set then the value will need to be confirmed + if it was prompted for. + :param hide_input: if this is `True` then the input on the prompt will be + hidden from the user. This is useful for password + input. + :param is_flag: forces this option to act as a flag. The default is + auto detection. + :param flag_value: which value should be used for this flag if it's + enabled. This is set to a boolean automatically if + the option string contains a slash to mark two options. + :param multiple: if this is set to `True` then the argument is accepted + multiple times and recorded. This is similar to ``nargs`` + in how it works but supports arbitrary number of + arguments. + :param count: this flag makes an option increment an integer. + :param allow_from_autoenv: if this is enabled then the value of this + parameter will be pulled from an environment + variable in case a prefix is defined on the + context. + :param help: the help string. + :param hidden: hide this option from help outputs. + """ + + param_type_name = "option" + + def __init__( + self, + param_decls=None, + show_default=False, + prompt=False, + confirmation_prompt=False, + hide_input=False, + is_flag=None, + flag_value=None, + multiple=False, + count=False, + allow_from_autoenv=True, + type=None, + help=None, + hidden=False, + show_choices=True, + show_envvar=False, + **attrs + ): + default_is_missing = attrs.get("default", _missing) is _missing + Parameter.__init__(self, param_decls, type=type, **attrs) + + if prompt is True: + prompt_text = self.name.replace("_", " ").capitalize() + elif prompt is False: + prompt_text = None + else: + prompt_text = prompt + self.prompt = prompt_text + self.confirmation_prompt = confirmation_prompt + self.hide_input = hide_input + self.hidden = hidden + + # Flags + if is_flag is None: + if flag_value is not None: + is_flag = True + else: + is_flag = bool(self.secondary_opts) + if is_flag and default_is_missing: + self.default = False + if flag_value is None: + flag_value = not self.default + self.is_flag = is_flag + self.flag_value = flag_value + if self.is_flag and isinstance(self.flag_value, bool) and type in [None, bool]: + self.type = BOOL + self.is_bool_flag = True + else: + self.is_bool_flag = False + + # Counting + self.count = count + if count: + if type is None: + self.type = IntRange(min=0) + if default_is_missing: + self.default = 0 + + self.multiple = multiple + self.allow_from_autoenv = allow_from_autoenv + self.help = help + self.show_default = show_default + self.show_choices = show_choices + self.show_envvar = show_envvar + + # Sanity check for stuff we don't support + if __debug__: + if self.nargs < 0: + raise TypeError("Options cannot have nargs < 0") + if self.prompt and self.is_flag and not self.is_bool_flag: + raise TypeError("Cannot prompt for flags that are not bools.") + if not self.is_bool_flag and self.secondary_opts: + raise TypeError("Got secondary option for non boolean flag.") + if self.is_bool_flag and self.hide_input and self.prompt is not None: + raise TypeError("Hidden input does not work with boolean flag prompts.") + if self.count: + if self.multiple: + raise TypeError( + "Options cannot be multiple and count at the same time." + ) + elif self.is_flag: + raise TypeError( + "Options cannot be count and flags at the same time." + ) + + def _parse_decls(self, decls, expose_value): + opts = [] + secondary_opts = [] + name = None + possible_names = [] + + for decl in decls: + if isidentifier(decl): + if name is not None: + raise TypeError("Name defined twice") + name = decl + else: + split_char = ";" if decl[:1] == "/" else "/" + if split_char in decl: + first, second = decl.split(split_char, 1) + first = first.rstrip() + if first: + possible_names.append(split_opt(first)) + opts.append(first) + second = second.lstrip() + if second: + secondary_opts.append(second.lstrip()) + else: + possible_names.append(split_opt(decl)) + opts.append(decl) + + if name is None and possible_names: + possible_names.sort(key=lambda x: -len(x[0])) # group long options first + name = possible_names[0][1].replace("-", "_").lower() + if not isidentifier(name): + name = None + + if name is None: + if not expose_value: + return None, opts, secondary_opts + raise TypeError("Could not determine name for option") + + if not opts and not secondary_opts: + raise TypeError( + "No options defined but a name was passed ({}). Did you" + " mean to declare an argument instead of an option?".format(name) + ) + + return name, opts, secondary_opts + + def add_to_parser(self, parser, ctx): + kwargs = { + "dest": self.name, + "nargs": self.nargs, + "obj": self, + } + + if self.multiple: + action = "append" + elif self.count: + action = "count" + else: + action = "store" + + if self.is_flag: + kwargs.pop("nargs", None) + action_const = "{}_const".format(action) + if self.is_bool_flag and self.secondary_opts: + parser.add_option(self.opts, action=action_const, const=True, **kwargs) + parser.add_option( + self.secondary_opts, action=action_const, const=False, **kwargs + ) + else: + parser.add_option( + self.opts, action=action_const, const=self.flag_value, **kwargs + ) + else: + kwargs["action"] = action + parser.add_option(self.opts, **kwargs) + + def get_help_record(self, ctx): + if self.hidden: + return + any_prefix_is_slash = [] + + def _write_opts(opts): + rv, any_slashes = join_options(opts) + if any_slashes: + any_prefix_is_slash[:] = [True] + if not self.is_flag and not self.count: + rv += " {}".format(self.make_metavar()) + return rv + + rv = [_write_opts(self.opts)] + if self.secondary_opts: + rv.append(_write_opts(self.secondary_opts)) + + help = self.help or "" + extra = [] + if self.show_envvar: + envvar = self.envvar + if envvar is None: + if self.allow_from_autoenv and ctx.auto_envvar_prefix is not None: + envvar = "{}_{}".format(ctx.auto_envvar_prefix, self.name.upper()) + if envvar is not None: + extra.append( + "env var: {}".format( + ", ".join(str(d) for d in envvar) + if isinstance(envvar, (list, tuple)) + else envvar + ) + ) + if self.default is not None and (self.show_default or ctx.show_default): + if isinstance(self.show_default, string_types): + default_string = "({})".format(self.show_default) + elif isinstance(self.default, (list, tuple)): + default_string = ", ".join(str(d) for d in self.default) + elif inspect.isfunction(self.default): + default_string = "(dynamic)" + else: + default_string = self.default + extra.append("default: {}".format(default_string)) + + if self.required: + extra.append("required") + if extra: + help = "{}[{}]".format( + "{} ".format(help) if help else "", "; ".join(extra) + ) + + return ("; " if any_prefix_is_slash else " / ").join(rv), help + + def get_default(self, ctx): + # If we're a non boolean flag our default is more complex because + # we need to look at all flags in the same group to figure out + # if we're the the default one in which case we return the flag + # value as default. + if self.is_flag and not self.is_bool_flag: + for param in ctx.command.params: + if param.name == self.name and param.default: + return param.flag_value + return None + return Parameter.get_default(self, ctx) + + def prompt_for_value(self, ctx): + """This is an alternative flow that can be activated in the full + value processing if a value does not exist. It will prompt the + user until a valid value exists and then returns the processed + value as result. + """ + # Calculate the default before prompting anything to be stable. + default = self.get_default(ctx) + + # If this is a prompt for a flag we need to handle this + # differently. + if self.is_bool_flag: + return confirm(self.prompt, default) + + return prompt( + self.prompt, + default=default, + type=self.type, + hide_input=self.hide_input, + show_choices=self.show_choices, + confirmation_prompt=self.confirmation_prompt, + value_proc=lambda x: self.process_value(ctx, x), + ) + + def resolve_envvar_value(self, ctx): + rv = Parameter.resolve_envvar_value(self, ctx) + if rv is not None: + return rv + if self.allow_from_autoenv and ctx.auto_envvar_prefix is not None: + envvar = "{}_{}".format(ctx.auto_envvar_prefix, self.name.upper()) + return os.environ.get(envvar) + + def value_from_envvar(self, ctx): + rv = self.resolve_envvar_value(ctx) + if rv is None: + return None + value_depth = (self.nargs != 1) + bool(self.multiple) + if value_depth > 0 and rv is not None: + rv = self.type.split_envvar_value(rv) + if self.multiple and self.nargs != 1: + rv = batch(rv, self.nargs) + return rv + + def full_process_value(self, ctx, value): + if value is None and self.prompt is not None and not ctx.resilient_parsing: + return self.prompt_for_value(ctx) + return Parameter.full_process_value(self, ctx, value) + + +class Argument(Parameter): + """Arguments are positional parameters to a command. They generally + provide fewer features than options but can have infinite ``nargs`` + and are required by default. + + All parameters are passed onwards to the parameter constructor. + """ + + param_type_name = "argument" + + def __init__(self, param_decls, required=None, **attrs): + if required is None: + if attrs.get("default") is not None: + required = False + else: + required = attrs.get("nargs", 1) > 0 + Parameter.__init__(self, param_decls, required=required, **attrs) + if self.default is not None and self.nargs < 0: + raise TypeError( + "nargs=-1 in combination with a default value is not supported." + ) + + @property + def human_readable_name(self): + if self.metavar is not None: + return self.metavar + return self.name.upper() + + def make_metavar(self): + if self.metavar is not None: + return self.metavar + var = self.type.get_metavar(self) + if not var: + var = self.name.upper() + if not self.required: + var = "[{}]".format(var) + if self.nargs != 1: + var += "..." + return var + + def _parse_decls(self, decls, expose_value): + if not decls: + if not expose_value: + return None, [], [] + raise TypeError("Could not determine name for argument") + if len(decls) == 1: + name = arg = decls[0] + name = name.replace("-", "_").lower() + else: + raise TypeError( + "Arguments take exactly one parameter declaration, got" + " {}".format(len(decls)) + ) + return name, [arg], [] + + def get_usage_pieces(self, ctx): + return [self.make_metavar()] + + def get_error_hint(self, ctx): + return repr(self.make_metavar()) + + def add_to_parser(self, parser, ctx): + parser.add_argument(dest=self.name, nargs=self.nargs, obj=self) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/decorators.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/decorators.py new file mode 100644 index 0000000..c7b5af6 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/decorators.py @@ -0,0 +1,333 @@ +import inspect +import sys +from functools import update_wrapper + +from ._compat import iteritems +from ._unicodefun import _check_for_unicode_literals +from .core import Argument +from .core import Command +from .core import Group +from .core import Option +from .globals import get_current_context +from .utils import echo + + +def pass_context(f): + """Marks a callback as wanting to receive the current context + object as first argument. + """ + + def new_func(*args, **kwargs): + return f(get_current_context(), *args, **kwargs) + + return update_wrapper(new_func, f) + + +def pass_obj(f): + """Similar to :func:`pass_context`, but only pass the object on the + context onwards (:attr:`Context.obj`). This is useful if that object + represents the state of a nested system. + """ + + def new_func(*args, **kwargs): + return f(get_current_context().obj, *args, **kwargs) + + return update_wrapper(new_func, f) + + +def make_pass_decorator(object_type, ensure=False): + """Given an object type this creates a decorator that will work + similar to :func:`pass_obj` but instead of passing the object of the + current context, it will find the innermost context of type + :func:`object_type`. + + This generates a decorator that works roughly like this:: + + from functools import update_wrapper + + def decorator(f): + @pass_context + def new_func(ctx, *args, **kwargs): + obj = ctx.find_object(object_type) + return ctx.invoke(f, obj, *args, **kwargs) + return update_wrapper(new_func, f) + return decorator + + :param object_type: the type of the object to pass. + :param ensure: if set to `True`, a new object will be created and + remembered on the context if it's not there yet. + """ + + def decorator(f): + def new_func(*args, **kwargs): + ctx = get_current_context() + if ensure: + obj = ctx.ensure_object(object_type) + else: + obj = ctx.find_object(object_type) + if obj is None: + raise RuntimeError( + "Managed to invoke callback without a context" + " object of type '{}' existing".format(object_type.__name__) + ) + return ctx.invoke(f, obj, *args, **kwargs) + + return update_wrapper(new_func, f) + + return decorator + + +def _make_command(f, name, attrs, cls): + if isinstance(f, Command): + raise TypeError("Attempted to convert a callback into a command twice.") + try: + params = f.__click_params__ + params.reverse() + del f.__click_params__ + except AttributeError: + params = [] + help = attrs.get("help") + if help is None: + help = inspect.getdoc(f) + if isinstance(help, bytes): + help = help.decode("utf-8") + else: + help = inspect.cleandoc(help) + attrs["help"] = help + _check_for_unicode_literals() + return cls( + name=name or f.__name__.lower().replace("_", "-"), + callback=f, + params=params, + **attrs + ) + + +def command(name=None, cls=None, **attrs): + r"""Creates a new :class:`Command` and uses the decorated function as + callback. This will also automatically attach all decorated + :func:`option`\s and :func:`argument`\s as parameters to the command. + + The name of the command defaults to the name of the function with + underscores replaced by dashes. If you want to change that, you can + pass the intended name as the first argument. + + All keyword arguments are forwarded to the underlying command class. + + Once decorated the function turns into a :class:`Command` instance + that can be invoked as a command line utility or be attached to a + command :class:`Group`. + + :param name: the name of the command. This defaults to the function + name with underscores replaced by dashes. + :param cls: the command class to instantiate. This defaults to + :class:`Command`. + """ + if cls is None: + cls = Command + + def decorator(f): + cmd = _make_command(f, name, attrs, cls) + cmd.__doc__ = f.__doc__ + return cmd + + return decorator + + +def group(name=None, **attrs): + """Creates a new :class:`Group` with a function as callback. This + works otherwise the same as :func:`command` just that the `cls` + parameter is set to :class:`Group`. + """ + attrs.setdefault("cls", Group) + return command(name, **attrs) + + +def _param_memo(f, param): + if isinstance(f, Command): + f.params.append(param) + else: + if not hasattr(f, "__click_params__"): + f.__click_params__ = [] + f.__click_params__.append(param) + + +def argument(*param_decls, **attrs): + """Attaches an argument to the command. All positional arguments are + passed as parameter declarations to :class:`Argument`; all keyword + arguments are forwarded unchanged (except ``cls``). + This is equivalent to creating an :class:`Argument` instance manually + and attaching it to the :attr:`Command.params` list. + + :param cls: the argument class to instantiate. This defaults to + :class:`Argument`. + """ + + def decorator(f): + ArgumentClass = attrs.pop("cls", Argument) + _param_memo(f, ArgumentClass(param_decls, **attrs)) + return f + + return decorator + + +def option(*param_decls, **attrs): + """Attaches an option to the command. All positional arguments are + passed as parameter declarations to :class:`Option`; all keyword + arguments are forwarded unchanged (except ``cls``). + This is equivalent to creating an :class:`Option` instance manually + and attaching it to the :attr:`Command.params` list. + + :param cls: the option class to instantiate. This defaults to + :class:`Option`. + """ + + def decorator(f): + # Issue 926, copy attrs, so pre-defined options can re-use the same cls= + option_attrs = attrs.copy() + + if "help" in option_attrs: + option_attrs["help"] = inspect.cleandoc(option_attrs["help"]) + OptionClass = option_attrs.pop("cls", Option) + _param_memo(f, OptionClass(param_decls, **option_attrs)) + return f + + return decorator + + +def confirmation_option(*param_decls, **attrs): + """Shortcut for confirmation prompts that can be ignored by passing + ``--yes`` as parameter. + + This is equivalent to decorating a function with :func:`option` with + the following parameters:: + + def callback(ctx, param, value): + if not value: + ctx.abort() + + @click.command() + @click.option('--yes', is_flag=True, callback=callback, + expose_value=False, prompt='Do you want to continue?') + def dropdb(): + pass + """ + + def decorator(f): + def callback(ctx, param, value): + if not value: + ctx.abort() + + attrs.setdefault("is_flag", True) + attrs.setdefault("callback", callback) + attrs.setdefault("expose_value", False) + attrs.setdefault("prompt", "Do you want to continue?") + attrs.setdefault("help", "Confirm the action without prompting.") + return option(*(param_decls or ("--yes",)), **attrs)(f) + + return decorator + + +def password_option(*param_decls, **attrs): + """Shortcut for password prompts. + + This is equivalent to decorating a function with :func:`option` with + the following parameters:: + + @click.command() + @click.option('--password', prompt=True, confirmation_prompt=True, + hide_input=True) + def changeadmin(password): + pass + """ + + def decorator(f): + attrs.setdefault("prompt", True) + attrs.setdefault("confirmation_prompt", True) + attrs.setdefault("hide_input", True) + return option(*(param_decls or ("--password",)), **attrs)(f) + + return decorator + + +def version_option(version=None, *param_decls, **attrs): + """Adds a ``--version`` option which immediately ends the program + printing out the version number. This is implemented as an eager + option that prints the version and exits the program in the callback. + + :param version: the version number to show. If not provided Click + attempts an auto discovery via setuptools. + :param prog_name: the name of the program (defaults to autodetection) + :param message: custom message to show instead of the default + (``'%(prog)s, version %(version)s'``) + :param others: everything else is forwarded to :func:`option`. + """ + if version is None: + if hasattr(sys, "_getframe"): + module = sys._getframe(1).f_globals.get("__name__") + else: + module = "" + + def decorator(f): + prog_name = attrs.pop("prog_name", None) + message = attrs.pop("message", "%(prog)s, version %(version)s") + + def callback(ctx, param, value): + if not value or ctx.resilient_parsing: + return + prog = prog_name + if prog is None: + prog = ctx.find_root().info_name + ver = version + if ver is None: + try: + import pkg_resources + except ImportError: + pass + else: + for dist in pkg_resources.working_set: + scripts = dist.get_entry_map().get("console_scripts") or {} + for _, entry_point in iteritems(scripts): + if entry_point.module_name == module: + ver = dist.version + break + if ver is None: + raise RuntimeError("Could not determine version") + echo(message % {"prog": prog, "version": ver}, color=ctx.color) + ctx.exit() + + attrs.setdefault("is_flag", True) + attrs.setdefault("expose_value", False) + attrs.setdefault("is_eager", True) + attrs.setdefault("help", "Show the version and exit.") + attrs["callback"] = callback + return option(*(param_decls or ("--version",)), **attrs)(f) + + return decorator + + +def help_option(*param_decls, **attrs): + """Adds a ``--help`` option which immediately ends the program + printing out the help page. This is usually unnecessary to add as + this is added by default to all commands unless suppressed. + + Like :func:`version_option`, this is implemented as eager option that + prints in the callback and exits. + + All arguments are forwarded to :func:`option`. + """ + + def decorator(f): + def callback(ctx, param, value): + if value and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + attrs.setdefault("is_flag", True) + attrs.setdefault("expose_value", False) + attrs.setdefault("help", "Show this message and exit.") + attrs.setdefault("is_eager", True) + attrs["callback"] = callback + return option(*(param_decls or ("--help",)), **attrs)(f) + + return decorator diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/exceptions.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/exceptions.py new file mode 100644 index 0000000..592ee38 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/exceptions.py @@ -0,0 +1,253 @@ +from ._compat import filename_to_ui +from ._compat import get_text_stderr +from ._compat import PY2 +from .utils import echo + + +def _join_param_hints(param_hint): + if isinstance(param_hint, (tuple, list)): + return " / ".join(repr(x) for x in param_hint) + return param_hint + + +class ClickException(Exception): + """An exception that Click can handle and show to the user.""" + + #: The exit code for this exception + exit_code = 1 + + def __init__(self, message): + ctor_msg = message + if PY2: + if ctor_msg is not None: + ctor_msg = ctor_msg.encode("utf-8") + Exception.__init__(self, ctor_msg) + self.message = message + + def format_message(self): + return self.message + + def __str__(self): + return self.message + + if PY2: + __unicode__ = __str__ + + def __str__(self): + return self.message.encode("utf-8") + + def show(self, file=None): + if file is None: + file = get_text_stderr() + echo("Error: {}".format(self.format_message()), file=file) + + +class UsageError(ClickException): + """An internal exception that signals a usage error. This typically + aborts any further handling. + + :param message: the error message to display. + :param ctx: optionally the context that caused this error. Click will + fill in the context automatically in some situations. + """ + + exit_code = 2 + + def __init__(self, message, ctx=None): + ClickException.__init__(self, message) + self.ctx = ctx + self.cmd = self.ctx.command if self.ctx else None + + def show(self, file=None): + if file is None: + file = get_text_stderr() + color = None + hint = "" + if self.cmd is not None and self.cmd.get_help_option(self.ctx) is not None: + hint = "Try '{} {}' for help.\n".format( + self.ctx.command_path, self.ctx.help_option_names[0] + ) + if self.ctx is not None: + color = self.ctx.color + echo("{}\n{}".format(self.ctx.get_usage(), hint), file=file, color=color) + echo("Error: {}".format(self.format_message()), file=file, color=color) + + +class BadParameter(UsageError): + """An exception that formats out a standardized error message for a + bad parameter. This is useful when thrown from a callback or type as + Click will attach contextual information to it (for instance, which + parameter it is). + + .. versionadded:: 2.0 + + :param param: the parameter object that caused this error. This can + be left out, and Click will attach this info itself + if possible. + :param param_hint: a string that shows up as parameter name. This + can be used as alternative to `param` in cases + where custom validation should happen. If it is + a string it's used as such, if it's a list then + each item is quoted and separated. + """ + + def __init__(self, message, ctx=None, param=None, param_hint=None): + UsageError.__init__(self, message, ctx) + self.param = param + self.param_hint = param_hint + + def format_message(self): + if self.param_hint is not None: + param_hint = self.param_hint + elif self.param is not None: + param_hint = self.param.get_error_hint(self.ctx) + else: + return "Invalid value: {}".format(self.message) + param_hint = _join_param_hints(param_hint) + + return "Invalid value for {}: {}".format(param_hint, self.message) + + +class MissingParameter(BadParameter): + """Raised if click required an option or argument but it was not + provided when invoking the script. + + .. versionadded:: 4.0 + + :param param_type: a string that indicates the type of the parameter. + The default is to inherit the parameter type from + the given `param`. Valid values are ``'parameter'``, + ``'option'`` or ``'argument'``. + """ + + def __init__( + self, message=None, ctx=None, param=None, param_hint=None, param_type=None + ): + BadParameter.__init__(self, message, ctx, param, param_hint) + self.param_type = param_type + + def format_message(self): + if self.param_hint is not None: + param_hint = self.param_hint + elif self.param is not None: + param_hint = self.param.get_error_hint(self.ctx) + else: + param_hint = None + param_hint = _join_param_hints(param_hint) + + param_type = self.param_type + if param_type is None and self.param is not None: + param_type = self.param.param_type_name + + msg = self.message + if self.param is not None: + msg_extra = self.param.type.get_missing_message(self.param) + if msg_extra: + if msg: + msg += ". {}".format(msg_extra) + else: + msg = msg_extra + + return "Missing {}{}{}{}".format( + param_type, + " {}".format(param_hint) if param_hint else "", + ". " if msg else ".", + msg or "", + ) + + def __str__(self): + if self.message is None: + param_name = self.param.name if self.param else None + return "missing parameter: {}".format(param_name) + else: + return self.message + + if PY2: + __unicode__ = __str__ + + def __str__(self): + return self.__unicode__().encode("utf-8") + + +class NoSuchOption(UsageError): + """Raised if click attempted to handle an option that does not + exist. + + .. versionadded:: 4.0 + """ + + def __init__(self, option_name, message=None, possibilities=None, ctx=None): + if message is None: + message = "no such option: {}".format(option_name) + UsageError.__init__(self, message, ctx) + self.option_name = option_name + self.possibilities = possibilities + + def format_message(self): + bits = [self.message] + if self.possibilities: + if len(self.possibilities) == 1: + bits.append("Did you mean {}?".format(self.possibilities[0])) + else: + possibilities = sorted(self.possibilities) + bits.append("(Possible options: {})".format(", ".join(possibilities))) + return " ".join(bits) + + +class BadOptionUsage(UsageError): + """Raised if an option is generally supplied but the use of the option + was incorrect. This is for instance raised if the number of arguments + for an option is not correct. + + .. versionadded:: 4.0 + + :param option_name: the name of the option being used incorrectly. + """ + + def __init__(self, option_name, message, ctx=None): + UsageError.__init__(self, message, ctx) + self.option_name = option_name + + +class BadArgumentUsage(UsageError): + """Raised if an argument is generally supplied but the use of the argument + was incorrect. This is for instance raised if the number of values + for an argument is not correct. + + .. versionadded:: 6.0 + """ + + def __init__(self, message, ctx=None): + UsageError.__init__(self, message, ctx) + + +class FileError(ClickException): + """Raised if a file cannot be opened.""" + + def __init__(self, filename, hint=None): + ui_filename = filename_to_ui(filename) + if hint is None: + hint = "unknown error" + ClickException.__init__(self, hint) + self.ui_filename = ui_filename + self.filename = filename + + def format_message(self): + return "Could not open file {}: {}".format(self.ui_filename, self.message) + + +class Abort(RuntimeError): + """An internal signalling exception that signals Click to abort.""" + + +class Exit(RuntimeError): + """An exception that indicates that the application should exit with some + status code. + + :param code: the status code to exit with. + """ + + __slots__ = ("exit_code",) + + def __init__(self, code=0): + self.exit_code = code diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/formatting.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/formatting.py new file mode 100644 index 0000000..319c7f6 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/formatting.py @@ -0,0 +1,283 @@ +from contextlib import contextmanager + +from ._compat import term_len +from .parser import split_opt +from .termui import get_terminal_size + +# Can force a width. This is used by the test system +FORCED_WIDTH = None + + +def measure_table(rows): + widths = {} + for row in rows: + for idx, col in enumerate(row): + widths[idx] = max(widths.get(idx, 0), term_len(col)) + return tuple(y for x, y in sorted(widths.items())) + + +def iter_rows(rows, col_count): + for row in rows: + row = tuple(row) + yield row + ("",) * (col_count - len(row)) + + +def wrap_text( + text, width=78, initial_indent="", subsequent_indent="", preserve_paragraphs=False +): + """A helper function that intelligently wraps text. By default, it + assumes that it operates on a single paragraph of text but if the + `preserve_paragraphs` parameter is provided it will intelligently + handle paragraphs (defined by two empty lines). + + If paragraphs are handled, a paragraph can be prefixed with an empty + line containing the ``\\b`` character (``\\x08``) to indicate that + no rewrapping should happen in that block. + + :param text: the text that should be rewrapped. + :param width: the maximum width for the text. + :param initial_indent: the initial indent that should be placed on the + first line as a string. + :param subsequent_indent: the indent string that should be placed on + each consecutive line. + :param preserve_paragraphs: if this flag is set then the wrapping will + intelligently handle paragraphs. + """ + from ._textwrap import TextWrapper + + text = text.expandtabs() + wrapper = TextWrapper( + width, + initial_indent=initial_indent, + subsequent_indent=subsequent_indent, + replace_whitespace=False, + ) + if not preserve_paragraphs: + return wrapper.fill(text) + + p = [] + buf = [] + indent = None + + def _flush_par(): + if not buf: + return + if buf[0].strip() == "\b": + p.append((indent or 0, True, "\n".join(buf[1:]))) + else: + p.append((indent or 0, False, " ".join(buf))) + del buf[:] + + for line in text.splitlines(): + if not line: + _flush_par() + indent = None + else: + if indent is None: + orig_len = term_len(line) + line = line.lstrip() + indent = orig_len - term_len(line) + buf.append(line) + _flush_par() + + rv = [] + for indent, raw, text in p: + with wrapper.extra_indent(" " * indent): + if raw: + rv.append(wrapper.indent_only(text)) + else: + rv.append(wrapper.fill(text)) + + return "\n\n".join(rv) + + +class HelpFormatter(object): + """This class helps with formatting text-based help pages. It's + usually just needed for very special internal cases, but it's also + exposed so that developers can write their own fancy outputs. + + At present, it always writes into memory. + + :param indent_increment: the additional increment for each level. + :param width: the width for the text. This defaults to the terminal + width clamped to a maximum of 78. + """ + + def __init__(self, indent_increment=2, width=None, max_width=None): + self.indent_increment = indent_increment + if max_width is None: + max_width = 80 + if width is None: + width = FORCED_WIDTH + if width is None: + width = max(min(get_terminal_size()[0], max_width) - 2, 50) + self.width = width + self.current_indent = 0 + self.buffer = [] + + def write(self, string): + """Writes a unicode string into the internal buffer.""" + self.buffer.append(string) + + def indent(self): + """Increases the indentation.""" + self.current_indent += self.indent_increment + + def dedent(self): + """Decreases the indentation.""" + self.current_indent -= self.indent_increment + + def write_usage(self, prog, args="", prefix="Usage: "): + """Writes a usage line into the buffer. + + :param prog: the program name. + :param args: whitespace separated list of arguments. + :param prefix: the prefix for the first line. + """ + usage_prefix = "{:>{w}}{} ".format(prefix, prog, w=self.current_indent) + text_width = self.width - self.current_indent + + if text_width >= (term_len(usage_prefix) + 20): + # The arguments will fit to the right of the prefix. + indent = " " * term_len(usage_prefix) + self.write( + wrap_text( + args, + text_width, + initial_indent=usage_prefix, + subsequent_indent=indent, + ) + ) + else: + # The prefix is too long, put the arguments on the next line. + self.write(usage_prefix) + self.write("\n") + indent = " " * (max(self.current_indent, term_len(prefix)) + 4) + self.write( + wrap_text( + args, text_width, initial_indent=indent, subsequent_indent=indent + ) + ) + + self.write("\n") + + def write_heading(self, heading): + """Writes a heading into the buffer.""" + self.write("{:>{w}}{}:\n".format("", heading, w=self.current_indent)) + + def write_paragraph(self): + """Writes a paragraph into the buffer.""" + if self.buffer: + self.write("\n") + + def write_text(self, text): + """Writes re-indented text into the buffer. This rewraps and + preserves paragraphs. + """ + text_width = max(self.width - self.current_indent, 11) + indent = " " * self.current_indent + self.write( + wrap_text( + text, + text_width, + initial_indent=indent, + subsequent_indent=indent, + preserve_paragraphs=True, + ) + ) + self.write("\n") + + def write_dl(self, rows, col_max=30, col_spacing=2): + """Writes a definition list into the buffer. This is how options + and commands are usually formatted. + + :param rows: a list of two item tuples for the terms and values. + :param col_max: the maximum width of the first column. + :param col_spacing: the number of spaces between the first and + second column. + """ + rows = list(rows) + widths = measure_table(rows) + if len(widths) != 2: + raise TypeError("Expected two columns for definition list") + + first_col = min(widths[0], col_max) + col_spacing + + for first, second in iter_rows(rows, len(widths)): + self.write("{:>{w}}{}".format("", first, w=self.current_indent)) + if not second: + self.write("\n") + continue + if term_len(first) <= first_col - col_spacing: + self.write(" " * (first_col - term_len(first))) + else: + self.write("\n") + self.write(" " * (first_col + self.current_indent)) + + text_width = max(self.width - first_col - 2, 10) + wrapped_text = wrap_text(second, text_width, preserve_paragraphs=True) + lines = wrapped_text.splitlines() + + if lines: + self.write("{}\n".format(lines[0])) + + for line in lines[1:]: + self.write( + "{:>{w}}{}\n".format( + "", line, w=first_col + self.current_indent + ) + ) + + if len(lines) > 1: + # separate long help from next option + self.write("\n") + else: + self.write("\n") + + @contextmanager + def section(self, name): + """Helpful context manager that writes a paragraph, a heading, + and the indents. + + :param name: the section name that is written as heading. + """ + self.write_paragraph() + self.write_heading(name) + self.indent() + try: + yield + finally: + self.dedent() + + @contextmanager + def indentation(self): + """A context manager that increases the indentation.""" + self.indent() + try: + yield + finally: + self.dedent() + + def getvalue(self): + """Returns the buffer contents.""" + return "".join(self.buffer) + + +def join_options(options): + """Given a list of option strings this joins them in the most appropriate + way and returns them in the form ``(formatted_string, + any_prefix_is_slash)`` where the second item in the tuple is a flag that + indicates if any of the option prefixes was a slash. + """ + rv = [] + any_prefix_is_slash = False + for opt in options: + prefix = split_opt(opt)[0] + if prefix == "/": + any_prefix_is_slash = True + rv.append((len(prefix), opt)) + + rv.sort(key=lambda x: x[0]) + + rv = ", ".join(x[1] for x in rv) + return rv, any_prefix_is_slash diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/globals.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/globals.py new file mode 100644 index 0000000..1649f9a --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/globals.py @@ -0,0 +1,47 @@ +from threading import local + +_local = local() + + +def get_current_context(silent=False): + """Returns the current click context. This can be used as a way to + access the current context object from anywhere. This is a more implicit + alternative to the :func:`pass_context` decorator. This function is + primarily useful for helpers such as :func:`echo` which might be + interested in changing its behavior based on the current context. + + To push the current context, :meth:`Context.scope` can be used. + + .. versionadded:: 5.0 + + :param silent: if set to `True` the return value is `None` if no context + is available. The default behavior is to raise a + :exc:`RuntimeError`. + """ + try: + return _local.stack[-1] + except (AttributeError, IndexError): + if not silent: + raise RuntimeError("There is no active click context.") + + +def push_context(ctx): + """Pushes a new context to the current stack.""" + _local.__dict__.setdefault("stack", []).append(ctx) + + +def pop_context(): + """Removes the top level from the stack.""" + _local.stack.pop() + + +def resolve_color_default(color=None): + """"Internal helper to get the default value of the color flag. If a + value is passed it's returned unchanged, otherwise it's looked up from + the current context. + """ + if color is not None: + return color + ctx = get_current_context(silent=True) + if ctx is not None: + return ctx.color diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/parser.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/parser.py new file mode 100644 index 0000000..f43ebfe --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/parser.py @@ -0,0 +1,428 @@ +# -*- coding: utf-8 -*- +""" +This module started out as largely a copy paste from the stdlib's +optparse module with the features removed that we do not need from +optparse because we implement them in Click on a higher level (for +instance type handling, help formatting and a lot more). + +The plan is to remove more and more from here over time. + +The reason this is a different module and not optparse from the stdlib +is that there are differences in 2.x and 3.x about the error messages +generated and optparse in the stdlib uses gettext for no good reason +and might cause us issues. + +Click uses parts of optparse written by Gregory P. Ward and maintained +by the Python Software Foundation. This is limited to code in parser.py. + +Copyright 2001-2006 Gregory P. Ward. All rights reserved. +Copyright 2002-2006 Python Software Foundation. All rights reserved. +""" +import re +from collections import deque + +from .exceptions import BadArgumentUsage +from .exceptions import BadOptionUsage +from .exceptions import NoSuchOption +from .exceptions import UsageError + + +def _unpack_args(args, nargs_spec): + """Given an iterable of arguments and an iterable of nargs specifications, + it returns a tuple with all the unpacked arguments at the first index + and all remaining arguments as the second. + + The nargs specification is the number of arguments that should be consumed + or `-1` to indicate that this position should eat up all the remainders. + + Missing items are filled with `None`. + """ + args = deque(args) + nargs_spec = deque(nargs_spec) + rv = [] + spos = None + + def _fetch(c): + try: + if spos is None: + return c.popleft() + else: + return c.pop() + except IndexError: + return None + + while nargs_spec: + nargs = _fetch(nargs_spec) + if nargs == 1: + rv.append(_fetch(args)) + elif nargs > 1: + x = [_fetch(args) for _ in range(nargs)] + # If we're reversed, we're pulling in the arguments in reverse, + # so we need to turn them around. + if spos is not None: + x.reverse() + rv.append(tuple(x)) + elif nargs < 0: + if spos is not None: + raise TypeError("Cannot have two nargs < 0") + spos = len(rv) + rv.append(None) + + # spos is the position of the wildcard (star). If it's not `None`, + # we fill it with the remainder. + if spos is not None: + rv[spos] = tuple(args) + args = [] + rv[spos + 1 :] = reversed(rv[spos + 1 :]) + + return tuple(rv), list(args) + + +def _error_opt_args(nargs, opt): + if nargs == 1: + raise BadOptionUsage(opt, "{} option requires an argument".format(opt)) + raise BadOptionUsage(opt, "{} option requires {} arguments".format(opt, nargs)) + + +def split_opt(opt): + first = opt[:1] + if first.isalnum(): + return "", opt + if opt[1:2] == first: + return opt[:2], opt[2:] + return first, opt[1:] + + +def normalize_opt(opt, ctx): + if ctx is None or ctx.token_normalize_func is None: + return opt + prefix, opt = split_opt(opt) + return prefix + ctx.token_normalize_func(opt) + + +def split_arg_string(string): + """Given an argument string this attempts to split it into small parts.""" + rv = [] + for match in re.finditer( + r"('([^'\\]*(?:\\.[^'\\]*)*)'|\"([^\"\\]*(?:\\.[^\"\\]*)*)\"|\S+)\s*", + string, + re.S, + ): + arg = match.group().strip() + if arg[:1] == arg[-1:] and arg[:1] in "\"'": + arg = arg[1:-1].encode("ascii", "backslashreplace").decode("unicode-escape") + try: + arg = type(string)(arg) + except UnicodeError: + pass + rv.append(arg) + return rv + + +class Option(object): + def __init__(self, opts, dest, action=None, nargs=1, const=None, obj=None): + self._short_opts = [] + self._long_opts = [] + self.prefixes = set() + + for opt in opts: + prefix, value = split_opt(opt) + if not prefix: + raise ValueError("Invalid start character for option ({})".format(opt)) + self.prefixes.add(prefix[0]) + if len(prefix) == 1 and len(value) == 1: + self._short_opts.append(opt) + else: + self._long_opts.append(opt) + self.prefixes.add(prefix) + + if action is None: + action = "store" + + self.dest = dest + self.action = action + self.nargs = nargs + self.const = const + self.obj = obj + + @property + def takes_value(self): + return self.action in ("store", "append") + + def process(self, value, state): + if self.action == "store": + state.opts[self.dest] = value + elif self.action == "store_const": + state.opts[self.dest] = self.const + elif self.action == "append": + state.opts.setdefault(self.dest, []).append(value) + elif self.action == "append_const": + state.opts.setdefault(self.dest, []).append(self.const) + elif self.action == "count": + state.opts[self.dest] = state.opts.get(self.dest, 0) + 1 + else: + raise ValueError("unknown action '{}'".format(self.action)) + state.order.append(self.obj) + + +class Argument(object): + def __init__(self, dest, nargs=1, obj=None): + self.dest = dest + self.nargs = nargs + self.obj = obj + + def process(self, value, state): + if self.nargs > 1: + holes = sum(1 for x in value if x is None) + if holes == len(value): + value = None + elif holes != 0: + raise BadArgumentUsage( + "argument {} takes {} values".format(self.dest, self.nargs) + ) + state.opts[self.dest] = value + state.order.append(self.obj) + + +class ParsingState(object): + def __init__(self, rargs): + self.opts = {} + self.largs = [] + self.rargs = rargs + self.order = [] + + +class OptionParser(object): + """The option parser is an internal class that is ultimately used to + parse options and arguments. It's modelled after optparse and brings + a similar but vastly simplified API. It should generally not be used + directly as the high level Click classes wrap it for you. + + It's not nearly as extensible as optparse or argparse as it does not + implement features that are implemented on a higher level (such as + types or defaults). + + :param ctx: optionally the :class:`~click.Context` where this parser + should go with. + """ + + def __init__(self, ctx=None): + #: The :class:`~click.Context` for this parser. This might be + #: `None` for some advanced use cases. + self.ctx = ctx + #: This controls how the parser deals with interspersed arguments. + #: If this is set to `False`, the parser will stop on the first + #: non-option. Click uses this to implement nested subcommands + #: safely. + self.allow_interspersed_args = True + #: This tells the parser how to deal with unknown options. By + #: default it will error out (which is sensible), but there is a + #: second mode where it will ignore it and continue processing + #: after shifting all the unknown options into the resulting args. + self.ignore_unknown_options = False + if ctx is not None: + self.allow_interspersed_args = ctx.allow_interspersed_args + self.ignore_unknown_options = ctx.ignore_unknown_options + self._short_opt = {} + self._long_opt = {} + self._opt_prefixes = {"-", "--"} + self._args = [] + + def add_option(self, opts, dest, action=None, nargs=1, const=None, obj=None): + """Adds a new option named `dest` to the parser. The destination + is not inferred (unlike with optparse) and needs to be explicitly + provided. Action can be any of ``store``, ``store_const``, + ``append``, ``appnd_const`` or ``count``. + + The `obj` can be used to identify the option in the order list + that is returned from the parser. + """ + if obj is None: + obj = dest + opts = [normalize_opt(opt, self.ctx) for opt in opts] + option = Option(opts, dest, action=action, nargs=nargs, const=const, obj=obj) + self._opt_prefixes.update(option.prefixes) + for opt in option._short_opts: + self._short_opt[opt] = option + for opt in option._long_opts: + self._long_opt[opt] = option + + def add_argument(self, dest, nargs=1, obj=None): + """Adds a positional argument named `dest` to the parser. + + The `obj` can be used to identify the option in the order list + that is returned from the parser. + """ + if obj is None: + obj = dest + self._args.append(Argument(dest=dest, nargs=nargs, obj=obj)) + + def parse_args(self, args): + """Parses positional arguments and returns ``(values, args, order)`` + for the parsed options and arguments as well as the leftover + arguments if there are any. The order is a list of objects as they + appear on the command line. If arguments appear multiple times they + will be memorized multiple times as well. + """ + state = ParsingState(args) + try: + self._process_args_for_options(state) + self._process_args_for_args(state) + except UsageError: + if self.ctx is None or not self.ctx.resilient_parsing: + raise + return state.opts, state.largs, state.order + + def _process_args_for_args(self, state): + pargs, args = _unpack_args( + state.largs + state.rargs, [x.nargs for x in self._args] + ) + + for idx, arg in enumerate(self._args): + arg.process(pargs[idx], state) + + state.largs = args + state.rargs = [] + + def _process_args_for_options(self, state): + while state.rargs: + arg = state.rargs.pop(0) + arglen = len(arg) + # Double dashes always handled explicitly regardless of what + # prefixes are valid. + if arg == "--": + return + elif arg[:1] in self._opt_prefixes and arglen > 1: + self._process_opts(arg, state) + elif self.allow_interspersed_args: + state.largs.append(arg) + else: + state.rargs.insert(0, arg) + return + + # Say this is the original argument list: + # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)] + # ^ + # (we are about to process arg(i)). + # + # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of + # [arg0, ..., arg(i-1)] (any options and their arguments will have + # been removed from largs). + # + # The while loop will usually consume 1 or more arguments per pass. + # If it consumes 1 (eg. arg is an option that takes no arguments), + # then after _process_arg() is done the situation is: + # + # largs = subset of [arg0, ..., arg(i)] + # rargs = [arg(i+1), ..., arg(N-1)] + # + # If allow_interspersed_args is false, largs will always be + # *empty* -- still a subset of [arg0, ..., arg(i-1)], but + # not a very interesting subset! + + def _match_long_opt(self, opt, explicit_value, state): + if opt not in self._long_opt: + possibilities = [word for word in self._long_opt if word.startswith(opt)] + raise NoSuchOption(opt, possibilities=possibilities, ctx=self.ctx) + + option = self._long_opt[opt] + if option.takes_value: + # At this point it's safe to modify rargs by injecting the + # explicit value, because no exception is raised in this + # branch. This means that the inserted value will be fully + # consumed. + if explicit_value is not None: + state.rargs.insert(0, explicit_value) + + nargs = option.nargs + if len(state.rargs) < nargs: + _error_opt_args(nargs, opt) + elif nargs == 1: + value = state.rargs.pop(0) + else: + value = tuple(state.rargs[:nargs]) + del state.rargs[:nargs] + + elif explicit_value is not None: + raise BadOptionUsage(opt, "{} option does not take a value".format(opt)) + + else: + value = None + + option.process(value, state) + + def _match_short_opt(self, arg, state): + stop = False + i = 1 + prefix = arg[0] + unknown_options = [] + + for ch in arg[1:]: + opt = normalize_opt(prefix + ch, self.ctx) + option = self._short_opt.get(opt) + i += 1 + + if not option: + if self.ignore_unknown_options: + unknown_options.append(ch) + continue + raise NoSuchOption(opt, ctx=self.ctx) + if option.takes_value: + # Any characters left in arg? Pretend they're the + # next arg, and stop consuming characters of arg. + if i < len(arg): + state.rargs.insert(0, arg[i:]) + stop = True + + nargs = option.nargs + if len(state.rargs) < nargs: + _error_opt_args(nargs, opt) + elif nargs == 1: + value = state.rargs.pop(0) + else: + value = tuple(state.rargs[:nargs]) + del state.rargs[:nargs] + + else: + value = None + + option.process(value, state) + + if stop: + break + + # If we got any unknown options we re-combinate the string of the + # remaining options and re-attach the prefix, then report that + # to the state as new larg. This way there is basic combinatorics + # that can be achieved while still ignoring unknown arguments. + if self.ignore_unknown_options and unknown_options: + state.largs.append("{}{}".format(prefix, "".join(unknown_options))) + + def _process_opts(self, arg, state): + explicit_value = None + # Long option handling happens in two parts. The first part is + # supporting explicitly attached values. In any case, we will try + # to long match the option first. + if "=" in arg: + long_opt, explicit_value = arg.split("=", 1) + else: + long_opt = arg + norm_long_opt = normalize_opt(long_opt, self.ctx) + + # At this point we will match the (assumed) long option through + # the long option matching code. Note that this allows options + # like "-foo" to be matched as long options. + try: + self._match_long_opt(norm_long_opt, explicit_value, state) + except NoSuchOption: + # At this point the long option matching failed, and we need + # to try with short options. However there is a special rule + # which says, that if we have a two character options prefix + # (applies to "--foo" for instance), we do not dispatch to the + # short option code and will instead raise the no option + # error. + if arg[:2] not in self._opt_prefixes: + return self._match_short_opt(arg, state) + if not self.ignore_unknown_options: + raise + state.largs.append(arg) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/termui.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/termui.py new file mode 100644 index 0000000..02ef9e9 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/termui.py @@ -0,0 +1,681 @@ +import inspect +import io +import itertools +import os +import struct +import sys + +from ._compat import DEFAULT_COLUMNS +from ._compat import get_winterm_size +from ._compat import isatty +from ._compat import raw_input +from ._compat import string_types +from ._compat import strip_ansi +from ._compat import text_type +from ._compat import WIN +from .exceptions import Abort +from .exceptions import UsageError +from .globals import resolve_color_default +from .types import Choice +from .types import convert_type +from .types import Path +from .utils import echo +from .utils import LazyFile + +# The prompt functions to use. The doc tools currently override these +# functions to customize how they work. +visible_prompt_func = raw_input + +_ansi_colors = { + "black": 30, + "red": 31, + "green": 32, + "yellow": 33, + "blue": 34, + "magenta": 35, + "cyan": 36, + "white": 37, + "reset": 39, + "bright_black": 90, + "bright_red": 91, + "bright_green": 92, + "bright_yellow": 93, + "bright_blue": 94, + "bright_magenta": 95, + "bright_cyan": 96, + "bright_white": 97, +} +_ansi_reset_all = "\033[0m" + + +def hidden_prompt_func(prompt): + import getpass + + return getpass.getpass(prompt) + + +def _build_prompt( + text, suffix, show_default=False, default=None, show_choices=True, type=None +): + prompt = text + if type is not None and show_choices and isinstance(type, Choice): + prompt += " ({})".format(", ".join(map(str, type.choices))) + if default is not None and show_default: + prompt = "{} [{}]".format(prompt, _format_default(default)) + return prompt + suffix + + +def _format_default(default): + if isinstance(default, (io.IOBase, LazyFile)) and hasattr(default, "name"): + return default.name + + return default + + +def prompt( + text, + default=None, + hide_input=False, + confirmation_prompt=False, + type=None, + value_proc=None, + prompt_suffix=": ", + show_default=True, + err=False, + show_choices=True, +): + """Prompts a user for input. This is a convenience function that can + be used to prompt a user for input later. + + If the user aborts the input by sending a interrupt signal, this + function will catch it and raise a :exc:`Abort` exception. + + .. versionadded:: 7.0 + Added the show_choices parameter. + + .. versionadded:: 6.0 + Added unicode support for cmd.exe on Windows. + + .. versionadded:: 4.0 + Added the `err` parameter. + + :param text: the text to show for the prompt. + :param default: the default value to use if no input happens. If this + is not given it will prompt until it's aborted. + :param hide_input: if this is set to true then the input value will + be hidden. + :param confirmation_prompt: asks for confirmation for the value. + :param type: the type to use to check the value against. + :param value_proc: if this parameter is provided it's a function that + is invoked instead of the type conversion to + convert a value. + :param prompt_suffix: a suffix that should be added to the prompt. + :param show_default: shows or hides the default value in the prompt. + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``, the same as with echo. + :param show_choices: Show or hide choices if the passed type is a Choice. + For example if type is a Choice of either day or week, + show_choices is true and text is "Group by" then the + prompt will be "Group by (day, week): ". + """ + result = None + + def prompt_func(text): + f = hidden_prompt_func if hide_input else visible_prompt_func + try: + # Write the prompt separately so that we get nice + # coloring through colorama on Windows + echo(text, nl=False, err=err) + return f("") + except (KeyboardInterrupt, EOFError): + # getpass doesn't print a newline if the user aborts input with ^C. + # Allegedly this behavior is inherited from getpass(3). + # A doc bug has been filed at https://bugs.python.org/issue24711 + if hide_input: + echo(None, err=err) + raise Abort() + + if value_proc is None: + value_proc = convert_type(type, default) + + prompt = _build_prompt( + text, prompt_suffix, show_default, default, show_choices, type + ) + + while 1: + while 1: + value = prompt_func(prompt) + if value: + break + elif default is not None: + if isinstance(value_proc, Path): + # validate Path default value(exists, dir_okay etc.) + value = default + break + return default + try: + result = value_proc(value) + except UsageError as e: + echo("Error: {}".format(e.message), err=err) # noqa: B306 + continue + if not confirmation_prompt: + return result + while 1: + value2 = prompt_func("Repeat for confirmation: ") + if value2: + break + if value == value2: + return result + echo("Error: the two entered values do not match", err=err) + + +def confirm( + text, default=False, abort=False, prompt_suffix=": ", show_default=True, err=False +): + """Prompts for confirmation (yes/no question). + + If the user aborts the input by sending a interrupt signal this + function will catch it and raise a :exc:`Abort` exception. + + .. versionadded:: 4.0 + Added the `err` parameter. + + :param text: the question to ask. + :param default: the default for the prompt. + :param abort: if this is set to `True` a negative answer aborts the + exception by raising :exc:`Abort`. + :param prompt_suffix: a suffix that should be added to the prompt. + :param show_default: shows or hides the default value in the prompt. + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``, the same as with echo. + """ + prompt = _build_prompt( + text, prompt_suffix, show_default, "Y/n" if default else "y/N" + ) + while 1: + try: + # Write the prompt separately so that we get nice + # coloring through colorama on Windows + echo(prompt, nl=False, err=err) + value = visible_prompt_func("").lower().strip() + except (KeyboardInterrupt, EOFError): + raise Abort() + if value in ("y", "yes"): + rv = True + elif value in ("n", "no"): + rv = False + elif value == "": + rv = default + else: + echo("Error: invalid input", err=err) + continue + break + if abort and not rv: + raise Abort() + return rv + + +def get_terminal_size(): + """Returns the current size of the terminal as tuple in the form + ``(width, height)`` in columns and rows. + """ + # If shutil has get_terminal_size() (Python 3.3 and later) use that + if sys.version_info >= (3, 3): + import shutil + + shutil_get_terminal_size = getattr(shutil, "get_terminal_size", None) + if shutil_get_terminal_size: + sz = shutil_get_terminal_size() + return sz.columns, sz.lines + + # We provide a sensible default for get_winterm_size() when being invoked + # inside a subprocess. Without this, it would not provide a useful input. + if get_winterm_size is not None: + size = get_winterm_size() + if size == (0, 0): + return (79, 24) + else: + return size + + def ioctl_gwinsz(fd): + try: + import fcntl + import termios + + cr = struct.unpack("hh", fcntl.ioctl(fd, termios.TIOCGWINSZ, "1234")) + except Exception: + return + return cr + + cr = ioctl_gwinsz(0) or ioctl_gwinsz(1) or ioctl_gwinsz(2) + if not cr: + try: + fd = os.open(os.ctermid(), os.O_RDONLY) + try: + cr = ioctl_gwinsz(fd) + finally: + os.close(fd) + except Exception: + pass + if not cr or not cr[0] or not cr[1]: + cr = (os.environ.get("LINES", 25), os.environ.get("COLUMNS", DEFAULT_COLUMNS)) + return int(cr[1]), int(cr[0]) + + +def echo_via_pager(text_or_generator, color=None): + """This function takes a text and shows it via an environment specific + pager on stdout. + + .. versionchanged:: 3.0 + Added the `color` flag. + + :param text_or_generator: the text to page, or alternatively, a + generator emitting the text to page. + :param color: controls if the pager supports ANSI colors or not. The + default is autodetection. + """ + color = resolve_color_default(color) + + if inspect.isgeneratorfunction(text_or_generator): + i = text_or_generator() + elif isinstance(text_or_generator, string_types): + i = [text_or_generator] + else: + i = iter(text_or_generator) + + # convert every element of i to a text type if necessary + text_generator = (el if isinstance(el, string_types) else text_type(el) for el in i) + + from ._termui_impl import pager + + return pager(itertools.chain(text_generator, "\n"), color) + + +def progressbar( + iterable=None, + length=None, + label=None, + show_eta=True, + show_percent=None, + show_pos=False, + item_show_func=None, + fill_char="#", + empty_char="-", + bar_template="%(label)s [%(bar)s] %(info)s", + info_sep=" ", + width=36, + file=None, + color=None, +): + """This function creates an iterable context manager that can be used + to iterate over something while showing a progress bar. It will + either iterate over the `iterable` or `length` items (that are counted + up). While iteration happens, this function will print a rendered + progress bar to the given `file` (defaults to stdout) and will attempt + to calculate remaining time and more. By default, this progress bar + will not be rendered if the file is not a terminal. + + The context manager creates the progress bar. When the context + manager is entered the progress bar is already created. With every + iteration over the progress bar, the iterable passed to the bar is + advanced and the bar is updated. When the context manager exits, + a newline is printed and the progress bar is finalized on screen. + + Note: The progress bar is currently designed for use cases where the + total progress can be expected to take at least several seconds. + Because of this, the ProgressBar class object won't display + progress that is considered too fast, and progress where the time + between steps is less than a second. + + No printing must happen or the progress bar will be unintentionally + destroyed. + + Example usage:: + + with progressbar(items) as bar: + for item in bar: + do_something_with(item) + + Alternatively, if no iterable is specified, one can manually update the + progress bar through the `update()` method instead of directly + iterating over the progress bar. The update method accepts the number + of steps to increment the bar with:: + + with progressbar(length=chunks.total_bytes) as bar: + for chunk in chunks: + process_chunk(chunk) + bar.update(chunks.bytes) + + .. versionadded:: 2.0 + + .. versionadded:: 4.0 + Added the `color` parameter. Added a `update` method to the + progressbar object. + + :param iterable: an iterable to iterate over. If not provided the length + is required. + :param length: the number of items to iterate over. By default the + progressbar will attempt to ask the iterator about its + length, which might or might not work. If an iterable is + also provided this parameter can be used to override the + length. If an iterable is not provided the progress bar + will iterate over a range of that length. + :param label: the label to show next to the progress bar. + :param show_eta: enables or disables the estimated time display. This is + automatically disabled if the length cannot be + determined. + :param show_percent: enables or disables the percentage display. The + default is `True` if the iterable has a length or + `False` if not. + :param show_pos: enables or disables the absolute position display. The + default is `False`. + :param item_show_func: a function called with the current item which + can return a string to show the current item + next to the progress bar. Note that the current + item can be `None`! + :param fill_char: the character to use to show the filled part of the + progress bar. + :param empty_char: the character to use to show the non-filled part of + the progress bar. + :param bar_template: the format string to use as template for the bar. + The parameters in it are ``label`` for the label, + ``bar`` for the progress bar and ``info`` for the + info section. + :param info_sep: the separator between multiple info items (eta etc.) + :param width: the width of the progress bar in characters, 0 means full + terminal width + :param file: the file to write to. If this is not a terminal then + only the label is printed. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. This is only needed if ANSI + codes are included anywhere in the progress bar output + which is not the case by default. + """ + from ._termui_impl import ProgressBar + + color = resolve_color_default(color) + return ProgressBar( + iterable=iterable, + length=length, + show_eta=show_eta, + show_percent=show_percent, + show_pos=show_pos, + item_show_func=item_show_func, + fill_char=fill_char, + empty_char=empty_char, + bar_template=bar_template, + info_sep=info_sep, + file=file, + label=label, + width=width, + color=color, + ) + + +def clear(): + """Clears the terminal screen. This will have the effect of clearing + the whole visible space of the terminal and moving the cursor to the + top left. This does not do anything if not connected to a terminal. + + .. versionadded:: 2.0 + """ + if not isatty(sys.stdout): + return + # If we're on Windows and we don't have colorama available, then we + # clear the screen by shelling out. Otherwise we can use an escape + # sequence. + if WIN: + os.system("cls") + else: + sys.stdout.write("\033[2J\033[1;1H") + + +def style( + text, + fg=None, + bg=None, + bold=None, + dim=None, + underline=None, + blink=None, + reverse=None, + reset=True, +): + """Styles a text with ANSI styles and returns the new string. By + default the styling is self contained which means that at the end + of the string a reset code is issued. This can be prevented by + passing ``reset=False``. + + Examples:: + + click.echo(click.style('Hello World!', fg='green')) + click.echo(click.style('ATTENTION!', blink=True)) + click.echo(click.style('Some things', reverse=True, fg='cyan')) + + Supported color names: + + * ``black`` (might be a gray) + * ``red`` + * ``green`` + * ``yellow`` (might be an orange) + * ``blue`` + * ``magenta`` + * ``cyan`` + * ``white`` (might be light gray) + * ``bright_black`` + * ``bright_red`` + * ``bright_green`` + * ``bright_yellow`` + * ``bright_blue`` + * ``bright_magenta`` + * ``bright_cyan`` + * ``bright_white`` + * ``reset`` (reset the color code only) + + .. versionadded:: 2.0 + + .. versionadded:: 7.0 + Added support for bright colors. + + :param text: the string to style with ansi codes. + :param fg: if provided this will become the foreground color. + :param bg: if provided this will become the background color. + :param bold: if provided this will enable or disable bold mode. + :param dim: if provided this will enable or disable dim mode. This is + badly supported. + :param underline: if provided this will enable or disable underline. + :param blink: if provided this will enable or disable blinking. + :param reverse: if provided this will enable or disable inverse + rendering (foreground becomes background and the + other way round). + :param reset: by default a reset-all code is added at the end of the + string which means that styles do not carry over. This + can be disabled to compose styles. + """ + bits = [] + if fg: + try: + bits.append("\033[{}m".format(_ansi_colors[fg])) + except KeyError: + raise TypeError("Unknown color '{}'".format(fg)) + if bg: + try: + bits.append("\033[{}m".format(_ansi_colors[bg] + 10)) + except KeyError: + raise TypeError("Unknown color '{}'".format(bg)) + if bold is not None: + bits.append("\033[{}m".format(1 if bold else 22)) + if dim is not None: + bits.append("\033[{}m".format(2 if dim else 22)) + if underline is not None: + bits.append("\033[{}m".format(4 if underline else 24)) + if blink is not None: + bits.append("\033[{}m".format(5 if blink else 25)) + if reverse is not None: + bits.append("\033[{}m".format(7 if reverse else 27)) + bits.append(text) + if reset: + bits.append(_ansi_reset_all) + return "".join(bits) + + +def unstyle(text): + """Removes ANSI styling information from a string. Usually it's not + necessary to use this function as Click's echo function will + automatically remove styling if necessary. + + .. versionadded:: 2.0 + + :param text: the text to remove style information from. + """ + return strip_ansi(text) + + +def secho(message=None, file=None, nl=True, err=False, color=None, **styles): + """This function combines :func:`echo` and :func:`style` into one + call. As such the following two calls are the same:: + + click.secho('Hello World!', fg='green') + click.echo(click.style('Hello World!', fg='green')) + + All keyword arguments are forwarded to the underlying functions + depending on which one they go with. + + .. versionadded:: 2.0 + """ + if message is not None: + message = style(message, **styles) + return echo(message, file=file, nl=nl, err=err, color=color) + + +def edit( + text=None, editor=None, env=None, require_save=True, extension=".txt", filename=None +): + r"""Edits the given text in the defined editor. If an editor is given + (should be the full path to the executable but the regular operating + system search path is used for finding the executable) it overrides + the detected editor. Optionally, some environment variables can be + used. If the editor is closed without changes, `None` is returned. In + case a file is edited directly the return value is always `None` and + `require_save` and `extension` are ignored. + + If the editor cannot be opened a :exc:`UsageError` is raised. + + Note for Windows: to simplify cross-platform usage, the newlines are + automatically converted from POSIX to Windows and vice versa. As such, + the message here will have ``\n`` as newline markers. + + :param text: the text to edit. + :param editor: optionally the editor to use. Defaults to automatic + detection. + :param env: environment variables to forward to the editor. + :param require_save: if this is true, then not saving in the editor + will make the return value become `None`. + :param extension: the extension to tell the editor about. This defaults + to `.txt` but changing this might change syntax + highlighting. + :param filename: if provided it will edit this file instead of the + provided text contents. It will not use a temporary + file as an indirection in that case. + """ + from ._termui_impl import Editor + + editor = Editor( + editor=editor, env=env, require_save=require_save, extension=extension + ) + if filename is None: + return editor.edit(text) + editor.edit_file(filename) + + +def launch(url, wait=False, locate=False): + """This function launches the given URL (or filename) in the default + viewer application for this file type. If this is an executable, it + might launch the executable in a new session. The return value is + the exit code of the launched application. Usually, ``0`` indicates + success. + + Examples:: + + click.launch('https://click.palletsprojects.com/') + click.launch('/my/downloaded/file', locate=True) + + .. versionadded:: 2.0 + + :param url: URL or filename of the thing to launch. + :param wait: waits for the program to stop. + :param locate: if this is set to `True` then instead of launching the + application associated with the URL it will attempt to + launch a file manager with the file located. This + might have weird effects if the URL does not point to + the filesystem. + """ + from ._termui_impl import open_url + + return open_url(url, wait=wait, locate=locate) + + +# If this is provided, getchar() calls into this instead. This is used +# for unittesting purposes. +_getchar = None + + +def getchar(echo=False): + """Fetches a single character from the terminal and returns it. This + will always return a unicode character and under certain rare + circumstances this might return more than one character. The + situations which more than one character is returned is when for + whatever reason multiple characters end up in the terminal buffer or + standard input was not actually a terminal. + + Note that this will always read from the terminal, even if something + is piped into the standard input. + + Note for Windows: in rare cases when typing non-ASCII characters, this + function might wait for a second character and then return both at once. + This is because certain Unicode characters look like special-key markers. + + .. versionadded:: 2.0 + + :param echo: if set to `True`, the character read will also show up on + the terminal. The default is to not show it. + """ + f = _getchar + if f is None: + from ._termui_impl import getchar as f + return f(echo) + + +def raw_terminal(): + from ._termui_impl import raw_terminal as f + + return f() + + +def pause(info="Press any key to continue ...", err=False): + """This command stops execution and waits for the user to press any + key to continue. This is similar to the Windows batch "pause" + command. If the program is not run through a terminal, this command + will instead do nothing. + + .. versionadded:: 2.0 + + .. versionadded:: 4.0 + Added the `err` parameter. + + :param info: the info string to print before pausing. + :param err: if set to message goes to ``stderr`` instead of + ``stdout``, the same as with echo. + """ + if not isatty(sys.stdin) or not isatty(sys.stdout): + return + try: + if info: + echo(info, nl=False, err=err) + try: + getchar() + except (KeyboardInterrupt, EOFError): + pass + finally: + if info: + echo(err=err) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/testing.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/testing.py new file mode 100644 index 0000000..a3dba3b --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/testing.py @@ -0,0 +1,382 @@ +import contextlib +import os +import shlex +import shutil +import sys +import tempfile + +from . import formatting +from . import termui +from . import utils +from ._compat import iteritems +from ._compat import PY2 +from ._compat import string_types + + +if PY2: + from cStringIO import StringIO +else: + import io + from ._compat import _find_binary_reader + + +class EchoingStdin(object): + def __init__(self, input, output): + self._input = input + self._output = output + + def __getattr__(self, x): + return getattr(self._input, x) + + def _echo(self, rv): + self._output.write(rv) + return rv + + def read(self, n=-1): + return self._echo(self._input.read(n)) + + def readline(self, n=-1): + return self._echo(self._input.readline(n)) + + def readlines(self): + return [self._echo(x) for x in self._input.readlines()] + + def __iter__(self): + return iter(self._echo(x) for x in self._input) + + def __repr__(self): + return repr(self._input) + + +def make_input_stream(input, charset): + # Is already an input stream. + if hasattr(input, "read"): + if PY2: + return input + rv = _find_binary_reader(input) + if rv is not None: + return rv + raise TypeError("Could not find binary reader for input stream.") + + if input is None: + input = b"" + elif not isinstance(input, bytes): + input = input.encode(charset) + if PY2: + return StringIO(input) + return io.BytesIO(input) + + +class Result(object): + """Holds the captured result of an invoked CLI script.""" + + def __init__( + self, runner, stdout_bytes, stderr_bytes, exit_code, exception, exc_info=None + ): + #: The runner that created the result + self.runner = runner + #: The standard output as bytes. + self.stdout_bytes = stdout_bytes + #: The standard error as bytes, or None if not available + self.stderr_bytes = stderr_bytes + #: The exit code as integer. + self.exit_code = exit_code + #: The exception that happened if one did. + self.exception = exception + #: The traceback + self.exc_info = exc_info + + @property + def output(self): + """The (standard) output as unicode string.""" + return self.stdout + + @property + def stdout(self): + """The standard output as unicode string.""" + return self.stdout_bytes.decode(self.runner.charset, "replace").replace( + "\r\n", "\n" + ) + + @property + def stderr(self): + """The standard error as unicode string.""" + if self.stderr_bytes is None: + raise ValueError("stderr not separately captured") + return self.stderr_bytes.decode(self.runner.charset, "replace").replace( + "\r\n", "\n" + ) + + def __repr__(self): + return "<{} {}>".format( + type(self).__name__, repr(self.exception) if self.exception else "okay" + ) + + +class CliRunner(object): + """The CLI runner provides functionality to invoke a Click command line + script for unittesting purposes in a isolated environment. This only + works in single-threaded systems without any concurrency as it changes the + global interpreter state. + + :param charset: the character set for the input and output data. This is + UTF-8 by default and should not be changed currently as + the reporting to Click only works in Python 2 properly. + :param env: a dictionary with environment variables for overriding. + :param echo_stdin: if this is set to `True`, then reading from stdin writes + to stdout. This is useful for showing examples in + some circumstances. Note that regular prompts + will automatically echo the input. + :param mix_stderr: if this is set to `False`, then stdout and stderr are + preserved as independent streams. This is useful for + Unix-philosophy apps that have predictable stdout and + noisy stderr, such that each may be measured + independently + """ + + def __init__(self, charset=None, env=None, echo_stdin=False, mix_stderr=True): + if charset is None: + charset = "utf-8" + self.charset = charset + self.env = env or {} + self.echo_stdin = echo_stdin + self.mix_stderr = mix_stderr + + def get_default_prog_name(self, cli): + """Given a command object it will return the default program name + for it. The default is the `name` attribute or ``"root"`` if not + set. + """ + return cli.name or "root" + + def make_env(self, overrides=None): + """Returns the environment overrides for invoking a script.""" + rv = dict(self.env) + if overrides: + rv.update(overrides) + return rv + + @contextlib.contextmanager + def isolation(self, input=None, env=None, color=False): + """A context manager that sets up the isolation for invoking of a + command line tool. This sets up stdin with the given input data + and `os.environ` with the overrides from the given dictionary. + This also rebinds some internals in Click to be mocked (like the + prompt functionality). + + This is automatically done in the :meth:`invoke` method. + + .. versionadded:: 4.0 + The ``color`` parameter was added. + + :param input: the input stream to put into sys.stdin. + :param env: the environment overrides as dictionary. + :param color: whether the output should contain color codes. The + application can still override this explicitly. + """ + input = make_input_stream(input, self.charset) + + old_stdin = sys.stdin + old_stdout = sys.stdout + old_stderr = sys.stderr + old_forced_width = formatting.FORCED_WIDTH + formatting.FORCED_WIDTH = 80 + + env = self.make_env(env) + + if PY2: + bytes_output = StringIO() + if self.echo_stdin: + input = EchoingStdin(input, bytes_output) + sys.stdout = bytes_output + if not self.mix_stderr: + bytes_error = StringIO() + sys.stderr = bytes_error + else: + bytes_output = io.BytesIO() + if self.echo_stdin: + input = EchoingStdin(input, bytes_output) + input = io.TextIOWrapper(input, encoding=self.charset) + sys.stdout = io.TextIOWrapper(bytes_output, encoding=self.charset) + if not self.mix_stderr: + bytes_error = io.BytesIO() + sys.stderr = io.TextIOWrapper(bytes_error, encoding=self.charset) + + if self.mix_stderr: + sys.stderr = sys.stdout + + sys.stdin = input + + def visible_input(prompt=None): + sys.stdout.write(prompt or "") + val = input.readline().rstrip("\r\n") + sys.stdout.write("{}\n".format(val)) + sys.stdout.flush() + return val + + def hidden_input(prompt=None): + sys.stdout.write("{}\n".format(prompt or "")) + sys.stdout.flush() + return input.readline().rstrip("\r\n") + + def _getchar(echo): + char = sys.stdin.read(1) + if echo: + sys.stdout.write(char) + sys.stdout.flush() + return char + + default_color = color + + def should_strip_ansi(stream=None, color=None): + if color is None: + return not default_color + return not color + + old_visible_prompt_func = termui.visible_prompt_func + old_hidden_prompt_func = termui.hidden_prompt_func + old__getchar_func = termui._getchar + old_should_strip_ansi = utils.should_strip_ansi + termui.visible_prompt_func = visible_input + termui.hidden_prompt_func = hidden_input + termui._getchar = _getchar + utils.should_strip_ansi = should_strip_ansi + + old_env = {} + try: + for key, value in iteritems(env): + old_env[key] = os.environ.get(key) + if value is None: + try: + del os.environ[key] + except Exception: + pass + else: + os.environ[key] = value + yield (bytes_output, not self.mix_stderr and bytes_error) + finally: + for key, value in iteritems(old_env): + if value is None: + try: + del os.environ[key] + except Exception: + pass + else: + os.environ[key] = value + sys.stdout = old_stdout + sys.stderr = old_stderr + sys.stdin = old_stdin + termui.visible_prompt_func = old_visible_prompt_func + termui.hidden_prompt_func = old_hidden_prompt_func + termui._getchar = old__getchar_func + utils.should_strip_ansi = old_should_strip_ansi + formatting.FORCED_WIDTH = old_forced_width + + def invoke( + self, + cli, + args=None, + input=None, + env=None, + catch_exceptions=True, + color=False, + **extra + ): + """Invokes a command in an isolated environment. The arguments are + forwarded directly to the command line script, the `extra` keyword + arguments are passed to the :meth:`~clickpkg.Command.main` function of + the command. + + This returns a :class:`Result` object. + + .. versionadded:: 3.0 + The ``catch_exceptions`` parameter was added. + + .. versionchanged:: 3.0 + The result object now has an `exc_info` attribute with the + traceback if available. + + .. versionadded:: 4.0 + The ``color`` parameter was added. + + :param cli: the command to invoke + :param args: the arguments to invoke. It may be given as an iterable + or a string. When given as string it will be interpreted + as a Unix shell command. More details at + :func:`shlex.split`. + :param input: the input data for `sys.stdin`. + :param env: the environment overrides. + :param catch_exceptions: Whether to catch any other exceptions than + ``SystemExit``. + :param extra: the keyword arguments to pass to :meth:`main`. + :param color: whether the output should contain color codes. The + application can still override this explicitly. + """ + exc_info = None + with self.isolation(input=input, env=env, color=color) as outstreams: + exception = None + exit_code = 0 + + if isinstance(args, string_types): + args = shlex.split(args) + + try: + prog_name = extra.pop("prog_name") + except KeyError: + prog_name = self.get_default_prog_name(cli) + + try: + cli.main(args=args or (), prog_name=prog_name, **extra) + except SystemExit as e: + exc_info = sys.exc_info() + exit_code = e.code + if exit_code is None: + exit_code = 0 + + if exit_code != 0: + exception = e + + if not isinstance(exit_code, int): + sys.stdout.write(str(exit_code)) + sys.stdout.write("\n") + exit_code = 1 + + except Exception as e: + if not catch_exceptions: + raise + exception = e + exit_code = 1 + exc_info = sys.exc_info() + finally: + sys.stdout.flush() + stdout = outstreams[0].getvalue() + if self.mix_stderr: + stderr = None + else: + stderr = outstreams[1].getvalue() + + return Result( + runner=self, + stdout_bytes=stdout, + stderr_bytes=stderr, + exit_code=exit_code, + exception=exception, + exc_info=exc_info, + ) + + @contextlib.contextmanager + def isolated_filesystem(self): + """A context manager that creates a temporary folder and changes + the current working directory to it for isolated filesystem tests. + """ + cwd = os.getcwd() + t = tempfile.mkdtemp() + os.chdir(t) + try: + yield t + finally: + os.chdir(cwd) + try: + shutil.rmtree(t) + except (OSError, IOError): # noqa: B014 + pass diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/types.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/types.py new file mode 100644 index 0000000..505c39f --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/types.py @@ -0,0 +1,762 @@ +import os +import stat +from datetime import datetime + +from ._compat import _get_argv_encoding +from ._compat import filename_to_ui +from ._compat import get_filesystem_encoding +from ._compat import get_streerror +from ._compat import open_stream +from ._compat import PY2 +from ._compat import text_type +from .exceptions import BadParameter +from .utils import LazyFile +from .utils import safecall + + +class ParamType(object): + """Helper for converting values through types. The following is + necessary for a valid type: + + * it needs a name + * it needs to pass through None unchanged + * it needs to convert from a string + * it needs to convert its result type through unchanged + (eg: needs to be idempotent) + * it needs to be able to deal with param and context being `None`. + This can be the case when the object is used with prompt + inputs. + """ + + is_composite = False + + #: the descriptive name of this type + name = None + + #: if a list of this type is expected and the value is pulled from a + #: string environment variable, this is what splits it up. `None` + #: means any whitespace. For all parameters the general rule is that + #: whitespace splits them up. The exception are paths and files which + #: are split by ``os.path.pathsep`` by default (":" on Unix and ";" on + #: Windows). + envvar_list_splitter = None + + def __call__(self, value, param=None, ctx=None): + if value is not None: + return self.convert(value, param, ctx) + + def get_metavar(self, param): + """Returns the metavar default for this param if it provides one.""" + + def get_missing_message(self, param): + """Optionally might return extra information about a missing + parameter. + + .. versionadded:: 2.0 + """ + + def convert(self, value, param, ctx): + """Converts the value. This is not invoked for values that are + `None` (the missing value). + """ + return value + + def split_envvar_value(self, rv): + """Given a value from an environment variable this splits it up + into small chunks depending on the defined envvar list splitter. + + If the splitter is set to `None`, which means that whitespace splits, + then leading and trailing whitespace is ignored. Otherwise, leading + and trailing splitters usually lead to empty items being included. + """ + return (rv or "").split(self.envvar_list_splitter) + + def fail(self, message, param=None, ctx=None): + """Helper method to fail with an invalid value message.""" + raise BadParameter(message, ctx=ctx, param=param) + + +class CompositeParamType(ParamType): + is_composite = True + + @property + def arity(self): + raise NotImplementedError() + + +class FuncParamType(ParamType): + def __init__(self, func): + self.name = func.__name__ + self.func = func + + def convert(self, value, param, ctx): + try: + return self.func(value) + except ValueError: + try: + value = text_type(value) + except UnicodeError: + value = str(value).decode("utf-8", "replace") + self.fail(value, param, ctx) + + +class UnprocessedParamType(ParamType): + name = "text" + + def convert(self, value, param, ctx): + return value + + def __repr__(self): + return "UNPROCESSED" + + +class StringParamType(ParamType): + name = "text" + + def convert(self, value, param, ctx): + if isinstance(value, bytes): + enc = _get_argv_encoding() + try: + value = value.decode(enc) + except UnicodeError: + fs_enc = get_filesystem_encoding() + if fs_enc != enc: + try: + value = value.decode(fs_enc) + except UnicodeError: + value = value.decode("utf-8", "replace") + else: + value = value.decode("utf-8", "replace") + return value + return value + + def __repr__(self): + return "STRING" + + +class Choice(ParamType): + """The choice type allows a value to be checked against a fixed set + of supported values. All of these values have to be strings. + + You should only pass a list or tuple of choices. Other iterables + (like generators) may lead to surprising results. + + The resulting value will always be one of the originally passed choices + regardless of ``case_sensitive`` or any ``ctx.token_normalize_func`` + being specified. + + See :ref:`choice-opts` for an example. + + :param case_sensitive: Set to false to make choices case + insensitive. Defaults to true. + """ + + name = "choice" + + def __init__(self, choices, case_sensitive=True): + self.choices = choices + self.case_sensitive = case_sensitive + + def get_metavar(self, param): + return "[{}]".format("|".join(self.choices)) + + def get_missing_message(self, param): + return "Choose from:\n\t{}.".format(",\n\t".join(self.choices)) + + def convert(self, value, param, ctx): + # Match through normalization and case sensitivity + # first do token_normalize_func, then lowercase + # preserve original `value` to produce an accurate message in + # `self.fail` + normed_value = value + normed_choices = {choice: choice for choice in self.choices} + + if ctx is not None and ctx.token_normalize_func is not None: + normed_value = ctx.token_normalize_func(value) + normed_choices = { + ctx.token_normalize_func(normed_choice): original + for normed_choice, original in normed_choices.items() + } + + if not self.case_sensitive: + if PY2: + lower = str.lower + else: + lower = str.casefold + + normed_value = lower(normed_value) + normed_choices = { + lower(normed_choice): original + for normed_choice, original in normed_choices.items() + } + + if normed_value in normed_choices: + return normed_choices[normed_value] + + self.fail( + "invalid choice: {}. (choose from {})".format( + value, ", ".join(self.choices) + ), + param, + ctx, + ) + + def __repr__(self): + return "Choice('{}')".format(list(self.choices)) + + +class DateTime(ParamType): + """The DateTime type converts date strings into `datetime` objects. + + The format strings which are checked are configurable, but default to some + common (non-timezone aware) ISO 8601 formats. + + When specifying *DateTime* formats, you should only pass a list or a tuple. + Other iterables, like generators, may lead to surprising results. + + The format strings are processed using ``datetime.strptime``, and this + consequently defines the format strings which are allowed. + + Parsing is tried using each format, in order, and the first format which + parses successfully is used. + + :param formats: A list or tuple of date format strings, in the order in + which they should be tried. Defaults to + ``'%Y-%m-%d'``, ``'%Y-%m-%dT%H:%M:%S'``, + ``'%Y-%m-%d %H:%M:%S'``. + """ + + name = "datetime" + + def __init__(self, formats=None): + self.formats = formats or ["%Y-%m-%d", "%Y-%m-%dT%H:%M:%S", "%Y-%m-%d %H:%M:%S"] + + def get_metavar(self, param): + return "[{}]".format("|".join(self.formats)) + + def _try_to_convert_date(self, value, format): + try: + return datetime.strptime(value, format) + except ValueError: + return None + + def convert(self, value, param, ctx): + # Exact match + for format in self.formats: + dtime = self._try_to_convert_date(value, format) + if dtime: + return dtime + + self.fail( + "invalid datetime format: {}. (choose from {})".format( + value, ", ".join(self.formats) + ) + ) + + def __repr__(self): + return "DateTime" + + +class IntParamType(ParamType): + name = "integer" + + def convert(self, value, param, ctx): + try: + return int(value) + except ValueError: + self.fail("{} is not a valid integer".format(value), param, ctx) + + def __repr__(self): + return "INT" + + +class IntRange(IntParamType): + """A parameter that works similar to :data:`click.INT` but restricts + the value to fit into a range. The default behavior is to fail if the + value falls outside the range, but it can also be silently clamped + between the two edges. + + See :ref:`ranges` for an example. + """ + + name = "integer range" + + def __init__(self, min=None, max=None, clamp=False): + self.min = min + self.max = max + self.clamp = clamp + + def convert(self, value, param, ctx): + rv = IntParamType.convert(self, value, param, ctx) + if self.clamp: + if self.min is not None and rv < self.min: + return self.min + if self.max is not None and rv > self.max: + return self.max + if ( + self.min is not None + and rv < self.min + or self.max is not None + and rv > self.max + ): + if self.min is None: + self.fail( + "{} is bigger than the maximum valid value {}.".format( + rv, self.max + ), + param, + ctx, + ) + elif self.max is None: + self.fail( + "{} is smaller than the minimum valid value {}.".format( + rv, self.min + ), + param, + ctx, + ) + else: + self.fail( + "{} is not in the valid range of {} to {}.".format( + rv, self.min, self.max + ), + param, + ctx, + ) + return rv + + def __repr__(self): + return "IntRange({}, {})".format(self.min, self.max) + + +class FloatParamType(ParamType): + name = "float" + + def convert(self, value, param, ctx): + try: + return float(value) + except ValueError: + self.fail( + "{} is not a valid floating point value".format(value), param, ctx + ) + + def __repr__(self): + return "FLOAT" + + +class FloatRange(FloatParamType): + """A parameter that works similar to :data:`click.FLOAT` but restricts + the value to fit into a range. The default behavior is to fail if the + value falls outside the range, but it can also be silently clamped + between the two edges. + + See :ref:`ranges` for an example. + """ + + name = "float range" + + def __init__(self, min=None, max=None, clamp=False): + self.min = min + self.max = max + self.clamp = clamp + + def convert(self, value, param, ctx): + rv = FloatParamType.convert(self, value, param, ctx) + if self.clamp: + if self.min is not None and rv < self.min: + return self.min + if self.max is not None and rv > self.max: + return self.max + if ( + self.min is not None + and rv < self.min + or self.max is not None + and rv > self.max + ): + if self.min is None: + self.fail( + "{} is bigger than the maximum valid value {}.".format( + rv, self.max + ), + param, + ctx, + ) + elif self.max is None: + self.fail( + "{} is smaller than the minimum valid value {}.".format( + rv, self.min + ), + param, + ctx, + ) + else: + self.fail( + "{} is not in the valid range of {} to {}.".format( + rv, self.min, self.max + ), + param, + ctx, + ) + return rv + + def __repr__(self): + return "FloatRange({}, {})".format(self.min, self.max) + + +class BoolParamType(ParamType): + name = "boolean" + + def convert(self, value, param, ctx): + if isinstance(value, bool): + return bool(value) + value = value.lower() + if value in ("true", "t", "1", "yes", "y"): + return True + elif value in ("false", "f", "0", "no", "n"): + return False + self.fail("{} is not a valid boolean".format(value), param, ctx) + + def __repr__(self): + return "BOOL" + + +class UUIDParameterType(ParamType): + name = "uuid" + + def convert(self, value, param, ctx): + import uuid + + try: + if PY2 and isinstance(value, text_type): + value = value.encode("ascii") + return uuid.UUID(value) + except ValueError: + self.fail("{} is not a valid UUID value".format(value), param, ctx) + + def __repr__(self): + return "UUID" + + +class File(ParamType): + """Declares a parameter to be a file for reading or writing. The file + is automatically closed once the context tears down (after the command + finished working). + + Files can be opened for reading or writing. The special value ``-`` + indicates stdin or stdout depending on the mode. + + By default, the file is opened for reading text data, but it can also be + opened in binary mode or for writing. The encoding parameter can be used + to force a specific encoding. + + The `lazy` flag controls if the file should be opened immediately or upon + first IO. The default is to be non-lazy for standard input and output + streams as well as files opened for reading, `lazy` otherwise. When opening a + file lazily for reading, it is still opened temporarily for validation, but + will not be held open until first IO. lazy is mainly useful when opening + for writing to avoid creating the file until it is needed. + + Starting with Click 2.0, files can also be opened atomically in which + case all writes go into a separate file in the same folder and upon + completion the file will be moved over to the original location. This + is useful if a file regularly read by other users is modified. + + See :ref:`file-args` for more information. + """ + + name = "filename" + envvar_list_splitter = os.path.pathsep + + def __init__( + self, mode="r", encoding=None, errors="strict", lazy=None, atomic=False + ): + self.mode = mode + self.encoding = encoding + self.errors = errors + self.lazy = lazy + self.atomic = atomic + + def resolve_lazy_flag(self, value): + if self.lazy is not None: + return self.lazy + if value == "-": + return False + elif "w" in self.mode: + return True + return False + + def convert(self, value, param, ctx): + try: + if hasattr(value, "read") or hasattr(value, "write"): + return value + + lazy = self.resolve_lazy_flag(value) + + if lazy: + f = LazyFile( + value, self.mode, self.encoding, self.errors, atomic=self.atomic + ) + if ctx is not None: + ctx.call_on_close(f.close_intelligently) + return f + + f, should_close = open_stream( + value, self.mode, self.encoding, self.errors, atomic=self.atomic + ) + # If a context is provided, we automatically close the file + # at the end of the context execution (or flush out). If a + # context does not exist, it's the caller's responsibility to + # properly close the file. This for instance happens when the + # type is used with prompts. + if ctx is not None: + if should_close: + ctx.call_on_close(safecall(f.close)) + else: + ctx.call_on_close(safecall(f.flush)) + return f + except (IOError, OSError) as e: # noqa: B014 + self.fail( + "Could not open file: {}: {}".format( + filename_to_ui(value), get_streerror(e) + ), + param, + ctx, + ) + + +class Path(ParamType): + """The path type is similar to the :class:`File` type but it performs + different checks. First of all, instead of returning an open file + handle it returns just the filename. Secondly, it can perform various + basic checks about what the file or directory should be. + + .. versionchanged:: 6.0 + `allow_dash` was added. + + :param exists: if set to true, the file or directory needs to exist for + this value to be valid. If this is not required and a + file does indeed not exist, then all further checks are + silently skipped. + :param file_okay: controls if a file is a possible value. + :param dir_okay: controls if a directory is a possible value. + :param writable: if true, a writable check is performed. + :param readable: if true, a readable check is performed. + :param resolve_path: if this is true, then the path is fully resolved + before the value is passed onwards. This means + that it's absolute and symlinks are resolved. It + will not expand a tilde-prefix, as this is + supposed to be done by the shell only. + :param allow_dash: If this is set to `True`, a single dash to indicate + standard streams is permitted. + :param path_type: optionally a string type that should be used to + represent the path. The default is `None` which + means the return value will be either bytes or + unicode depending on what makes most sense given the + input data Click deals with. + """ + + envvar_list_splitter = os.path.pathsep + + def __init__( + self, + exists=False, + file_okay=True, + dir_okay=True, + writable=False, + readable=True, + resolve_path=False, + allow_dash=False, + path_type=None, + ): + self.exists = exists + self.file_okay = file_okay + self.dir_okay = dir_okay + self.writable = writable + self.readable = readable + self.resolve_path = resolve_path + self.allow_dash = allow_dash + self.type = path_type + + if self.file_okay and not self.dir_okay: + self.name = "file" + self.path_type = "File" + elif self.dir_okay and not self.file_okay: + self.name = "directory" + self.path_type = "Directory" + else: + self.name = "path" + self.path_type = "Path" + + def coerce_path_result(self, rv): + if self.type is not None and not isinstance(rv, self.type): + if self.type is text_type: + rv = rv.decode(get_filesystem_encoding()) + else: + rv = rv.encode(get_filesystem_encoding()) + return rv + + def convert(self, value, param, ctx): + rv = value + + is_dash = self.file_okay and self.allow_dash and rv in (b"-", "-") + + if not is_dash: + if self.resolve_path: + rv = os.path.realpath(rv) + + try: + st = os.stat(rv) + except OSError: + if not self.exists: + return self.coerce_path_result(rv) + self.fail( + "{} '{}' does not exist.".format( + self.path_type, filename_to_ui(value) + ), + param, + ctx, + ) + + if not self.file_okay and stat.S_ISREG(st.st_mode): + self.fail( + "{} '{}' is a file.".format(self.path_type, filename_to_ui(value)), + param, + ctx, + ) + if not self.dir_okay and stat.S_ISDIR(st.st_mode): + self.fail( + "{} '{}' is a directory.".format( + self.path_type, filename_to_ui(value) + ), + param, + ctx, + ) + if self.writable and not os.access(value, os.W_OK): + self.fail( + "{} '{}' is not writable.".format( + self.path_type, filename_to_ui(value) + ), + param, + ctx, + ) + if self.readable and not os.access(value, os.R_OK): + self.fail( + "{} '{}' is not readable.".format( + self.path_type, filename_to_ui(value) + ), + param, + ctx, + ) + + return self.coerce_path_result(rv) + + +class Tuple(CompositeParamType): + """The default behavior of Click is to apply a type on a value directly. + This works well in most cases, except for when `nargs` is set to a fixed + count and different types should be used for different items. In this + case the :class:`Tuple` type can be used. This type can only be used + if `nargs` is set to a fixed number. + + For more information see :ref:`tuple-type`. + + This can be selected by using a Python tuple literal as a type. + + :param types: a list of types that should be used for the tuple items. + """ + + def __init__(self, types): + self.types = [convert_type(ty) for ty in types] + + @property + def name(self): + return "<{}>".format(" ".join(ty.name for ty in self.types)) + + @property + def arity(self): + return len(self.types) + + def convert(self, value, param, ctx): + if len(value) != len(self.types): + raise TypeError( + "It would appear that nargs is set to conflict with the" + " composite type arity." + ) + return tuple(ty(x, param, ctx) for ty, x in zip(self.types, value)) + + +def convert_type(ty, default=None): + """Converts a callable or python type into the most appropriate + param type. + """ + guessed_type = False + if ty is None and default is not None: + if isinstance(default, tuple): + ty = tuple(map(type, default)) + else: + ty = type(default) + guessed_type = True + + if isinstance(ty, tuple): + return Tuple(ty) + if isinstance(ty, ParamType): + return ty + if ty is text_type or ty is str or ty is None: + return STRING + if ty is int: + return INT + # Booleans are only okay if not guessed. This is done because for + # flags the default value is actually a bit of a lie in that it + # indicates which of the flags is the one we want. See get_default() + # for more information. + if ty is bool and not guessed_type: + return BOOL + if ty is float: + return FLOAT + if guessed_type: + return STRING + + # Catch a common mistake + if __debug__: + try: + if issubclass(ty, ParamType): + raise AssertionError( + "Attempted to use an uninstantiated parameter type ({}).".format(ty) + ) + except TypeError: + pass + return FuncParamType(ty) + + +#: A dummy parameter type that just does nothing. From a user's +#: perspective this appears to just be the same as `STRING` but internally +#: no string conversion takes place. This is necessary to achieve the +#: same bytes/unicode behavior on Python 2/3 in situations where you want +#: to not convert argument types. This is usually useful when working +#: with file paths as they can appear in bytes and unicode. +#: +#: For path related uses the :class:`Path` type is a better choice but +#: there are situations where an unprocessed type is useful which is why +#: it is is provided. +#: +#: .. versionadded:: 4.0 +UNPROCESSED = UnprocessedParamType() + +#: A unicode string parameter type which is the implicit default. This +#: can also be selected by using ``str`` as type. +STRING = StringParamType() + +#: An integer parameter. This can also be selected by using ``int`` as +#: type. +INT = IntParamType() + +#: A floating point value parameter. This can also be selected by using +#: ``float`` as type. +FLOAT = FloatParamType() + +#: A boolean parameter. This is the default for boolean flags. This can +#: also be selected by using ``bool`` as a type. +BOOL = BoolParamType() + +#: A UUID parameter. +UUID = UUIDParameterType() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/utils.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/utils.py new file mode 100644 index 0000000..79265e7 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/click/utils.py @@ -0,0 +1,455 @@ +import os +import sys + +from ._compat import _default_text_stderr +from ._compat import _default_text_stdout +from ._compat import auto_wrap_for_ansi +from ._compat import binary_streams +from ._compat import filename_to_ui +from ._compat import get_filesystem_encoding +from ._compat import get_streerror +from ._compat import is_bytes +from ._compat import open_stream +from ._compat import PY2 +from ._compat import should_strip_ansi +from ._compat import string_types +from ._compat import strip_ansi +from ._compat import text_streams +from ._compat import text_type +from ._compat import WIN +from .globals import resolve_color_default + +if not PY2: + from ._compat import _find_binary_writer +elif WIN: + from ._winconsole import _get_windows_argv + from ._winconsole import _hash_py_argv + from ._winconsole import _initial_argv_hash + +echo_native_types = string_types + (bytes, bytearray) + + +def _posixify(name): + return "-".join(name.split()).lower() + + +def safecall(func): + """Wraps a function so that it swallows exceptions.""" + + def wrapper(*args, **kwargs): + try: + return func(*args, **kwargs) + except Exception: + pass + + return wrapper + + +def make_str(value): + """Converts a value into a valid string.""" + if isinstance(value, bytes): + try: + return value.decode(get_filesystem_encoding()) + except UnicodeError: + return value.decode("utf-8", "replace") + return text_type(value) + + +def make_default_short_help(help, max_length=45): + """Return a condensed version of help string.""" + words = help.split() + total_length = 0 + result = [] + done = False + + for word in words: + if word[-1:] == ".": + done = True + new_length = 1 + len(word) if result else len(word) + if total_length + new_length > max_length: + result.append("...") + done = True + else: + if result: + result.append(" ") + result.append(word) + if done: + break + total_length += new_length + + return "".join(result) + + +class LazyFile(object): + """A lazy file works like a regular file but it does not fully open + the file but it does perform some basic checks early to see if the + filename parameter does make sense. This is useful for safely opening + files for writing. + """ + + def __init__( + self, filename, mode="r", encoding=None, errors="strict", atomic=False + ): + self.name = filename + self.mode = mode + self.encoding = encoding + self.errors = errors + self.atomic = atomic + + if filename == "-": + self._f, self.should_close = open_stream(filename, mode, encoding, errors) + else: + if "r" in mode: + # Open and close the file in case we're opening it for + # reading so that we can catch at least some errors in + # some cases early. + open(filename, mode).close() + self._f = None + self.should_close = True + + def __getattr__(self, name): + return getattr(self.open(), name) + + def __repr__(self): + if self._f is not None: + return repr(self._f) + return "".format(self.name, self.mode) + + def open(self): + """Opens the file if it's not yet open. This call might fail with + a :exc:`FileError`. Not handling this error will produce an error + that Click shows. + """ + if self._f is not None: + return self._f + try: + rv, self.should_close = open_stream( + self.name, self.mode, self.encoding, self.errors, atomic=self.atomic + ) + except (IOError, OSError) as e: # noqa: E402 + from .exceptions import FileError + + raise FileError(self.name, hint=get_streerror(e)) + self._f = rv + return rv + + def close(self): + """Closes the underlying file, no matter what.""" + if self._f is not None: + self._f.close() + + def close_intelligently(self): + """This function only closes the file if it was opened by the lazy + file wrapper. For instance this will never close stdin. + """ + if self.should_close: + self.close() + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, tb): + self.close_intelligently() + + def __iter__(self): + self.open() + return iter(self._f) + + +class KeepOpenFile(object): + def __init__(self, file): + self._file = file + + def __getattr__(self, name): + return getattr(self._file, name) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, tb): + pass + + def __repr__(self): + return repr(self._file) + + def __iter__(self): + return iter(self._file) + + +def echo(message=None, file=None, nl=True, err=False, color=None): + """Prints a message plus a newline to the given file or stdout. On + first sight, this looks like the print function, but it has improved + support for handling Unicode and binary data that does not fail no + matter how badly configured the system is. + + Primarily it means that you can print binary data as well as Unicode + data on both 2.x and 3.x to the given file in the most appropriate way + possible. This is a very carefree function in that it will try its + best to not fail. As of Click 6.0 this includes support for unicode + output on the Windows console. + + In addition to that, if `colorama`_ is installed, the echo function will + also support clever handling of ANSI codes. Essentially it will then + do the following: + + - add transparent handling of ANSI color codes on Windows. + - hide ANSI codes automatically if the destination file is not a + terminal. + + .. _colorama: https://pypi.org/project/colorama/ + + .. versionchanged:: 6.0 + As of Click 6.0 the echo function will properly support unicode + output on the windows console. Not that click does not modify + the interpreter in any way which means that `sys.stdout` or the + print statement or function will still not provide unicode support. + + .. versionchanged:: 2.0 + Starting with version 2.0 of Click, the echo function will work + with colorama if it's installed. + + .. versionadded:: 3.0 + The `err` parameter was added. + + .. versionchanged:: 4.0 + Added the `color` flag. + + :param message: the message to print + :param file: the file to write to (defaults to ``stdout``) + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``. This is faster and easier than calling + :func:`get_text_stderr` yourself. + :param nl: if set to `True` (the default) a newline is printed afterwards. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. + """ + if file is None: + if err: + file = _default_text_stderr() + else: + file = _default_text_stdout() + + # Convert non bytes/text into the native string type. + if message is not None and not isinstance(message, echo_native_types): + message = text_type(message) + + if nl: + message = message or u"" + if isinstance(message, text_type): + message += u"\n" + else: + message += b"\n" + + # If there is a message, and we're in Python 3, and the value looks + # like bytes, we manually need to find the binary stream and write the + # message in there. This is done separately so that most stream + # types will work as you would expect. Eg: you can write to StringIO + # for other cases. + if message and not PY2 and is_bytes(message): + binary_file = _find_binary_writer(file) + if binary_file is not None: + file.flush() + binary_file.write(message) + binary_file.flush() + return + + # ANSI-style support. If there is no message or we are dealing with + # bytes nothing is happening. If we are connected to a file we want + # to strip colors. If we are on windows we either wrap the stream + # to strip the color or we use the colorama support to translate the + # ansi codes to API calls. + if message and not is_bytes(message): + color = resolve_color_default(color) + if should_strip_ansi(file, color): + message = strip_ansi(message) + elif WIN: + if auto_wrap_for_ansi is not None: + file = auto_wrap_for_ansi(file) + elif not color: + message = strip_ansi(message) + + if message: + file.write(message) + file.flush() + + +def get_binary_stream(name): + """Returns a system stream for byte processing. This essentially + returns the stream from the sys module with the given name but it + solves some compatibility issues between different Python versions. + Primarily this function is necessary for getting binary streams on + Python 3. + + :param name: the name of the stream to open. Valid names are ``'stdin'``, + ``'stdout'`` and ``'stderr'`` + """ + opener = binary_streams.get(name) + if opener is None: + raise TypeError("Unknown standard stream '{}'".format(name)) + return opener() + + +def get_text_stream(name, encoding=None, errors="strict"): + """Returns a system stream for text processing. This usually returns + a wrapped stream around a binary stream returned from + :func:`get_binary_stream` but it also can take shortcuts on Python 3 + for already correctly configured streams. + + :param name: the name of the stream to open. Valid names are ``'stdin'``, + ``'stdout'`` and ``'stderr'`` + :param encoding: overrides the detected default encoding. + :param errors: overrides the default error mode. + """ + opener = text_streams.get(name) + if opener is None: + raise TypeError("Unknown standard stream '{}'".format(name)) + return opener(encoding, errors) + + +def open_file( + filename, mode="r", encoding=None, errors="strict", lazy=False, atomic=False +): + """This is similar to how the :class:`File` works but for manual + usage. Files are opened non lazy by default. This can open regular + files as well as stdin/stdout if ``'-'`` is passed. + + If stdin/stdout is returned the stream is wrapped so that the context + manager will not close the stream accidentally. This makes it possible + to always use the function like this without having to worry to + accidentally close a standard stream:: + + with open_file(filename) as f: + ... + + .. versionadded:: 3.0 + + :param filename: the name of the file to open (or ``'-'`` for stdin/stdout). + :param mode: the mode in which to open the file. + :param encoding: the encoding to use. + :param errors: the error handling for this file. + :param lazy: can be flipped to true to open the file lazily. + :param atomic: in atomic mode writes go into a temporary file and it's + moved on close. + """ + if lazy: + return LazyFile(filename, mode, encoding, errors, atomic=atomic) + f, should_close = open_stream(filename, mode, encoding, errors, atomic=atomic) + if not should_close: + f = KeepOpenFile(f) + return f + + +def get_os_args(): + """This returns the argument part of sys.argv in the most appropriate + form for processing. What this means is that this return value is in + a format that works for Click to process but does not necessarily + correspond well to what's actually standard for the interpreter. + + On most environments the return value is ``sys.argv[:1]`` unchanged. + However if you are on Windows and running Python 2 the return value + will actually be a list of unicode strings instead because the + default behavior on that platform otherwise will not be able to + carry all possible values that sys.argv can have. + + .. versionadded:: 6.0 + """ + # We can only extract the unicode argv if sys.argv has not been + # changed since the startup of the application. + if PY2 and WIN and _initial_argv_hash == _hash_py_argv(): + return _get_windows_argv() + return sys.argv[1:] + + +def format_filename(filename, shorten=False): + """Formats a filename for user display. The main purpose of this + function is to ensure that the filename can be displayed at all. This + will decode the filename to unicode if necessary in a way that it will + not fail. Optionally, it can shorten the filename to not include the + full path to the filename. + + :param filename: formats a filename for UI display. This will also convert + the filename into unicode without failing. + :param shorten: this optionally shortens the filename to strip of the + path that leads up to it. + """ + if shorten: + filename = os.path.basename(filename) + return filename_to_ui(filename) + + +def get_app_dir(app_name, roaming=True, force_posix=False): + r"""Returns the config folder for the application. The default behavior + is to return whatever is most appropriate for the operating system. + + To give you an idea, for an app called ``"Foo Bar"``, something like + the following folders could be returned: + + Mac OS X: + ``~/Library/Application Support/Foo Bar`` + Mac OS X (POSIX): + ``~/.foo-bar`` + Unix: + ``~/.config/foo-bar`` + Unix (POSIX): + ``~/.foo-bar`` + Win XP (roaming): + ``C:\Documents and Settings\\Local Settings\Application Data\Foo Bar`` + Win XP (not roaming): + ``C:\Documents and Settings\\Application Data\Foo Bar`` + Win 7 (roaming): + ``C:\Users\\AppData\Roaming\Foo Bar`` + Win 7 (not roaming): + ``C:\Users\\AppData\Local\Foo Bar`` + + .. versionadded:: 2.0 + + :param app_name: the application name. This should be properly capitalized + and can contain whitespace. + :param roaming: controls if the folder should be roaming or not on Windows. + Has no affect otherwise. + :param force_posix: if this is set to `True` then on any POSIX system the + folder will be stored in the home folder with a leading + dot instead of the XDG config home or darwin's + application support folder. + """ + if WIN: + key = "APPDATA" if roaming else "LOCALAPPDATA" + folder = os.environ.get(key) + if folder is None: + folder = os.path.expanduser("~") + return os.path.join(folder, app_name) + if force_posix: + return os.path.join(os.path.expanduser("~/.{}".format(_posixify(app_name)))) + if sys.platform == "darwin": + return os.path.join( + os.path.expanduser("~/Library/Application Support"), app_name + ) + return os.path.join( + os.environ.get("XDG_CONFIG_HOME", os.path.expanduser("~/.config")), + _posixify(app_name), + ) + + +class PacifyFlushWrapper(object): + """This wrapper is used to catch and suppress BrokenPipeErrors resulting + from ``.flush()`` being called on broken pipe during the shutdown/final-GC + of the Python interpreter. Notably ``.flush()`` is always called on + ``sys.stdout`` and ``sys.stderr``. So as to have minimal impact on any + other cleanup code, and the case where the underlying file is not a broken + pipe, all calls and attributes are proxied. + """ + + def __init__(self, wrapped): + self.wrapped = wrapped + + def flush(self): + try: + self.wrapped.flush() + except IOError as e: + import errno + + if e.errno != errno.EPIPE: + raise + + def __getattr__(self, attr): + return getattr(self.wrapped, attr) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/AUTHORS.rst b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/AUTHORS.rst new file mode 100644 index 0000000..8ba7e0e --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/AUTHORS.rst @@ -0,0 +1,44 @@ +AUTHORS +======= + +PGP key fingerprints are enclosed in parentheses. + +* Alex Gaynor (E27D 4AA0 1651 72CB C5D2 AF2B 125F 5C67 DFE9 4084) +* Hynek Schlawack (C2A0 4F86 ACE2 8ADC F817 DBB7 AE25 3622 7F69 F181) +* Donald Stufft +* Laurens Van Houtven <_@lvh.io> (D9DC 4315 772F 8E91 DD22 B153 DFD1 3DF7 A8DD 569B) +* Christian Heimes +* Paul Kehrer (05FD 9FA1 6CF7 5735 0D91 A560 235A E5F1 29F9 ED98) +* Jarret Raim +* Alex Stapleton (A1C7 E50B 66DE 39ED C847 9665 8E3C 20D1 9BD9 5C4C) +* David Reid (0F83 CC87 B32F 482B C726 B58A 9FBF D8F4 DA89 6D74) +* Matthew Lefkowitz (06AB F638 E878 CD29 1264 18AB 7EC2 8125 0FBC 4A07) +* Konstantinos Koukopoulos (D6BD 52B6 8C99 A91C E2C8 934D 3300 566B 3A46 726E) +* Stephen Holsapple +* Terry Chia +* Matthew Iversen (2F04 3DCC D6E6 D5AC D262 2E0B C046 E8A8 7452 2973) +* Mohammed Attia +* Michael Hart +* Mark Adams (A18A 7DD3 283C CF2A B0CE FE0E C7A0 5E3F C972 098C) +* Gregory Haynes (6FB6 44BF 9FD0 EBA2 1CE9 471F B08F 42F9 0DC6 599F) +* Chelsea Winfree +* Steven Buss (1FB9 2EC1 CF93 DFD6 B47F F583 B1A5 6C22 290D A4C3) +* Andre Caron +* Jiangge Zhang (BBEC 782B 015F 71B1 5FF7 EACA 1A8C AA98 255F 5000) +* Major Hayden (1BF9 9264 9596 0033 698C 252B 7370 51E0 C101 1FB1) +* Phoebe Queen (10D4 7741 AB65 50F4 B264 3888 DA40 201A 072B C1FA) +* Google Inc. +* Amaury Forgeot d'Arc +* Dirkjan Ochtman (25BB BAC1 13C1 BFD5 AA59 4A4C 9F96 B929 3038 0381) +* Maximilian Hils +* Simo Sorce +* Thomas Sileo +* Fraser Tweedale +* Ofek Lev (FFB6 B92B 30B1 7848 546E 9912 972F E913 DAD5 A46E) +* Erik Daguerre +* Aviv Palivoda +* Chris Wolfe +* Jeremy Lainé +* Denis Gladkikh +* John Pacific (2CF6 0381 B5EF 29B7 D48C 2020 7BB9 71A0 E891 44D9) +* Marti Raudsepp diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/INSTALLER b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/LICENSE b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/LICENSE new file mode 100644 index 0000000..fe5af51 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/LICENSE @@ -0,0 +1,6 @@ +This software is made available under the terms of *either* of the licenses +found in LICENSE.APACHE or LICENSE.BSD. Contributions to cryptography are made +under the terms of *both* these licenses. + +The code used in the OpenSSL locking callback and OS random engine is derived +from CPython, and is licensed under the terms of the PSF License Agreement. diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/LICENSE.APACHE b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/LICENSE.APACHE new file mode 100644 index 0000000..62589ed --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/LICENSE.APACHE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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 + + https://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. diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/LICENSE.BSD b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/LICENSE.BSD new file mode 100644 index 0000000..ec1a29d --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/LICENSE.BSD @@ -0,0 +1,27 @@ +Copyright (c) Individual contributors. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of PyCA Cryptography nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/LICENSE.PSF b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/LICENSE.PSF new file mode 100644 index 0000000..4d3a4f5 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/LICENSE.PSF @@ -0,0 +1,41 @@ +1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and + the Individual or Organization ("Licensee") accessing and otherwise using Python + 2.7.12 software in source or binary form and its associated documentation. + +2. Subject to the terms and conditions of this License Agreement, PSF hereby + grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, + analyze, test, perform and/or display publicly, prepare derivative works, + distribute, and otherwise use Python 2.7.12 alone or in any derivative + version, provided, however, that PSF's License Agreement and PSF's notice of + copyright, i.e., "Copyright © 2001-2016 Python Software Foundation; All Rights + Reserved" are retained in Python 2.7.12 alone or in any derivative version + prepared by Licensee. + +3. In the event Licensee prepares a derivative work that is based on or + incorporates Python 2.7.12 or any part thereof, and wants to make the + derivative work available to others as provided herein, then Licensee hereby + agrees to include in any such work a brief summary of the changes made to Python + 2.7.12. + +4. PSF is making Python 2.7.12 available to Licensee on an "AS IS" basis. + PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF + EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR + WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE + USE OF PYTHON 2.7.12 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. + +5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 2.7.12 + FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF + MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 2.7.12, OR ANY DERIVATIVE + THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material breach of + its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any relationship + of agency, partnership, or joint venture between PSF and Licensee. This License + Agreement does not grant permission to use PSF trademarks or trade name in a + trademark sense to endorse or promote products or services of Licensee, or any + third party. + +8. By copying, installing or otherwise using Python 2.7.12, Licensee agrees + to be bound by the terms and conditions of this License Agreement. diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/METADATA b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/METADATA new file mode 100644 index 0000000..7041828 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/METADATA @@ -0,0 +1,134 @@ +Metadata-Version: 2.1 +Name: cryptography +Version: 3.2.1 +Summary: cryptography is a package which provides cryptographic recipes and primitives to Python developers. +Home-page: https://github.com/pyca/cryptography +Author: The cryptography developers +Author-email: cryptography-dev@python.org +License: BSD or Apache License, Version 2.0 +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Apache Software License +Classifier: License :: OSI Approved :: BSD License +Classifier: Natural Language :: English +Classifier: Operating System :: MacOS :: MacOS X +Classifier: Operating System :: POSIX +Classifier: Operating System :: POSIX :: BSD +Classifier: Operating System :: POSIX :: Linux +Classifier: Operating System :: Microsoft :: Windows +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Security :: Cryptography +Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.* +Description-Content-Type: text/x-rst +Requires-Dist: six (>=1.4.1) +Requires-Dist: cffi (!=1.11.3,>=1.8) +Requires-Dist: enum34 ; python_version < '3' +Requires-Dist: ipaddress ; python_version < '3' +Provides-Extra: docs +Requires-Dist: sphinx (!=1.8.0,!=3.1.0,!=3.1.1,>=1.6.5) ; extra == 'docs' +Requires-Dist: sphinx-rtd-theme ; extra == 'docs' +Provides-Extra: docstest +Requires-Dist: doc8 ; extra == 'docstest' +Requires-Dist: pyenchant (>=1.6.11) ; extra == 'docstest' +Requires-Dist: twine (>=1.12.0) ; extra == 'docstest' +Requires-Dist: sphinxcontrib-spelling (>=4.0.1) ; extra == 'docstest' +Provides-Extra: pep8test +Requires-Dist: black ; extra == 'pep8test' +Requires-Dist: flake8 ; extra == 'pep8test' +Requires-Dist: flake8-import-order ; extra == 'pep8test' +Requires-Dist: pep8-naming ; extra == 'pep8test' +Provides-Extra: ssh +Requires-Dist: bcrypt (>=3.1.5) ; extra == 'ssh' +Provides-Extra: test +Requires-Dist: pytest (!=3.9.0,!=3.9.1,!=3.9.2,>=3.6.0) ; extra == 'test' +Requires-Dist: pretend ; extra == 'test' +Requires-Dist: iso8601 ; extra == 'test' +Requires-Dist: pytz ; extra == 'test' +Requires-Dist: hypothesis (!=3.79.2,>=1.11.4) ; extra == 'test' + +pyca/cryptography +================= + +.. image:: https://img.shields.io/pypi/v/cryptography.svg + :target: https://pypi.org/project/cryptography/ + :alt: Latest Version + +.. image:: https://readthedocs.org/projects/cryptography/badge/?version=latest + :target: https://cryptography.io + :alt: Latest Docs + +.. image:: https://travis-ci.org/pyca/cryptography.svg?branch=master + :target: https://travis-ci.org/pyca/cryptography + +.. image:: https://github.com/pyca/cryptography/workflows/CI/badge.svg?branch=master + :target: https://github.com/pyca/cryptography/actions?query=workflow%3ACI+branch%3Amaster + +.. image:: https://codecov.io/github/pyca/cryptography/coverage.svg?branch=master + :target: https://codecov.io/github/pyca/cryptography?branch=master + + +``cryptography`` is a package which provides cryptographic recipes and +primitives to Python developers. Our goal is for it to be your "cryptographic +standard library". It supports Python 2.7, Python 3.5+, and PyPy 5.4+. + +``cryptography`` includes both high level recipes and low level interfaces to +common cryptographic algorithms such as symmetric ciphers, message digests, and +key derivation functions. For example, to encrypt something with +``cryptography``'s high level symmetric encryption recipe: + +.. code-block:: pycon + + >>> from cryptography.fernet import Fernet + >>> # Put this somewhere safe! + >>> key = Fernet.generate_key() + >>> f = Fernet(key) + >>> token = f.encrypt(b"A really secret message. Not for prying eyes.") + >>> token + '...' + >>> f.decrypt(token) + 'A really secret message. Not for prying eyes.' + +You can find more information in the `documentation`_. + +You can install ``cryptography`` with: + +.. code-block:: console + + $ pip install cryptography + +For full details see `the installation documentation`_. + +Discussion +~~~~~~~~~~ + +If you run into bugs, you can file them in our `issue tracker`_. + +We maintain a `cryptography-dev`_ mailing list for development discussion. + +You can also join ``#cryptography-dev`` on Freenode to ask questions or get +involved. + +Security +~~~~~~~~ + +Need to report a security issue? Please consult our `security reporting`_ +documentation. + + +.. _`documentation`: https://cryptography.io/ +.. _`the installation documentation`: https://cryptography.io/en/latest/installation/ +.. _`issue tracker`: https://github.com/pyca/cryptography/issues +.. _`cryptography-dev`: https://mail.python.org/mailman/listinfo/cryptography-dev +.. _`security reporting`: https://cryptography.io/en/latest/security/ + + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/RECORD b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/RECORD new file mode 100644 index 0000000..756e98b --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/RECORD @@ -0,0 +1,178 @@ +cryptography-3.2.1.dist-info/AUTHORS.rst,sha256=MoKTlP6yOmnLC_KXarHVQP0sItBk11dtZ7LzV0VhNB0,2475 +cryptography-3.2.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +cryptography-3.2.1.dist-info/LICENSE,sha256=NUUrVX-rDvsegNftucTlEYuThAgq2qBR3eNCECy53o0,352 +cryptography-3.2.1.dist-info/LICENSE.APACHE,sha256=qsc7MUj20dcRHbyjIJn2jSbGRMaBOuHk8F9leaomY_4,11360 +cryptography-3.2.1.dist-info/LICENSE.BSD,sha256=YCxMdILeZHndLpeTzaJ15eY9dz2s0eymiSMqtwCPtPs,1532 +cryptography-3.2.1.dist-info/LICENSE.PSF,sha256=aT7ApmKzn5laTyUrA6YiKUVHDBtvEsoCkY5O_g32S58,2415 +cryptography-3.2.1.dist-info/METADATA,sha256=K4QDrQjRb0TnQsG4KpvZM5QRVEfls0MVvLqUo_0eNs8,5176 +cryptography-3.2.1.dist-info/RECORD,, +cryptography-3.2.1.dist-info/WHEEL,sha256=idZhaAgCajrx6mqUbq2PISSyVyiBdD7cMlbcSPPaZS8,111 +cryptography-3.2.1.dist-info/top_level.txt,sha256=rR2wh6A6juD02TBZNJqqonh8x9UP9Sa5Z9Hl1pCPCiM,31 +cryptography/__about__.py,sha256=iHoSlgQT3eVMw3nbzphBoO21jB6DHdPnglb0l9xsIhE,835 +cryptography/__init__.py,sha256=fX3TLbJsUEhtvbj0MH9cSFt_r6Xglw8TzGTDs2X_0TQ,1208 +cryptography/__pycache__/__about__.cpython-38.pyc,, +cryptography/__pycache__/__init__.cpython-38.pyc,, +cryptography/__pycache__/exceptions.cpython-38.pyc,, +cryptography/__pycache__/fernet.cpython-38.pyc,, +cryptography/__pycache__/utils.cpython-38.pyc,, +cryptography/exceptions.py,sha256=NPtDqIq1lsQ1Gb1BXkjsGIvbMrWMaKCaT8epiSgi010,1259 +cryptography/fernet.py,sha256=sg5RNOCKx9BrPV6wIfyXB9sDWJcw9-GPcPgN4lVmr8w,5980 +cryptography/hazmat/__init__.py,sha256=hEPNQw8dgjIPIn42qaLwXNRLCyTGNZeSvkQb57DPhbs,483 +cryptography/hazmat/__pycache__/__init__.cpython-38.pyc,, +cryptography/hazmat/__pycache__/_der.cpython-38.pyc,, +cryptography/hazmat/__pycache__/_oid.cpython-38.pyc,, +cryptography/hazmat/_der.py,sha256=NkwxQBcrR_KMAZCM3WKidXgx8CHFVU5iBnoFIrhQMQs,5205 +cryptography/hazmat/_oid.py,sha256=3L1KLxAsQJJoy15ZCl0T4I-PU-DVvzGS-ZTdS-PNy14,2432 +cryptography/hazmat/backends/__init__.py,sha256=EEhjIZgqApO7coGuybLXyaEaWIHcdg8oC0i2vxQ4RSI,616 +cryptography/hazmat/backends/__pycache__/__init__.cpython-38.pyc,, +cryptography/hazmat/backends/__pycache__/interfaces.cpython-38.pyc,, +cryptography/hazmat/backends/interfaces.py,sha256=GXySHrpGLgeTrjUgxOYtK6viaphO1dDKAOA95JFj_pM,10770 +cryptography/hazmat/backends/openssl/__init__.py,sha256=k4DMe228_hTuB2kY3Lwk62JdI3EmCd7VkV01zJm57ps,336 +cryptography/hazmat/backends/openssl/__pycache__/__init__.cpython-38.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/aead.cpython-38.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/backend.cpython-38.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/ciphers.cpython-38.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/cmac.cpython-38.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/decode_asn1.cpython-38.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/dh.cpython-38.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/dsa.cpython-38.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/ec.cpython-38.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/ed25519.cpython-38.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/ed448.cpython-38.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/encode_asn1.cpython-38.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/hashes.cpython-38.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/hmac.cpython-38.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/ocsp.cpython-38.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/poly1305.cpython-38.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/rsa.cpython-38.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/utils.cpython-38.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/x25519.cpython-38.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/x448.cpython-38.pyc,, +cryptography/hazmat/backends/openssl/__pycache__/x509.cpython-38.pyc,, +cryptography/hazmat/backends/openssl/aead.py,sha256=ljOSkI7NXgXi9OyfHjm9J07m3EVHFNm9kfHAIogSWtc,5765 +cryptography/hazmat/backends/openssl/backend.py,sha256=UowgXYKTalYIgEWGd2rqh9eMSSJSgmkEqJ1DOTZczQo,106907 +cryptography/hazmat/backends/openssl/ciphers.py,sha256=WrmBgZ2PCVbaMkHdfKmYUvoVZwwQ5O-1ylzstNadONc,8608 +cryptography/hazmat/backends/openssl/cmac.py,sha256=n34WXNXt-r0trp207u0cSKwGMth8qEiEs2jjgmHNtWE,2855 +cryptography/hazmat/backends/openssl/decode_asn1.py,sha256=AHOzN74MwF3b_fZhQf5_0hB649nS7Z1Dz8tJ6WeD780,32345 +cryptography/hazmat/backends/openssl/dh.py,sha256=1fZn8one2aSla85LIe6vXbf0qoLTDS-B7tYMcrJshnY,10239 +cryptography/hazmat/backends/openssl/dsa.py,sha256=Cp1w1Z6J_PEW-Qd2RAzfC04MU9YxqYOaef57f_QVpYI,10036 +cryptography/hazmat/backends/openssl/ec.py,sha256=HC2Q3drRTdBAJmUiiSs4qdZXCgZ5xhGmha4Qk77RVJY,12085 +cryptography/hazmat/backends/openssl/ed25519.py,sha256=1uIjZ6OC0JJssRF9lMQLlGPCcQf_FGE5voVkaz6RwF8,5670 +cryptography/hazmat/backends/openssl/ed448.py,sha256=mXAHwlMNSP_jQ0hPBLB5GtZUAyZL3MsKuqf8iRTkrk0,5626 +cryptography/hazmat/backends/openssl/encode_asn1.py,sha256=DsIMFa6dpA0gTW9IS2_K2dd0RIgfDXISz7X0hS2OSgY,23553 +cryptography/hazmat/backends/openssl/hashes.py,sha256=7AOmGxZTAiuMpbWLs15HIG2Nr06V-2nM3u91HlY90r0,3169 +cryptography/hazmat/backends/openssl/hmac.py,sha256=6LtwqIFF7HpuhtVEY4Ytjt_EmeVY4eYnDz66iLNb1d4,3015 +cryptography/hazmat/backends/openssl/ocsp.py,sha256=NEGrc30GfPBLbjnt-K3K48-dZK2dEyQa2oCyv7-laMs,14028 +cryptography/hazmat/backends/openssl/poly1305.py,sha256=ZPIuTJ0JoG8XYz-qnbSMUrLG1RVb58gbfZnQ6eVaKbk,2419 +cryptography/hazmat/backends/openssl/rsa.py,sha256=qq2_mRhlRPlO631x4DwI1fkGJ0fi9Qx4WoCb3ILkV-c,17378 +cryptography/hazmat/backends/openssl/utils.py,sha256=JI8K4BYq7Dwsdm2l-ff1dOw8Kxu4f8dNL1dTwQCrZXg,2304 +cryptography/hazmat/backends/openssl/x25519.py,sha256=-MNAPGS_DZ37-skSn17-gIakFLoJmuNx8PlC8s2-00g,4488 +cryptography/hazmat/backends/openssl/x448.py,sha256=5WH3Rw7kZGLS3EDDVzjrYriAG-tzUnyWetyqMYTiEhA,4011 +cryptography/hazmat/backends/openssl/x509.py,sha256=EMN9qSPW1BVZ1VAOHzgi8oO8idI8iOb0wrWjdrr5FpI,21620 +cryptography/hazmat/bindings/__init__.py,sha256=0wGw2OF9R7fHX7NWENCmrsYigbXHU2ojgn-N4Rkjs9U,246 +cryptography/hazmat/bindings/__pycache__/__init__.cpython-38.pyc,, +cryptography/hazmat/bindings/_openssl.abi3.so,sha256=ucvElQ-tsGPCRtlqssojuBPT2vzKMMtbrvbbUgMIumM,7050912 +cryptography/hazmat/bindings/_padding.abi3.so,sha256=s4FZ4BySPkNpjwcJnm0c97hUIVer8xvDVpO9yPsFwr8,37232 +cryptography/hazmat/bindings/openssl/__init__.py,sha256=0wGw2OF9R7fHX7NWENCmrsYigbXHU2ojgn-N4Rkjs9U,246 +cryptography/hazmat/bindings/openssl/__pycache__/__init__.cpython-38.pyc,, +cryptography/hazmat/bindings/openssl/__pycache__/_conditional.cpython-38.pyc,, +cryptography/hazmat/bindings/openssl/__pycache__/binding.cpython-38.pyc,, +cryptography/hazmat/bindings/openssl/_conditional.py,sha256=-ca21IgntHM7yUdaO_m1rhk9CmZzAXsyXQGMaCAmge4,8762 +cryptography/hazmat/bindings/openssl/binding.py,sha256=MGvM9VEvMZHCFgBJcj2iPQoVnmEsYC3JjqGHQLZur8Y,7947 +cryptography/hazmat/primitives/__init__.py,sha256=0wGw2OF9R7fHX7NWENCmrsYigbXHU2ojgn-N4Rkjs9U,246 +cryptography/hazmat/primitives/__pycache__/__init__.cpython-38.pyc,, +cryptography/hazmat/primitives/__pycache__/cmac.cpython-38.pyc,, +cryptography/hazmat/primitives/__pycache__/constant_time.cpython-38.pyc,, +cryptography/hazmat/primitives/__pycache__/hashes.cpython-38.pyc,, +cryptography/hazmat/primitives/__pycache__/hmac.cpython-38.pyc,, +cryptography/hazmat/primitives/__pycache__/keywrap.cpython-38.pyc,, +cryptography/hazmat/primitives/__pycache__/padding.cpython-38.pyc,, +cryptography/hazmat/primitives/__pycache__/poly1305.cpython-38.pyc,, +cryptography/hazmat/primitives/asymmetric/__init__.py,sha256=WhUn3tGxoLAxGAsZHElJ2aOILXSh55AZi04MBudYmQA,1020 +cryptography/hazmat/primitives/asymmetric/__pycache__/__init__.cpython-38.pyc,, +cryptography/hazmat/primitives/asymmetric/__pycache__/dh.cpython-38.pyc,, +cryptography/hazmat/primitives/asymmetric/__pycache__/dsa.cpython-38.pyc,, +cryptography/hazmat/primitives/asymmetric/__pycache__/ec.cpython-38.pyc,, +cryptography/hazmat/primitives/asymmetric/__pycache__/ed25519.cpython-38.pyc,, +cryptography/hazmat/primitives/asymmetric/__pycache__/ed448.cpython-38.pyc,, +cryptography/hazmat/primitives/asymmetric/__pycache__/padding.cpython-38.pyc,, +cryptography/hazmat/primitives/asymmetric/__pycache__/rsa.cpython-38.pyc,, +cryptography/hazmat/primitives/asymmetric/__pycache__/utils.cpython-38.pyc,, +cryptography/hazmat/primitives/asymmetric/__pycache__/x25519.cpython-38.pyc,, +cryptography/hazmat/primitives/asymmetric/__pycache__/x448.cpython-38.pyc,, +cryptography/hazmat/primitives/asymmetric/dh.py,sha256=ZObmAtofuhW1RZJZNVJ5xl8JPnH2ML-wZjK5GedChHw,5661 +cryptography/hazmat/primitives/asymmetric/dsa.py,sha256=XuE2mUXl-fXi2q7w22qKyiCTFUz-852cFTwV4WOUQgw,7181 +cryptography/hazmat/primitives/asymmetric/ec.py,sha256=2rorlIEXHGkLnI8bbeFKMRr-gJfEipuJigQDQh4xk7w,14006 +cryptography/hazmat/primitives/asymmetric/ed25519.py,sha256=rfImUQH-PcTliuxiF864aSww7dQCWVwZgjPPbDXiGlI,2401 +cryptography/hazmat/primitives/asymmetric/ed448.py,sha256=JyrEHwYF_Ftj_E60t-Gmvm3CGnQSxVbasptZBW84eBk,2328 +cryptography/hazmat/primitives/asymmetric/padding.py,sha256=2pPqBu4dGERtFPHnPRTZ0iRO_XY9hr9RTwlTcr_J5bw,2250 +cryptography/hazmat/primitives/asymmetric/rsa.py,sha256=UYFExBDj-8IT6Z6nc-oF3vqQArdsb2cmsGkLjY72YYQ,10494 +cryptography/hazmat/primitives/asymmetric/utils.py,sha256=w2lQIcKrFvS9D_Ekt7qWed39TXM6hueg72FFrfwIo58,1201 +cryptography/hazmat/primitives/asymmetric/x25519.py,sha256=vrN1jcO6sjbQrc7auIlf2aEvcH3P17cKUuaVXxaTvxI,2277 +cryptography/hazmat/primitives/asymmetric/x448.py,sha256=u3v-L1IJIG2RyLVTh7FMkXh_Y-oVb3HdEj5b1c-JlKk,2255 +cryptography/hazmat/primitives/ciphers/__init__.py,sha256=mi4yR3Fxc4-Au3yX4PyhFNaiFn0yywZKiTzecdI77EI,647 +cryptography/hazmat/primitives/ciphers/__pycache__/__init__.cpython-38.pyc,, +cryptography/hazmat/primitives/ciphers/__pycache__/aead.cpython-38.pyc,, +cryptography/hazmat/primitives/ciphers/__pycache__/algorithms.cpython-38.pyc,, +cryptography/hazmat/primitives/ciphers/__pycache__/base.cpython-38.pyc,, +cryptography/hazmat/primitives/ciphers/__pycache__/modes.cpython-38.pyc,, +cryptography/hazmat/primitives/ciphers/aead.py,sha256=NsNjstdbIOAlLddffPPCUr0HZZ5apZ-vE0LEQmHxQxE,6107 +cryptography/hazmat/primitives/ciphers/algorithms.py,sha256=GKFIhvOoqsYscjjP7onl8XnAmOa-kSQ6jiMMS2zeGBM,4225 +cryptography/hazmat/primitives/ciphers/base.py,sha256=vceN5l7yxLWmNTptlzC3gmfFY-K_ANKk4HdNl2Ptz2k,7253 +cryptography/hazmat/primitives/ciphers/modes.py,sha256=_PhdnJHdIb3ePWz8Ul1k1_Ioqc5oLUUexqVadvohqO4,6730 +cryptography/hazmat/primitives/cmac.py,sha256=eJpysDFbc7W6OiplzWKWrL4owy30Cq6Nsao8mzapqbE,2130 +cryptography/hazmat/primitives/constant_time.py,sha256=_x4mrHW-9ihfgY89BwhATFiIuG2_1l-HMkCxmOUkydM,430 +cryptography/hazmat/primitives/hashes.py,sha256=dzL1QcEFj4eElzczo8QmuOeooZ96EFwBy3c-6cpew0w,6315 +cryptography/hazmat/primitives/hmac.py,sha256=AYzTQMDiruKmZKKLR6ceVjX5yQ3mpciWIx__tpNLyr4,2306 +cryptography/hazmat/primitives/kdf/__init__.py,sha256=nod5HjPswjZr8wFp6Tsu6en9blHYF3khgXI5R0zIcnM,771 +cryptography/hazmat/primitives/kdf/__pycache__/__init__.cpython-38.pyc,, +cryptography/hazmat/primitives/kdf/__pycache__/concatkdf.cpython-38.pyc,, +cryptography/hazmat/primitives/kdf/__pycache__/hkdf.cpython-38.pyc,, +cryptography/hazmat/primitives/kdf/__pycache__/kbkdf.cpython-38.pyc,, +cryptography/hazmat/primitives/kdf/__pycache__/pbkdf2.cpython-38.pyc,, +cryptography/hazmat/primitives/kdf/__pycache__/scrypt.cpython-38.pyc,, +cryptography/hazmat/primitives/kdf/__pycache__/x963kdf.cpython-38.pyc,, +cryptography/hazmat/primitives/kdf/concatkdf.py,sha256=gW-xAU6sPE6aZhg_G9ucZ5b_uctSbPcfSpHyyt7Q8MA,4095 +cryptography/hazmat/primitives/kdf/hkdf.py,sha256=SJJQzeQ9OH0t3tUdUq2GT6IQXv9oPLDjulT7wnLTkMg,3598 +cryptography/hazmat/primitives/kdf/kbkdf.py,sha256=awf7zessT-amokp2VBdyW8TWrDnmTXGzHHX4scBO9Uc,5100 +cryptography/hazmat/primitives/kdf/pbkdf2.py,sha256=RYexIlGomzUEU-_QQXTW81rdY5YVZB30XrfnJq8NsIU,2220 +cryptography/hazmat/primitives/kdf/scrypt.py,sha256=C0C3m-gEnlLlAVxzRFdzx1mfDuWs_BkZDoSV2hfahfk,2268 +cryptography/hazmat/primitives/kdf/x963kdf.py,sha256=26-b_ckyUYiqbWM9mZ7FEWbuvR7eTLksIeWQeW1TJ04,2407 +cryptography/hazmat/primitives/keywrap.py,sha256=fF-HA5ETz9RH8s8LB94uDoWRLPvwPkYAC5_Kylej6sA,5730 +cryptography/hazmat/primitives/padding.py,sha256=HDkHguBkryYox5S9h2LieI8LmA2LQsNZlwJCoXRjeeE,5743 +cryptography/hazmat/primitives/poly1305.py,sha256=NNC1WYiYQGNJ8mblkaHRxBm1PLdaKRzkILocsYH5zgY,1679 +cryptography/hazmat/primitives/serialization/__init__.py,sha256=eLzmqoHgVlPK1aTGiEfpaIrUf9mX5PRrM7IHEc8FeQU,1132 +cryptography/hazmat/primitives/serialization/__pycache__/__init__.cpython-38.pyc,, +cryptography/hazmat/primitives/serialization/__pycache__/base.cpython-38.pyc,, +cryptography/hazmat/primitives/serialization/__pycache__/pkcs12.cpython-38.pyc,, +cryptography/hazmat/primitives/serialization/__pycache__/pkcs7.cpython-38.pyc,, +cryptography/hazmat/primitives/serialization/__pycache__/ssh.cpython-38.pyc,, +cryptography/hazmat/primitives/serialization/base.py,sha256=ZSzV-5zl2Bt_mmihcPqieBC6UjMSryUaehgExvjZksg,2249 +cryptography/hazmat/primitives/serialization/pkcs12.py,sha256=oJxangAtSSsniXfguLaoPgejVchs-VpCTBdWSW4rF54,1853 +cryptography/hazmat/primitives/serialization/pkcs7.py,sha256=vGlw_2R4VeLWtoRxkfz8fMLE5i_CCdaY9bEtYMV62rk,4625 +cryptography/hazmat/primitives/serialization/ssh.py,sha256=a_FKWuqpHO-RzUBEoBWS5q7WyMZwS56MD92Wr6j3KBA,21682 +cryptography/hazmat/primitives/twofactor/__init__.py,sha256=BWrm3DKDoAa281E7U_nzz8v44OmAiXmlIycFcsehwfE,288 +cryptography/hazmat/primitives/twofactor/__pycache__/__init__.cpython-38.pyc,, +cryptography/hazmat/primitives/twofactor/__pycache__/hotp.cpython-38.pyc,, +cryptography/hazmat/primitives/twofactor/__pycache__/totp.cpython-38.pyc,, +cryptography/hazmat/primitives/twofactor/__pycache__/utils.cpython-38.pyc,, +cryptography/hazmat/primitives/twofactor/hotp.py,sha256=2uCTCTHMFmWL9kOjA890F0CVrljsvOjJYISKBup7GyI,2679 +cryptography/hazmat/primitives/twofactor/totp.py,sha256=iJRTxPNWPdsTQHePgSE6KGdRNURTv188VNqpyvBwvBY,1780 +cryptography/hazmat/primitives/twofactor/utils.py,sha256=ZKZSOL2cLsGCsSNfx3kYlYt91A4bcU1w9up2EL1hwaA,982 +cryptography/utils.py,sha256=QpZgLOABfeaDciPlrF-W8giJiOL2AzU6Ajjq6h6WkzY,4745 +cryptography/x509/__init__.py,sha256=1juFH-nvLS7kU0x52VMN7pN6s7H55Y86NqUszaBhhi4,7699 +cryptography/x509/__pycache__/__init__.cpython-38.pyc,, +cryptography/x509/__pycache__/base.cpython-38.pyc,, +cryptography/x509/__pycache__/certificate_transparency.cpython-38.pyc,, +cryptography/x509/__pycache__/extensions.cpython-38.pyc,, +cryptography/x509/__pycache__/general_name.cpython-38.pyc,, +cryptography/x509/__pycache__/name.cpython-38.pyc,, +cryptography/x509/__pycache__/ocsp.cpython-38.pyc,, +cryptography/x509/__pycache__/oid.cpython-38.pyc,, +cryptography/x509/base.py,sha256=burWvWUouPiPzmPUzNZUzEe64gR-WMkNyiDpjYCvEc8,26409 +cryptography/x509/certificate_transparency.py,sha256=eJ9lrITdyMn4XsrcVdrTaFVI_RR7mX_VzMZyiaEpbps,1000 +cryptography/x509/extensions.py,sha256=HOwYCKAy-4qK5eWWYB4UnJejC9Ru3FBQMsLXodasR9Y,52924 +cryptography/x509/general_name.py,sha256=nNIG--rJ-TzREkhEq727Fe3tjvxVflW7iPIMjJs6LrI,7942 +cryptography/x509/name.py,sha256=j2khdee8jQBkbZd4RV60ji8V0ZngbsB07i5cnflDBPk,8291 +cryptography/x509/ocsp.py,sha256=nr5Bk3B_b9LaG-1njEmo0f_smAg2B6CU5Wr6wMr81MI,13245 +cryptography/x509/oid.py,sha256=Wp6Y4WMrFa7vsUmV4tbMvPPAl0Iiu4QxQ7on2np94QU,12594 diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/WHEEL b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/WHEEL new file mode 100644 index 0000000..9983060 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.35.1) +Root-Is-Purelib: false +Tag: cp35-abi3-manylinux2010_x86_64 + diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/top_level.txt b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/top_level.txt new file mode 100644 index 0000000..52ccfc6 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography-3.2.1.dist-info/top_level.txt @@ -0,0 +1,3 @@ +_openssl +_padding +cryptography diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/__about__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/__about__.py new file mode 100644 index 0000000..1c9e511 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/__about__.py @@ -0,0 +1,31 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +__all__ = [ + "__title__", + "__summary__", + "__uri__", + "__version__", + "__author__", + "__email__", + "__license__", + "__copyright__", +] + +__title__ = "cryptography" +__summary__ = ( + "cryptography is a package which provides cryptographic recipes" + " and primitives to Python developers." +) +__uri__ = "https://github.com/pyca/cryptography" + +__version__ = "3.2.1" + +__author__ = "The cryptography developers" +__email__ = "cryptography-dev@python.org" + +__license__ = "BSD or Apache License, Version 2.0" +__copyright__ = "Copyright 2013-2020 {}".format(__author__) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/__init__.py new file mode 100644 index 0000000..7211614 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/__init__.py @@ -0,0 +1,48 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import sys +import warnings + +from cryptography.__about__ import ( + __author__, + __copyright__, + __email__, + __license__, + __summary__, + __title__, + __uri__, + __version__, +) +from cryptography.utils import CryptographyDeprecationWarning + + +__all__ = [ + "__title__", + "__summary__", + "__uri__", + "__version__", + "__author__", + "__email__", + "__license__", + "__copyright__", +] + +if sys.version_info[0] == 2: + warnings.warn( + "Python 2 is no longer supported by the Python core team. Support for " + "it is now deprecated in cryptography, and will be removed in a " + "future release.", + CryptographyDeprecationWarning, + stacklevel=2, + ) +if sys.version_info[:2] == (3, 5): + warnings.warn( + "Python 3.5 support will be dropped in the next release of " + "cryptography. Please upgrade your Python.", + CryptographyDeprecationWarning, + stacklevel=2, + ) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/exceptions.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/exceptions.py new file mode 100644 index 0000000..1d52d7d --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/exceptions.py @@ -0,0 +1,58 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from enum import Enum + + +class _Reasons(Enum): + BACKEND_MISSING_INTERFACE = 0 + UNSUPPORTED_HASH = 1 + UNSUPPORTED_CIPHER = 2 + UNSUPPORTED_PADDING = 3 + UNSUPPORTED_MGF = 4 + UNSUPPORTED_PUBLIC_KEY_ALGORITHM = 5 + UNSUPPORTED_ELLIPTIC_CURVE = 6 + UNSUPPORTED_SERIALIZATION = 7 + UNSUPPORTED_X509 = 8 + UNSUPPORTED_EXCHANGE_ALGORITHM = 9 + UNSUPPORTED_DIFFIE_HELLMAN = 10 + UNSUPPORTED_MAC = 11 + + +class UnsupportedAlgorithm(Exception): + def __init__(self, message, reason=None): + super(UnsupportedAlgorithm, self).__init__(message) + self._reason = reason + + +class AlreadyFinalized(Exception): + pass + + +class AlreadyUpdated(Exception): + pass + + +class NotYetFinalized(Exception): + pass + + +class InvalidTag(Exception): + pass + + +class InvalidSignature(Exception): + pass + + +class InternalError(Exception): + def __init__(self, msg, err_code): + super(InternalError, self).__init__(msg) + self.err_code = err_code + + +class InvalidKey(Exception): + pass diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/fernet.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/fernet.py new file mode 100644 index 0000000..00c2528 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/fernet.py @@ -0,0 +1,190 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import base64 +import binascii +import os +import struct +import time + +import six + +from cryptography import utils +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.backends import _get_backend +from cryptography.hazmat.primitives import hashes, padding +from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes +from cryptography.hazmat.primitives.hmac import HMAC + + +class InvalidToken(Exception): + pass + + +_MAX_CLOCK_SKEW = 60 + + +class Fernet(object): + def __init__(self, key, backend=None): + backend = _get_backend(backend) + + key = base64.urlsafe_b64decode(key) + if len(key) != 32: + raise ValueError( + "Fernet key must be 32 url-safe base64-encoded bytes." + ) + + self._signing_key = key[:16] + self._encryption_key = key[16:] + self._backend = backend + + @classmethod + def generate_key(cls): + return base64.urlsafe_b64encode(os.urandom(32)) + + def encrypt(self, data): + return self.encrypt_at_time(data, int(time.time())) + + def encrypt_at_time(self, data, current_time): + iv = os.urandom(16) + return self._encrypt_from_parts(data, current_time, iv) + + def _encrypt_from_parts(self, data, current_time, iv): + utils._check_bytes("data", data) + + padder = padding.PKCS7(algorithms.AES.block_size).padder() + padded_data = padder.update(data) + padder.finalize() + encryptor = Cipher( + algorithms.AES(self._encryption_key), modes.CBC(iv), self._backend + ).encryptor() + ciphertext = encryptor.update(padded_data) + encryptor.finalize() + + basic_parts = ( + b"\x80" + struct.pack(">Q", current_time) + iv + ciphertext + ) + + h = HMAC(self._signing_key, hashes.SHA256(), backend=self._backend) + h.update(basic_parts) + hmac = h.finalize() + return base64.urlsafe_b64encode(basic_parts + hmac) + + def decrypt(self, token, ttl=None): + timestamp, data = Fernet._get_unverified_token_data(token) + return self._decrypt_data(data, timestamp, ttl, int(time.time())) + + def decrypt_at_time(self, token, ttl, current_time): + if ttl is None: + raise ValueError( + "decrypt_at_time() can only be used with a non-None ttl" + ) + timestamp, data = Fernet._get_unverified_token_data(token) + return self._decrypt_data(data, timestamp, ttl, current_time) + + def extract_timestamp(self, token): + timestamp, data = Fernet._get_unverified_token_data(token) + # Verify the token was not tampered with. + self._verify_signature(data) + return timestamp + + @staticmethod + def _get_unverified_token_data(token): + utils._check_bytes("token", token) + try: + data = base64.urlsafe_b64decode(token) + except (TypeError, binascii.Error): + raise InvalidToken + + if not data or six.indexbytes(data, 0) != 0x80: + raise InvalidToken + + try: + (timestamp,) = struct.unpack(">Q", data[1:9]) + except struct.error: + raise InvalidToken + return timestamp, data + + def _verify_signature(self, data): + h = HMAC(self._signing_key, hashes.SHA256(), backend=self._backend) + h.update(data[:-32]) + try: + h.verify(data[-32:]) + except InvalidSignature: + raise InvalidToken + + def _decrypt_data(self, data, timestamp, ttl, current_time): + if ttl is not None: + if timestamp + ttl < current_time: + raise InvalidToken + + if current_time + _MAX_CLOCK_SKEW < timestamp: + raise InvalidToken + + self._verify_signature(data) + + iv = data[9:25] + ciphertext = data[25:-32] + decryptor = Cipher( + algorithms.AES(self._encryption_key), modes.CBC(iv), self._backend + ).decryptor() + plaintext_padded = decryptor.update(ciphertext) + try: + plaintext_padded += decryptor.finalize() + except ValueError: + raise InvalidToken + unpadder = padding.PKCS7(algorithms.AES.block_size).unpadder() + + unpadded = unpadder.update(plaintext_padded) + try: + unpadded += unpadder.finalize() + except ValueError: + raise InvalidToken + return unpadded + + +class MultiFernet(object): + def __init__(self, fernets): + fernets = list(fernets) + if not fernets: + raise ValueError( + "MultiFernet requires at least one Fernet instance" + ) + self._fernets = fernets + + def encrypt(self, msg): + return self.encrypt_at_time(msg, int(time.time())) + + def encrypt_at_time(self, msg, current_time): + return self._fernets[0].encrypt_at_time(msg, current_time) + + def rotate(self, msg): + timestamp, data = Fernet._get_unverified_token_data(msg) + for f in self._fernets: + try: + p = f._decrypt_data(data, timestamp, None, None) + break + except InvalidToken: + pass + else: + raise InvalidToken + + iv = os.urandom(16) + return self._fernets[0]._encrypt_from_parts(p, timestamp, iv) + + def decrypt(self, msg, ttl=None): + for f in self._fernets: + try: + return f.decrypt(msg, ttl) + except InvalidToken: + pass + raise InvalidToken + + def decrypt_at_time(self, msg, ttl, current_time): + for f in self._fernets: + try: + return f.decrypt_at_time(msg, ttl, current_time) + except InvalidToken: + pass + raise InvalidToken diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/__init__.py new file mode 100644 index 0000000..9f06a99 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/__init__.py @@ -0,0 +1,11 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. +""" +Hazardous Materials + +This is a "Hazardous Materials" module. You should ONLY use it if you're +100% absolutely sure that you know what you're doing because this module +is full of land mines, dragons, and dinosaurs with laser guns. +""" +from __future__ import absolute_import, division, print_function diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/_der.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/_der.py new file mode 100644 index 0000000..462b911 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/_der.py @@ -0,0 +1,156 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import six + +from cryptography.utils import int_from_bytes, int_to_bytes + + +# This module contains a lightweight DER encoder and decoder. See X.690 for the +# specification. This module intentionally does not implement the more complex +# BER encoding, only DER. +# +# Note this implementation treats an element's constructed bit as part of the +# tag. This is fine for DER, where the bit is always computable from the type. + + +CONSTRUCTED = 0x20 +CONTEXT_SPECIFIC = 0x80 + +INTEGER = 0x02 +BIT_STRING = 0x03 +OCTET_STRING = 0x04 +NULL = 0x05 +OBJECT_IDENTIFIER = 0x06 +SEQUENCE = 0x10 | CONSTRUCTED +SET = 0x11 | CONSTRUCTED +PRINTABLE_STRING = 0x13 +UTC_TIME = 0x17 +GENERALIZED_TIME = 0x18 + + +class DERReader(object): + def __init__(self, data): + self.data = memoryview(data) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, tb): + if exc_value is None: + self.check_empty() + + def is_empty(self): + return len(self.data) == 0 + + def check_empty(self): + if not self.is_empty(): + raise ValueError("Invalid DER input: trailing data") + + def read_byte(self): + if len(self.data) < 1: + raise ValueError("Invalid DER input: insufficient data") + ret = six.indexbytes(self.data, 0) + self.data = self.data[1:] + return ret + + def read_bytes(self, n): + if len(self.data) < n: + raise ValueError("Invalid DER input: insufficient data") + ret = self.data[:n] + self.data = self.data[n:] + return ret + + def read_any_element(self): + tag = self.read_byte() + # Tag numbers 31 or higher are stored in multiple bytes. No supported + # ASN.1 types use such tags, so reject these. + if tag & 0x1F == 0x1F: + raise ValueError("Invalid DER input: unexpected high tag number") + length_byte = self.read_byte() + if length_byte & 0x80 == 0: + # If the high bit is clear, the first length byte is the length. + length = length_byte + else: + # If the high bit is set, the first length byte encodes the length + # of the length. + length_byte &= 0x7F + if length_byte == 0: + raise ValueError( + "Invalid DER input: indefinite length form is not allowed " + "in DER" + ) + length = 0 + for i in range(length_byte): + length <<= 8 + length |= self.read_byte() + if length == 0: + raise ValueError( + "Invalid DER input: length was not minimally-encoded" + ) + if length < 0x80: + # If the length could have been encoded in short form, it must + # not use long form. + raise ValueError( + "Invalid DER input: length was not minimally-encoded" + ) + body = self.read_bytes(length) + return tag, DERReader(body) + + def read_element(self, expected_tag): + tag, body = self.read_any_element() + if tag != expected_tag: + raise ValueError("Invalid DER input: unexpected tag") + return body + + def read_single_element(self, expected_tag): + with self: + return self.read_element(expected_tag) + + def read_optional_element(self, expected_tag): + if len(self.data) > 0 and six.indexbytes(self.data, 0) == expected_tag: + return self.read_element(expected_tag) + return None + + def as_integer(self): + if len(self.data) == 0: + raise ValueError("Invalid DER input: empty integer contents") + first = six.indexbytes(self.data, 0) + if first & 0x80 == 0x80: + raise ValueError("Negative DER integers are not supported") + # The first 9 bits must not all be zero or all be ones. Otherwise, the + # encoding should have been one byte shorter. + if len(self.data) > 1: + second = six.indexbytes(self.data, 1) + if first == 0 and second & 0x80 == 0: + raise ValueError( + "Invalid DER input: integer not minimally-encoded" + ) + return int_from_bytes(self.data, "big") + + +def encode_der_integer(x): + if not isinstance(x, six.integer_types): + raise ValueError("Value must be an integer") + if x < 0: + raise ValueError("Negative integers are not supported") + n = x.bit_length() // 8 + 1 + return int_to_bytes(x, n) + + +def encode_der(tag, *children): + length = 0 + for child in children: + length += len(child) + chunks = [six.int2byte(tag)] + if length < 0x80: + chunks.append(six.int2byte(length)) + else: + length_bytes = int_to_bytes(length) + chunks.append(six.int2byte(0x80 | len(length_bytes))) + chunks.append(length_bytes) + chunks.extend(children) + return b"".join(chunks) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/_oid.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/_oid.py new file mode 100644 index 0000000..de2771a --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/_oid.py @@ -0,0 +1,77 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography import utils + + +class ObjectIdentifier(object): + def __init__(self, dotted_string): + self._dotted_string = dotted_string + + nodes = self._dotted_string.split(".") + intnodes = [] + + # There must be at least 2 nodes, the first node must be 0..2, and + # if less than 2, the second node cannot have a value outside the + # range 0..39. All nodes must be integers. + for node in nodes: + try: + node_value = int(node, 10) + except ValueError: + raise ValueError( + "Malformed OID: %s (non-integer nodes)" + % (self._dotted_string) + ) + if node_value < 0: + raise ValueError( + "Malformed OID: %s (negative-integer nodes)" + % (self._dotted_string) + ) + intnodes.append(node_value) + + if len(nodes) < 2: + raise ValueError( + "Malformed OID: %s (insufficient number of nodes)" + % (self._dotted_string) + ) + + if intnodes[0] > 2: + raise ValueError( + "Malformed OID: %s (first node outside valid range)" + % (self._dotted_string) + ) + + if intnodes[0] < 2 and intnodes[1] >= 40: + raise ValueError( + "Malformed OID: %s (second node outside valid range)" + % (self._dotted_string) + ) + + def __eq__(self, other): + if not isinstance(other, ObjectIdentifier): + return NotImplemented + + return self.dotted_string == other.dotted_string + + def __ne__(self, other): + return not self == other + + def __repr__(self): + return "".format( + self.dotted_string, self._name + ) + + def __hash__(self): + return hash(self.dotted_string) + + @property + def _name(self): + # Lazy import to avoid an import cycle + from cryptography.x509.oid import _OID_NAMES + + return _OID_NAMES.get(self, "Unknown OID") + + dotted_string = utils.read_only_property("_dotted_string") diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/__init__.py new file mode 100644 index 0000000..1563936 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/__init__.py @@ -0,0 +1,26 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + + +_default_backend = None + + +def default_backend(): + global _default_backend + + if _default_backend is None: + from cryptography.hazmat.backends.openssl.backend import backend + + _default_backend = backend + + return _default_backend + + +def _get_backend(backend): + if backend is None: + return default_backend() + else: + return backend diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/interfaces.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/interfaces.py new file mode 100644 index 0000000..418980a --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/interfaces.py @@ -0,0 +1,396 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import abc + +import six + + +@six.add_metaclass(abc.ABCMeta) +class CipherBackend(object): + @abc.abstractmethod + def cipher_supported(self, cipher, mode): + """ + Return True if the given cipher and mode are supported. + """ + + @abc.abstractmethod + def create_symmetric_encryption_ctx(self, cipher, mode): + """ + Get a CipherContext that can be used for encryption. + """ + + @abc.abstractmethod + def create_symmetric_decryption_ctx(self, cipher, mode): + """ + Get a CipherContext that can be used for decryption. + """ + + +@six.add_metaclass(abc.ABCMeta) +class HashBackend(object): + @abc.abstractmethod + def hash_supported(self, algorithm): + """ + Return True if the hash algorithm is supported by this backend. + """ + + @abc.abstractmethod + def create_hash_ctx(self, algorithm): + """ + Create a HashContext for calculating a message digest. + """ + + +@six.add_metaclass(abc.ABCMeta) +class HMACBackend(object): + @abc.abstractmethod + def hmac_supported(self, algorithm): + """ + Return True if the hash algorithm is supported for HMAC by this + backend. + """ + + @abc.abstractmethod + def create_hmac_ctx(self, key, algorithm): + """ + Create a context for calculating a message authentication code. + """ + + +@six.add_metaclass(abc.ABCMeta) +class CMACBackend(object): + @abc.abstractmethod + def cmac_algorithm_supported(self, algorithm): + """ + Returns True if the block cipher is supported for CMAC by this backend + """ + + @abc.abstractmethod + def create_cmac_ctx(self, algorithm): + """ + Create a context for calculating a message authentication code. + """ + + +@six.add_metaclass(abc.ABCMeta) +class PBKDF2HMACBackend(object): + @abc.abstractmethod + def pbkdf2_hmac_supported(self, algorithm): + """ + Return True if the hash algorithm is supported for PBKDF2 by this + backend. + """ + + @abc.abstractmethod + def derive_pbkdf2_hmac( + self, algorithm, length, salt, iterations, key_material + ): + """ + Return length bytes derived from provided PBKDF2 parameters. + """ + + +@six.add_metaclass(abc.ABCMeta) +class RSABackend(object): + @abc.abstractmethod + def generate_rsa_private_key(self, public_exponent, key_size): + """ + Generate an RSAPrivateKey instance with public_exponent and a modulus + of key_size bits. + """ + + @abc.abstractmethod + def rsa_padding_supported(self, padding): + """ + Returns True if the backend supports the given padding options. + """ + + @abc.abstractmethod + def generate_rsa_parameters_supported(self, public_exponent, key_size): + """ + Returns True if the backend supports the given parameters for key + generation. + """ + + @abc.abstractmethod + def load_rsa_private_numbers(self, numbers): + """ + Returns an RSAPrivateKey provider. + """ + + @abc.abstractmethod + def load_rsa_public_numbers(self, numbers): + """ + Returns an RSAPublicKey provider. + """ + + +@six.add_metaclass(abc.ABCMeta) +class DSABackend(object): + @abc.abstractmethod + def generate_dsa_parameters(self, key_size): + """ + Generate a DSAParameters instance with a modulus of key_size bits. + """ + + @abc.abstractmethod + def generate_dsa_private_key(self, parameters): + """ + Generate a DSAPrivateKey instance with parameters as a DSAParameters + object. + """ + + @abc.abstractmethod + def generate_dsa_private_key_and_parameters(self, key_size): + """ + Generate a DSAPrivateKey instance using key size only. + """ + + @abc.abstractmethod + def dsa_hash_supported(self, algorithm): + """ + Return True if the hash algorithm is supported by the backend for DSA. + """ + + @abc.abstractmethod + def dsa_parameters_supported(self, p, q, g): + """ + Return True if the parameters are supported by the backend for DSA. + """ + + @abc.abstractmethod + def load_dsa_private_numbers(self, numbers): + """ + Returns a DSAPrivateKey provider. + """ + + @abc.abstractmethod + def load_dsa_public_numbers(self, numbers): + """ + Returns a DSAPublicKey provider. + """ + + @abc.abstractmethod + def load_dsa_parameter_numbers(self, numbers): + """ + Returns a DSAParameters provider. + """ + + +@six.add_metaclass(abc.ABCMeta) +class EllipticCurveBackend(object): + @abc.abstractmethod + def elliptic_curve_signature_algorithm_supported( + self, signature_algorithm, curve + ): + """ + Returns True if the backend supports the named elliptic curve with the + specified signature algorithm. + """ + + @abc.abstractmethod + def elliptic_curve_supported(self, curve): + """ + Returns True if the backend supports the named elliptic curve. + """ + + @abc.abstractmethod + def generate_elliptic_curve_private_key(self, curve): + """ + Return an object conforming to the EllipticCurvePrivateKey interface. + """ + + @abc.abstractmethod + def load_elliptic_curve_public_numbers(self, numbers): + """ + Return an EllipticCurvePublicKey provider using the given numbers. + """ + + @abc.abstractmethod + def load_elliptic_curve_private_numbers(self, numbers): + """ + Return an EllipticCurvePrivateKey provider using the given numbers. + """ + + @abc.abstractmethod + def elliptic_curve_exchange_algorithm_supported(self, algorithm, curve): + """ + Returns whether the exchange algorithm is supported by this backend. + """ + + @abc.abstractmethod + def derive_elliptic_curve_private_key(self, private_value, curve): + """ + Compute the private key given the private value and curve. + """ + + +@six.add_metaclass(abc.ABCMeta) +class PEMSerializationBackend(object): + @abc.abstractmethod + def load_pem_private_key(self, data, password): + """ + Loads a private key from PEM encoded data, using the provided password + if the data is encrypted. + """ + + @abc.abstractmethod + def load_pem_public_key(self, data): + """ + Loads a public key from PEM encoded data. + """ + + @abc.abstractmethod + def load_pem_parameters(self, data): + """ + Load encryption parameters from PEM encoded data. + """ + + +@six.add_metaclass(abc.ABCMeta) +class DERSerializationBackend(object): + @abc.abstractmethod + def load_der_private_key(self, data, password): + """ + Loads a private key from DER encoded data. Uses the provided password + if the data is encrypted. + """ + + @abc.abstractmethod + def load_der_public_key(self, data): + """ + Loads a public key from DER encoded data. + """ + + @abc.abstractmethod + def load_der_parameters(self, data): + """ + Load encryption parameters from DER encoded data. + """ + + +@six.add_metaclass(abc.ABCMeta) +class X509Backend(object): + @abc.abstractmethod + def load_pem_x509_certificate(self, data): + """ + Load an X.509 certificate from PEM encoded data. + """ + + @abc.abstractmethod + def load_der_x509_certificate(self, data): + """ + Load an X.509 certificate from DER encoded data. + """ + + @abc.abstractmethod + def load_der_x509_csr(self, data): + """ + Load an X.509 CSR from DER encoded data. + """ + + @abc.abstractmethod + def load_pem_x509_csr(self, data): + """ + Load an X.509 CSR from PEM encoded data. + """ + + @abc.abstractmethod + def create_x509_csr(self, builder, private_key, algorithm): + """ + Create and sign an X.509 CSR from a CSR builder object. + """ + + @abc.abstractmethod + def create_x509_certificate(self, builder, private_key, algorithm): + """ + Create and sign an X.509 certificate from a CertificateBuilder object. + """ + + @abc.abstractmethod + def create_x509_crl(self, builder, private_key, algorithm): + """ + Create and sign an X.509 CertificateRevocationList from a + CertificateRevocationListBuilder object. + """ + + @abc.abstractmethod + def create_x509_revoked_certificate(self, builder): + """ + Create a RevokedCertificate object from a RevokedCertificateBuilder + object. + """ + + @abc.abstractmethod + def x509_name_bytes(self, name): + """ + Compute the DER encoded bytes of an X509 Name object. + """ + + +@six.add_metaclass(abc.ABCMeta) +class DHBackend(object): + @abc.abstractmethod + def generate_dh_parameters(self, generator, key_size): + """ + Generate a DHParameters instance with a modulus of key_size bits. + Using the given generator. Often 2 or 5. + """ + + @abc.abstractmethod + def generate_dh_private_key(self, parameters): + """ + Generate a DHPrivateKey instance with parameters as a DHParameters + object. + """ + + @abc.abstractmethod + def generate_dh_private_key_and_parameters(self, generator, key_size): + """ + Generate a DHPrivateKey instance using key size only. + Using the given generator. Often 2 or 5. + """ + + @abc.abstractmethod + def load_dh_private_numbers(self, numbers): + """ + Load a DHPrivateKey from DHPrivateNumbers + """ + + @abc.abstractmethod + def load_dh_public_numbers(self, numbers): + """ + Load a DHPublicKey from DHPublicNumbers. + """ + + @abc.abstractmethod + def load_dh_parameter_numbers(self, numbers): + """ + Load DHParameters from DHParameterNumbers. + """ + + @abc.abstractmethod + def dh_parameters_supported(self, p, g, q=None): + """ + Returns whether the backend supports DH with these parameter values. + """ + + @abc.abstractmethod + def dh_x942_serialization_supported(self): + """ + Returns True if the backend supports the serialization of DH objects + with subgroup order (q). + """ + + +@six.add_metaclass(abc.ABCMeta) +class ScryptBackend(object): + @abc.abstractmethod + def derive_scrypt(self, key_material, salt, length, n, r, p): + """ + Return bytes derived from provided Scrypt parameters. + """ diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/__init__.py new file mode 100644 index 0000000..8eadeb6 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/__init__.py @@ -0,0 +1,10 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography.hazmat.backends.openssl.backend import backend + + +__all__ = ["backend"] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/aead.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/aead.py new file mode 100644 index 0000000..4494916 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/aead.py @@ -0,0 +1,166 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography.exceptions import InvalidTag + + +_ENCRYPT = 1 +_DECRYPT = 0 + + +def _aead_cipher_name(cipher): + from cryptography.hazmat.primitives.ciphers.aead import ( + AESCCM, + AESGCM, + ChaCha20Poly1305, + ) + + if isinstance(cipher, ChaCha20Poly1305): + return b"chacha20-poly1305" + elif isinstance(cipher, AESCCM): + return "aes-{}-ccm".format(len(cipher._key) * 8).encode("ascii") + else: + assert isinstance(cipher, AESGCM) + return "aes-{}-gcm".format(len(cipher._key) * 8).encode("ascii") + + +def _aead_setup(backend, cipher_name, key, nonce, tag, tag_len, operation): + evp_cipher = backend._lib.EVP_get_cipherbyname(cipher_name) + backend.openssl_assert(evp_cipher != backend._ffi.NULL) + ctx = backend._lib.EVP_CIPHER_CTX_new() + ctx = backend._ffi.gc(ctx, backend._lib.EVP_CIPHER_CTX_free) + res = backend._lib.EVP_CipherInit_ex( + ctx, + evp_cipher, + backend._ffi.NULL, + backend._ffi.NULL, + backend._ffi.NULL, + int(operation == _ENCRYPT), + ) + backend.openssl_assert(res != 0) + res = backend._lib.EVP_CIPHER_CTX_set_key_length(ctx, len(key)) + backend.openssl_assert(res != 0) + res = backend._lib.EVP_CIPHER_CTX_ctrl( + ctx, + backend._lib.EVP_CTRL_AEAD_SET_IVLEN, + len(nonce), + backend._ffi.NULL, + ) + backend.openssl_assert(res != 0) + if operation == _DECRYPT: + res = backend._lib.EVP_CIPHER_CTX_ctrl( + ctx, backend._lib.EVP_CTRL_AEAD_SET_TAG, len(tag), tag + ) + backend.openssl_assert(res != 0) + elif cipher_name.endswith(b"-ccm"): + res = backend._lib.EVP_CIPHER_CTX_ctrl( + ctx, backend._lib.EVP_CTRL_AEAD_SET_TAG, tag_len, backend._ffi.NULL + ) + backend.openssl_assert(res != 0) + + nonce_ptr = backend._ffi.from_buffer(nonce) + key_ptr = backend._ffi.from_buffer(key) + res = backend._lib.EVP_CipherInit_ex( + ctx, + backend._ffi.NULL, + backend._ffi.NULL, + key_ptr, + nonce_ptr, + int(operation == _ENCRYPT), + ) + backend.openssl_assert(res != 0) + return ctx + + +def _set_length(backend, ctx, data_len): + intptr = backend._ffi.new("int *") + res = backend._lib.EVP_CipherUpdate( + ctx, backend._ffi.NULL, intptr, backend._ffi.NULL, data_len + ) + backend.openssl_assert(res != 0) + + +def _process_aad(backend, ctx, associated_data): + outlen = backend._ffi.new("int *") + res = backend._lib.EVP_CipherUpdate( + ctx, backend._ffi.NULL, outlen, associated_data, len(associated_data) + ) + backend.openssl_assert(res != 0) + + +def _process_data(backend, ctx, data): + outlen = backend._ffi.new("int *") + buf = backend._ffi.new("unsigned char[]", len(data)) + res = backend._lib.EVP_CipherUpdate(ctx, buf, outlen, data, len(data)) + backend.openssl_assert(res != 0) + return backend._ffi.buffer(buf, outlen[0])[:] + + +def _encrypt(backend, cipher, nonce, data, associated_data, tag_length): + from cryptography.hazmat.primitives.ciphers.aead import AESCCM + + cipher_name = _aead_cipher_name(cipher) + ctx = _aead_setup( + backend, cipher_name, cipher._key, nonce, None, tag_length, _ENCRYPT + ) + # CCM requires us to pass the length of the data before processing anything + # However calling this with any other AEAD results in an error + if isinstance(cipher, AESCCM): + _set_length(backend, ctx, len(data)) + + _process_aad(backend, ctx, associated_data) + processed_data = _process_data(backend, ctx, data) + outlen = backend._ffi.new("int *") + res = backend._lib.EVP_CipherFinal_ex(ctx, backend._ffi.NULL, outlen) + backend.openssl_assert(res != 0) + backend.openssl_assert(outlen[0] == 0) + tag_buf = backend._ffi.new("unsigned char[]", tag_length) + res = backend._lib.EVP_CIPHER_CTX_ctrl( + ctx, backend._lib.EVP_CTRL_AEAD_GET_TAG, tag_length, tag_buf + ) + backend.openssl_assert(res != 0) + tag = backend._ffi.buffer(tag_buf)[:] + + return processed_data + tag + + +def _decrypt(backend, cipher, nonce, data, associated_data, tag_length): + from cryptography.hazmat.primitives.ciphers.aead import AESCCM + + if len(data) < tag_length: + raise InvalidTag + tag = data[-tag_length:] + data = data[:-tag_length] + cipher_name = _aead_cipher_name(cipher) + ctx = _aead_setup( + backend, cipher_name, cipher._key, nonce, tag, tag_length, _DECRYPT + ) + # CCM requires us to pass the length of the data before processing anything + # However calling this with any other AEAD results in an error + if isinstance(cipher, AESCCM): + _set_length(backend, ctx, len(data)) + + _process_aad(backend, ctx, associated_data) + # CCM has a different error path if the tag doesn't match. Errors are + # raised in Update and Final is irrelevant. + if isinstance(cipher, AESCCM): + outlen = backend._ffi.new("int *") + buf = backend._ffi.new("unsigned char[]", len(data)) + res = backend._lib.EVP_CipherUpdate(ctx, buf, outlen, data, len(data)) + if res != 1: + backend._consume_errors() + raise InvalidTag + + processed_data = backend._ffi.buffer(buf, outlen[0])[:] + else: + processed_data = _process_data(backend, ctx, data) + outlen = backend._ffi.new("int *") + res = backend._lib.EVP_CipherFinal_ex(ctx, backend._ffi.NULL, outlen) + if res == 0: + backend._consume_errors() + raise InvalidTag + + return processed_data diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/backend.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/backend.py new file mode 100644 index 0000000..b7757e3 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/backend.py @@ -0,0 +1,2785 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import collections +import contextlib +import itertools +import warnings +from contextlib import contextmanager + +import six +from six.moves import range + +from cryptography import utils, x509 +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat._der import ( + INTEGER, + NULL, + SEQUENCE, + encode_der, + encode_der_integer, +) +from cryptography.hazmat.backends.interfaces import ( + CMACBackend, + CipherBackend, + DERSerializationBackend, + DHBackend, + DSABackend, + EllipticCurveBackend, + HMACBackend, + HashBackend, + PBKDF2HMACBackend, + PEMSerializationBackend, + RSABackend, + ScryptBackend, + X509Backend, +) +from cryptography.hazmat.backends.openssl import aead +from cryptography.hazmat.backends.openssl.ciphers import _CipherContext +from cryptography.hazmat.backends.openssl.cmac import _CMACContext +from cryptography.hazmat.backends.openssl.decode_asn1 import ( + _CRL_ENTRY_REASON_ENUM_TO_CODE, + _CRL_EXTENSION_HANDLERS, + _EXTENSION_HANDLERS_BASE, + _EXTENSION_HANDLERS_SCT, + _OCSP_BASICRESP_EXTENSION_HANDLERS, + _OCSP_REQ_EXTENSION_HANDLERS, + _OCSP_SINGLERESP_EXTENSION_HANDLERS_SCT, + _REVOKED_EXTENSION_HANDLERS, + _X509ExtensionParser, +) +from cryptography.hazmat.backends.openssl.dh import ( + _DHParameters, + _DHPrivateKey, + _DHPublicKey, + _dh_params_dup, +) +from cryptography.hazmat.backends.openssl.dsa import ( + _DSAParameters, + _DSAPrivateKey, + _DSAPublicKey, +) +from cryptography.hazmat.backends.openssl.ec import ( + _EllipticCurvePrivateKey, + _EllipticCurvePublicKey, +) +from cryptography.hazmat.backends.openssl.ed25519 import ( + _Ed25519PrivateKey, + _Ed25519PublicKey, +) +from cryptography.hazmat.backends.openssl.ed448 import ( + _ED448_KEY_SIZE, + _Ed448PrivateKey, + _Ed448PublicKey, +) +from cryptography.hazmat.backends.openssl.encode_asn1 import ( + _CRL_ENTRY_EXTENSION_ENCODE_HANDLERS, + _CRL_EXTENSION_ENCODE_HANDLERS, + _EXTENSION_ENCODE_HANDLERS, + _OCSP_BASICRESP_EXTENSION_ENCODE_HANDLERS, + _OCSP_REQUEST_EXTENSION_ENCODE_HANDLERS, + _encode_asn1_int_gc, + _encode_asn1_str_gc, + _encode_name_gc, + _txt2obj_gc, +) +from cryptography.hazmat.backends.openssl.hashes import _HashContext +from cryptography.hazmat.backends.openssl.hmac import _HMACContext +from cryptography.hazmat.backends.openssl.ocsp import ( + _OCSPRequest, + _OCSPResponse, +) +from cryptography.hazmat.backends.openssl.poly1305 import ( + _POLY1305_KEY_SIZE, + _Poly1305Context, +) +from cryptography.hazmat.backends.openssl.rsa import ( + _RSAPrivateKey, + _RSAPublicKey, +) +from cryptography.hazmat.backends.openssl.x25519 import ( + _X25519PrivateKey, + _X25519PublicKey, +) +from cryptography.hazmat.backends.openssl.x448 import ( + _X448PrivateKey, + _X448PublicKey, +) +from cryptography.hazmat.backends.openssl.x509 import ( + _Certificate, + _CertificateRevocationList, + _CertificateSigningRequest, + _RevokedCertificate, +) +from cryptography.hazmat.bindings.openssl import binding +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import ( + dsa, + ec, + ed25519, + ed448, + rsa, +) +from cryptography.hazmat.primitives.asymmetric.padding import ( + MGF1, + OAEP, + PKCS1v15, + PSS, +) +from cryptography.hazmat.primitives.ciphers.algorithms import ( + AES, + ARC4, + Blowfish, + CAST5, + Camellia, + ChaCha20, + IDEA, + SEED, + TripleDES, +) +from cryptography.hazmat.primitives.ciphers.modes import ( + CBC, + CFB, + CFB8, + CTR, + ECB, + GCM, + OFB, + XTS, +) +from cryptography.hazmat.primitives.kdf import scrypt +from cryptography.hazmat.primitives.serialization import pkcs7, ssh +from cryptography.x509 import ocsp + + +_MemoryBIO = collections.namedtuple("_MemoryBIO", ["bio", "char_ptr"]) + + +# Not actually supported, just used as a marker for some serialization tests. +class _RC2(object): + pass + + +@utils.register_interface(CipherBackend) +@utils.register_interface(CMACBackend) +@utils.register_interface(DERSerializationBackend) +@utils.register_interface(DHBackend) +@utils.register_interface(DSABackend) +@utils.register_interface(EllipticCurveBackend) +@utils.register_interface(HashBackend) +@utils.register_interface(HMACBackend) +@utils.register_interface(PBKDF2HMACBackend) +@utils.register_interface(RSABackend) +@utils.register_interface(PEMSerializationBackend) +@utils.register_interface(X509Backend) +@utils.register_interface_if( + binding.Binding().lib.Cryptography_HAS_SCRYPT, ScryptBackend +) +class Backend(object): + """ + OpenSSL API binding interfaces. + """ + + name = "openssl" + + # FIPS has opinions about acceptable algorithms and key sizes, but the + # disallowed algorithms are still present in OpenSSL. They just error if + # you try to use them. To avoid that we allowlist the algorithms in + # FIPS 140-3. This isn't ideal, but FIPS 140-3 is trash so here we are. + _fips_aead = { + b"aes-128-ccm", + b"aes-192-ccm", + b"aes-256-ccm", + b"aes-128-gcm", + b"aes-192-gcm", + b"aes-256-gcm", + } + _fips_ciphers = (AES, TripleDES) + _fips_hashes = ( + hashes.SHA1, + hashes.SHA224, + hashes.SHA256, + hashes.SHA384, + hashes.SHA512, + hashes.SHA512_224, + hashes.SHA512_256, + hashes.SHA3_224, + hashes.SHA3_256, + hashes.SHA3_384, + hashes.SHA3_512, + hashes.SHAKE128, + hashes.SHAKE256, + ) + _fips_rsa_min_key_size = 2048 + _fips_rsa_min_public_exponent = 65537 + _fips_dsa_min_modulus = 1 << 2048 + _fips_dh_min_key_size = 2048 + _fips_dh_min_modulus = 1 << _fips_dh_min_key_size + + def __init__(self): + self._binding = binding.Binding() + self._ffi = self._binding.ffi + self._lib = self._binding.lib + self._fips_enabled = self._is_fips_enabled() + + self._cipher_registry = {} + self._register_default_ciphers() + self._register_x509_ext_parsers() + self._register_x509_encoders() + if self._fips_enabled and self._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE: + warnings.warn( + "OpenSSL FIPS mode is enabled. Can't enable DRBG fork safety.", + UserWarning, + ) + else: + self.activate_osrandom_engine() + self._dh_types = [self._lib.EVP_PKEY_DH] + if self._lib.Cryptography_HAS_EVP_PKEY_DHX: + self._dh_types.append(self._lib.EVP_PKEY_DHX) + + def openssl_assert(self, ok, errors=None): + return binding._openssl_assert(self._lib, ok, errors=errors) + + def _is_fips_enabled(self): + fips_mode = getattr(self._lib, "FIPS_mode", lambda: 0) + mode = fips_mode() + if mode == 0: + # OpenSSL without FIPS pushes an error on the error stack + self._lib.ERR_clear_error() + return bool(mode) + + def activate_builtin_random(self): + if self._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE: + # Obtain a new structural reference. + e = self._lib.ENGINE_get_default_RAND() + if e != self._ffi.NULL: + self._lib.ENGINE_unregister_RAND(e) + # Reset the RNG to use the built-in. + res = self._lib.RAND_set_rand_method(self._ffi.NULL) + self.openssl_assert(res == 1) + # decrement the structural reference from get_default_RAND + res = self._lib.ENGINE_finish(e) + self.openssl_assert(res == 1) + + @contextlib.contextmanager + def _get_osurandom_engine(self): + # Fetches an engine by id and returns it. This creates a structural + # reference. + e = self._lib.ENGINE_by_id(self._lib.Cryptography_osrandom_engine_id) + self.openssl_assert(e != self._ffi.NULL) + # Initialize the engine for use. This adds a functional reference. + res = self._lib.ENGINE_init(e) + self.openssl_assert(res == 1) + + try: + yield e + finally: + # Decrement the structural ref incremented by ENGINE_by_id. + res = self._lib.ENGINE_free(e) + self.openssl_assert(res == 1) + # Decrement the functional ref incremented by ENGINE_init. + res = self._lib.ENGINE_finish(e) + self.openssl_assert(res == 1) + + def activate_osrandom_engine(self): + if self._lib.CRYPTOGRAPHY_NEEDS_OSRANDOM_ENGINE: + # Unregister and free the current engine. + self.activate_builtin_random() + with self._get_osurandom_engine() as e: + # Set the engine as the default RAND provider. + res = self._lib.ENGINE_set_default_RAND(e) + self.openssl_assert(res == 1) + # Reset the RNG to use the engine + res = self._lib.RAND_set_rand_method(self._ffi.NULL) + self.openssl_assert(res == 1) + + def osrandom_engine_implementation(self): + buf = self._ffi.new("char[]", 64) + with self._get_osurandom_engine() as e: + res = self._lib.ENGINE_ctrl_cmd( + e, b"get_implementation", len(buf), buf, self._ffi.NULL, 0 + ) + self.openssl_assert(res > 0) + return self._ffi.string(buf).decode("ascii") + + def openssl_version_text(self): + """ + Friendly string name of the loaded OpenSSL library. This is not + necessarily the same version as it was compiled against. + + Example: OpenSSL 1.1.1d 10 Sep 2019 + """ + return self._ffi.string( + self._lib.OpenSSL_version(self._lib.OPENSSL_VERSION) + ).decode("ascii") + + def openssl_version_number(self): + return self._lib.OpenSSL_version_num() + + def create_hmac_ctx(self, key, algorithm): + return _HMACContext(self, key, algorithm) + + def _evp_md_from_algorithm(self, algorithm): + if algorithm.name == "blake2b" or algorithm.name == "blake2s": + alg = "{}{}".format( + algorithm.name, algorithm.digest_size * 8 + ).encode("ascii") + else: + alg = algorithm.name.encode("ascii") + + evp_md = self._lib.EVP_get_digestbyname(alg) + return evp_md + + def _evp_md_non_null_from_algorithm(self, algorithm): + evp_md = self._evp_md_from_algorithm(algorithm) + self.openssl_assert(evp_md != self._ffi.NULL) + return evp_md + + def hash_supported(self, algorithm): + if self._fips_enabled and not isinstance(algorithm, self._fips_hashes): + return False + + evp_md = self._evp_md_from_algorithm(algorithm) + return evp_md != self._ffi.NULL + + def hmac_supported(self, algorithm): + return self.hash_supported(algorithm) + + def create_hash_ctx(self, algorithm): + return _HashContext(self, algorithm) + + def cipher_supported(self, cipher, mode): + if self._fips_enabled and not isinstance(cipher, self._fips_ciphers): + return False + try: + adapter = self._cipher_registry[type(cipher), type(mode)] + except KeyError: + return False + evp_cipher = adapter(self, cipher, mode) + return self._ffi.NULL != evp_cipher + + def register_cipher_adapter(self, cipher_cls, mode_cls, adapter): + if (cipher_cls, mode_cls) in self._cipher_registry: + raise ValueError( + "Duplicate registration for: {} {}.".format( + cipher_cls, mode_cls + ) + ) + self._cipher_registry[cipher_cls, mode_cls] = adapter + + def _register_default_ciphers(self): + for mode_cls in [CBC, CTR, ECB, OFB, CFB, CFB8, GCM]: + self.register_cipher_adapter( + AES, + mode_cls, + GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}"), + ) + for mode_cls in [CBC, CTR, ECB, OFB, CFB]: + self.register_cipher_adapter( + Camellia, + mode_cls, + GetCipherByName("{cipher.name}-{cipher.key_size}-{mode.name}"), + ) + for mode_cls in [CBC, CFB, CFB8, OFB]: + self.register_cipher_adapter( + TripleDES, mode_cls, GetCipherByName("des-ede3-{mode.name}") + ) + self.register_cipher_adapter( + TripleDES, ECB, GetCipherByName("des-ede3") + ) + for mode_cls in [CBC, CFB, OFB, ECB]: + self.register_cipher_adapter( + Blowfish, mode_cls, GetCipherByName("bf-{mode.name}") + ) + for mode_cls in [CBC, CFB, OFB, ECB]: + self.register_cipher_adapter( + SEED, mode_cls, GetCipherByName("seed-{mode.name}") + ) + for cipher_cls, mode_cls in itertools.product( + [CAST5, IDEA], + [CBC, OFB, CFB, ECB], + ): + self.register_cipher_adapter( + cipher_cls, + mode_cls, + GetCipherByName("{cipher.name}-{mode.name}"), + ) + self.register_cipher_adapter(ARC4, type(None), GetCipherByName("rc4")) + # We don't actually support RC2, this is just used by some tests. + self.register_cipher_adapter(_RC2, type(None), GetCipherByName("rc2")) + self.register_cipher_adapter( + ChaCha20, type(None), GetCipherByName("chacha20") + ) + self.register_cipher_adapter(AES, XTS, _get_xts_cipher) + + def _register_x509_ext_parsers(self): + ext_handlers = _EXTENSION_HANDLERS_BASE.copy() + # All revoked extensions are valid single response extensions, see: + # https://tools.ietf.org/html/rfc6960#section-4.4.5 + singleresp_handlers = _REVOKED_EXTENSION_HANDLERS.copy() + + if self._lib.Cryptography_HAS_SCT: + ext_handlers.update(_EXTENSION_HANDLERS_SCT) + singleresp_handlers.update(_OCSP_SINGLERESP_EXTENSION_HANDLERS_SCT) + + self._certificate_extension_parser = _X509ExtensionParser( + self, + ext_count=self._lib.X509_get_ext_count, + get_ext=self._lib.X509_get_ext, + handlers=ext_handlers, + ) + self._csr_extension_parser = _X509ExtensionParser( + self, + ext_count=self._lib.sk_X509_EXTENSION_num, + get_ext=self._lib.sk_X509_EXTENSION_value, + handlers=ext_handlers, + ) + self._revoked_cert_extension_parser = _X509ExtensionParser( + self, + ext_count=self._lib.X509_REVOKED_get_ext_count, + get_ext=self._lib.X509_REVOKED_get_ext, + handlers=_REVOKED_EXTENSION_HANDLERS, + ) + self._crl_extension_parser = _X509ExtensionParser( + self, + ext_count=self._lib.X509_CRL_get_ext_count, + get_ext=self._lib.X509_CRL_get_ext, + handlers=_CRL_EXTENSION_HANDLERS, + ) + self._ocsp_req_ext_parser = _X509ExtensionParser( + self, + ext_count=self._lib.OCSP_REQUEST_get_ext_count, + get_ext=self._lib.OCSP_REQUEST_get_ext, + handlers=_OCSP_REQ_EXTENSION_HANDLERS, + ) + self._ocsp_basicresp_ext_parser = _X509ExtensionParser( + self, + ext_count=self._lib.OCSP_BASICRESP_get_ext_count, + get_ext=self._lib.OCSP_BASICRESP_get_ext, + handlers=_OCSP_BASICRESP_EXTENSION_HANDLERS, + ) + self._ocsp_singleresp_ext_parser = _X509ExtensionParser( + self, + ext_count=self._lib.OCSP_SINGLERESP_get_ext_count, + get_ext=self._lib.OCSP_SINGLERESP_get_ext, + handlers=singleresp_handlers, + ) + + def _register_x509_encoders(self): + self._extension_encode_handlers = _EXTENSION_ENCODE_HANDLERS.copy() + self._crl_extension_encode_handlers = ( + _CRL_EXTENSION_ENCODE_HANDLERS.copy() + ) + self._crl_entry_extension_encode_handlers = ( + _CRL_ENTRY_EXTENSION_ENCODE_HANDLERS.copy() + ) + self._ocsp_request_extension_encode_handlers = ( + _OCSP_REQUEST_EXTENSION_ENCODE_HANDLERS.copy() + ) + self._ocsp_basicresp_extension_encode_handlers = ( + _OCSP_BASICRESP_EXTENSION_ENCODE_HANDLERS.copy() + ) + + def create_symmetric_encryption_ctx(self, cipher, mode): + return _CipherContext(self, cipher, mode, _CipherContext._ENCRYPT) + + def create_symmetric_decryption_ctx(self, cipher, mode): + return _CipherContext(self, cipher, mode, _CipherContext._DECRYPT) + + def pbkdf2_hmac_supported(self, algorithm): + return self.hmac_supported(algorithm) + + def derive_pbkdf2_hmac( + self, algorithm, length, salt, iterations, key_material + ): + buf = self._ffi.new("unsigned char[]", length) + evp_md = self._evp_md_non_null_from_algorithm(algorithm) + key_material_ptr = self._ffi.from_buffer(key_material) + res = self._lib.PKCS5_PBKDF2_HMAC( + key_material_ptr, + len(key_material), + salt, + len(salt), + iterations, + evp_md, + length, + buf, + ) + self.openssl_assert(res == 1) + return self._ffi.buffer(buf)[:] + + def _consume_errors(self): + return binding._consume_errors(self._lib) + + def _consume_errors_with_text(self): + return binding._consume_errors_with_text(self._lib) + + def _bn_to_int(self, bn): + assert bn != self._ffi.NULL + + if not six.PY2: + # Python 3 has constant time from_bytes, so use that. + bn_num_bytes = self._lib.BN_num_bytes(bn) + bin_ptr = self._ffi.new("unsigned char[]", bn_num_bytes) + bin_len = self._lib.BN_bn2bin(bn, bin_ptr) + # A zero length means the BN has value 0 + self.openssl_assert(bin_len >= 0) + val = int.from_bytes(self._ffi.buffer(bin_ptr)[:bin_len], "big") + if self._lib.BN_is_negative(bn): + val = -val + return val + else: + # Under Python 2 the best we can do is hex() + hex_cdata = self._lib.BN_bn2hex(bn) + self.openssl_assert(hex_cdata != self._ffi.NULL) + hex_str = self._ffi.string(hex_cdata) + self._lib.OPENSSL_free(hex_cdata) + return int(hex_str, 16) + + def _int_to_bn(self, num, bn=None): + """ + Converts a python integer to a BIGNUM. The returned BIGNUM will not + be garbage collected (to support adding them to structs that take + ownership of the object). Be sure to register it for GC if it will + be discarded after use. + """ + assert bn is None or bn != self._ffi.NULL + + if bn is None: + bn = self._ffi.NULL + + if not six.PY2: + # Python 3 has constant time to_bytes, so use that. + + binary = num.to_bytes(int(num.bit_length() / 8.0 + 1), "big") + bn_ptr = self._lib.BN_bin2bn(binary, len(binary), bn) + self.openssl_assert(bn_ptr != self._ffi.NULL) + return bn_ptr + + else: + # Under Python 2 the best we can do is hex(), [2:] removes the 0x + # prefix. + hex_num = hex(num).rstrip("L")[2:].encode("ascii") + bn_ptr = self._ffi.new("BIGNUM **") + bn_ptr[0] = bn + res = self._lib.BN_hex2bn(bn_ptr, hex_num) + self.openssl_assert(res != 0) + self.openssl_assert(bn_ptr[0] != self._ffi.NULL) + return bn_ptr[0] + + def generate_rsa_private_key(self, public_exponent, key_size): + rsa._verify_rsa_parameters(public_exponent, key_size) + + rsa_cdata = self._lib.RSA_new() + self.openssl_assert(rsa_cdata != self._ffi.NULL) + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + + bn = self._int_to_bn(public_exponent) + bn = self._ffi.gc(bn, self._lib.BN_free) + + res = self._lib.RSA_generate_key_ex( + rsa_cdata, key_size, bn, self._ffi.NULL + ) + self.openssl_assert(res == 1) + evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata) + + return _RSAPrivateKey(self, rsa_cdata, evp_pkey) + + def generate_rsa_parameters_supported(self, public_exponent, key_size): + return ( + public_exponent >= 3 + and public_exponent & 1 != 0 + and key_size >= 512 + ) + + def load_rsa_private_numbers(self, numbers): + rsa._check_private_key_components( + numbers.p, + numbers.q, + numbers.d, + numbers.dmp1, + numbers.dmq1, + numbers.iqmp, + numbers.public_numbers.e, + numbers.public_numbers.n, + ) + rsa_cdata = self._lib.RSA_new() + self.openssl_assert(rsa_cdata != self._ffi.NULL) + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + p = self._int_to_bn(numbers.p) + q = self._int_to_bn(numbers.q) + d = self._int_to_bn(numbers.d) + dmp1 = self._int_to_bn(numbers.dmp1) + dmq1 = self._int_to_bn(numbers.dmq1) + iqmp = self._int_to_bn(numbers.iqmp) + e = self._int_to_bn(numbers.public_numbers.e) + n = self._int_to_bn(numbers.public_numbers.n) + res = self._lib.RSA_set0_factors(rsa_cdata, p, q) + self.openssl_assert(res == 1) + res = self._lib.RSA_set0_key(rsa_cdata, n, e, d) + self.openssl_assert(res == 1) + res = self._lib.RSA_set0_crt_params(rsa_cdata, dmp1, dmq1, iqmp) + self.openssl_assert(res == 1) + evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata) + + return _RSAPrivateKey(self, rsa_cdata, evp_pkey) + + def load_rsa_public_numbers(self, numbers): + rsa._check_public_key_components(numbers.e, numbers.n) + rsa_cdata = self._lib.RSA_new() + self.openssl_assert(rsa_cdata != self._ffi.NULL) + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + e = self._int_to_bn(numbers.e) + n = self._int_to_bn(numbers.n) + res = self._lib.RSA_set0_key(rsa_cdata, n, e, self._ffi.NULL) + self.openssl_assert(res == 1) + evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata) + + return _RSAPublicKey(self, rsa_cdata, evp_pkey) + + def _create_evp_pkey_gc(self): + evp_pkey = self._lib.EVP_PKEY_new() + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + return evp_pkey + + def _rsa_cdata_to_evp_pkey(self, rsa_cdata): + evp_pkey = self._create_evp_pkey_gc() + res = self._lib.EVP_PKEY_set1_RSA(evp_pkey, rsa_cdata) + self.openssl_assert(res == 1) + return evp_pkey + + def _bytes_to_bio(self, data): + """ + Return a _MemoryBIO namedtuple of (BIO, char*). + + The char* is the storage for the BIO and it must stay alive until the + BIO is finished with. + """ + data_ptr = self._ffi.from_buffer(data) + bio = self._lib.BIO_new_mem_buf(data_ptr, len(data)) + self.openssl_assert(bio != self._ffi.NULL) + + return _MemoryBIO(self._ffi.gc(bio, self._lib.BIO_free), data_ptr) + + def _create_mem_bio_gc(self): + """ + Creates an empty memory BIO. + """ + bio_method = self._lib.BIO_s_mem() + self.openssl_assert(bio_method != self._ffi.NULL) + bio = self._lib.BIO_new(bio_method) + self.openssl_assert(bio != self._ffi.NULL) + bio = self._ffi.gc(bio, self._lib.BIO_free) + return bio + + def _read_mem_bio(self, bio): + """ + Reads a memory BIO. This only works on memory BIOs. + """ + buf = self._ffi.new("char **") + buf_len = self._lib.BIO_get_mem_data(bio, buf) + self.openssl_assert(buf_len > 0) + self.openssl_assert(buf[0] != self._ffi.NULL) + bio_data = self._ffi.buffer(buf[0], buf_len)[:] + return bio_data + + def _evp_pkey_to_private_key(self, evp_pkey): + """ + Return the appropriate type of PrivateKey given an evp_pkey cdata + pointer. + """ + + key_type = self._lib.EVP_PKEY_id(evp_pkey) + + if key_type == self._lib.EVP_PKEY_RSA: + rsa_cdata = self._lib.EVP_PKEY_get1_RSA(evp_pkey) + self.openssl_assert(rsa_cdata != self._ffi.NULL) + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + return _RSAPrivateKey(self, rsa_cdata, evp_pkey) + elif key_type == self._lib.EVP_PKEY_DSA: + dsa_cdata = self._lib.EVP_PKEY_get1_DSA(evp_pkey) + self.openssl_assert(dsa_cdata != self._ffi.NULL) + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + return _DSAPrivateKey(self, dsa_cdata, evp_pkey) + elif key_type == self._lib.EVP_PKEY_EC: + ec_cdata = self._lib.EVP_PKEY_get1_EC_KEY(evp_pkey) + self.openssl_assert(ec_cdata != self._ffi.NULL) + ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) + return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey) + elif key_type in self._dh_types: + dh_cdata = self._lib.EVP_PKEY_get1_DH(evp_pkey) + self.openssl_assert(dh_cdata != self._ffi.NULL) + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + return _DHPrivateKey(self, dh_cdata, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_ED25519", None): + # EVP_PKEY_ED25519 is not present in OpenSSL < 1.1.1 + return _Ed25519PrivateKey(self, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_X448", None): + # EVP_PKEY_X448 is not present in OpenSSL < 1.1.1 + return _X448PrivateKey(self, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_X25519", None): + # EVP_PKEY_X25519 is not present in OpenSSL < 1.1.0 + return _X25519PrivateKey(self, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_ED448", None): + # EVP_PKEY_ED448 is not present in OpenSSL < 1.1.1 + return _Ed448PrivateKey(self, evp_pkey) + else: + raise UnsupportedAlgorithm("Unsupported key type.") + + def _evp_pkey_to_public_key(self, evp_pkey): + """ + Return the appropriate type of PublicKey given an evp_pkey cdata + pointer. + """ + + key_type = self._lib.EVP_PKEY_id(evp_pkey) + + if key_type == self._lib.EVP_PKEY_RSA: + rsa_cdata = self._lib.EVP_PKEY_get1_RSA(evp_pkey) + self.openssl_assert(rsa_cdata != self._ffi.NULL) + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + return _RSAPublicKey(self, rsa_cdata, evp_pkey) + elif key_type == self._lib.EVP_PKEY_DSA: + dsa_cdata = self._lib.EVP_PKEY_get1_DSA(evp_pkey) + self.openssl_assert(dsa_cdata != self._ffi.NULL) + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + return _DSAPublicKey(self, dsa_cdata, evp_pkey) + elif key_type == self._lib.EVP_PKEY_EC: + ec_cdata = self._lib.EVP_PKEY_get1_EC_KEY(evp_pkey) + self.openssl_assert(ec_cdata != self._ffi.NULL) + ec_cdata = self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) + return _EllipticCurvePublicKey(self, ec_cdata, evp_pkey) + elif key_type in self._dh_types: + dh_cdata = self._lib.EVP_PKEY_get1_DH(evp_pkey) + self.openssl_assert(dh_cdata != self._ffi.NULL) + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + return _DHPublicKey(self, dh_cdata, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_ED25519", None): + # EVP_PKEY_ED25519 is not present in OpenSSL < 1.1.1 + return _Ed25519PublicKey(self, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_X448", None): + # EVP_PKEY_X448 is not present in OpenSSL < 1.1.1 + return _X448PublicKey(self, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_X25519", None): + # EVP_PKEY_X25519 is not present in OpenSSL < 1.1.0 + return _X25519PublicKey(self, evp_pkey) + elif key_type == getattr(self._lib, "EVP_PKEY_ED448", None): + # EVP_PKEY_X25519 is not present in OpenSSL < 1.1.1 + return _Ed448PublicKey(self, evp_pkey) + else: + raise UnsupportedAlgorithm("Unsupported key type.") + + def _oaep_hash_supported(self, algorithm): + if self._lib.Cryptography_HAS_RSA_OAEP_MD: + return isinstance( + algorithm, + ( + hashes.SHA1, + hashes.SHA224, + hashes.SHA256, + hashes.SHA384, + hashes.SHA512, + ), + ) + else: + return isinstance(algorithm, hashes.SHA1) + + def rsa_padding_supported(self, padding): + if isinstance(padding, PKCS1v15): + return True + elif isinstance(padding, PSS) and isinstance(padding._mgf, MGF1): + return self.hash_supported(padding._mgf._algorithm) + elif isinstance(padding, OAEP) and isinstance(padding._mgf, MGF1): + return ( + self._oaep_hash_supported(padding._mgf._algorithm) + and self._oaep_hash_supported(padding._algorithm) + and ( + (padding._label is None or len(padding._label) == 0) + or self._lib.Cryptography_HAS_RSA_OAEP_LABEL == 1 + ) + ) + else: + return False + + def generate_dsa_parameters(self, key_size): + if key_size not in (1024, 2048, 3072, 4096): + raise ValueError( + "Key size must be 1024, 2048, 3072, or 4096 bits." + ) + + ctx = self._lib.DSA_new() + self.openssl_assert(ctx != self._ffi.NULL) + ctx = self._ffi.gc(ctx, self._lib.DSA_free) + + res = self._lib.DSA_generate_parameters_ex( + ctx, + key_size, + self._ffi.NULL, + 0, + self._ffi.NULL, + self._ffi.NULL, + self._ffi.NULL, + ) + + self.openssl_assert(res == 1) + + return _DSAParameters(self, ctx) + + def generate_dsa_private_key(self, parameters): + ctx = self._lib.DSAparams_dup(parameters._dsa_cdata) + self.openssl_assert(ctx != self._ffi.NULL) + ctx = self._ffi.gc(ctx, self._lib.DSA_free) + self._lib.DSA_generate_key(ctx) + evp_pkey = self._dsa_cdata_to_evp_pkey(ctx) + + return _DSAPrivateKey(self, ctx, evp_pkey) + + def generate_dsa_private_key_and_parameters(self, key_size): + parameters = self.generate_dsa_parameters(key_size) + return self.generate_dsa_private_key(parameters) + + def _dsa_cdata_set_values(self, dsa_cdata, p, q, g, pub_key, priv_key): + res = self._lib.DSA_set0_pqg(dsa_cdata, p, q, g) + self.openssl_assert(res == 1) + res = self._lib.DSA_set0_key(dsa_cdata, pub_key, priv_key) + self.openssl_assert(res == 1) + + def load_dsa_private_numbers(self, numbers): + dsa._check_dsa_private_numbers(numbers) + parameter_numbers = numbers.public_numbers.parameter_numbers + + dsa_cdata = self._lib.DSA_new() + self.openssl_assert(dsa_cdata != self._ffi.NULL) + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + + p = self._int_to_bn(parameter_numbers.p) + q = self._int_to_bn(parameter_numbers.q) + g = self._int_to_bn(parameter_numbers.g) + pub_key = self._int_to_bn(numbers.public_numbers.y) + priv_key = self._int_to_bn(numbers.x) + self._dsa_cdata_set_values(dsa_cdata, p, q, g, pub_key, priv_key) + + evp_pkey = self._dsa_cdata_to_evp_pkey(dsa_cdata) + + return _DSAPrivateKey(self, dsa_cdata, evp_pkey) + + def load_dsa_public_numbers(self, numbers): + dsa._check_dsa_parameters(numbers.parameter_numbers) + dsa_cdata = self._lib.DSA_new() + self.openssl_assert(dsa_cdata != self._ffi.NULL) + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + + p = self._int_to_bn(numbers.parameter_numbers.p) + q = self._int_to_bn(numbers.parameter_numbers.q) + g = self._int_to_bn(numbers.parameter_numbers.g) + pub_key = self._int_to_bn(numbers.y) + priv_key = self._ffi.NULL + self._dsa_cdata_set_values(dsa_cdata, p, q, g, pub_key, priv_key) + + evp_pkey = self._dsa_cdata_to_evp_pkey(dsa_cdata) + + return _DSAPublicKey(self, dsa_cdata, evp_pkey) + + def load_dsa_parameter_numbers(self, numbers): + dsa._check_dsa_parameters(numbers) + dsa_cdata = self._lib.DSA_new() + self.openssl_assert(dsa_cdata != self._ffi.NULL) + dsa_cdata = self._ffi.gc(dsa_cdata, self._lib.DSA_free) + + p = self._int_to_bn(numbers.p) + q = self._int_to_bn(numbers.q) + g = self._int_to_bn(numbers.g) + res = self._lib.DSA_set0_pqg(dsa_cdata, p, q, g) + self.openssl_assert(res == 1) + + return _DSAParameters(self, dsa_cdata) + + def _dsa_cdata_to_evp_pkey(self, dsa_cdata): + evp_pkey = self._create_evp_pkey_gc() + res = self._lib.EVP_PKEY_set1_DSA(evp_pkey, dsa_cdata) + self.openssl_assert(res == 1) + return evp_pkey + + def dsa_hash_supported(self, algorithm): + return self.hash_supported(algorithm) + + def dsa_parameters_supported(self, p, q, g): + return True + + def cmac_algorithm_supported(self, algorithm): + return self.cipher_supported( + algorithm, CBC(b"\x00" * algorithm.block_size) + ) + + def create_cmac_ctx(self, algorithm): + return _CMACContext(self, algorithm) + + def _x509_check_signature_params(self, private_key, algorithm): + if isinstance( + private_key, (ed25519.Ed25519PrivateKey, ed448.Ed448PrivateKey) + ): + if algorithm is not None: + raise ValueError( + "algorithm must be None when signing via ed25519 or ed448" + ) + elif not isinstance( + private_key, + (rsa.RSAPrivateKey, dsa.DSAPrivateKey, ec.EllipticCurvePrivateKey), + ): + raise TypeError( + "Key must be an rsa, dsa, ec, ed25519, or ed448 private key." + ) + elif not isinstance(algorithm, hashes.HashAlgorithm): + raise TypeError("Algorithm must be a registered hash algorithm.") + elif isinstance(algorithm, hashes.MD5) and not isinstance( + private_key, rsa.RSAPrivateKey + ): + raise ValueError( + "MD5 hash algorithm is only supported with RSA keys" + ) + + def create_x509_csr(self, builder, private_key, algorithm): + if not isinstance(builder, x509.CertificateSigningRequestBuilder): + raise TypeError("Builder type mismatch.") + self._x509_check_signature_params(private_key, algorithm) + + # Resolve the signature algorithm. + evp_md = self._evp_md_x509_null_if_eddsa(private_key, algorithm) + + # Create an empty request. + x509_req = self._lib.X509_REQ_new() + self.openssl_assert(x509_req != self._ffi.NULL) + x509_req = self._ffi.gc(x509_req, self._lib.X509_REQ_free) + + # Set x509 version. + res = self._lib.X509_REQ_set_version(x509_req, x509.Version.v1.value) + self.openssl_assert(res == 1) + + # Set subject name. + res = self._lib.X509_REQ_set_subject_name( + x509_req, _encode_name_gc(self, builder._subject_name) + ) + self.openssl_assert(res == 1) + + # Set subject public key. + public_key = private_key.public_key() + res = self._lib.X509_REQ_set_pubkey(x509_req, public_key._evp_pkey) + self.openssl_assert(res == 1) + + # Add extensions. + sk_extension = self._lib.sk_X509_EXTENSION_new_null() + self.openssl_assert(sk_extension != self._ffi.NULL) + sk_extension = self._ffi.gc( + sk_extension, + lambda x: self._lib.sk_X509_EXTENSION_pop_free( + x, + self._ffi.addressof( + self._lib._original_lib, "X509_EXTENSION_free" + ), + ), + ) + # Don't GC individual extensions because the memory is owned by + # sk_extensions and will be freed along with it. + self._create_x509_extensions( + extensions=builder._extensions, + handlers=self._extension_encode_handlers, + x509_obj=sk_extension, + add_func=self._lib.sk_X509_EXTENSION_insert, + gc=False, + ) + res = self._lib.X509_REQ_add_extensions(x509_req, sk_extension) + self.openssl_assert(res == 1) + + # Add attributes (all bytes encoded as ASN1 UTF8_STRING) + for attr_oid, attr_val in builder._attributes: + obj = _txt2obj_gc(self, attr_oid.dotted_string) + res = self._lib.X509_REQ_add1_attr_by_OBJ( + x509_req, + obj, + x509.name._ASN1Type.UTF8String.value, + attr_val, + len(attr_val), + ) + self.openssl_assert(res == 1) + + # Sign the request using the requester's private key. + res = self._lib.X509_REQ_sign(x509_req, private_key._evp_pkey, evp_md) + if res == 0: + errors = self._consume_errors_with_text() + raise ValueError("Signing failed", errors) + + return _CertificateSigningRequest(self, x509_req) + + def create_x509_certificate(self, builder, private_key, algorithm): + if not isinstance(builder, x509.CertificateBuilder): + raise TypeError("Builder type mismatch.") + self._x509_check_signature_params(private_key, algorithm) + + # Resolve the signature algorithm. + evp_md = self._evp_md_x509_null_if_eddsa(private_key, algorithm) + + # Create an empty certificate. + x509_cert = self._lib.X509_new() + x509_cert = self._ffi.gc(x509_cert, self._lib.X509_free) + + # Set the x509 version. + res = self._lib.X509_set_version(x509_cert, builder._version.value) + self.openssl_assert(res == 1) + + # Set the subject's name. + res = self._lib.X509_set_subject_name( + x509_cert, _encode_name_gc(self, builder._subject_name) + ) + self.openssl_assert(res == 1) + + # Set the subject's public key. + res = self._lib.X509_set_pubkey( + x509_cert, builder._public_key._evp_pkey + ) + self.openssl_assert(res == 1) + + # Set the certificate serial number. + serial_number = _encode_asn1_int_gc(self, builder._serial_number) + res = self._lib.X509_set_serialNumber(x509_cert, serial_number) + self.openssl_assert(res == 1) + + # Set the "not before" time. + self._set_asn1_time( + self._lib.X509_getm_notBefore(x509_cert), builder._not_valid_before + ) + + # Set the "not after" time. + self._set_asn1_time( + self._lib.X509_getm_notAfter(x509_cert), builder._not_valid_after + ) + + # Add extensions. + self._create_x509_extensions( + extensions=builder._extensions, + handlers=self._extension_encode_handlers, + x509_obj=x509_cert, + add_func=self._lib.X509_add_ext, + gc=True, + ) + + # Set the issuer name. + res = self._lib.X509_set_issuer_name( + x509_cert, _encode_name_gc(self, builder._issuer_name) + ) + self.openssl_assert(res == 1) + + # Sign the certificate with the issuer's private key. + res = self._lib.X509_sign(x509_cert, private_key._evp_pkey, evp_md) + if res == 0: + errors = self._consume_errors_with_text() + raise ValueError("Signing failed", errors) + + return _Certificate(self, x509_cert) + + def _evp_md_x509_null_if_eddsa(self, private_key, algorithm): + if isinstance( + private_key, (ed25519.Ed25519PrivateKey, ed448.Ed448PrivateKey) + ): + # OpenSSL requires us to pass NULL for EVP_MD for ed25519/ed448 + return self._ffi.NULL + else: + return self._evp_md_non_null_from_algorithm(algorithm) + + def _set_asn1_time(self, asn1_time, time): + if time.year >= 2050: + asn1_str = time.strftime("%Y%m%d%H%M%SZ").encode("ascii") + else: + asn1_str = time.strftime("%y%m%d%H%M%SZ").encode("ascii") + res = self._lib.ASN1_TIME_set_string(asn1_time, asn1_str) + self.openssl_assert(res == 1) + + def _create_asn1_time(self, time): + asn1_time = self._lib.ASN1_TIME_new() + self.openssl_assert(asn1_time != self._ffi.NULL) + asn1_time = self._ffi.gc(asn1_time, self._lib.ASN1_TIME_free) + self._set_asn1_time(asn1_time, time) + return asn1_time + + def create_x509_crl(self, builder, private_key, algorithm): + if not isinstance(builder, x509.CertificateRevocationListBuilder): + raise TypeError("Builder type mismatch.") + self._x509_check_signature_params(private_key, algorithm) + + evp_md = self._evp_md_x509_null_if_eddsa(private_key, algorithm) + + # Create an empty CRL. + x509_crl = self._lib.X509_CRL_new() + x509_crl = self._ffi.gc(x509_crl, self._lib.X509_CRL_free) + + # Set the x509 CRL version. We only support v2 (integer value 1). + res = self._lib.X509_CRL_set_version(x509_crl, 1) + self.openssl_assert(res == 1) + + # Set the issuer name. + res = self._lib.X509_CRL_set_issuer_name( + x509_crl, _encode_name_gc(self, builder._issuer_name) + ) + self.openssl_assert(res == 1) + + # Set the last update time. + last_update = self._create_asn1_time(builder._last_update) + res = self._lib.X509_CRL_set_lastUpdate(x509_crl, last_update) + self.openssl_assert(res == 1) + + # Set the next update time. + next_update = self._create_asn1_time(builder._next_update) + res = self._lib.X509_CRL_set_nextUpdate(x509_crl, next_update) + self.openssl_assert(res == 1) + + # Add extensions. + self._create_x509_extensions( + extensions=builder._extensions, + handlers=self._crl_extension_encode_handlers, + x509_obj=x509_crl, + add_func=self._lib.X509_CRL_add_ext, + gc=True, + ) + + # add revoked certificates + for revoked_cert in builder._revoked_certificates: + # Duplicating because the X509_CRL takes ownership and will free + # this memory when X509_CRL_free is called. + revoked = self._lib.X509_REVOKED_dup(revoked_cert._x509_revoked) + self.openssl_assert(revoked != self._ffi.NULL) + res = self._lib.X509_CRL_add0_revoked(x509_crl, revoked) + self.openssl_assert(res == 1) + + res = self._lib.X509_CRL_sign(x509_crl, private_key._evp_pkey, evp_md) + if res == 0: + errors = self._consume_errors_with_text() + raise ValueError("Signing failed", errors) + + return _CertificateRevocationList(self, x509_crl) + + def _create_x509_extensions( + self, extensions, handlers, x509_obj, add_func, gc + ): + for i, extension in enumerate(extensions): + x509_extension = self._create_x509_extension(handlers, extension) + self.openssl_assert(x509_extension != self._ffi.NULL) + + if gc: + x509_extension = self._ffi.gc( + x509_extension, self._lib.X509_EXTENSION_free + ) + res = add_func(x509_obj, x509_extension, i) + self.openssl_assert(res >= 1) + + def _create_raw_x509_extension(self, extension, value): + obj = _txt2obj_gc(self, extension.oid.dotted_string) + return self._lib.X509_EXTENSION_create_by_OBJ( + self._ffi.NULL, obj, 1 if extension.critical else 0, value + ) + + def _create_x509_extension(self, handlers, extension): + if isinstance(extension.value, x509.UnrecognizedExtension): + value = _encode_asn1_str_gc(self, extension.value.value) + return self._create_raw_x509_extension(extension, value) + elif isinstance(extension.value, x509.TLSFeature): + asn1 = encode_der( + SEQUENCE, + *[ + encode_der(INTEGER, encode_der_integer(x.value)) + for x in extension.value + ] + ) + value = _encode_asn1_str_gc(self, asn1) + return self._create_raw_x509_extension(extension, value) + elif isinstance(extension.value, x509.PrecertPoison): + value = _encode_asn1_str_gc(self, encode_der(NULL)) + return self._create_raw_x509_extension(extension, value) + else: + try: + encode = handlers[extension.oid] + except KeyError: + raise NotImplementedError( + "Extension not supported: {}".format(extension.oid) + ) + + ext_struct = encode(self, extension.value) + nid = self._lib.OBJ_txt2nid( + extension.oid.dotted_string.encode("ascii") + ) + self.openssl_assert(nid != self._lib.NID_undef) + return self._lib.X509V3_EXT_i2d( + nid, 1 if extension.critical else 0, ext_struct + ) + + def create_x509_revoked_certificate(self, builder): + if not isinstance(builder, x509.RevokedCertificateBuilder): + raise TypeError("Builder type mismatch.") + + x509_revoked = self._lib.X509_REVOKED_new() + self.openssl_assert(x509_revoked != self._ffi.NULL) + x509_revoked = self._ffi.gc(x509_revoked, self._lib.X509_REVOKED_free) + serial_number = _encode_asn1_int_gc(self, builder._serial_number) + res = self._lib.X509_REVOKED_set_serialNumber( + x509_revoked, serial_number + ) + self.openssl_assert(res == 1) + rev_date = self._create_asn1_time(builder._revocation_date) + res = self._lib.X509_REVOKED_set_revocationDate(x509_revoked, rev_date) + self.openssl_assert(res == 1) + # add CRL entry extensions + self._create_x509_extensions( + extensions=builder._extensions, + handlers=self._crl_entry_extension_encode_handlers, + x509_obj=x509_revoked, + add_func=self._lib.X509_REVOKED_add_ext, + gc=True, + ) + return _RevokedCertificate(self, None, x509_revoked) + + def load_pem_private_key(self, data, password): + return self._load_key( + self._lib.PEM_read_bio_PrivateKey, + self._evp_pkey_to_private_key, + data, + password, + ) + + def load_pem_public_key(self, data): + mem_bio = self._bytes_to_bio(data) + evp_pkey = self._lib.PEM_read_bio_PUBKEY( + mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL + ) + if evp_pkey != self._ffi.NULL: + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + return self._evp_pkey_to_public_key(evp_pkey) + else: + # It's not a (RSA/DSA/ECDSA) subjectPublicKeyInfo, but we still + # need to check to see if it is a pure PKCS1 RSA public key (not + # embedded in a subjectPublicKeyInfo) + self._consume_errors() + res = self._lib.BIO_reset(mem_bio.bio) + self.openssl_assert(res == 1) + rsa_cdata = self._lib.PEM_read_bio_RSAPublicKey( + mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL + ) + if rsa_cdata != self._ffi.NULL: + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata) + return _RSAPublicKey(self, rsa_cdata, evp_pkey) + else: + self._handle_key_loading_error() + + def load_pem_parameters(self, data): + mem_bio = self._bytes_to_bio(data) + # only DH is supported currently + dh_cdata = self._lib.PEM_read_bio_DHparams( + mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL + ) + if dh_cdata != self._ffi.NULL: + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + return _DHParameters(self, dh_cdata) + else: + self._handle_key_loading_error() + + def load_der_private_key(self, data, password): + # OpenSSL has a function called d2i_AutoPrivateKey that in theory + # handles this automatically, however it doesn't handle encrypted + # private keys. Instead we try to load the key two different ways. + # First we'll try to load it as a traditional key. + bio_data = self._bytes_to_bio(data) + key = self._evp_pkey_from_der_traditional_key(bio_data, password) + if key: + return self._evp_pkey_to_private_key(key) + else: + # Finally we try to load it with the method that handles encrypted + # PKCS8 properly. + return self._load_key( + self._lib.d2i_PKCS8PrivateKey_bio, + self._evp_pkey_to_private_key, + data, + password, + ) + + def _evp_pkey_from_der_traditional_key(self, bio_data, password): + key = self._lib.d2i_PrivateKey_bio(bio_data.bio, self._ffi.NULL) + if key != self._ffi.NULL: + key = self._ffi.gc(key, self._lib.EVP_PKEY_free) + if password is not None: + raise TypeError( + "Password was given but private key is not encrypted." + ) + + return key + else: + self._consume_errors() + return None + + def load_der_public_key(self, data): + mem_bio = self._bytes_to_bio(data) + evp_pkey = self._lib.d2i_PUBKEY_bio(mem_bio.bio, self._ffi.NULL) + if evp_pkey != self._ffi.NULL: + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + return self._evp_pkey_to_public_key(evp_pkey) + else: + # It's not a (RSA/DSA/ECDSA) subjectPublicKeyInfo, but we still + # need to check to see if it is a pure PKCS1 RSA public key (not + # embedded in a subjectPublicKeyInfo) + self._consume_errors() + res = self._lib.BIO_reset(mem_bio.bio) + self.openssl_assert(res == 1) + rsa_cdata = self._lib.d2i_RSAPublicKey_bio( + mem_bio.bio, self._ffi.NULL + ) + if rsa_cdata != self._ffi.NULL: + rsa_cdata = self._ffi.gc(rsa_cdata, self._lib.RSA_free) + evp_pkey = self._rsa_cdata_to_evp_pkey(rsa_cdata) + return _RSAPublicKey(self, rsa_cdata, evp_pkey) + else: + self._handle_key_loading_error() + + def load_der_parameters(self, data): + mem_bio = self._bytes_to_bio(data) + dh_cdata = self._lib.d2i_DHparams_bio(mem_bio.bio, self._ffi.NULL) + if dh_cdata != self._ffi.NULL: + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + return _DHParameters(self, dh_cdata) + elif self._lib.Cryptography_HAS_EVP_PKEY_DHX: + # We check to see if the is dhx. + self._consume_errors() + res = self._lib.BIO_reset(mem_bio.bio) + self.openssl_assert(res == 1) + dh_cdata = self._lib.Cryptography_d2i_DHxparams_bio( + mem_bio.bio, self._ffi.NULL + ) + if dh_cdata != self._ffi.NULL: + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + return _DHParameters(self, dh_cdata) + + self._handle_key_loading_error() + + def load_pem_x509_certificate(self, data): + mem_bio = self._bytes_to_bio(data) + x509 = self._lib.PEM_read_bio_X509( + mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL + ) + if x509 == self._ffi.NULL: + self._consume_errors() + raise ValueError( + "Unable to load certificate. See https://cryptography.io/en/la" + "test/faq/#why-can-t-i-import-my-pem-file for more details." + ) + + x509 = self._ffi.gc(x509, self._lib.X509_free) + return _Certificate(self, x509) + + def load_der_x509_certificate(self, data): + mem_bio = self._bytes_to_bio(data) + x509 = self._lib.d2i_X509_bio(mem_bio.bio, self._ffi.NULL) + if x509 == self._ffi.NULL: + self._consume_errors() + raise ValueError("Unable to load certificate") + + x509 = self._ffi.gc(x509, self._lib.X509_free) + return _Certificate(self, x509) + + def load_pem_x509_crl(self, data): + mem_bio = self._bytes_to_bio(data) + x509_crl = self._lib.PEM_read_bio_X509_CRL( + mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL + ) + if x509_crl == self._ffi.NULL: + self._consume_errors() + raise ValueError( + "Unable to load CRL. See https://cryptography.io/en/la" + "test/faq/#why-can-t-i-import-my-pem-file for more details." + ) + + x509_crl = self._ffi.gc(x509_crl, self._lib.X509_CRL_free) + return _CertificateRevocationList(self, x509_crl) + + def load_der_x509_crl(self, data): + mem_bio = self._bytes_to_bio(data) + x509_crl = self._lib.d2i_X509_CRL_bio(mem_bio.bio, self._ffi.NULL) + if x509_crl == self._ffi.NULL: + self._consume_errors() + raise ValueError("Unable to load CRL") + + x509_crl = self._ffi.gc(x509_crl, self._lib.X509_CRL_free) + return _CertificateRevocationList(self, x509_crl) + + def load_pem_x509_csr(self, data): + mem_bio = self._bytes_to_bio(data) + x509_req = self._lib.PEM_read_bio_X509_REQ( + mem_bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL + ) + if x509_req == self._ffi.NULL: + self._consume_errors() + raise ValueError( + "Unable to load request. See https://cryptography.io/en/la" + "test/faq/#why-can-t-i-import-my-pem-file for more details." + ) + + x509_req = self._ffi.gc(x509_req, self._lib.X509_REQ_free) + return _CertificateSigningRequest(self, x509_req) + + def load_der_x509_csr(self, data): + mem_bio = self._bytes_to_bio(data) + x509_req = self._lib.d2i_X509_REQ_bio(mem_bio.bio, self._ffi.NULL) + if x509_req == self._ffi.NULL: + self._consume_errors() + raise ValueError("Unable to load request") + + x509_req = self._ffi.gc(x509_req, self._lib.X509_REQ_free) + return _CertificateSigningRequest(self, x509_req) + + def _load_key(self, openssl_read_func, convert_func, data, password): + mem_bio = self._bytes_to_bio(data) + + userdata = self._ffi.new("CRYPTOGRAPHY_PASSWORD_DATA *") + if password is not None: + utils._check_byteslike("password", password) + password_ptr = self._ffi.from_buffer(password) + userdata.password = password_ptr + userdata.length = len(password) + + evp_pkey = openssl_read_func( + mem_bio.bio, + self._ffi.NULL, + self._ffi.addressof( + self._lib._original_lib, "Cryptography_pem_password_cb" + ), + userdata, + ) + + if evp_pkey == self._ffi.NULL: + if userdata.error != 0: + errors = self._consume_errors() + self.openssl_assert(errors) + if userdata.error == -1: + raise TypeError( + "Password was not given but private key is encrypted" + ) + else: + assert userdata.error == -2 + raise ValueError( + "Passwords longer than {} bytes are not supported " + "by this backend.".format(userdata.maxsize - 1) + ) + else: + self._handle_key_loading_error() + + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + + if password is not None and userdata.called == 0: + raise TypeError( + "Password was given but private key is not encrypted." + ) + + assert ( + password is not None and userdata.called == 1 + ) or password is None + + return convert_func(evp_pkey) + + def _handle_key_loading_error(self): + errors = self._consume_errors() + + if not errors: + raise ValueError("Could not deserialize key data.") + + elif errors[0]._lib_reason_match( + self._lib.ERR_LIB_EVP, self._lib.EVP_R_BAD_DECRYPT + ) or errors[0]._lib_reason_match( + self._lib.ERR_LIB_PKCS12, + self._lib.PKCS12_R_PKCS12_CIPHERFINAL_ERROR, + ): + raise ValueError("Bad decrypt. Incorrect password?") + + elif errors[0]._lib_reason_match( + self._lib.ERR_LIB_EVP, self._lib.EVP_R_UNKNOWN_PBE_ALGORITHM + ) or errors[0]._lib_reason_match( + self._lib.ERR_LIB_PEM, self._lib.PEM_R_UNSUPPORTED_ENCRYPTION + ): + raise UnsupportedAlgorithm( + "PEM data is encrypted with an unsupported cipher", + _Reasons.UNSUPPORTED_CIPHER, + ) + + elif any( + error._lib_reason_match( + self._lib.ERR_LIB_EVP, + self._lib.EVP_R_UNSUPPORTED_PRIVATE_KEY_ALGORITHM, + ) + for error in errors + ): + raise ValueError("Unsupported public key algorithm.") + + else: + assert errors[0].lib in ( + self._lib.ERR_LIB_EVP, + self._lib.ERR_LIB_PEM, + self._lib.ERR_LIB_ASN1, + ) + raise ValueError("Could not deserialize key data.") + + def elliptic_curve_supported(self, curve): + try: + curve_nid = self._elliptic_curve_to_nid(curve) + except UnsupportedAlgorithm: + curve_nid = self._lib.NID_undef + + group = self._lib.EC_GROUP_new_by_curve_name(curve_nid) + + if group == self._ffi.NULL: + self._consume_errors() + return False + else: + self.openssl_assert(curve_nid != self._lib.NID_undef) + self._lib.EC_GROUP_free(group) + return True + + def elliptic_curve_signature_algorithm_supported( + self, signature_algorithm, curve + ): + # We only support ECDSA right now. + if not isinstance(signature_algorithm, ec.ECDSA): + return False + + return self.elliptic_curve_supported(curve) + + def generate_elliptic_curve_private_key(self, curve): + """ + Generate a new private key on the named curve. + """ + + if self.elliptic_curve_supported(curve): + ec_cdata = self._ec_key_new_by_curve(curve) + + res = self._lib.EC_KEY_generate_key(ec_cdata) + self.openssl_assert(res == 1) + + evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata) + + return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey) + else: + raise UnsupportedAlgorithm( + "Backend object does not support {}.".format(curve.name), + _Reasons.UNSUPPORTED_ELLIPTIC_CURVE, + ) + + def load_elliptic_curve_private_numbers(self, numbers): + public = numbers.public_numbers + + ec_cdata = self._ec_key_new_by_curve(public.curve) + + private_value = self._ffi.gc( + self._int_to_bn(numbers.private_value), self._lib.BN_clear_free + ) + res = self._lib.EC_KEY_set_private_key(ec_cdata, private_value) + self.openssl_assert(res == 1) + + ec_cdata = self._ec_key_set_public_key_affine_coordinates( + ec_cdata, public.x, public.y + ) + + evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata) + + return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey) + + def load_elliptic_curve_public_numbers(self, numbers): + ec_cdata = self._ec_key_new_by_curve(numbers.curve) + ec_cdata = self._ec_key_set_public_key_affine_coordinates( + ec_cdata, numbers.x, numbers.y + ) + evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata) + + return _EllipticCurvePublicKey(self, ec_cdata, evp_pkey) + + def load_elliptic_curve_public_bytes(self, curve, point_bytes): + ec_cdata = self._ec_key_new_by_curve(curve) + group = self._lib.EC_KEY_get0_group(ec_cdata) + self.openssl_assert(group != self._ffi.NULL) + point = self._lib.EC_POINT_new(group) + self.openssl_assert(point != self._ffi.NULL) + point = self._ffi.gc(point, self._lib.EC_POINT_free) + with self._tmp_bn_ctx() as bn_ctx: + res = self._lib.EC_POINT_oct2point( + group, point, point_bytes, len(point_bytes), bn_ctx + ) + if res != 1: + self._consume_errors() + raise ValueError("Invalid public bytes for the given curve") + + res = self._lib.EC_KEY_set_public_key(ec_cdata, point) + self.openssl_assert(res == 1) + evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata) + return _EllipticCurvePublicKey(self, ec_cdata, evp_pkey) + + def derive_elliptic_curve_private_key(self, private_value, curve): + ec_cdata = self._ec_key_new_by_curve(curve) + + get_func, group = self._ec_key_determine_group_get_func(ec_cdata) + + point = self._lib.EC_POINT_new(group) + self.openssl_assert(point != self._ffi.NULL) + point = self._ffi.gc(point, self._lib.EC_POINT_free) + + value = self._int_to_bn(private_value) + value = self._ffi.gc(value, self._lib.BN_clear_free) + + with self._tmp_bn_ctx() as bn_ctx: + res = self._lib.EC_POINT_mul( + group, point, value, self._ffi.NULL, self._ffi.NULL, bn_ctx + ) + self.openssl_assert(res == 1) + + bn_x = self._lib.BN_CTX_get(bn_ctx) + bn_y = self._lib.BN_CTX_get(bn_ctx) + + res = get_func(group, point, bn_x, bn_y, bn_ctx) + self.openssl_assert(res == 1) + + res = self._lib.EC_KEY_set_public_key(ec_cdata, point) + self.openssl_assert(res == 1) + private = self._int_to_bn(private_value) + private = self._ffi.gc(private, self._lib.BN_clear_free) + res = self._lib.EC_KEY_set_private_key(ec_cdata, private) + self.openssl_assert(res == 1) + + evp_pkey = self._ec_cdata_to_evp_pkey(ec_cdata) + + return _EllipticCurvePrivateKey(self, ec_cdata, evp_pkey) + + def _ec_key_new_by_curve(self, curve): + curve_nid = self._elliptic_curve_to_nid(curve) + return self._ec_key_new_by_curve_nid(curve_nid) + + def _ec_key_new_by_curve_nid(self, curve_nid): + ec_cdata = self._lib.EC_KEY_new_by_curve_name(curve_nid) + self.openssl_assert(ec_cdata != self._ffi.NULL) + # Setting the ASN.1 flag to OPENSSL_EC_NAMED_CURVE is + # only necessary on OpenSSL 1.0.2t/u. Once we drop support for 1.0.2 + # we can remove this as it's done automatically when getting an EC_KEY + # from new_by_curve_name + # CRYPTOGRAPHY_OPENSSL_102U_OR_GREATER + self._lib.EC_KEY_set_asn1_flag( + ec_cdata, backend._lib.OPENSSL_EC_NAMED_CURVE + ) + return self._ffi.gc(ec_cdata, self._lib.EC_KEY_free) + + def load_der_ocsp_request(self, data): + mem_bio = self._bytes_to_bio(data) + request = self._lib.d2i_OCSP_REQUEST_bio(mem_bio.bio, self._ffi.NULL) + if request == self._ffi.NULL: + self._consume_errors() + raise ValueError("Unable to load OCSP request") + + request = self._ffi.gc(request, self._lib.OCSP_REQUEST_free) + return _OCSPRequest(self, request) + + def load_der_ocsp_response(self, data): + mem_bio = self._bytes_to_bio(data) + response = self._lib.d2i_OCSP_RESPONSE_bio(mem_bio.bio, self._ffi.NULL) + if response == self._ffi.NULL: + self._consume_errors() + raise ValueError("Unable to load OCSP response") + + response = self._ffi.gc(response, self._lib.OCSP_RESPONSE_free) + return _OCSPResponse(self, response) + + def create_ocsp_request(self, builder): + ocsp_req = self._lib.OCSP_REQUEST_new() + self.openssl_assert(ocsp_req != self._ffi.NULL) + ocsp_req = self._ffi.gc(ocsp_req, self._lib.OCSP_REQUEST_free) + cert, issuer, algorithm = builder._request + evp_md = self._evp_md_non_null_from_algorithm(algorithm) + certid = self._lib.OCSP_cert_to_id(evp_md, cert._x509, issuer._x509) + self.openssl_assert(certid != self._ffi.NULL) + onereq = self._lib.OCSP_request_add0_id(ocsp_req, certid) + self.openssl_assert(onereq != self._ffi.NULL) + self._create_x509_extensions( + extensions=builder._extensions, + handlers=self._ocsp_request_extension_encode_handlers, + x509_obj=ocsp_req, + add_func=self._lib.OCSP_REQUEST_add_ext, + gc=True, + ) + return _OCSPRequest(self, ocsp_req) + + def _create_ocsp_basic_response(self, builder, private_key, algorithm): + self._x509_check_signature_params(private_key, algorithm) + + basic = self._lib.OCSP_BASICRESP_new() + self.openssl_assert(basic != self._ffi.NULL) + basic = self._ffi.gc(basic, self._lib.OCSP_BASICRESP_free) + evp_md = self._evp_md_non_null_from_algorithm( + builder._response._algorithm + ) + certid = self._lib.OCSP_cert_to_id( + evp_md, + builder._response._cert._x509, + builder._response._issuer._x509, + ) + self.openssl_assert(certid != self._ffi.NULL) + certid = self._ffi.gc(certid, self._lib.OCSP_CERTID_free) + if builder._response._revocation_reason is None: + reason = -1 + else: + reason = _CRL_ENTRY_REASON_ENUM_TO_CODE[ + builder._response._revocation_reason + ] + if builder._response._revocation_time is None: + rev_time = self._ffi.NULL + else: + rev_time = self._create_asn1_time( + builder._response._revocation_time + ) + + next_update = self._ffi.NULL + if builder._response._next_update is not None: + next_update = self._create_asn1_time( + builder._response._next_update + ) + + this_update = self._create_asn1_time(builder._response._this_update) + + res = self._lib.OCSP_basic_add1_status( + basic, + certid, + builder._response._cert_status.value, + reason, + rev_time, + this_update, + next_update, + ) + self.openssl_assert(res != self._ffi.NULL) + # okay, now sign the basic structure + evp_md = self._evp_md_x509_null_if_eddsa(private_key, algorithm) + responder_cert, responder_encoding = builder._responder_id + flags = self._lib.OCSP_NOCERTS + if responder_encoding is ocsp.OCSPResponderEncoding.HASH: + flags |= self._lib.OCSP_RESPID_KEY + + if builder._certs is not None: + for cert in builder._certs: + res = self._lib.OCSP_basic_add1_cert(basic, cert._x509) + self.openssl_assert(res == 1) + + self._create_x509_extensions( + extensions=builder._extensions, + handlers=self._ocsp_basicresp_extension_encode_handlers, + x509_obj=basic, + add_func=self._lib.OCSP_BASICRESP_add_ext, + gc=True, + ) + + res = self._lib.OCSP_basic_sign( + basic, + responder_cert._x509, + private_key._evp_pkey, + evp_md, + self._ffi.NULL, + flags, + ) + if res != 1: + errors = self._consume_errors_with_text() + raise ValueError( + "Error while signing. responder_cert must be signed " + "by private_key", + errors, + ) + + return basic + + def create_ocsp_response( + self, response_status, builder, private_key, algorithm + ): + if response_status is ocsp.OCSPResponseStatus.SUCCESSFUL: + basic = self._create_ocsp_basic_response( + builder, private_key, algorithm + ) + else: + basic = self._ffi.NULL + + ocsp_resp = self._lib.OCSP_response_create( + response_status.value, basic + ) + self.openssl_assert(ocsp_resp != self._ffi.NULL) + ocsp_resp = self._ffi.gc(ocsp_resp, self._lib.OCSP_RESPONSE_free) + return _OCSPResponse(self, ocsp_resp) + + def elliptic_curve_exchange_algorithm_supported(self, algorithm, curve): + return self.elliptic_curve_supported(curve) and isinstance( + algorithm, ec.ECDH + ) + + def _ec_cdata_to_evp_pkey(self, ec_cdata): + evp_pkey = self._create_evp_pkey_gc() + res = self._lib.EVP_PKEY_set1_EC_KEY(evp_pkey, ec_cdata) + self.openssl_assert(res == 1) + return evp_pkey + + def _elliptic_curve_to_nid(self, curve): + """ + Get the NID for a curve name. + """ + + curve_aliases = {"secp192r1": "prime192v1", "secp256r1": "prime256v1"} + + curve_name = curve_aliases.get(curve.name, curve.name) + + curve_nid = self._lib.OBJ_sn2nid(curve_name.encode()) + if curve_nid == self._lib.NID_undef: + raise UnsupportedAlgorithm( + "{} is not a supported elliptic curve".format(curve.name), + _Reasons.UNSUPPORTED_ELLIPTIC_CURVE, + ) + return curve_nid + + @contextmanager + def _tmp_bn_ctx(self): + bn_ctx = self._lib.BN_CTX_new() + self.openssl_assert(bn_ctx != self._ffi.NULL) + bn_ctx = self._ffi.gc(bn_ctx, self._lib.BN_CTX_free) + self._lib.BN_CTX_start(bn_ctx) + try: + yield bn_ctx + finally: + self._lib.BN_CTX_end(bn_ctx) + + def _ec_key_determine_group_get_func(self, ctx): + """ + Given an EC_KEY determine the group and what function is required to + get point coordinates. + """ + self.openssl_assert(ctx != self._ffi.NULL) + + nid_two_field = self._lib.OBJ_sn2nid(b"characteristic-two-field") + self.openssl_assert(nid_two_field != self._lib.NID_undef) + + group = self._lib.EC_KEY_get0_group(ctx) + self.openssl_assert(group != self._ffi.NULL) + + method = self._lib.EC_GROUP_method_of(group) + self.openssl_assert(method != self._ffi.NULL) + + nid = self._lib.EC_METHOD_get_field_type(method) + self.openssl_assert(nid != self._lib.NID_undef) + + if nid == nid_two_field and self._lib.Cryptography_HAS_EC2M: + get_func = self._lib.EC_POINT_get_affine_coordinates_GF2m + else: + get_func = self._lib.EC_POINT_get_affine_coordinates_GFp + + assert get_func + + return get_func, group + + def _ec_key_set_public_key_affine_coordinates(self, ctx, x, y): + """ + Sets the public key point in the EC_KEY context to the affine x and y + values. + """ + + if x < 0 or y < 0: + raise ValueError( + "Invalid EC key. Both x and y must be non-negative." + ) + + x = self._ffi.gc(self._int_to_bn(x), self._lib.BN_free) + y = self._ffi.gc(self._int_to_bn(y), self._lib.BN_free) + res = self._lib.EC_KEY_set_public_key_affine_coordinates(ctx, x, y) + if res != 1: + self._consume_errors() + raise ValueError("Invalid EC key.") + + return ctx + + def _private_key_bytes( + self, encoding, format, encryption_algorithm, key, evp_pkey, cdata + ): + # validate argument types + if not isinstance(encoding, serialization.Encoding): + raise TypeError("encoding must be an item from the Encoding enum") + if not isinstance(format, serialization.PrivateFormat): + raise TypeError( + "format must be an item from the PrivateFormat enum" + ) + if not isinstance( + encryption_algorithm, serialization.KeySerializationEncryption + ): + raise TypeError( + "Encryption algorithm must be a KeySerializationEncryption " + "instance" + ) + + # validate password + if isinstance(encryption_algorithm, serialization.NoEncryption): + password = b"" + elif isinstance( + encryption_algorithm, serialization.BestAvailableEncryption + ): + password = encryption_algorithm.password + if len(password) > 1023: + raise ValueError( + "Passwords longer than 1023 bytes are not supported by " + "this backend" + ) + else: + raise ValueError("Unsupported encryption type") + + # PKCS8 + PEM/DER + if format is serialization.PrivateFormat.PKCS8: + if encoding is serialization.Encoding.PEM: + write_bio = self._lib.PEM_write_bio_PKCS8PrivateKey + elif encoding is serialization.Encoding.DER: + write_bio = self._lib.i2d_PKCS8PrivateKey_bio + else: + raise ValueError("Unsupported encoding for PKCS8") + return self._private_key_bytes_via_bio( + write_bio, evp_pkey, password + ) + + # TraditionalOpenSSL + PEM/DER + if format is serialization.PrivateFormat.TraditionalOpenSSL: + if self._fips_enabled and not isinstance( + encryption_algorithm, serialization.NoEncryption + ): + raise ValueError( + "Encrypted traditional OpenSSL format is not " + "supported in FIPS mode." + ) + key_type = self._lib.EVP_PKEY_id(evp_pkey) + + if encoding is serialization.Encoding.PEM: + if key_type == self._lib.EVP_PKEY_RSA: + write_bio = self._lib.PEM_write_bio_RSAPrivateKey + elif key_type == self._lib.EVP_PKEY_DSA: + write_bio = self._lib.PEM_write_bio_DSAPrivateKey + elif key_type == self._lib.EVP_PKEY_EC: + write_bio = self._lib.PEM_write_bio_ECPrivateKey + else: + raise ValueError( + "Unsupported key type for TraditionalOpenSSL" + ) + return self._private_key_bytes_via_bio( + write_bio, cdata, password + ) + + if encoding is serialization.Encoding.DER: + if password: + raise ValueError( + "Encryption is not supported for DER encoded " + "traditional OpenSSL keys" + ) + if key_type == self._lib.EVP_PKEY_RSA: + write_bio = self._lib.i2d_RSAPrivateKey_bio + elif key_type == self._lib.EVP_PKEY_EC: + write_bio = self._lib.i2d_ECPrivateKey_bio + elif key_type == self._lib.EVP_PKEY_DSA: + write_bio = self._lib.i2d_DSAPrivateKey_bio + else: + raise ValueError( + "Unsupported key type for TraditionalOpenSSL" + ) + return self._bio_func_output(write_bio, cdata) + + raise ValueError("Unsupported encoding for TraditionalOpenSSL") + + # OpenSSH + PEM + if format is serialization.PrivateFormat.OpenSSH: + if encoding is serialization.Encoding.PEM: + return ssh.serialize_ssh_private_key(key, password) + + raise ValueError( + "OpenSSH private key format can only be used" + " with PEM encoding" + ) + + # Anything that key-specific code was supposed to handle earlier, + # like Raw. + raise ValueError("format is invalid with this key") + + def _private_key_bytes_via_bio(self, write_bio, evp_pkey, password): + if not password: + evp_cipher = self._ffi.NULL + else: + # This is a curated value that we will update over time. + evp_cipher = self._lib.EVP_get_cipherbyname(b"aes-256-cbc") + + return self._bio_func_output( + write_bio, + evp_pkey, + evp_cipher, + password, + len(password), + self._ffi.NULL, + self._ffi.NULL, + ) + + def _bio_func_output(self, write_bio, *args): + bio = self._create_mem_bio_gc() + res = write_bio(bio, *args) + self.openssl_assert(res == 1) + return self._read_mem_bio(bio) + + def _public_key_bytes(self, encoding, format, key, evp_pkey, cdata): + if not isinstance(encoding, serialization.Encoding): + raise TypeError("encoding must be an item from the Encoding enum") + if not isinstance(format, serialization.PublicFormat): + raise TypeError( + "format must be an item from the PublicFormat enum" + ) + + # SubjectPublicKeyInfo + PEM/DER + if format is serialization.PublicFormat.SubjectPublicKeyInfo: + if encoding is serialization.Encoding.PEM: + write_bio = self._lib.PEM_write_bio_PUBKEY + elif encoding is serialization.Encoding.DER: + write_bio = self._lib.i2d_PUBKEY_bio + else: + raise ValueError( + "SubjectPublicKeyInfo works only with PEM or DER encoding" + ) + return self._bio_func_output(write_bio, evp_pkey) + + # PKCS1 + PEM/DER + if format is serialization.PublicFormat.PKCS1: + # Only RSA is supported here. + key_type = self._lib.EVP_PKEY_id(evp_pkey) + if key_type != self._lib.EVP_PKEY_RSA: + raise ValueError("PKCS1 format is supported only for RSA keys") + + if encoding is serialization.Encoding.PEM: + write_bio = self._lib.PEM_write_bio_RSAPublicKey + elif encoding is serialization.Encoding.DER: + write_bio = self._lib.i2d_RSAPublicKey_bio + else: + raise ValueError("PKCS1 works only with PEM or DER encoding") + return self._bio_func_output(write_bio, cdata) + + # OpenSSH + OpenSSH + if format is serialization.PublicFormat.OpenSSH: + if encoding is serialization.Encoding.OpenSSH: + return ssh.serialize_ssh_public_key(key) + + raise ValueError( + "OpenSSH format must be used with OpenSSH encoding" + ) + + # Anything that key-specific code was supposed to handle earlier, + # like Raw, CompressedPoint, UncompressedPoint + raise ValueError("format is invalid with this key") + + def _parameter_bytes(self, encoding, format, cdata): + if encoding is serialization.Encoding.OpenSSH: + raise TypeError("OpenSSH encoding is not supported") + + # Only DH is supported here currently. + q = self._ffi.new("BIGNUM **") + self._lib.DH_get0_pqg(cdata, self._ffi.NULL, q, self._ffi.NULL) + if encoding is serialization.Encoding.PEM: + if q[0] != self._ffi.NULL: + write_bio = self._lib.PEM_write_bio_DHxparams + else: + write_bio = self._lib.PEM_write_bio_DHparams + elif encoding is serialization.Encoding.DER: + if q[0] != self._ffi.NULL: + write_bio = self._lib.Cryptography_i2d_DHxparams_bio + else: + write_bio = self._lib.i2d_DHparams_bio + else: + raise TypeError("encoding must be an item from the Encoding enum") + + bio = self._create_mem_bio_gc() + res = write_bio(bio, cdata) + self.openssl_assert(res == 1) + return self._read_mem_bio(bio) + + def generate_dh_parameters(self, generator, key_size): + if key_size < 512: + raise ValueError("DH key_size must be at least 512 bits") + + if generator not in (2, 5): + raise ValueError("DH generator must be 2 or 5") + + dh_param_cdata = self._lib.DH_new() + self.openssl_assert(dh_param_cdata != self._ffi.NULL) + dh_param_cdata = self._ffi.gc(dh_param_cdata, self._lib.DH_free) + + res = self._lib.DH_generate_parameters_ex( + dh_param_cdata, key_size, generator, self._ffi.NULL + ) + self.openssl_assert(res == 1) + + return _DHParameters(self, dh_param_cdata) + + def _dh_cdata_to_evp_pkey(self, dh_cdata): + evp_pkey = self._create_evp_pkey_gc() + res = self._lib.EVP_PKEY_set1_DH(evp_pkey, dh_cdata) + self.openssl_assert(res == 1) + return evp_pkey + + def generate_dh_private_key(self, parameters): + dh_key_cdata = _dh_params_dup(parameters._dh_cdata, self) + + res = self._lib.DH_generate_key(dh_key_cdata) + self.openssl_assert(res == 1) + + evp_pkey = self._dh_cdata_to_evp_pkey(dh_key_cdata) + + return _DHPrivateKey(self, dh_key_cdata, evp_pkey) + + def generate_dh_private_key_and_parameters(self, generator, key_size): + return self.generate_dh_private_key( + self.generate_dh_parameters(generator, key_size) + ) + + def load_dh_private_numbers(self, numbers): + parameter_numbers = numbers.public_numbers.parameter_numbers + + dh_cdata = self._lib.DH_new() + self.openssl_assert(dh_cdata != self._ffi.NULL) + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + + p = self._int_to_bn(parameter_numbers.p) + g = self._int_to_bn(parameter_numbers.g) + + if parameter_numbers.q is not None: + q = self._int_to_bn(parameter_numbers.q) + else: + q = self._ffi.NULL + + pub_key = self._int_to_bn(numbers.public_numbers.y) + priv_key = self._int_to_bn(numbers.x) + + res = self._lib.DH_set0_pqg(dh_cdata, p, q, g) + self.openssl_assert(res == 1) + + res = self._lib.DH_set0_key(dh_cdata, pub_key, priv_key) + self.openssl_assert(res == 1) + + codes = self._ffi.new("int[]", 1) + res = self._lib.Cryptography_DH_check(dh_cdata, codes) + self.openssl_assert(res == 1) + + # DH_check will return DH_NOT_SUITABLE_GENERATOR if p % 24 does not + # equal 11 when the generator is 2 (a quadratic nonresidue). + # We want to ignore that error because p % 24 == 23 is also fine. + # Specifically, g is then a quadratic residue. Within the context of + # Diffie-Hellman this means it can only generate half the possible + # values. That sounds bad, but quadratic nonresidues leak a bit of + # the key to the attacker in exchange for having the full key space + # available. See: https://crypto.stackexchange.com/questions/12961 + if codes[0] != 0 and not ( + parameter_numbers.g == 2 + and codes[0] ^ self._lib.DH_NOT_SUITABLE_GENERATOR == 0 + ): + raise ValueError("DH private numbers did not pass safety checks.") + + evp_pkey = self._dh_cdata_to_evp_pkey(dh_cdata) + + return _DHPrivateKey(self, dh_cdata, evp_pkey) + + def load_dh_public_numbers(self, numbers): + dh_cdata = self._lib.DH_new() + self.openssl_assert(dh_cdata != self._ffi.NULL) + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + + parameter_numbers = numbers.parameter_numbers + + p = self._int_to_bn(parameter_numbers.p) + g = self._int_to_bn(parameter_numbers.g) + + if parameter_numbers.q is not None: + q = self._int_to_bn(parameter_numbers.q) + else: + q = self._ffi.NULL + + pub_key = self._int_to_bn(numbers.y) + + res = self._lib.DH_set0_pqg(dh_cdata, p, q, g) + self.openssl_assert(res == 1) + + res = self._lib.DH_set0_key(dh_cdata, pub_key, self._ffi.NULL) + self.openssl_assert(res == 1) + + evp_pkey = self._dh_cdata_to_evp_pkey(dh_cdata) + + return _DHPublicKey(self, dh_cdata, evp_pkey) + + def load_dh_parameter_numbers(self, numbers): + dh_cdata = self._lib.DH_new() + self.openssl_assert(dh_cdata != self._ffi.NULL) + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + + p = self._int_to_bn(numbers.p) + g = self._int_to_bn(numbers.g) + + if numbers.q is not None: + q = self._int_to_bn(numbers.q) + else: + q = self._ffi.NULL + + res = self._lib.DH_set0_pqg(dh_cdata, p, q, g) + self.openssl_assert(res == 1) + + return _DHParameters(self, dh_cdata) + + def dh_parameters_supported(self, p, g, q=None): + dh_cdata = self._lib.DH_new() + self.openssl_assert(dh_cdata != self._ffi.NULL) + dh_cdata = self._ffi.gc(dh_cdata, self._lib.DH_free) + + p = self._int_to_bn(p) + g = self._int_to_bn(g) + + if q is not None: + q = self._int_to_bn(q) + else: + q = self._ffi.NULL + + res = self._lib.DH_set0_pqg(dh_cdata, p, q, g) + self.openssl_assert(res == 1) + + codes = self._ffi.new("int[]", 1) + res = self._lib.Cryptography_DH_check(dh_cdata, codes) + self.openssl_assert(res == 1) + + return codes[0] == 0 + + def dh_x942_serialization_supported(self): + return self._lib.Cryptography_HAS_EVP_PKEY_DHX == 1 + + def x509_name_bytes(self, name): + x509_name = _encode_name_gc(self, name) + pp = self._ffi.new("unsigned char **") + res = self._lib.i2d_X509_NAME(x509_name, pp) + self.openssl_assert(pp[0] != self._ffi.NULL) + pp = self._ffi.gc( + pp, lambda pointer: self._lib.OPENSSL_free(pointer[0]) + ) + self.openssl_assert(res > 0) + return self._ffi.buffer(pp[0], res)[:] + + def x25519_load_public_bytes(self, data): + # When we drop support for CRYPTOGRAPHY_OPENSSL_LESS_THAN_111 we can + # switch this to EVP_PKEY_new_raw_public_key + if len(data) != 32: + raise ValueError("An X25519 public key is 32 bytes long") + + evp_pkey = self._create_evp_pkey_gc() + res = self._lib.EVP_PKEY_set_type(evp_pkey, self._lib.NID_X25519) + self.openssl_assert(res == 1) + res = self._lib.EVP_PKEY_set1_tls_encodedpoint( + evp_pkey, data, len(data) + ) + self.openssl_assert(res == 1) + return _X25519PublicKey(self, evp_pkey) + + def x25519_load_private_bytes(self, data): + # When we drop support for CRYPTOGRAPHY_OPENSSL_LESS_THAN_111 we can + # switch this to EVP_PKEY_new_raw_private_key and drop the + # zeroed_bytearray garbage. + # OpenSSL only has facilities for loading PKCS8 formatted private + # keys using the algorithm identifiers specified in + # https://tools.ietf.org/html/draft-ietf-curdle-pkix-09. + # This is the standard PKCS8 prefix for a 32 byte X25519 key. + # The form is: + # 0:d=0 hl=2 l= 46 cons: SEQUENCE + # 2:d=1 hl=2 l= 1 prim: INTEGER :00 + # 5:d=1 hl=2 l= 5 cons: SEQUENCE + # 7:d=2 hl=2 l= 3 prim: OBJECT :1.3.101.110 + # 12:d=1 hl=2 l= 34 prim: OCTET STRING (the key) + # Of course there's a bit more complexity. In reality OCTET STRING + # contains an OCTET STRING of length 32! So the last two bytes here + # are \x04\x20, which is an OCTET STRING of length 32. + if len(data) != 32: + raise ValueError("An X25519 private key is 32 bytes long") + + pkcs8_prefix = b'0.\x02\x01\x000\x05\x06\x03+en\x04"\x04 ' + with self._zeroed_bytearray(48) as ba: + ba[0:16] = pkcs8_prefix + ba[16:] = data + bio = self._bytes_to_bio(ba) + evp_pkey = self._lib.d2i_PrivateKey_bio(bio.bio, self._ffi.NULL) + + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + self.openssl_assert( + self._lib.EVP_PKEY_id(evp_pkey) == self._lib.EVP_PKEY_X25519 + ) + return _X25519PrivateKey(self, evp_pkey) + + def _evp_pkey_keygen_gc(self, nid): + evp_pkey_ctx = self._lib.EVP_PKEY_CTX_new_id(nid, self._ffi.NULL) + self.openssl_assert(evp_pkey_ctx != self._ffi.NULL) + evp_pkey_ctx = self._ffi.gc(evp_pkey_ctx, self._lib.EVP_PKEY_CTX_free) + res = self._lib.EVP_PKEY_keygen_init(evp_pkey_ctx) + self.openssl_assert(res == 1) + evp_ppkey = self._ffi.new("EVP_PKEY **") + res = self._lib.EVP_PKEY_keygen(evp_pkey_ctx, evp_ppkey) + self.openssl_assert(res == 1) + self.openssl_assert(evp_ppkey[0] != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_ppkey[0], self._lib.EVP_PKEY_free) + return evp_pkey + + def x25519_generate_key(self): + evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_X25519) + return _X25519PrivateKey(self, evp_pkey) + + def x25519_supported(self): + if self._fips_enabled: + return False + return self._lib.CRYPTOGRAPHY_OPENSSL_110_OR_GREATER + + def x448_load_public_bytes(self, data): + if len(data) != 56: + raise ValueError("An X448 public key is 56 bytes long") + + evp_pkey = self._lib.EVP_PKEY_new_raw_public_key( + self._lib.NID_X448, self._ffi.NULL, data, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + return _X448PublicKey(self, evp_pkey) + + def x448_load_private_bytes(self, data): + if len(data) != 56: + raise ValueError("An X448 private key is 56 bytes long") + + data_ptr = self._ffi.from_buffer(data) + evp_pkey = self._lib.EVP_PKEY_new_raw_private_key( + self._lib.NID_X448, self._ffi.NULL, data_ptr, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + return _X448PrivateKey(self, evp_pkey) + + def x448_generate_key(self): + evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_X448) + return _X448PrivateKey(self, evp_pkey) + + def x448_supported(self): + if self._fips_enabled: + return False + return not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111 + + def ed25519_supported(self): + if self._fips_enabled: + return False + return not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B + + def ed25519_load_public_bytes(self, data): + utils._check_bytes("data", data) + + if len(data) != ed25519._ED25519_KEY_SIZE: + raise ValueError("An Ed25519 public key is 32 bytes long") + + evp_pkey = self._lib.EVP_PKEY_new_raw_public_key( + self._lib.NID_ED25519, self._ffi.NULL, data, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + + return _Ed25519PublicKey(self, evp_pkey) + + def ed25519_load_private_bytes(self, data): + if len(data) != ed25519._ED25519_KEY_SIZE: + raise ValueError("An Ed25519 private key is 32 bytes long") + + utils._check_byteslike("data", data) + data_ptr = self._ffi.from_buffer(data) + evp_pkey = self._lib.EVP_PKEY_new_raw_private_key( + self._lib.NID_ED25519, self._ffi.NULL, data_ptr, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + + return _Ed25519PrivateKey(self, evp_pkey) + + def ed25519_generate_key(self): + evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_ED25519) + return _Ed25519PrivateKey(self, evp_pkey) + + def ed448_supported(self): + if self._fips_enabled: + return False + return not self._lib.CRYPTOGRAPHY_OPENSSL_LESS_THAN_111B + + def ed448_load_public_bytes(self, data): + utils._check_bytes("data", data) + if len(data) != _ED448_KEY_SIZE: + raise ValueError("An Ed448 public key is 57 bytes long") + + evp_pkey = self._lib.EVP_PKEY_new_raw_public_key( + self._lib.NID_ED448, self._ffi.NULL, data, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + + return _Ed448PublicKey(self, evp_pkey) + + def ed448_load_private_bytes(self, data): + utils._check_byteslike("data", data) + if len(data) != _ED448_KEY_SIZE: + raise ValueError("An Ed448 private key is 57 bytes long") + + data_ptr = self._ffi.from_buffer(data) + evp_pkey = self._lib.EVP_PKEY_new_raw_private_key( + self._lib.NID_ED448, self._ffi.NULL, data_ptr, len(data) + ) + self.openssl_assert(evp_pkey != self._ffi.NULL) + evp_pkey = self._ffi.gc(evp_pkey, self._lib.EVP_PKEY_free) + + return _Ed448PrivateKey(self, evp_pkey) + + def ed448_generate_key(self): + evp_pkey = self._evp_pkey_keygen_gc(self._lib.NID_ED448) + return _Ed448PrivateKey(self, evp_pkey) + + def derive_scrypt(self, key_material, salt, length, n, r, p): + buf = self._ffi.new("unsigned char[]", length) + key_material_ptr = self._ffi.from_buffer(key_material) + res = self._lib.EVP_PBE_scrypt( + key_material_ptr, + len(key_material), + salt, + len(salt), + n, + r, + p, + scrypt._MEM_LIMIT, + buf, + length, + ) + if res != 1: + errors = self._consume_errors_with_text() + # memory required formula explained here: + # https://blog.filippo.io/the-scrypt-parameters/ + min_memory = 128 * n * r // (1024 ** 2) + raise MemoryError( + "Not enough memory to derive key. These parameters require" + " {} MB of memory.".format(min_memory), + errors, + ) + return self._ffi.buffer(buf)[:] + + def aead_cipher_supported(self, cipher): + cipher_name = aead._aead_cipher_name(cipher) + if self._fips_enabled and cipher_name not in self._fips_aead: + return False + return self._lib.EVP_get_cipherbyname(cipher_name) != self._ffi.NULL + + @contextlib.contextmanager + def _zeroed_bytearray(self, length): + """ + This method creates a bytearray, which we copy data into (hopefully + also from a mutable buffer that can be dynamically erased!), and then + zero when we're done. + """ + ba = bytearray(length) + try: + yield ba + finally: + self._zero_data(ba, length) + + def _zero_data(self, data, length): + # We clear things this way because at the moment we're not + # sure of a better way that can guarantee it overwrites the + # memory of a bytearray and doesn't just replace the underlying char *. + for i in range(length): + data[i] = 0 + + @contextlib.contextmanager + def _zeroed_null_terminated_buf(self, data): + """ + This method takes bytes, which can be a bytestring or a mutable + buffer like a bytearray, and yields a null-terminated version of that + data. This is required because PKCS12_parse doesn't take a length with + its password char * and ffi.from_buffer doesn't provide null + termination. So, to support zeroing the data via bytearray we + need to build this ridiculous construct that copies the memory, but + zeroes it after use. + """ + if data is None: + yield self._ffi.NULL + else: + data_len = len(data) + buf = self._ffi.new("char[]", data_len + 1) + self._ffi.memmove(buf, data, data_len) + try: + yield buf + finally: + # Cast to a uint8_t * so we can assign by integer + self._zero_data(self._ffi.cast("uint8_t *", buf), data_len) + + def load_key_and_certificates_from_pkcs12(self, data, password): + if password is not None: + utils._check_byteslike("password", password) + + bio = self._bytes_to_bio(data) + p12 = self._lib.d2i_PKCS12_bio(bio.bio, self._ffi.NULL) + if p12 == self._ffi.NULL: + self._consume_errors() + raise ValueError("Could not deserialize PKCS12 data") + + p12 = self._ffi.gc(p12, self._lib.PKCS12_free) + evp_pkey_ptr = self._ffi.new("EVP_PKEY **") + x509_ptr = self._ffi.new("X509 **") + sk_x509_ptr = self._ffi.new("Cryptography_STACK_OF_X509 **") + with self._zeroed_null_terminated_buf(password) as password_buf: + res = self._lib.PKCS12_parse( + p12, password_buf, evp_pkey_ptr, x509_ptr, sk_x509_ptr + ) + + if res == 0: + self._consume_errors() + raise ValueError("Invalid password or PKCS12 data") + + cert = None + key = None + additional_certificates = [] + + if evp_pkey_ptr[0] != self._ffi.NULL: + evp_pkey = self._ffi.gc(evp_pkey_ptr[0], self._lib.EVP_PKEY_free) + key = self._evp_pkey_to_private_key(evp_pkey) + + if x509_ptr[0] != self._ffi.NULL: + x509 = self._ffi.gc(x509_ptr[0], self._lib.X509_free) + cert = _Certificate(self, x509) + + if sk_x509_ptr[0] != self._ffi.NULL: + sk_x509 = self._ffi.gc(sk_x509_ptr[0], self._lib.sk_X509_free) + num = self._lib.sk_X509_num(sk_x509_ptr[0]) + for i in range(num): + x509 = self._lib.sk_X509_value(sk_x509, i) + self.openssl_assert(x509 != self._ffi.NULL) + x509 = self._ffi.gc(x509, self._lib.X509_free) + additional_certificates.append(_Certificate(self, x509)) + + return (key, cert, additional_certificates) + + def serialize_key_and_certificates_to_pkcs12( + self, name, key, cert, cas, encryption_algorithm + ): + password = None + if name is not None: + utils._check_bytes("name", name) + + if isinstance(encryption_algorithm, serialization.NoEncryption): + nid_cert = -1 + nid_key = -1 + pkcs12_iter = 0 + mac_iter = 0 + elif isinstance( + encryption_algorithm, serialization.BestAvailableEncryption + ): + # PKCS12 encryption is hopeless trash and can never be fixed. + # This is the least terrible option. + nid_cert = self._lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC + nid_key = self._lib.NID_pbe_WithSHA1And3_Key_TripleDES_CBC + # At least we can set this higher than OpenSSL's default + pkcs12_iter = 20000 + # mac_iter chosen for compatibility reasons, see: + # https://www.openssl.org/docs/man1.1.1/man3/PKCS12_create.html + # Did we mention how lousy PKCS12 encryption is? + mac_iter = 1 + password = encryption_algorithm.password + else: + raise ValueError("Unsupported key encryption type") + + if cas is None or len(cas) == 0: + sk_x509 = self._ffi.NULL + else: + sk_x509 = self._lib.sk_X509_new_null() + sk_x509 = self._ffi.gc(sk_x509, self._lib.sk_X509_free) + + # reverse the list when building the stack so that they're encoded + # in the order they were originally provided. it is a mystery + for ca in reversed(cas): + res = self._lib.sk_X509_push(sk_x509, ca._x509) + backend.openssl_assert(res >= 1) + + with self._zeroed_null_terminated_buf(password) as password_buf: + with self._zeroed_null_terminated_buf(name) as name_buf: + p12 = self._lib.PKCS12_create( + password_buf, + name_buf, + key._evp_pkey if key else self._ffi.NULL, + cert._x509 if cert else self._ffi.NULL, + sk_x509, + nid_key, + nid_cert, + pkcs12_iter, + mac_iter, + 0, + ) + + self.openssl_assert(p12 != self._ffi.NULL) + p12 = self._ffi.gc(p12, self._lib.PKCS12_free) + + bio = self._create_mem_bio_gc() + res = self._lib.i2d_PKCS12_bio(bio, p12) + self.openssl_assert(res > 0) + return self._read_mem_bio(bio) + + def poly1305_supported(self): + if self._fips_enabled: + return False + return self._lib.Cryptography_HAS_POLY1305 == 1 + + def create_poly1305_ctx(self, key): + utils._check_byteslike("key", key) + if len(key) != _POLY1305_KEY_SIZE: + raise ValueError("A poly1305 key is 32 bytes long") + + return _Poly1305Context(self, key) + + def load_pem_pkcs7_certificates(self, data): + utils._check_bytes("data", data) + bio = self._bytes_to_bio(data) + p7 = self._lib.PEM_read_bio_PKCS7( + bio.bio, self._ffi.NULL, self._ffi.NULL, self._ffi.NULL + ) + if p7 == self._ffi.NULL: + self._consume_errors() + raise ValueError("Unable to parse PKCS7 data") + + p7 = self._ffi.gc(p7, self._lib.PKCS7_free) + return self._load_pkcs7_certificates(p7) + + def load_der_pkcs7_certificates(self, data): + utils._check_bytes("data", data) + bio = self._bytes_to_bio(data) + p7 = self._lib.d2i_PKCS7_bio(bio.bio, self._ffi.NULL) + if p7 == self._ffi.NULL: + self._consume_errors() + raise ValueError("Unable to parse PKCS7 data") + + p7 = self._ffi.gc(p7, self._lib.PKCS7_free) + return self._load_pkcs7_certificates(p7) + + def _load_pkcs7_certificates(self, p7): + nid = self._lib.OBJ_obj2nid(p7.type) + self.openssl_assert(nid != self._lib.NID_undef) + if nid != self._lib.NID_pkcs7_signed: + raise UnsupportedAlgorithm( + "Only basic signed structures are currently supported. NID" + " for this data was {}".format(nid), + _Reasons.UNSUPPORTED_SERIALIZATION, + ) + + sk_x509 = p7.d.sign.cert + num = self._lib.sk_X509_num(sk_x509) + certs = [] + for i in range(num): + x509 = self._lib.sk_X509_value(sk_x509, i) + self.openssl_assert(x509 != self._ffi.NULL) + res = self._lib.X509_up_ref(x509) + # When OpenSSL is less than 1.1.0 up_ref returns the current + # refcount. On 1.1.0+ it returns 1 for success. + self.openssl_assert(res >= 1) + x509 = self._ffi.gc(x509, self._lib.X509_free) + certs.append(_Certificate(self, x509)) + + return certs + + def pkcs7_sign(self, builder, encoding, options): + bio = self._bytes_to_bio(builder._data) + init_flags = self._lib.PKCS7_PARTIAL + final_flags = 0 + + if len(builder._additional_certs) == 0: + certs = self._ffi.NULL + else: + certs = self._lib.sk_X509_new_null() + certs = self._ffi.gc(certs, self._lib.sk_X509_free) + for cert in builder._additional_certs: + res = self._lib.sk_X509_push(certs, cert._x509) + self.openssl_assert(res >= 1) + + if pkcs7.PKCS7Options.DetachedSignature in options: + # Don't embed the data in the PKCS7 structure + init_flags |= self._lib.PKCS7_DETACHED + final_flags |= self._lib.PKCS7_DETACHED + + # This just inits a structure for us. However, there + # are flags we need to set, joy. + p7 = self._lib.PKCS7_sign( + self._ffi.NULL, + self._ffi.NULL, + certs, + self._ffi.NULL, + init_flags, + ) + self.openssl_assert(p7 != self._ffi.NULL) + p7 = self._ffi.gc(p7, self._lib.PKCS7_free) + signer_flags = 0 + # These flags are configurable on a per-signature basis + # but we've deliberately chosen to make the API only allow + # setting it across all signatures for now. + if pkcs7.PKCS7Options.NoCapabilities in options: + signer_flags |= self._lib.PKCS7_NOSMIMECAP + elif pkcs7.PKCS7Options.NoAttributes in options: + signer_flags |= self._lib.PKCS7_NOATTR + + if pkcs7.PKCS7Options.NoCerts in options: + signer_flags |= self._lib.PKCS7_NOCERTS + + for certificate, private_key, hash_algorithm in builder._signers: + md = self._evp_md_non_null_from_algorithm(hash_algorithm) + p7signerinfo = self._lib.PKCS7_sign_add_signer( + p7, certificate._x509, private_key._evp_pkey, md, signer_flags + ) + self.openssl_assert(p7signerinfo != self._ffi.NULL) + + for option in options: + # DetachedSignature, NoCapabilities, and NoAttributes are already + # handled so we just need to check these last two options. + if option is pkcs7.PKCS7Options.Text: + final_flags |= self._lib.PKCS7_TEXT + elif option is pkcs7.PKCS7Options.Binary: + final_flags |= self._lib.PKCS7_BINARY + + bio_out = self._create_mem_bio_gc() + if encoding is serialization.Encoding.SMIME: + # This finalizes the structure + res = self._lib.SMIME_write_PKCS7( + bio_out, p7, bio.bio, final_flags + ) + elif encoding is serialization.Encoding.PEM: + res = self._lib.PKCS7_final(p7, bio.bio, final_flags) + self.openssl_assert(res == 1) + res = self._lib.PEM_write_bio_PKCS7_stream( + bio_out, p7, bio.bio, final_flags + ) + else: + assert encoding is serialization.Encoding.DER + # We need to call finalize here becauase i2d_PKCS7_bio does not + # finalize. + res = self._lib.PKCS7_final(p7, bio.bio, final_flags) + self.openssl_assert(res == 1) + res = self._lib.i2d_PKCS7_bio(bio_out, p7) + self.openssl_assert(res == 1) + return self._read_mem_bio(bio_out) + + +class GetCipherByName(object): + def __init__(self, fmt): + self._fmt = fmt + + def __call__(self, backend, cipher, mode): + cipher_name = self._fmt.format(cipher=cipher, mode=mode).lower() + return backend._lib.EVP_get_cipherbyname(cipher_name.encode("ascii")) + + +def _get_xts_cipher(backend, cipher, mode): + cipher_name = "aes-{}-xts".format(cipher.key_size // 2) + return backend._lib.EVP_get_cipherbyname(cipher_name.encode("ascii")) + + +backend = Backend() diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/ciphers.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/ciphers.py new file mode 100644 index 0000000..1e805d2 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/ciphers.py @@ -0,0 +1,231 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography import utils +from cryptography.exceptions import InvalidTag, UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.primitives import ciphers +from cryptography.hazmat.primitives.ciphers import modes + + +@utils.register_interface(ciphers.CipherContext) +@utils.register_interface(ciphers.AEADCipherContext) +@utils.register_interface(ciphers.AEADEncryptionContext) +@utils.register_interface(ciphers.AEADDecryptionContext) +class _CipherContext(object): + _ENCRYPT = 1 + _DECRYPT = 0 + _MAX_CHUNK_SIZE = 2 ** 31 - 1 + + def __init__(self, backend, cipher, mode, operation): + self._backend = backend + self._cipher = cipher + self._mode = mode + self._operation = operation + self._tag = None + + if isinstance(self._cipher, ciphers.BlockCipherAlgorithm): + self._block_size_bytes = self._cipher.block_size // 8 + else: + self._block_size_bytes = 1 + + ctx = self._backend._lib.EVP_CIPHER_CTX_new() + ctx = self._backend._ffi.gc( + ctx, self._backend._lib.EVP_CIPHER_CTX_free + ) + + registry = self._backend._cipher_registry + try: + adapter = registry[type(cipher), type(mode)] + except KeyError: + raise UnsupportedAlgorithm( + "cipher {} in {} mode is not supported " + "by this backend.".format( + cipher.name, mode.name if mode else mode + ), + _Reasons.UNSUPPORTED_CIPHER, + ) + + evp_cipher = adapter(self._backend, cipher, mode) + if evp_cipher == self._backend._ffi.NULL: + msg = "cipher {0.name} ".format(cipher) + if mode is not None: + msg += "in {0.name} mode ".format(mode) + msg += ( + "is not supported by this backend (Your version of OpenSSL " + "may be too old. Current version: {}.)" + ).format(self._backend.openssl_version_text()) + raise UnsupportedAlgorithm(msg, _Reasons.UNSUPPORTED_CIPHER) + + if isinstance(mode, modes.ModeWithInitializationVector): + iv_nonce = self._backend._ffi.from_buffer( + mode.initialization_vector + ) + elif isinstance(mode, modes.ModeWithTweak): + iv_nonce = self._backend._ffi.from_buffer(mode.tweak) + elif isinstance(mode, modes.ModeWithNonce): + iv_nonce = self._backend._ffi.from_buffer(mode.nonce) + elif isinstance(cipher, modes.ModeWithNonce): + iv_nonce = self._backend._ffi.from_buffer(cipher.nonce) + else: + iv_nonce = self._backend._ffi.NULL + # begin init with cipher and operation type + res = self._backend._lib.EVP_CipherInit_ex( + ctx, + evp_cipher, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + operation, + ) + self._backend.openssl_assert(res != 0) + # set the key length to handle variable key ciphers + res = self._backend._lib.EVP_CIPHER_CTX_set_key_length( + ctx, len(cipher.key) + ) + self._backend.openssl_assert(res != 0) + if isinstance(mode, modes.GCM): + res = self._backend._lib.EVP_CIPHER_CTX_ctrl( + ctx, + self._backend._lib.EVP_CTRL_AEAD_SET_IVLEN, + len(iv_nonce), + self._backend._ffi.NULL, + ) + self._backend.openssl_assert(res != 0) + if mode.tag is not None: + res = self._backend._lib.EVP_CIPHER_CTX_ctrl( + ctx, + self._backend._lib.EVP_CTRL_AEAD_SET_TAG, + len(mode.tag), + mode.tag, + ) + self._backend.openssl_assert(res != 0) + self._tag = mode.tag + + # pass key/iv + res = self._backend._lib.EVP_CipherInit_ex( + ctx, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.from_buffer(cipher.key), + iv_nonce, + operation, + ) + self._backend.openssl_assert(res != 0) + # We purposely disable padding here as it's handled higher up in the + # API. + self._backend._lib.EVP_CIPHER_CTX_set_padding(ctx, 0) + self._ctx = ctx + + def update(self, data): + buf = bytearray(len(data) + self._block_size_bytes - 1) + n = self.update_into(data, buf) + return bytes(buf[:n]) + + def update_into(self, data, buf): + total_data_len = len(data) + if len(buf) < (total_data_len + self._block_size_bytes - 1): + raise ValueError( + "buffer must be at least {} bytes for this " + "payload".format(len(data) + self._block_size_bytes - 1) + ) + + data_processed = 0 + total_out = 0 + outlen = self._backend._ffi.new("int *") + baseoutbuf = self._backend._ffi.from_buffer(buf) + baseinbuf = self._backend._ffi.from_buffer(data) + + while data_processed != total_data_len: + outbuf = baseoutbuf + total_out + inbuf = baseinbuf + data_processed + inlen = min(self._MAX_CHUNK_SIZE, total_data_len - data_processed) + + res = self._backend._lib.EVP_CipherUpdate( + self._ctx, outbuf, outlen, inbuf, inlen + ) + self._backend.openssl_assert(res != 0) + data_processed += inlen + total_out += outlen[0] + + return total_out + + def finalize(self): + if ( + self._operation == self._DECRYPT + and isinstance(self._mode, modes.ModeWithAuthenticationTag) + and self.tag is None + ): + raise ValueError( + "Authentication tag must be provided when decrypting." + ) + + buf = self._backend._ffi.new("unsigned char[]", self._block_size_bytes) + outlen = self._backend._ffi.new("int *") + res = self._backend._lib.EVP_CipherFinal_ex(self._ctx, buf, outlen) + if res == 0: + errors = self._backend._consume_errors() + + if not errors and isinstance(self._mode, modes.GCM): + raise InvalidTag + + self._backend.openssl_assert( + errors[0]._lib_reason_match( + self._backend._lib.ERR_LIB_EVP, + self._backend._lib.EVP_R_DATA_NOT_MULTIPLE_OF_BLOCK_LENGTH, + ), + errors=errors, + ) + raise ValueError( + "The length of the provided data is not a multiple of " + "the block length." + ) + + if ( + isinstance(self._mode, modes.GCM) + and self._operation == self._ENCRYPT + ): + tag_buf = self._backend._ffi.new( + "unsigned char[]", self._block_size_bytes + ) + res = self._backend._lib.EVP_CIPHER_CTX_ctrl( + self._ctx, + self._backend._lib.EVP_CTRL_AEAD_GET_TAG, + self._block_size_bytes, + tag_buf, + ) + self._backend.openssl_assert(res != 0) + self._tag = self._backend._ffi.buffer(tag_buf)[:] + + res = self._backend._lib.EVP_CIPHER_CTX_cleanup(self._ctx) + self._backend.openssl_assert(res == 1) + return self._backend._ffi.buffer(buf)[: outlen[0]] + + def finalize_with_tag(self, tag): + if len(tag) < self._mode._min_tag_length: + raise ValueError( + "Authentication tag must be {} bytes or longer.".format( + self._mode._min_tag_length + ) + ) + res = self._backend._lib.EVP_CIPHER_CTX_ctrl( + self._ctx, self._backend._lib.EVP_CTRL_AEAD_SET_TAG, len(tag), tag + ) + self._backend.openssl_assert(res != 0) + self._tag = tag + return self.finalize() + + def authenticate_additional_data(self, data): + outlen = self._backend._ffi.new("int *") + res = self._backend._lib.EVP_CipherUpdate( + self._ctx, + self._backend._ffi.NULL, + outlen, + self._backend._ffi.from_buffer(data), + len(data), + ) + self._backend.openssl_assert(res != 0) + + tag = utils.read_only_property("_tag") diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/cmac.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/cmac.py new file mode 100644 index 0000000..195fc23 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/cmac.py @@ -0,0 +1,82 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + + +from cryptography import utils +from cryptography.exceptions import ( + InvalidSignature, + UnsupportedAlgorithm, + _Reasons, +) +from cryptography.hazmat.primitives import constant_time +from cryptography.hazmat.primitives.ciphers.modes import CBC + + +class _CMACContext(object): + def __init__(self, backend, algorithm, ctx=None): + if not backend.cmac_algorithm_supported(algorithm): + raise UnsupportedAlgorithm( + "This backend does not support CMAC.", + _Reasons.UNSUPPORTED_CIPHER, + ) + + self._backend = backend + self._key = algorithm.key + self._algorithm = algorithm + self._output_length = algorithm.block_size // 8 + + if ctx is None: + registry = self._backend._cipher_registry + adapter = registry[type(algorithm), CBC] + + evp_cipher = adapter(self._backend, algorithm, CBC) + + ctx = self._backend._lib.CMAC_CTX_new() + + self._backend.openssl_assert(ctx != self._backend._ffi.NULL) + ctx = self._backend._ffi.gc(ctx, self._backend._lib.CMAC_CTX_free) + + key_ptr = self._backend._ffi.from_buffer(self._key) + res = self._backend._lib.CMAC_Init( + ctx, + key_ptr, + len(self._key), + evp_cipher, + self._backend._ffi.NULL, + ) + self._backend.openssl_assert(res == 1) + + self._ctx = ctx + + algorithm = utils.read_only_property("_algorithm") + + def update(self, data): + res = self._backend._lib.CMAC_Update(self._ctx, data, len(data)) + self._backend.openssl_assert(res == 1) + + def finalize(self): + buf = self._backend._ffi.new("unsigned char[]", self._output_length) + length = self._backend._ffi.new("size_t *", self._output_length) + res = self._backend._lib.CMAC_Final(self._ctx, buf, length) + self._backend.openssl_assert(res == 1) + + self._ctx = None + + return self._backend._ffi.buffer(buf)[:] + + def copy(self): + copied_ctx = self._backend._lib.CMAC_CTX_new() + copied_ctx = self._backend._ffi.gc( + copied_ctx, self._backend._lib.CMAC_CTX_free + ) + res = self._backend._lib.CMAC_CTX_copy(copied_ctx, self._ctx) + self._backend.openssl_assert(res == 1) + return _CMACContext(self._backend, self._algorithm, ctx=copied_ctx) + + def verify(self, signature): + digest = self.finalize() + if not constant_time.bytes_eq(digest, signature): + raise InvalidSignature("Signature did not match digest.") diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/decode_asn1.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/decode_asn1.py new file mode 100644 index 0000000..279b00c --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/decode_asn1.py @@ -0,0 +1,878 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import datetime +import ipaddress + +import six + +from cryptography import x509 +from cryptography.hazmat._der import DERReader, INTEGER, NULL, SEQUENCE +from cryptography.x509.extensions import _TLS_FEATURE_TYPE_TO_ENUM +from cryptography.x509.name import _ASN1_TYPE_TO_ENUM +from cryptography.x509.oid import ( + CRLEntryExtensionOID, + CertificatePoliciesOID, + ExtensionOID, + OCSPExtensionOID, +) + + +def _obj2txt(backend, obj): + # Set to 80 on the recommendation of + # https://www.openssl.org/docs/crypto/OBJ_nid2ln.html#return_values + # + # But OIDs longer than this occur in real life (e.g. Active + # Directory makes some very long OIDs). So we need to detect + # and properly handle the case where the default buffer is not + # big enough. + # + buf_len = 80 + buf = backend._ffi.new("char[]", buf_len) + + # 'res' is the number of bytes that *would* be written if the + # buffer is large enough. If 'res' > buf_len - 1, we need to + # alloc a big-enough buffer and go again. + res = backend._lib.OBJ_obj2txt(buf, buf_len, obj, 1) + if res > buf_len - 1: # account for terminating null byte + buf_len = res + 1 + buf = backend._ffi.new("char[]", buf_len) + res = backend._lib.OBJ_obj2txt(buf, buf_len, obj, 1) + backend.openssl_assert(res > 0) + return backend._ffi.buffer(buf, res)[:].decode() + + +def _decode_x509_name_entry(backend, x509_name_entry): + obj = backend._lib.X509_NAME_ENTRY_get_object(x509_name_entry) + backend.openssl_assert(obj != backend._ffi.NULL) + data = backend._lib.X509_NAME_ENTRY_get_data(x509_name_entry) + backend.openssl_assert(data != backend._ffi.NULL) + value = _asn1_string_to_utf8(backend, data) + oid = _obj2txt(backend, obj) + type = _ASN1_TYPE_TO_ENUM[data.type] + + return x509.NameAttribute(x509.ObjectIdentifier(oid), value, type) + + +def _decode_x509_name(backend, x509_name): + count = backend._lib.X509_NAME_entry_count(x509_name) + attributes = [] + prev_set_id = -1 + for x in range(count): + entry = backend._lib.X509_NAME_get_entry(x509_name, x) + attribute = _decode_x509_name_entry(backend, entry) + set_id = backend._lib.Cryptography_X509_NAME_ENTRY_set(entry) + if set_id != prev_set_id: + attributes.append({attribute}) + else: + # is in the same RDN a previous entry + attributes[-1].add(attribute) + prev_set_id = set_id + + return x509.Name(x509.RelativeDistinguishedName(rdn) for rdn in attributes) + + +def _decode_general_names(backend, gns): + num = backend._lib.sk_GENERAL_NAME_num(gns) + names = [] + for i in range(num): + gn = backend._lib.sk_GENERAL_NAME_value(gns, i) + backend.openssl_assert(gn != backend._ffi.NULL) + names.append(_decode_general_name(backend, gn)) + + return names + + +def _decode_general_name(backend, gn): + if gn.type == backend._lib.GEN_DNS: + # Convert to bytes and then decode to utf8. We don't use + # asn1_string_to_utf8 here because it doesn't properly convert + # utf8 from ia5strings. + data = _asn1_string_to_bytes(backend, gn.d.dNSName).decode("utf8") + # We don't use the constructor for DNSName so we can bypass validation + # This allows us to create DNSName objects that have unicode chars + # when a certificate (against the RFC) contains them. + return x509.DNSName._init_without_validation(data) + elif gn.type == backend._lib.GEN_URI: + # Convert to bytes and then decode to utf8. We don't use + # asn1_string_to_utf8 here because it doesn't properly convert + # utf8 from ia5strings. + data = _asn1_string_to_bytes( + backend, gn.d.uniformResourceIdentifier + ).decode("utf8") + # We don't use the constructor for URI so we can bypass validation + # This allows us to create URI objects that have unicode chars + # when a certificate (against the RFC) contains them. + return x509.UniformResourceIdentifier._init_without_validation(data) + elif gn.type == backend._lib.GEN_RID: + oid = _obj2txt(backend, gn.d.registeredID) + return x509.RegisteredID(x509.ObjectIdentifier(oid)) + elif gn.type == backend._lib.GEN_IPADD: + data = _asn1_string_to_bytes(backend, gn.d.iPAddress) + data_len = len(data) + if data_len == 8 or data_len == 32: + # This is an IPv4 or IPv6 Network and not a single IP. This + # type of data appears in Name Constraints. Unfortunately, + # ipaddress doesn't support packed bytes + netmask. Additionally, + # IPv6Network can only handle CIDR rather than the full 16 byte + # netmask. To handle this we convert the netmask to integer, then + # find the first 0 bit, which will be the prefix. If another 1 + # bit is present after that the netmask is invalid. + base = ipaddress.ip_address(data[: data_len // 2]) + netmask = ipaddress.ip_address(data[data_len // 2 :]) + bits = bin(int(netmask))[2:] + prefix = bits.find("0") + # If no 0 bits are found it is a /32 or /128 + if prefix == -1: + prefix = len(bits) + + if "1" in bits[prefix:]: + raise ValueError("Invalid netmask") + + ip = ipaddress.ip_network(base.exploded + u"/{}".format(prefix)) + else: + ip = ipaddress.ip_address(data) + + return x509.IPAddress(ip) + elif gn.type == backend._lib.GEN_DIRNAME: + return x509.DirectoryName( + _decode_x509_name(backend, gn.d.directoryName) + ) + elif gn.type == backend._lib.GEN_EMAIL: + # Convert to bytes and then decode to utf8. We don't use + # asn1_string_to_utf8 here because it doesn't properly convert + # utf8 from ia5strings. + data = _asn1_string_to_bytes(backend, gn.d.rfc822Name).decode("utf8") + # We don't use the constructor for RFC822Name so we can bypass + # validation. This allows us to create RFC822Name objects that have + # unicode chars when a certificate (against the RFC) contains them. + return x509.RFC822Name._init_without_validation(data) + elif gn.type == backend._lib.GEN_OTHERNAME: + type_id = _obj2txt(backend, gn.d.otherName.type_id) + value = _asn1_to_der(backend, gn.d.otherName.value) + return x509.OtherName(x509.ObjectIdentifier(type_id), value) + else: + # x400Address or ediPartyName + raise x509.UnsupportedGeneralNameType( + "{} is not a supported type".format( + x509._GENERAL_NAMES.get(gn.type, gn.type) + ), + gn.type, + ) + + +def _decode_ocsp_no_check(backend, ext): + return x509.OCSPNoCheck() + + +def _decode_crl_number(backend, ext): + asn1_int = backend._ffi.cast("ASN1_INTEGER *", ext) + asn1_int = backend._ffi.gc(asn1_int, backend._lib.ASN1_INTEGER_free) + return x509.CRLNumber(_asn1_integer_to_int(backend, asn1_int)) + + +def _decode_delta_crl_indicator(backend, ext): + asn1_int = backend._ffi.cast("ASN1_INTEGER *", ext) + asn1_int = backend._ffi.gc(asn1_int, backend._lib.ASN1_INTEGER_free) + return x509.DeltaCRLIndicator(_asn1_integer_to_int(backend, asn1_int)) + + +class _X509ExtensionParser(object): + def __init__(self, backend, ext_count, get_ext, handlers): + self.ext_count = ext_count + self.get_ext = get_ext + self.handlers = handlers + self._backend = backend + + def parse(self, x509_obj): + extensions = [] + seen_oids = set() + for i in range(self.ext_count(x509_obj)): + ext = self.get_ext(x509_obj, i) + self._backend.openssl_assert(ext != self._backend._ffi.NULL) + crit = self._backend._lib.X509_EXTENSION_get_critical(ext) + critical = crit == 1 + oid = x509.ObjectIdentifier( + _obj2txt( + self._backend, + self._backend._lib.X509_EXTENSION_get_object(ext), + ) + ) + if oid in seen_oids: + raise x509.DuplicateExtension( + "Duplicate {} extension found".format(oid), oid + ) + + # These OIDs are only supported in OpenSSL 1.1.0+ but we want + # to support them in all versions of OpenSSL so we decode them + # ourselves. + if oid == ExtensionOID.TLS_FEATURE: + # The extension contents are a SEQUENCE OF INTEGERs. + data = self._backend._lib.X509_EXTENSION_get_data(ext) + data_bytes = _asn1_string_to_bytes(self._backend, data) + features = DERReader(data_bytes).read_single_element(SEQUENCE) + parsed = [] + while not features.is_empty(): + parsed.append(features.read_element(INTEGER).as_integer()) + # Map the features to their enum value. + value = x509.TLSFeature( + [_TLS_FEATURE_TYPE_TO_ENUM[x] for x in parsed] + ) + extensions.append(x509.Extension(oid, critical, value)) + seen_oids.add(oid) + continue + elif oid == ExtensionOID.PRECERT_POISON: + data = self._backend._lib.X509_EXTENSION_get_data(ext) + # The contents of the extension must be an ASN.1 NULL. + reader = DERReader(_asn1_string_to_bytes(self._backend, data)) + reader.read_single_element(NULL).check_empty() + extensions.append( + x509.Extension(oid, critical, x509.PrecertPoison()) + ) + seen_oids.add(oid) + continue + + try: + handler = self.handlers[oid] + except KeyError: + # Dump the DER payload into an UnrecognizedExtension object + data = self._backend._lib.X509_EXTENSION_get_data(ext) + self._backend.openssl_assert(data != self._backend._ffi.NULL) + der = self._backend._ffi.buffer(data.data, data.length)[:] + unrecognized = x509.UnrecognizedExtension(oid, der) + extensions.append(x509.Extension(oid, critical, unrecognized)) + else: + ext_data = self._backend._lib.X509V3_EXT_d2i(ext) + if ext_data == self._backend._ffi.NULL: + self._backend._consume_errors() + raise ValueError( + "The {} extension is invalid and can't be " + "parsed".format(oid) + ) + + value = handler(self._backend, ext_data) + extensions.append(x509.Extension(oid, critical, value)) + + seen_oids.add(oid) + + return x509.Extensions(extensions) + + +def _decode_certificate_policies(backend, cp): + cp = backend._ffi.cast("Cryptography_STACK_OF_POLICYINFO *", cp) + cp = backend._ffi.gc(cp, backend._lib.CERTIFICATEPOLICIES_free) + + num = backend._lib.sk_POLICYINFO_num(cp) + certificate_policies = [] + for i in range(num): + qualifiers = None + pi = backend._lib.sk_POLICYINFO_value(cp, i) + oid = x509.ObjectIdentifier(_obj2txt(backend, pi.policyid)) + if pi.qualifiers != backend._ffi.NULL: + qnum = backend._lib.sk_POLICYQUALINFO_num(pi.qualifiers) + qualifiers = [] + for j in range(qnum): + pqi = backend._lib.sk_POLICYQUALINFO_value(pi.qualifiers, j) + pqualid = x509.ObjectIdentifier(_obj2txt(backend, pqi.pqualid)) + if pqualid == CertificatePoliciesOID.CPS_QUALIFIER: + cpsuri = backend._ffi.buffer( + pqi.d.cpsuri.data, pqi.d.cpsuri.length + )[:].decode("ascii") + qualifiers.append(cpsuri) + else: + assert pqualid == CertificatePoliciesOID.CPS_USER_NOTICE + user_notice = _decode_user_notice( + backend, pqi.d.usernotice + ) + qualifiers.append(user_notice) + + certificate_policies.append(x509.PolicyInformation(oid, qualifiers)) + + return x509.CertificatePolicies(certificate_policies) + + +def _decode_user_notice(backend, un): + explicit_text = None + notice_reference = None + + if un.exptext != backend._ffi.NULL: + explicit_text = _asn1_string_to_utf8(backend, un.exptext) + + if un.noticeref != backend._ffi.NULL: + organization = _asn1_string_to_utf8(backend, un.noticeref.organization) + + num = backend._lib.sk_ASN1_INTEGER_num(un.noticeref.noticenos) + notice_numbers = [] + for i in range(num): + asn1_int = backend._lib.sk_ASN1_INTEGER_value( + un.noticeref.noticenos, i + ) + notice_num = _asn1_integer_to_int(backend, asn1_int) + notice_numbers.append(notice_num) + + notice_reference = x509.NoticeReference(organization, notice_numbers) + + return x509.UserNotice(notice_reference, explicit_text) + + +def _decode_basic_constraints(backend, bc_st): + basic_constraints = backend._ffi.cast("BASIC_CONSTRAINTS *", bc_st) + basic_constraints = backend._ffi.gc( + basic_constraints, backend._lib.BASIC_CONSTRAINTS_free + ) + # The byte representation of an ASN.1 boolean true is \xff. OpenSSL + # chooses to just map this to its ordinal value, so true is 255 and + # false is 0. + ca = basic_constraints.ca == 255 + path_length = _asn1_integer_to_int_or_none( + backend, basic_constraints.pathlen + ) + + return x509.BasicConstraints(ca, path_length) + + +def _decode_subject_key_identifier(backend, asn1_string): + asn1_string = backend._ffi.cast("ASN1_OCTET_STRING *", asn1_string) + asn1_string = backend._ffi.gc( + asn1_string, backend._lib.ASN1_OCTET_STRING_free + ) + return x509.SubjectKeyIdentifier( + backend._ffi.buffer(asn1_string.data, asn1_string.length)[:] + ) + + +def _decode_authority_key_identifier(backend, akid): + akid = backend._ffi.cast("AUTHORITY_KEYID *", akid) + akid = backend._ffi.gc(akid, backend._lib.AUTHORITY_KEYID_free) + key_identifier = None + authority_cert_issuer = None + + if akid.keyid != backend._ffi.NULL: + key_identifier = backend._ffi.buffer( + akid.keyid.data, akid.keyid.length + )[:] + + if akid.issuer != backend._ffi.NULL: + authority_cert_issuer = _decode_general_names(backend, akid.issuer) + + authority_cert_serial_number = _asn1_integer_to_int_or_none( + backend, akid.serial + ) + + return x509.AuthorityKeyIdentifier( + key_identifier, authority_cert_issuer, authority_cert_serial_number + ) + + +def _decode_information_access(backend, ia): + ia = backend._ffi.cast("Cryptography_STACK_OF_ACCESS_DESCRIPTION *", ia) + ia = backend._ffi.gc( + ia, + lambda x: backend._lib.sk_ACCESS_DESCRIPTION_pop_free( + x, + backend._ffi.addressof( + backend._lib._original_lib, "ACCESS_DESCRIPTION_free" + ), + ), + ) + num = backend._lib.sk_ACCESS_DESCRIPTION_num(ia) + access_descriptions = [] + for i in range(num): + ad = backend._lib.sk_ACCESS_DESCRIPTION_value(ia, i) + backend.openssl_assert(ad.method != backend._ffi.NULL) + oid = x509.ObjectIdentifier(_obj2txt(backend, ad.method)) + backend.openssl_assert(ad.location != backend._ffi.NULL) + gn = _decode_general_name(backend, ad.location) + access_descriptions.append(x509.AccessDescription(oid, gn)) + + return access_descriptions + + +def _decode_authority_information_access(backend, aia): + access_descriptions = _decode_information_access(backend, aia) + return x509.AuthorityInformationAccess(access_descriptions) + + +def _decode_subject_information_access(backend, aia): + access_descriptions = _decode_information_access(backend, aia) + return x509.SubjectInformationAccess(access_descriptions) + + +def _decode_key_usage(backend, bit_string): + bit_string = backend._ffi.cast("ASN1_BIT_STRING *", bit_string) + bit_string = backend._ffi.gc(bit_string, backend._lib.ASN1_BIT_STRING_free) + get_bit = backend._lib.ASN1_BIT_STRING_get_bit + digital_signature = get_bit(bit_string, 0) == 1 + content_commitment = get_bit(bit_string, 1) == 1 + key_encipherment = get_bit(bit_string, 2) == 1 + data_encipherment = get_bit(bit_string, 3) == 1 + key_agreement = get_bit(bit_string, 4) == 1 + key_cert_sign = get_bit(bit_string, 5) == 1 + crl_sign = get_bit(bit_string, 6) == 1 + encipher_only = get_bit(bit_string, 7) == 1 + decipher_only = get_bit(bit_string, 8) == 1 + return x509.KeyUsage( + digital_signature, + content_commitment, + key_encipherment, + data_encipherment, + key_agreement, + key_cert_sign, + crl_sign, + encipher_only, + decipher_only, + ) + + +def _decode_general_names_extension(backend, gns): + gns = backend._ffi.cast("GENERAL_NAMES *", gns) + gns = backend._ffi.gc(gns, backend._lib.GENERAL_NAMES_free) + general_names = _decode_general_names(backend, gns) + return general_names + + +def _decode_subject_alt_name(backend, ext): + return x509.SubjectAlternativeName( + _decode_general_names_extension(backend, ext) + ) + + +def _decode_issuer_alt_name(backend, ext): + return x509.IssuerAlternativeName( + _decode_general_names_extension(backend, ext) + ) + + +def _decode_name_constraints(backend, nc): + nc = backend._ffi.cast("NAME_CONSTRAINTS *", nc) + nc = backend._ffi.gc(nc, backend._lib.NAME_CONSTRAINTS_free) + permitted = _decode_general_subtrees(backend, nc.permittedSubtrees) + excluded = _decode_general_subtrees(backend, nc.excludedSubtrees) + return x509.NameConstraints( + permitted_subtrees=permitted, excluded_subtrees=excluded + ) + + +def _decode_general_subtrees(backend, stack_subtrees): + if stack_subtrees == backend._ffi.NULL: + return None + + num = backend._lib.sk_GENERAL_SUBTREE_num(stack_subtrees) + subtrees = [] + + for i in range(num): + obj = backend._lib.sk_GENERAL_SUBTREE_value(stack_subtrees, i) + backend.openssl_assert(obj != backend._ffi.NULL) + name = _decode_general_name(backend, obj.base) + subtrees.append(name) + + return subtrees + + +def _decode_issuing_dist_point(backend, idp): + idp = backend._ffi.cast("ISSUING_DIST_POINT *", idp) + idp = backend._ffi.gc(idp, backend._lib.ISSUING_DIST_POINT_free) + if idp.distpoint != backend._ffi.NULL: + full_name, relative_name = _decode_distpoint(backend, idp.distpoint) + else: + full_name = None + relative_name = None + + only_user = idp.onlyuser == 255 + only_ca = idp.onlyCA == 255 + indirect_crl = idp.indirectCRL == 255 + only_attr = idp.onlyattr == 255 + if idp.onlysomereasons != backend._ffi.NULL: + only_some_reasons = _decode_reasons(backend, idp.onlysomereasons) + else: + only_some_reasons = None + + return x509.IssuingDistributionPoint( + full_name, + relative_name, + only_user, + only_ca, + only_some_reasons, + indirect_crl, + only_attr, + ) + + +def _decode_policy_constraints(backend, pc): + pc = backend._ffi.cast("POLICY_CONSTRAINTS *", pc) + pc = backend._ffi.gc(pc, backend._lib.POLICY_CONSTRAINTS_free) + + require_explicit_policy = _asn1_integer_to_int_or_none( + backend, pc.requireExplicitPolicy + ) + inhibit_policy_mapping = _asn1_integer_to_int_or_none( + backend, pc.inhibitPolicyMapping + ) + + return x509.PolicyConstraints( + require_explicit_policy, inhibit_policy_mapping + ) + + +def _decode_extended_key_usage(backend, sk): + sk = backend._ffi.cast("Cryptography_STACK_OF_ASN1_OBJECT *", sk) + sk = backend._ffi.gc(sk, backend._lib.sk_ASN1_OBJECT_free) + num = backend._lib.sk_ASN1_OBJECT_num(sk) + ekus = [] + + for i in range(num): + obj = backend._lib.sk_ASN1_OBJECT_value(sk, i) + backend.openssl_assert(obj != backend._ffi.NULL) + oid = x509.ObjectIdentifier(_obj2txt(backend, obj)) + ekus.append(oid) + + return x509.ExtendedKeyUsage(ekus) + + +_DISTPOINT_TYPE_FULLNAME = 0 +_DISTPOINT_TYPE_RELATIVENAME = 1 + + +def _decode_dist_points(backend, cdps): + cdps = backend._ffi.cast("Cryptography_STACK_OF_DIST_POINT *", cdps) + cdps = backend._ffi.gc(cdps, backend._lib.CRL_DIST_POINTS_free) + + num = backend._lib.sk_DIST_POINT_num(cdps) + dist_points = [] + for i in range(num): + full_name = None + relative_name = None + crl_issuer = None + reasons = None + cdp = backend._lib.sk_DIST_POINT_value(cdps, i) + if cdp.reasons != backend._ffi.NULL: + reasons = _decode_reasons(backend, cdp.reasons) + + if cdp.CRLissuer != backend._ffi.NULL: + crl_issuer = _decode_general_names(backend, cdp.CRLissuer) + + # Certificates may have a crl_issuer/reasons and no distribution + # point so make sure it's not null. + if cdp.distpoint != backend._ffi.NULL: + full_name, relative_name = _decode_distpoint( + backend, cdp.distpoint + ) + + dist_points.append( + x509.DistributionPoint( + full_name, relative_name, reasons, crl_issuer + ) + ) + + return dist_points + + +# ReasonFlags ::= BIT STRING { +# unused (0), +# keyCompromise (1), +# cACompromise (2), +# affiliationChanged (3), +# superseded (4), +# cessationOfOperation (5), +# certificateHold (6), +# privilegeWithdrawn (7), +# aACompromise (8) } +_REASON_BIT_MAPPING = { + 1: x509.ReasonFlags.key_compromise, + 2: x509.ReasonFlags.ca_compromise, + 3: x509.ReasonFlags.affiliation_changed, + 4: x509.ReasonFlags.superseded, + 5: x509.ReasonFlags.cessation_of_operation, + 6: x509.ReasonFlags.certificate_hold, + 7: x509.ReasonFlags.privilege_withdrawn, + 8: x509.ReasonFlags.aa_compromise, +} + + +def _decode_reasons(backend, reasons): + # We will check each bit from RFC 5280 + enum_reasons = [] + for bit_position, reason in six.iteritems(_REASON_BIT_MAPPING): + if backend._lib.ASN1_BIT_STRING_get_bit(reasons, bit_position): + enum_reasons.append(reason) + + return frozenset(enum_reasons) + + +def _decode_distpoint(backend, distpoint): + if distpoint.type == _DISTPOINT_TYPE_FULLNAME: + full_name = _decode_general_names(backend, distpoint.name.fullname) + return full_name, None + + # OpenSSL code doesn't test for a specific type for + # relativename, everything that isn't fullname is considered + # relativename. Per RFC 5280: + # + # DistributionPointName ::= CHOICE { + # fullName [0] GeneralNames, + # nameRelativeToCRLIssuer [1] RelativeDistinguishedName } + rns = distpoint.name.relativename + rnum = backend._lib.sk_X509_NAME_ENTRY_num(rns) + attributes = set() + for i in range(rnum): + rn = backend._lib.sk_X509_NAME_ENTRY_value(rns, i) + backend.openssl_assert(rn != backend._ffi.NULL) + attributes.add(_decode_x509_name_entry(backend, rn)) + + relative_name = x509.RelativeDistinguishedName(attributes) + + return None, relative_name + + +def _decode_crl_distribution_points(backend, cdps): + dist_points = _decode_dist_points(backend, cdps) + return x509.CRLDistributionPoints(dist_points) + + +def _decode_freshest_crl(backend, cdps): + dist_points = _decode_dist_points(backend, cdps) + return x509.FreshestCRL(dist_points) + + +def _decode_inhibit_any_policy(backend, asn1_int): + asn1_int = backend._ffi.cast("ASN1_INTEGER *", asn1_int) + asn1_int = backend._ffi.gc(asn1_int, backend._lib.ASN1_INTEGER_free) + skip_certs = _asn1_integer_to_int(backend, asn1_int) + return x509.InhibitAnyPolicy(skip_certs) + + +def _decode_scts(backend, asn1_scts): + from cryptography.hazmat.backends.openssl.x509 import ( + _SignedCertificateTimestamp, + ) + + asn1_scts = backend._ffi.cast("Cryptography_STACK_OF_SCT *", asn1_scts) + asn1_scts = backend._ffi.gc(asn1_scts, backend._lib.SCT_LIST_free) + + scts = [] + for i in range(backend._lib.sk_SCT_num(asn1_scts)): + sct = backend._lib.sk_SCT_value(asn1_scts, i) + + scts.append(_SignedCertificateTimestamp(backend, asn1_scts, sct)) + return scts + + +def _decode_precert_signed_certificate_timestamps(backend, asn1_scts): + return x509.PrecertificateSignedCertificateTimestamps( + _decode_scts(backend, asn1_scts) + ) + + +def _decode_signed_certificate_timestamps(backend, asn1_scts): + return x509.SignedCertificateTimestamps(_decode_scts(backend, asn1_scts)) + + +# CRLReason ::= ENUMERATED { +# unspecified (0), +# keyCompromise (1), +# cACompromise (2), +# affiliationChanged (3), +# superseded (4), +# cessationOfOperation (5), +# certificateHold (6), +# -- value 7 is not used +# removeFromCRL (8), +# privilegeWithdrawn (9), +# aACompromise (10) } +_CRL_ENTRY_REASON_CODE_TO_ENUM = { + 0: x509.ReasonFlags.unspecified, + 1: x509.ReasonFlags.key_compromise, + 2: x509.ReasonFlags.ca_compromise, + 3: x509.ReasonFlags.affiliation_changed, + 4: x509.ReasonFlags.superseded, + 5: x509.ReasonFlags.cessation_of_operation, + 6: x509.ReasonFlags.certificate_hold, + 8: x509.ReasonFlags.remove_from_crl, + 9: x509.ReasonFlags.privilege_withdrawn, + 10: x509.ReasonFlags.aa_compromise, +} + + +_CRL_ENTRY_REASON_ENUM_TO_CODE = { + x509.ReasonFlags.unspecified: 0, + x509.ReasonFlags.key_compromise: 1, + x509.ReasonFlags.ca_compromise: 2, + x509.ReasonFlags.affiliation_changed: 3, + x509.ReasonFlags.superseded: 4, + x509.ReasonFlags.cessation_of_operation: 5, + x509.ReasonFlags.certificate_hold: 6, + x509.ReasonFlags.remove_from_crl: 8, + x509.ReasonFlags.privilege_withdrawn: 9, + x509.ReasonFlags.aa_compromise: 10, +} + + +def _decode_crl_reason(backend, enum): + enum = backend._ffi.cast("ASN1_ENUMERATED *", enum) + enum = backend._ffi.gc(enum, backend._lib.ASN1_ENUMERATED_free) + code = backend._lib.ASN1_ENUMERATED_get(enum) + + try: + return x509.CRLReason(_CRL_ENTRY_REASON_CODE_TO_ENUM[code]) + except KeyError: + raise ValueError("Unsupported reason code: {}".format(code)) + + +def _decode_invalidity_date(backend, inv_date): + generalized_time = backend._ffi.cast("ASN1_GENERALIZEDTIME *", inv_date) + generalized_time = backend._ffi.gc( + generalized_time, backend._lib.ASN1_GENERALIZEDTIME_free + ) + return x509.InvalidityDate( + _parse_asn1_generalized_time(backend, generalized_time) + ) + + +def _decode_cert_issuer(backend, gns): + gns = backend._ffi.cast("GENERAL_NAMES *", gns) + gns = backend._ffi.gc(gns, backend._lib.GENERAL_NAMES_free) + general_names = _decode_general_names(backend, gns) + return x509.CertificateIssuer(general_names) + + +def _asn1_to_der(backend, asn1_type): + buf = backend._ffi.new("unsigned char **") + res = backend._lib.i2d_ASN1_TYPE(asn1_type, buf) + backend.openssl_assert(res >= 0) + backend.openssl_assert(buf[0] != backend._ffi.NULL) + buf = backend._ffi.gc( + buf, lambda buffer: backend._lib.OPENSSL_free(buffer[0]) + ) + return backend._ffi.buffer(buf[0], res)[:] + + +def _asn1_integer_to_int(backend, asn1_int): + bn = backend._lib.ASN1_INTEGER_to_BN(asn1_int, backend._ffi.NULL) + backend.openssl_assert(bn != backend._ffi.NULL) + bn = backend._ffi.gc(bn, backend._lib.BN_free) + return backend._bn_to_int(bn) + + +def _asn1_integer_to_int_or_none(backend, asn1_int): + if asn1_int == backend._ffi.NULL: + return None + else: + return _asn1_integer_to_int(backend, asn1_int) + + +def _asn1_string_to_bytes(backend, asn1_string): + return backend._ffi.buffer(asn1_string.data, asn1_string.length)[:] + + +def _asn1_string_to_ascii(backend, asn1_string): + return _asn1_string_to_bytes(backend, asn1_string).decode("ascii") + + +def _asn1_string_to_utf8(backend, asn1_string): + buf = backend._ffi.new("unsigned char **") + res = backend._lib.ASN1_STRING_to_UTF8(buf, asn1_string) + if res == -1: + raise ValueError( + "Unsupported ASN1 string type. Type: {}".format(asn1_string.type) + ) + + backend.openssl_assert(buf[0] != backend._ffi.NULL) + buf = backend._ffi.gc( + buf, lambda buffer: backend._lib.OPENSSL_free(buffer[0]) + ) + return backend._ffi.buffer(buf[0], res)[:].decode("utf8") + + +def _parse_asn1_time(backend, asn1_time): + backend.openssl_assert(asn1_time != backend._ffi.NULL) + generalized_time = backend._lib.ASN1_TIME_to_generalizedtime( + asn1_time, backend._ffi.NULL + ) + if generalized_time == backend._ffi.NULL: + raise ValueError( + "Couldn't parse ASN.1 time as generalizedtime {!r}".format( + _asn1_string_to_bytes(backend, asn1_time) + ) + ) + + generalized_time = backend._ffi.gc( + generalized_time, backend._lib.ASN1_GENERALIZEDTIME_free + ) + return _parse_asn1_generalized_time(backend, generalized_time) + + +def _parse_asn1_generalized_time(backend, generalized_time): + time = _asn1_string_to_ascii( + backend, backend._ffi.cast("ASN1_STRING *", generalized_time) + ) + return datetime.datetime.strptime(time, "%Y%m%d%H%M%SZ") + + +def _decode_nonce(backend, nonce): + nonce = backend._ffi.cast("ASN1_OCTET_STRING *", nonce) + nonce = backend._ffi.gc(nonce, backend._lib.ASN1_OCTET_STRING_free) + return x509.OCSPNonce(_asn1_string_to_bytes(backend, nonce)) + + +_EXTENSION_HANDLERS_BASE = { + ExtensionOID.BASIC_CONSTRAINTS: _decode_basic_constraints, + ExtensionOID.SUBJECT_KEY_IDENTIFIER: _decode_subject_key_identifier, + ExtensionOID.KEY_USAGE: _decode_key_usage, + ExtensionOID.SUBJECT_ALTERNATIVE_NAME: _decode_subject_alt_name, + ExtensionOID.EXTENDED_KEY_USAGE: _decode_extended_key_usage, + ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _decode_authority_key_identifier, + ExtensionOID.AUTHORITY_INFORMATION_ACCESS: ( + _decode_authority_information_access + ), + ExtensionOID.SUBJECT_INFORMATION_ACCESS: ( + _decode_subject_information_access + ), + ExtensionOID.CERTIFICATE_POLICIES: _decode_certificate_policies, + ExtensionOID.CRL_DISTRIBUTION_POINTS: _decode_crl_distribution_points, + ExtensionOID.FRESHEST_CRL: _decode_freshest_crl, + ExtensionOID.OCSP_NO_CHECK: _decode_ocsp_no_check, + ExtensionOID.INHIBIT_ANY_POLICY: _decode_inhibit_any_policy, + ExtensionOID.ISSUER_ALTERNATIVE_NAME: _decode_issuer_alt_name, + ExtensionOID.NAME_CONSTRAINTS: _decode_name_constraints, + ExtensionOID.POLICY_CONSTRAINTS: _decode_policy_constraints, +} +_EXTENSION_HANDLERS_SCT = { + ExtensionOID.PRECERT_SIGNED_CERTIFICATE_TIMESTAMPS: ( + _decode_precert_signed_certificate_timestamps + ) +} + +_REVOKED_EXTENSION_HANDLERS = { + CRLEntryExtensionOID.CRL_REASON: _decode_crl_reason, + CRLEntryExtensionOID.INVALIDITY_DATE: _decode_invalidity_date, + CRLEntryExtensionOID.CERTIFICATE_ISSUER: _decode_cert_issuer, +} + +_CRL_EXTENSION_HANDLERS = { + ExtensionOID.CRL_NUMBER: _decode_crl_number, + ExtensionOID.DELTA_CRL_INDICATOR: _decode_delta_crl_indicator, + ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _decode_authority_key_identifier, + ExtensionOID.ISSUER_ALTERNATIVE_NAME: _decode_issuer_alt_name, + ExtensionOID.AUTHORITY_INFORMATION_ACCESS: ( + _decode_authority_information_access + ), + ExtensionOID.ISSUING_DISTRIBUTION_POINT: _decode_issuing_dist_point, + ExtensionOID.FRESHEST_CRL: _decode_freshest_crl, +} + +_OCSP_REQ_EXTENSION_HANDLERS = { + OCSPExtensionOID.NONCE: _decode_nonce, +} + +_OCSP_BASICRESP_EXTENSION_HANDLERS = { + OCSPExtensionOID.NONCE: _decode_nonce, +} + +_OCSP_SINGLERESP_EXTENSION_HANDLERS_SCT = { + ExtensionOID.SIGNED_CERTIFICATE_TIMESTAMPS: ( + _decode_signed_certificate_timestamps + ) +} diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/dh.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/dh.py new file mode 100644 index 0000000..2862676 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/dh.py @@ -0,0 +1,271 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography import utils +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric import dh + + +def _dh_params_dup(dh_cdata, backend): + lib = backend._lib + ffi = backend._ffi + + param_cdata = lib.DHparams_dup(dh_cdata) + backend.openssl_assert(param_cdata != ffi.NULL) + param_cdata = ffi.gc(param_cdata, lib.DH_free) + if lib.CRYPTOGRAPHY_IS_LIBRESSL: + # In libressl DHparams_dup don't copy q + q = ffi.new("BIGNUM **") + lib.DH_get0_pqg(dh_cdata, ffi.NULL, q, ffi.NULL) + q_dup = lib.BN_dup(q[0]) + res = lib.DH_set0_pqg(param_cdata, ffi.NULL, q_dup, ffi.NULL) + backend.openssl_assert(res == 1) + + return param_cdata + + +def _dh_cdata_to_parameters(dh_cdata, backend): + param_cdata = _dh_params_dup(dh_cdata, backend) + return _DHParameters(backend, param_cdata) + + +@utils.register_interface(dh.DHParametersWithSerialization) +class _DHParameters(object): + def __init__(self, backend, dh_cdata): + self._backend = backend + self._dh_cdata = dh_cdata + + def parameter_numbers(self): + p = self._backend._ffi.new("BIGNUM **") + g = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) + if q[0] == self._backend._ffi.NULL: + q_val = None + else: + q_val = self._backend._bn_to_int(q[0]) + return dh.DHParameterNumbers( + p=self._backend._bn_to_int(p[0]), + g=self._backend._bn_to_int(g[0]), + q=q_val, + ) + + def generate_private_key(self): + return self._backend.generate_dh_private_key(self) + + def parameter_bytes(self, encoding, format): + if format is not serialization.ParameterFormat.PKCS3: + raise ValueError("Only PKCS3 serialization is supported") + if not self._backend._lib.Cryptography_HAS_EVP_PKEY_DHX: + q = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_pqg( + self._dh_cdata, + self._backend._ffi.NULL, + q, + self._backend._ffi.NULL, + ) + if q[0] != self._backend._ffi.NULL: + raise UnsupportedAlgorithm( + "DH X9.42 serialization is not supported", + _Reasons.UNSUPPORTED_SERIALIZATION, + ) + + return self._backend._parameter_bytes(encoding, format, self._dh_cdata) + + +def _get_dh_num_bits(backend, dh_cdata): + p = backend._ffi.new("BIGNUM **") + backend._lib.DH_get0_pqg(dh_cdata, p, backend._ffi.NULL, backend._ffi.NULL) + backend.openssl_assert(p[0] != backend._ffi.NULL) + return backend._lib.BN_num_bits(p[0]) + + +@utils.register_interface(dh.DHPrivateKeyWithSerialization) +class _DHPrivateKey(object): + def __init__(self, backend, dh_cdata, evp_pkey): + self._backend = backend + self._dh_cdata = dh_cdata + self._evp_pkey = evp_pkey + self._key_size_bytes = self._backend._lib.DH_size(dh_cdata) + + @property + def key_size(self): + return _get_dh_num_bits(self._backend, self._dh_cdata) + + def private_numbers(self): + p = self._backend._ffi.new("BIGNUM **") + g = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) + if q[0] == self._backend._ffi.NULL: + q_val = None + else: + q_val = self._backend._bn_to_int(q[0]) + pub_key = self._backend._ffi.new("BIGNUM **") + priv_key = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_key(self._dh_cdata, pub_key, priv_key) + self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(priv_key[0] != self._backend._ffi.NULL) + return dh.DHPrivateNumbers( + public_numbers=dh.DHPublicNumbers( + parameter_numbers=dh.DHParameterNumbers( + p=self._backend._bn_to_int(p[0]), + g=self._backend._bn_to_int(g[0]), + q=q_val, + ), + y=self._backend._bn_to_int(pub_key[0]), + ), + x=self._backend._bn_to_int(priv_key[0]), + ) + + def exchange(self, peer_public_key): + + buf = self._backend._ffi.new("unsigned char[]", self._key_size_bytes) + pub_key = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_key( + peer_public_key._dh_cdata, pub_key, self._backend._ffi.NULL + ) + self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) + res = self._backend._lib.DH_compute_key( + buf, pub_key[0], self._dh_cdata + ) + + if res == -1: + errors_with_text = self._backend._consume_errors_with_text() + raise ValueError( + "Error computing shared key. Public key is likely invalid " + "for this exchange.", + errors_with_text, + ) + else: + self._backend.openssl_assert(res >= 1) + + key = self._backend._ffi.buffer(buf)[:res] + pad = self._key_size_bytes - len(key) + + if pad > 0: + key = (b"\x00" * pad) + key + + return key + + def public_key(self): + dh_cdata = _dh_params_dup(self._dh_cdata, self._backend) + pub_key = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_key( + self._dh_cdata, pub_key, self._backend._ffi.NULL + ) + self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) + pub_key_dup = self._backend._lib.BN_dup(pub_key[0]) + self._backend.openssl_assert(pub_key_dup != self._backend._ffi.NULL) + + res = self._backend._lib.DH_set0_key( + dh_cdata, pub_key_dup, self._backend._ffi.NULL + ) + self._backend.openssl_assert(res == 1) + evp_pkey = self._backend._dh_cdata_to_evp_pkey(dh_cdata) + return _DHPublicKey(self._backend, dh_cdata, evp_pkey) + + def parameters(self): + return _dh_cdata_to_parameters(self._dh_cdata, self._backend) + + def private_bytes(self, encoding, format, encryption_algorithm): + if format is not serialization.PrivateFormat.PKCS8: + raise ValueError( + "DH private keys support only PKCS8 serialization" + ) + if not self._backend._lib.Cryptography_HAS_EVP_PKEY_DHX: + q = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_pqg( + self._dh_cdata, + self._backend._ffi.NULL, + q, + self._backend._ffi.NULL, + ) + if q[0] != self._backend._ffi.NULL: + raise UnsupportedAlgorithm( + "DH X9.42 serialization is not supported", + _Reasons.UNSUPPORTED_SERIALIZATION, + ) + + return self._backend._private_key_bytes( + encoding, + format, + encryption_algorithm, + self, + self._evp_pkey, + self._dh_cdata, + ) + + +@utils.register_interface(dh.DHPublicKeyWithSerialization) +class _DHPublicKey(object): + def __init__(self, backend, dh_cdata, evp_pkey): + self._backend = backend + self._dh_cdata = dh_cdata + self._evp_pkey = evp_pkey + self._key_size_bits = _get_dh_num_bits(self._backend, self._dh_cdata) + + @property + def key_size(self): + return self._key_size_bits + + def public_numbers(self): + p = self._backend._ffi.new("BIGNUM **") + g = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_pqg(self._dh_cdata, p, q, g) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) + if q[0] == self._backend._ffi.NULL: + q_val = None + else: + q_val = self._backend._bn_to_int(q[0]) + pub_key = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_key( + self._dh_cdata, pub_key, self._backend._ffi.NULL + ) + self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) + return dh.DHPublicNumbers( + parameter_numbers=dh.DHParameterNumbers( + p=self._backend._bn_to_int(p[0]), + g=self._backend._bn_to_int(g[0]), + q=q_val, + ), + y=self._backend._bn_to_int(pub_key[0]), + ) + + def parameters(self): + return _dh_cdata_to_parameters(self._dh_cdata, self._backend) + + def public_bytes(self, encoding, format): + if format is not serialization.PublicFormat.SubjectPublicKeyInfo: + raise ValueError( + "DH public keys support only " + "SubjectPublicKeyInfo serialization" + ) + + if not self._backend._lib.Cryptography_HAS_EVP_PKEY_DHX: + q = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DH_get0_pqg( + self._dh_cdata, + self._backend._ffi.NULL, + q, + self._backend._ffi.NULL, + ) + if q[0] != self._backend._ffi.NULL: + raise UnsupportedAlgorithm( + "DH X9.42 serialization is not supported", + _Reasons.UNSUPPORTED_SERIALIZATION, + ) + + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, None + ) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/dsa.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/dsa.py new file mode 100644 index 0000000..0c5faba --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/dsa.py @@ -0,0 +1,263 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography import utils +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.backends.openssl.utils import ( + _calculate_digest_and_algorithm, + _check_not_prehashed, + _warn_sign_verify_deprecated, +) +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric import ( + AsymmetricSignatureContext, + AsymmetricVerificationContext, + dsa, +) + + +def _dsa_sig_sign(backend, private_key, data): + sig_buf_len = backend._lib.DSA_size(private_key._dsa_cdata) + sig_buf = backend._ffi.new("unsigned char[]", sig_buf_len) + buflen = backend._ffi.new("unsigned int *") + + # The first parameter passed to DSA_sign is unused by OpenSSL but + # must be an integer. + res = backend._lib.DSA_sign( + 0, data, len(data), sig_buf, buflen, private_key._dsa_cdata + ) + backend.openssl_assert(res == 1) + backend.openssl_assert(buflen[0]) + + return backend._ffi.buffer(sig_buf)[: buflen[0]] + + +def _dsa_sig_verify(backend, public_key, signature, data): + # The first parameter passed to DSA_verify is unused by OpenSSL but + # must be an integer. + res = backend._lib.DSA_verify( + 0, data, len(data), signature, len(signature), public_key._dsa_cdata + ) + + if res != 1: + backend._consume_errors() + raise InvalidSignature + + +@utils.register_interface(AsymmetricVerificationContext) +class _DSAVerificationContext(object): + def __init__(self, backend, public_key, signature, algorithm): + self._backend = backend + self._public_key = public_key + self._signature = signature + self._algorithm = algorithm + + self._hash_ctx = hashes.Hash(self._algorithm, self._backend) + + def update(self, data): + self._hash_ctx.update(data) + + def verify(self): + data_to_verify = self._hash_ctx.finalize() + + _dsa_sig_verify( + self._backend, self._public_key, self._signature, data_to_verify + ) + + +@utils.register_interface(AsymmetricSignatureContext) +class _DSASignatureContext(object): + def __init__(self, backend, private_key, algorithm): + self._backend = backend + self._private_key = private_key + self._algorithm = algorithm + self._hash_ctx = hashes.Hash(self._algorithm, self._backend) + + def update(self, data): + self._hash_ctx.update(data) + + def finalize(self): + data_to_sign = self._hash_ctx.finalize() + return _dsa_sig_sign(self._backend, self._private_key, data_to_sign) + + +@utils.register_interface(dsa.DSAParametersWithNumbers) +class _DSAParameters(object): + def __init__(self, backend, dsa_cdata): + self._backend = backend + self._dsa_cdata = dsa_cdata + + def parameter_numbers(self): + p = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + g = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DSA_get0_pqg(self._dsa_cdata, p, q, g) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(q[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) + return dsa.DSAParameterNumbers( + p=self._backend._bn_to_int(p[0]), + q=self._backend._bn_to_int(q[0]), + g=self._backend._bn_to_int(g[0]), + ) + + def generate_private_key(self): + return self._backend.generate_dsa_private_key(self) + + +@utils.register_interface(dsa.DSAPrivateKeyWithSerialization) +class _DSAPrivateKey(object): + def __init__(self, backend, dsa_cdata, evp_pkey): + self._backend = backend + self._dsa_cdata = dsa_cdata + self._evp_pkey = evp_pkey + + p = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DSA_get0_pqg( + dsa_cdata, p, self._backend._ffi.NULL, self._backend._ffi.NULL + ) + self._backend.openssl_assert(p[0] != backend._ffi.NULL) + self._key_size = self._backend._lib.BN_num_bits(p[0]) + + key_size = utils.read_only_property("_key_size") + + def signer(self, signature_algorithm): + _warn_sign_verify_deprecated() + _check_not_prehashed(signature_algorithm) + return _DSASignatureContext(self._backend, self, signature_algorithm) + + def private_numbers(self): + p = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + g = self._backend._ffi.new("BIGNUM **") + pub_key = self._backend._ffi.new("BIGNUM **") + priv_key = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DSA_get0_pqg(self._dsa_cdata, p, q, g) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(q[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) + self._backend._lib.DSA_get0_key(self._dsa_cdata, pub_key, priv_key) + self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(priv_key[0] != self._backend._ffi.NULL) + return dsa.DSAPrivateNumbers( + public_numbers=dsa.DSAPublicNumbers( + parameter_numbers=dsa.DSAParameterNumbers( + p=self._backend._bn_to_int(p[0]), + q=self._backend._bn_to_int(q[0]), + g=self._backend._bn_to_int(g[0]), + ), + y=self._backend._bn_to_int(pub_key[0]), + ), + x=self._backend._bn_to_int(priv_key[0]), + ) + + def public_key(self): + dsa_cdata = self._backend._lib.DSAparams_dup(self._dsa_cdata) + self._backend.openssl_assert(dsa_cdata != self._backend._ffi.NULL) + dsa_cdata = self._backend._ffi.gc( + dsa_cdata, self._backend._lib.DSA_free + ) + pub_key = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DSA_get0_key( + self._dsa_cdata, pub_key, self._backend._ffi.NULL + ) + self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) + pub_key_dup = self._backend._lib.BN_dup(pub_key[0]) + res = self._backend._lib.DSA_set0_key( + dsa_cdata, pub_key_dup, self._backend._ffi.NULL + ) + self._backend.openssl_assert(res == 1) + evp_pkey = self._backend._dsa_cdata_to_evp_pkey(dsa_cdata) + return _DSAPublicKey(self._backend, dsa_cdata, evp_pkey) + + def parameters(self): + dsa_cdata = self._backend._lib.DSAparams_dup(self._dsa_cdata) + self._backend.openssl_assert(dsa_cdata != self._backend._ffi.NULL) + dsa_cdata = self._backend._ffi.gc( + dsa_cdata, self._backend._lib.DSA_free + ) + return _DSAParameters(self._backend, dsa_cdata) + + def private_bytes(self, encoding, format, encryption_algorithm): + return self._backend._private_key_bytes( + encoding, + format, + encryption_algorithm, + self, + self._evp_pkey, + self._dsa_cdata, + ) + + def sign(self, data, algorithm): + data, algorithm = _calculate_digest_and_algorithm( + self._backend, data, algorithm + ) + return _dsa_sig_sign(self._backend, self, data) + + +@utils.register_interface(dsa.DSAPublicKeyWithSerialization) +class _DSAPublicKey(object): + def __init__(self, backend, dsa_cdata, evp_pkey): + self._backend = backend + self._dsa_cdata = dsa_cdata + self._evp_pkey = evp_pkey + p = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DSA_get0_pqg( + dsa_cdata, p, self._backend._ffi.NULL, self._backend._ffi.NULL + ) + self._backend.openssl_assert(p[0] != backend._ffi.NULL) + self._key_size = self._backend._lib.BN_num_bits(p[0]) + + key_size = utils.read_only_property("_key_size") + + def verifier(self, signature, signature_algorithm): + _warn_sign_verify_deprecated() + utils._check_bytes("signature", signature) + + _check_not_prehashed(signature_algorithm) + return _DSAVerificationContext( + self._backend, self, signature, signature_algorithm + ) + + def public_numbers(self): + p = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + g = self._backend._ffi.new("BIGNUM **") + pub_key = self._backend._ffi.new("BIGNUM **") + self._backend._lib.DSA_get0_pqg(self._dsa_cdata, p, q, g) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(q[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(g[0] != self._backend._ffi.NULL) + self._backend._lib.DSA_get0_key( + self._dsa_cdata, pub_key, self._backend._ffi.NULL + ) + self._backend.openssl_assert(pub_key[0] != self._backend._ffi.NULL) + return dsa.DSAPublicNumbers( + parameter_numbers=dsa.DSAParameterNumbers( + p=self._backend._bn_to_int(p[0]), + q=self._backend._bn_to_int(q[0]), + g=self._backend._bn_to_int(g[0]), + ), + y=self._backend._bn_to_int(pub_key[0]), + ) + + def parameters(self): + dsa_cdata = self._backend._lib.DSAparams_dup(self._dsa_cdata) + dsa_cdata = self._backend._ffi.gc( + dsa_cdata, self._backend._lib.DSA_free + ) + return _DSAParameters(self._backend, dsa_cdata) + + def public_bytes(self, encoding, format): + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, None + ) + + def verify(self, signature, data, algorithm): + data, algorithm = _calculate_digest_and_algorithm( + self._backend, data, algorithm + ) + return _dsa_sig_verify(self._backend, self, signature, data) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/ec.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/ec.py new file mode 100644 index 0000000..bf61bcf --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/ec.py @@ -0,0 +1,337 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography import utils +from cryptography.exceptions import ( + InvalidSignature, + UnsupportedAlgorithm, + _Reasons, +) +from cryptography.hazmat.backends.openssl.utils import ( + _calculate_digest_and_algorithm, + _check_not_prehashed, + _warn_sign_verify_deprecated, +) +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import ( + AsymmetricSignatureContext, + AsymmetricVerificationContext, + ec, +) + + +def _check_signature_algorithm(signature_algorithm): + if not isinstance(signature_algorithm, ec.ECDSA): + raise UnsupportedAlgorithm( + "Unsupported elliptic curve signature algorithm.", + _Reasons.UNSUPPORTED_PUBLIC_KEY_ALGORITHM, + ) + + +def _ec_key_curve_sn(backend, ec_key): + group = backend._lib.EC_KEY_get0_group(ec_key) + backend.openssl_assert(group != backend._ffi.NULL) + + nid = backend._lib.EC_GROUP_get_curve_name(group) + # The following check is to find EC keys with unnamed curves and raise + # an error for now. + if nid == backend._lib.NID_undef: + raise NotImplementedError( + "ECDSA keys with unnamed curves are unsupported " "at this time" + ) + + # This is like the above check, but it also catches the case where you + # explicitly encoded a curve with the same parameters as a named curve. + # Don't do that. + if ( + backend._lib.CRYPTOGRAPHY_OPENSSL_102U_OR_GREATER + and backend._lib.EC_GROUP_get_asn1_flag(group) == 0 + ): + raise NotImplementedError( + "ECDSA keys with unnamed curves are unsupported " "at this time" + ) + + curve_name = backend._lib.OBJ_nid2sn(nid) + backend.openssl_assert(curve_name != backend._ffi.NULL) + + sn = backend._ffi.string(curve_name).decode("ascii") + return sn + + +def _mark_asn1_named_ec_curve(backend, ec_cdata): + """ + Set the named curve flag on the EC_KEY. This causes OpenSSL to + serialize EC keys along with their curve OID which makes + deserialization easier. + """ + + backend._lib.EC_KEY_set_asn1_flag( + ec_cdata, backend._lib.OPENSSL_EC_NAMED_CURVE + ) + + +def _sn_to_elliptic_curve(backend, sn): + try: + return ec._CURVE_TYPES[sn]() + except KeyError: + raise UnsupportedAlgorithm( + "{} is not a supported elliptic curve".format(sn), + _Reasons.UNSUPPORTED_ELLIPTIC_CURVE, + ) + + +def _ecdsa_sig_sign(backend, private_key, data): + max_size = backend._lib.ECDSA_size(private_key._ec_key) + backend.openssl_assert(max_size > 0) + + sigbuf = backend._ffi.new("unsigned char[]", max_size) + siglen_ptr = backend._ffi.new("unsigned int[]", 1) + res = backend._lib.ECDSA_sign( + 0, data, len(data), sigbuf, siglen_ptr, private_key._ec_key + ) + backend.openssl_assert(res == 1) + return backend._ffi.buffer(sigbuf)[: siglen_ptr[0]] + + +def _ecdsa_sig_verify(backend, public_key, signature, data): + res = backend._lib.ECDSA_verify( + 0, data, len(data), signature, len(signature), public_key._ec_key + ) + if res != 1: + backend._consume_errors() + raise InvalidSignature + + +@utils.register_interface(AsymmetricSignatureContext) +class _ECDSASignatureContext(object): + def __init__(self, backend, private_key, algorithm): + self._backend = backend + self._private_key = private_key + self._digest = hashes.Hash(algorithm, backend) + + def update(self, data): + self._digest.update(data) + + def finalize(self): + digest = self._digest.finalize() + + return _ecdsa_sig_sign(self._backend, self._private_key, digest) + + +@utils.register_interface(AsymmetricVerificationContext) +class _ECDSAVerificationContext(object): + def __init__(self, backend, public_key, signature, algorithm): + self._backend = backend + self._public_key = public_key + self._signature = signature + self._digest = hashes.Hash(algorithm, backend) + + def update(self, data): + self._digest.update(data) + + def verify(self): + digest = self._digest.finalize() + _ecdsa_sig_verify( + self._backend, self._public_key, self._signature, digest + ) + + +@utils.register_interface(ec.EllipticCurvePrivateKeyWithSerialization) +class _EllipticCurvePrivateKey(object): + def __init__(self, backend, ec_key_cdata, evp_pkey): + self._backend = backend + self._ec_key = ec_key_cdata + self._evp_pkey = evp_pkey + + sn = _ec_key_curve_sn(backend, ec_key_cdata) + self._curve = _sn_to_elliptic_curve(backend, sn) + _mark_asn1_named_ec_curve(backend, ec_key_cdata) + + curve = utils.read_only_property("_curve") + + @property + def key_size(self): + return self.curve.key_size + + def signer(self, signature_algorithm): + _warn_sign_verify_deprecated() + _check_signature_algorithm(signature_algorithm) + _check_not_prehashed(signature_algorithm.algorithm) + return _ECDSASignatureContext( + self._backend, self, signature_algorithm.algorithm + ) + + def exchange(self, algorithm, peer_public_key): + if not ( + self._backend.elliptic_curve_exchange_algorithm_supported( + algorithm, self.curve + ) + ): + raise UnsupportedAlgorithm( + "This backend does not support the ECDH algorithm.", + _Reasons.UNSUPPORTED_EXCHANGE_ALGORITHM, + ) + + if peer_public_key.curve.name != self.curve.name: + raise ValueError( + "peer_public_key and self are not on the same curve" + ) + + group = self._backend._lib.EC_KEY_get0_group(self._ec_key) + z_len = (self._backend._lib.EC_GROUP_get_degree(group) + 7) // 8 + self._backend.openssl_assert(z_len > 0) + z_buf = self._backend._ffi.new("uint8_t[]", z_len) + peer_key = self._backend._lib.EC_KEY_get0_public_key( + peer_public_key._ec_key + ) + + r = self._backend._lib.ECDH_compute_key( + z_buf, z_len, peer_key, self._ec_key, self._backend._ffi.NULL + ) + self._backend.openssl_assert(r > 0) + return self._backend._ffi.buffer(z_buf)[:z_len] + + def public_key(self): + group = self._backend._lib.EC_KEY_get0_group(self._ec_key) + self._backend.openssl_assert(group != self._backend._ffi.NULL) + + curve_nid = self._backend._lib.EC_GROUP_get_curve_name(group) + public_ec_key = self._backend._ec_key_new_by_curve_nid(curve_nid) + + point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key) + self._backend.openssl_assert(point != self._backend._ffi.NULL) + + res = self._backend._lib.EC_KEY_set_public_key(public_ec_key, point) + self._backend.openssl_assert(res == 1) + + evp_pkey = self._backend._ec_cdata_to_evp_pkey(public_ec_key) + + return _EllipticCurvePublicKey(self._backend, public_ec_key, evp_pkey) + + def private_numbers(self): + bn = self._backend._lib.EC_KEY_get0_private_key(self._ec_key) + private_value = self._backend._bn_to_int(bn) + return ec.EllipticCurvePrivateNumbers( + private_value=private_value, + public_numbers=self.public_key().public_numbers(), + ) + + def private_bytes(self, encoding, format, encryption_algorithm): + return self._backend._private_key_bytes( + encoding, + format, + encryption_algorithm, + self, + self._evp_pkey, + self._ec_key, + ) + + def sign(self, data, signature_algorithm): + _check_signature_algorithm(signature_algorithm) + data, algorithm = _calculate_digest_and_algorithm( + self._backend, data, signature_algorithm._algorithm + ) + return _ecdsa_sig_sign(self._backend, self, data) + + +@utils.register_interface(ec.EllipticCurvePublicKeyWithSerialization) +class _EllipticCurvePublicKey(object): + def __init__(self, backend, ec_key_cdata, evp_pkey): + self._backend = backend + self._ec_key = ec_key_cdata + self._evp_pkey = evp_pkey + + sn = _ec_key_curve_sn(backend, ec_key_cdata) + self._curve = _sn_to_elliptic_curve(backend, sn) + _mark_asn1_named_ec_curve(backend, ec_key_cdata) + + curve = utils.read_only_property("_curve") + + @property + def key_size(self): + return self.curve.key_size + + def verifier(self, signature, signature_algorithm): + _warn_sign_verify_deprecated() + utils._check_bytes("signature", signature) + + _check_signature_algorithm(signature_algorithm) + _check_not_prehashed(signature_algorithm.algorithm) + return _ECDSAVerificationContext( + self._backend, self, signature, signature_algorithm.algorithm + ) + + def public_numbers(self): + get_func, group = self._backend._ec_key_determine_group_get_func( + self._ec_key + ) + point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key) + self._backend.openssl_assert(point != self._backend._ffi.NULL) + + with self._backend._tmp_bn_ctx() as bn_ctx: + bn_x = self._backend._lib.BN_CTX_get(bn_ctx) + bn_y = self._backend._lib.BN_CTX_get(bn_ctx) + + res = get_func(group, point, bn_x, bn_y, bn_ctx) + self._backend.openssl_assert(res == 1) + + x = self._backend._bn_to_int(bn_x) + y = self._backend._bn_to_int(bn_y) + + return ec.EllipticCurvePublicNumbers(x=x, y=y, curve=self._curve) + + def _encode_point(self, format): + if format is serialization.PublicFormat.CompressedPoint: + conversion = self._backend._lib.POINT_CONVERSION_COMPRESSED + else: + assert format is serialization.PublicFormat.UncompressedPoint + conversion = self._backend._lib.POINT_CONVERSION_UNCOMPRESSED + + group = self._backend._lib.EC_KEY_get0_group(self._ec_key) + self._backend.openssl_assert(group != self._backend._ffi.NULL) + point = self._backend._lib.EC_KEY_get0_public_key(self._ec_key) + self._backend.openssl_assert(point != self._backend._ffi.NULL) + with self._backend._tmp_bn_ctx() as bn_ctx: + buflen = self._backend._lib.EC_POINT_point2oct( + group, point, conversion, self._backend._ffi.NULL, 0, bn_ctx + ) + self._backend.openssl_assert(buflen > 0) + buf = self._backend._ffi.new("char[]", buflen) + res = self._backend._lib.EC_POINT_point2oct( + group, point, conversion, buf, buflen, bn_ctx + ) + self._backend.openssl_assert(buflen == res) + + return self._backend._ffi.buffer(buf)[:] + + def public_bytes(self, encoding, format): + + if ( + encoding is serialization.Encoding.X962 + or format is serialization.PublicFormat.CompressedPoint + or format is serialization.PublicFormat.UncompressedPoint + ): + if encoding is not serialization.Encoding.X962 or format not in ( + serialization.PublicFormat.CompressedPoint, + serialization.PublicFormat.UncompressedPoint, + ): + raise ValueError( + "X962 encoding must be used with CompressedPoint or " + "UncompressedPoint format" + ) + + return self._encode_point(format) + else: + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, None + ) + + def verify(self, signature, data, signature_algorithm): + _check_signature_algorithm(signature_algorithm) + data, algorithm = _calculate_digest_and_algorithm( + self._backend, data, signature_algorithm._algorithm + ) + _ecdsa_sig_verify(self._backend, self, signature, data) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/ed25519.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/ed25519.py new file mode 100644 index 0000000..7565337 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/ed25519.py @@ -0,0 +1,145 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography import exceptions, utils +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric.ed25519 import ( + Ed25519PrivateKey, + Ed25519PublicKey, + _ED25519_KEY_SIZE, + _ED25519_SIG_SIZE, +) + + +@utils.register_interface(Ed25519PublicKey) +class _Ed25519PublicKey(object): + def __init__(self, backend, evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_bytes(self, encoding, format): + if ( + encoding is serialization.Encoding.Raw + or format is serialization.PublicFormat.Raw + ): + if ( + encoding is not serialization.Encoding.Raw + or format is not serialization.PublicFormat.Raw + ): + raise ValueError( + "When using Raw both encoding and format must be Raw" + ) + + return self._raw_public_bytes() + + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, None + ) + + def _raw_public_bytes(self): + buf = self._backend._ffi.new("unsigned char []", _ED25519_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED25519_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED25519_KEY_SIZE) + return self._backend._ffi.buffer(buf, _ED25519_KEY_SIZE)[:] + + def verify(self, signature, data): + evp_md_ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new() + self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL) + evp_md_ctx = self._backend._ffi.gc( + evp_md_ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free + ) + res = self._backend._lib.EVP_DigestVerifyInit( + evp_md_ctx, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._evp_pkey, + ) + self._backend.openssl_assert(res == 1) + res = self._backend._lib.EVP_DigestVerify( + evp_md_ctx, signature, len(signature), data, len(data) + ) + if res != 1: + self._backend._consume_errors() + raise exceptions.InvalidSignature + + +@utils.register_interface(Ed25519PrivateKey) +class _Ed25519PrivateKey(object): + def __init__(self, backend, evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_key(self): + buf = self._backend._ffi.new("unsigned char []", _ED25519_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED25519_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED25519_KEY_SIZE) + public_bytes = self._backend._ffi.buffer(buf)[:] + return self._backend.ed25519_load_public_bytes(public_bytes) + + def sign(self, data): + evp_md_ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new() + self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL) + evp_md_ctx = self._backend._ffi.gc( + evp_md_ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free + ) + res = self._backend._lib.EVP_DigestSignInit( + evp_md_ctx, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._evp_pkey, + ) + self._backend.openssl_assert(res == 1) + buf = self._backend._ffi.new("unsigned char[]", _ED25519_SIG_SIZE) + buflen = self._backend._ffi.new("size_t *", len(buf)) + res = self._backend._lib.EVP_DigestSign( + evp_md_ctx, buf, buflen, data, len(data) + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED25519_SIG_SIZE) + return self._backend._ffi.buffer(buf, buflen[0])[:] + + def private_bytes(self, encoding, format, encryption_algorithm): + if ( + encoding is serialization.Encoding.Raw + or format is serialization.PublicFormat.Raw + ): + if ( + format is not serialization.PrivateFormat.Raw + or encoding is not serialization.Encoding.Raw + or not isinstance( + encryption_algorithm, serialization.NoEncryption + ) + ): + raise ValueError( + "When using Raw both encoding and format must be Raw " + "and encryption_algorithm must be NoEncryption()" + ) + + return self._raw_private_bytes() + + return self._backend._private_key_bytes( + encoding, format, encryption_algorithm, self, self._evp_pkey, None + ) + + def _raw_private_bytes(self): + buf = self._backend._ffi.new("unsigned char []", _ED25519_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED25519_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_private_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED25519_KEY_SIZE) + return self._backend._ffi.buffer(buf, _ED25519_KEY_SIZE)[:] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/ed448.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/ed448.py new file mode 100644 index 0000000..4a8dab1 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/ed448.py @@ -0,0 +1,146 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography import exceptions, utils +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric.ed448 import ( + Ed448PrivateKey, + Ed448PublicKey, +) + +_ED448_KEY_SIZE = 57 +_ED448_SIG_SIZE = 114 + + +@utils.register_interface(Ed448PublicKey) +class _Ed448PublicKey(object): + def __init__(self, backend, evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_bytes(self, encoding, format): + if ( + encoding is serialization.Encoding.Raw + or format is serialization.PublicFormat.Raw + ): + if ( + encoding is not serialization.Encoding.Raw + or format is not serialization.PublicFormat.Raw + ): + raise ValueError( + "When using Raw both encoding and format must be Raw" + ) + + return self._raw_public_bytes() + + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, None + ) + + def _raw_public_bytes(self): + buf = self._backend._ffi.new("unsigned char []", _ED448_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED448_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED448_KEY_SIZE) + return self._backend._ffi.buffer(buf, _ED448_KEY_SIZE)[:] + + def verify(self, signature, data): + evp_md_ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new() + self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL) + evp_md_ctx = self._backend._ffi.gc( + evp_md_ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free + ) + res = self._backend._lib.EVP_DigestVerifyInit( + evp_md_ctx, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._evp_pkey, + ) + self._backend.openssl_assert(res == 1) + res = self._backend._lib.EVP_DigestVerify( + evp_md_ctx, signature, len(signature), data, len(data) + ) + if res != 1: + self._backend._consume_errors() + raise exceptions.InvalidSignature + + +@utils.register_interface(Ed448PrivateKey) +class _Ed448PrivateKey(object): + def __init__(self, backend, evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_key(self): + buf = self._backend._ffi.new("unsigned char []", _ED448_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED448_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED448_KEY_SIZE) + public_bytes = self._backend._ffi.buffer(buf)[:] + return self._backend.ed448_load_public_bytes(public_bytes) + + def sign(self, data): + evp_md_ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new() + self._backend.openssl_assert(evp_md_ctx != self._backend._ffi.NULL) + evp_md_ctx = self._backend._ffi.gc( + evp_md_ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free + ) + res = self._backend._lib.EVP_DigestSignInit( + evp_md_ctx, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._evp_pkey, + ) + self._backend.openssl_assert(res == 1) + buf = self._backend._ffi.new("unsigned char[]", _ED448_SIG_SIZE) + buflen = self._backend._ffi.new("size_t *", len(buf)) + res = self._backend._lib.EVP_DigestSign( + evp_md_ctx, buf, buflen, data, len(data) + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED448_SIG_SIZE) + return self._backend._ffi.buffer(buf, buflen[0])[:] + + def private_bytes(self, encoding, format, encryption_algorithm): + if ( + encoding is serialization.Encoding.Raw + or format is serialization.PublicFormat.Raw + ): + if ( + format is not serialization.PrivateFormat.Raw + or encoding is not serialization.Encoding.Raw + or not isinstance( + encryption_algorithm, serialization.NoEncryption + ) + ): + raise ValueError( + "When using Raw both encoding and format must be Raw " + "and encryption_algorithm must be NoEncryption()" + ) + + return self._raw_private_bytes() + + return self._backend._private_key_bytes( + encoding, format, encryption_algorithm, self, self._evp_pkey, None + ) + + def _raw_private_bytes(self): + buf = self._backend._ffi.new("unsigned char []", _ED448_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _ED448_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_private_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _ED448_KEY_SIZE) + return self._backend._ffi.buffer(buf, _ED448_KEY_SIZE)[:] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/encode_asn1.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/encode_asn1.py new file mode 100644 index 0000000..88d709d --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/encode_asn1.py @@ -0,0 +1,657 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import calendar +import ipaddress + +import six + +from cryptography import utils, x509 +from cryptography.hazmat.backends.openssl.decode_asn1 import ( + _CRL_ENTRY_REASON_ENUM_TO_CODE, + _DISTPOINT_TYPE_FULLNAME, + _DISTPOINT_TYPE_RELATIVENAME, +) +from cryptography.x509.name import _ASN1Type +from cryptography.x509.oid import ( + CRLEntryExtensionOID, + ExtensionOID, + OCSPExtensionOID, +) + + +def _encode_asn1_int(backend, x): + """ + Converts a python integer to an ASN1_INTEGER. The returned ASN1_INTEGER + will not be garbage collected (to support adding them to structs that take + ownership of the object). Be sure to register it for GC if it will be + discarded after use. + + """ + # Convert Python integer to OpenSSL "bignum" in case value exceeds + # machine's native integer limits (note: `int_to_bn` doesn't automatically + # GC). + i = backend._int_to_bn(x) + i = backend._ffi.gc(i, backend._lib.BN_free) + + # Wrap in an ASN.1 integer. Don't GC -- as documented. + i = backend._lib.BN_to_ASN1_INTEGER(i, backend._ffi.NULL) + backend.openssl_assert(i != backend._ffi.NULL) + return i + + +def _encode_asn1_int_gc(backend, x): + i = _encode_asn1_int(backend, x) + i = backend._ffi.gc(i, backend._lib.ASN1_INTEGER_free) + return i + + +def _encode_asn1_str(backend, data): + """ + Create an ASN1_OCTET_STRING from a Python byte string. + """ + s = backend._lib.ASN1_OCTET_STRING_new() + res = backend._lib.ASN1_OCTET_STRING_set(s, data, len(data)) + backend.openssl_assert(res == 1) + return s + + +def _encode_asn1_utf8_str(backend, string): + """ + Create an ASN1_UTF8STRING from a Python unicode string. + This object will be an ASN1_STRING with UTF8 type in OpenSSL and + can be decoded with ASN1_STRING_to_UTF8. + """ + s = backend._lib.ASN1_UTF8STRING_new() + res = backend._lib.ASN1_STRING_set( + s, string.encode("utf8"), len(string.encode("utf8")) + ) + backend.openssl_assert(res == 1) + return s + + +def _encode_asn1_str_gc(backend, data): + s = _encode_asn1_str(backend, data) + s = backend._ffi.gc(s, backend._lib.ASN1_OCTET_STRING_free) + return s + + +def _encode_inhibit_any_policy(backend, inhibit_any_policy): + return _encode_asn1_int_gc(backend, inhibit_any_policy.skip_certs) + + +def _encode_name(backend, name): + """ + The X509_NAME created will not be gc'd. Use _encode_name_gc if needed. + """ + subject = backend._lib.X509_NAME_new() + for rdn in name.rdns: + set_flag = 0 # indicate whether to add to last RDN or create new RDN + for attribute in rdn: + name_entry = _encode_name_entry(backend, attribute) + # X509_NAME_add_entry dups the object so we need to gc this copy + name_entry = backend._ffi.gc( + name_entry, backend._lib.X509_NAME_ENTRY_free + ) + res = backend._lib.X509_NAME_add_entry( + subject, name_entry, -1, set_flag + ) + backend.openssl_assert(res == 1) + set_flag = -1 + return subject + + +def _encode_name_gc(backend, attributes): + subject = _encode_name(backend, attributes) + subject = backend._ffi.gc(subject, backend._lib.X509_NAME_free) + return subject + + +def _encode_sk_name_entry(backend, attributes): + """ + The sk_X509_NAME_ENTRY created will not be gc'd. + """ + stack = backend._lib.sk_X509_NAME_ENTRY_new_null() + for attribute in attributes: + name_entry = _encode_name_entry(backend, attribute) + res = backend._lib.sk_X509_NAME_ENTRY_push(stack, name_entry) + backend.openssl_assert(res >= 1) + return stack + + +def _encode_name_entry(backend, attribute): + if attribute._type is _ASN1Type.BMPString: + value = attribute.value.encode("utf_16_be") + elif attribute._type is _ASN1Type.UniversalString: + value = attribute.value.encode("utf_32_be") + else: + value = attribute.value.encode("utf8") + + obj = _txt2obj_gc(backend, attribute.oid.dotted_string) + + name_entry = backend._lib.X509_NAME_ENTRY_create_by_OBJ( + backend._ffi.NULL, obj, attribute._type.value, value, len(value) + ) + return name_entry + + +def _encode_crl_number_delta_crl_indicator(backend, ext): + return _encode_asn1_int_gc(backend, ext.crl_number) + + +def _encode_issuing_dist_point(backend, ext): + idp = backend._lib.ISSUING_DIST_POINT_new() + backend.openssl_assert(idp != backend._ffi.NULL) + idp = backend._ffi.gc(idp, backend._lib.ISSUING_DIST_POINT_free) + idp.onlyuser = 255 if ext.only_contains_user_certs else 0 + idp.onlyCA = 255 if ext.only_contains_ca_certs else 0 + idp.indirectCRL = 255 if ext.indirect_crl else 0 + idp.onlyattr = 255 if ext.only_contains_attribute_certs else 0 + if ext.only_some_reasons: + idp.onlysomereasons = _encode_reasonflags( + backend, ext.only_some_reasons + ) + + if ext.full_name: + idp.distpoint = _encode_full_name(backend, ext.full_name) + + if ext.relative_name: + idp.distpoint = _encode_relative_name(backend, ext.relative_name) + + return idp + + +def _encode_crl_reason(backend, crl_reason): + asn1enum = backend._lib.ASN1_ENUMERATED_new() + backend.openssl_assert(asn1enum != backend._ffi.NULL) + asn1enum = backend._ffi.gc(asn1enum, backend._lib.ASN1_ENUMERATED_free) + res = backend._lib.ASN1_ENUMERATED_set( + asn1enum, _CRL_ENTRY_REASON_ENUM_TO_CODE[crl_reason.reason] + ) + backend.openssl_assert(res == 1) + + return asn1enum + + +def _encode_invalidity_date(backend, invalidity_date): + time = backend._lib.ASN1_GENERALIZEDTIME_set( + backend._ffi.NULL, + calendar.timegm(invalidity_date.invalidity_date.timetuple()), + ) + backend.openssl_assert(time != backend._ffi.NULL) + time = backend._ffi.gc(time, backend._lib.ASN1_GENERALIZEDTIME_free) + + return time + + +def _encode_certificate_policies(backend, certificate_policies): + cp = backend._lib.sk_POLICYINFO_new_null() + backend.openssl_assert(cp != backend._ffi.NULL) + cp = backend._ffi.gc(cp, backend._lib.sk_POLICYINFO_free) + for policy_info in certificate_policies: + pi = backend._lib.POLICYINFO_new() + backend.openssl_assert(pi != backend._ffi.NULL) + res = backend._lib.sk_POLICYINFO_push(cp, pi) + backend.openssl_assert(res >= 1) + oid = _txt2obj(backend, policy_info.policy_identifier.dotted_string) + pi.policyid = oid + if policy_info.policy_qualifiers: + pqis = backend._lib.sk_POLICYQUALINFO_new_null() + backend.openssl_assert(pqis != backend._ffi.NULL) + for qualifier in policy_info.policy_qualifiers: + pqi = backend._lib.POLICYQUALINFO_new() + backend.openssl_assert(pqi != backend._ffi.NULL) + res = backend._lib.sk_POLICYQUALINFO_push(pqis, pqi) + backend.openssl_assert(res >= 1) + if isinstance(qualifier, six.text_type): + pqi.pqualid = _txt2obj( + backend, x509.OID_CPS_QUALIFIER.dotted_string + ) + pqi.d.cpsuri = _encode_asn1_str( + backend, + qualifier.encode("ascii"), + ) + else: + assert isinstance(qualifier, x509.UserNotice) + pqi.pqualid = _txt2obj( + backend, x509.OID_CPS_USER_NOTICE.dotted_string + ) + un = backend._lib.USERNOTICE_new() + backend.openssl_assert(un != backend._ffi.NULL) + pqi.d.usernotice = un + if qualifier.explicit_text: + un.exptext = _encode_asn1_utf8_str( + backend, qualifier.explicit_text + ) + + un.noticeref = _encode_notice_reference( + backend, qualifier.notice_reference + ) + + pi.qualifiers = pqis + + return cp + + +def _encode_notice_reference(backend, notice): + if notice is None: + return backend._ffi.NULL + else: + nr = backend._lib.NOTICEREF_new() + backend.openssl_assert(nr != backend._ffi.NULL) + # organization is a required field + nr.organization = _encode_asn1_utf8_str(backend, notice.organization) + + notice_stack = backend._lib.sk_ASN1_INTEGER_new_null() + nr.noticenos = notice_stack + for number in notice.notice_numbers: + num = _encode_asn1_int(backend, number) + res = backend._lib.sk_ASN1_INTEGER_push(notice_stack, num) + backend.openssl_assert(res >= 1) + + return nr + + +def _txt2obj(backend, name): + """ + Converts a Python string with an ASN.1 object ID in dotted form to a + ASN1_OBJECT. + """ + name = name.encode("ascii") + obj = backend._lib.OBJ_txt2obj(name, 1) + backend.openssl_assert(obj != backend._ffi.NULL) + return obj + + +def _txt2obj_gc(backend, name): + obj = _txt2obj(backend, name) + obj = backend._ffi.gc(obj, backend._lib.ASN1_OBJECT_free) + return obj + + +def _encode_ocsp_nocheck(backend, ext): + # Doesn't need to be GC'd + return backend._lib.ASN1_NULL_new() + + +def _encode_key_usage(backend, key_usage): + set_bit = backend._lib.ASN1_BIT_STRING_set_bit + ku = backend._lib.ASN1_BIT_STRING_new() + ku = backend._ffi.gc(ku, backend._lib.ASN1_BIT_STRING_free) + res = set_bit(ku, 0, key_usage.digital_signature) + backend.openssl_assert(res == 1) + res = set_bit(ku, 1, key_usage.content_commitment) + backend.openssl_assert(res == 1) + res = set_bit(ku, 2, key_usage.key_encipherment) + backend.openssl_assert(res == 1) + res = set_bit(ku, 3, key_usage.data_encipherment) + backend.openssl_assert(res == 1) + res = set_bit(ku, 4, key_usage.key_agreement) + backend.openssl_assert(res == 1) + res = set_bit(ku, 5, key_usage.key_cert_sign) + backend.openssl_assert(res == 1) + res = set_bit(ku, 6, key_usage.crl_sign) + backend.openssl_assert(res == 1) + if key_usage.key_agreement: + res = set_bit(ku, 7, key_usage.encipher_only) + backend.openssl_assert(res == 1) + res = set_bit(ku, 8, key_usage.decipher_only) + backend.openssl_assert(res == 1) + else: + res = set_bit(ku, 7, 0) + backend.openssl_assert(res == 1) + res = set_bit(ku, 8, 0) + backend.openssl_assert(res == 1) + + return ku + + +def _encode_authority_key_identifier(backend, authority_keyid): + akid = backend._lib.AUTHORITY_KEYID_new() + backend.openssl_assert(akid != backend._ffi.NULL) + akid = backend._ffi.gc(akid, backend._lib.AUTHORITY_KEYID_free) + if authority_keyid.key_identifier is not None: + akid.keyid = _encode_asn1_str( + backend, + authority_keyid.key_identifier, + ) + + if authority_keyid.authority_cert_issuer is not None: + akid.issuer = _encode_general_names( + backend, authority_keyid.authority_cert_issuer + ) + + if authority_keyid.authority_cert_serial_number is not None: + akid.serial = _encode_asn1_int( + backend, authority_keyid.authority_cert_serial_number + ) + + return akid + + +def _encode_basic_constraints(backend, basic_constraints): + constraints = backend._lib.BASIC_CONSTRAINTS_new() + constraints = backend._ffi.gc( + constraints, backend._lib.BASIC_CONSTRAINTS_free + ) + constraints.ca = 255 if basic_constraints.ca else 0 + if basic_constraints.ca and basic_constraints.path_length is not None: + constraints.pathlen = _encode_asn1_int( + backend, basic_constraints.path_length + ) + + return constraints + + +def _encode_information_access(backend, info_access): + aia = backend._lib.sk_ACCESS_DESCRIPTION_new_null() + backend.openssl_assert(aia != backend._ffi.NULL) + aia = backend._ffi.gc( + aia, + lambda x: backend._lib.sk_ACCESS_DESCRIPTION_pop_free( + x, + backend._ffi.addressof( + backend._lib._original_lib, "ACCESS_DESCRIPTION_free" + ), + ), + ) + for access_description in info_access: + ad = backend._lib.ACCESS_DESCRIPTION_new() + method = _txt2obj( + backend, access_description.access_method.dotted_string + ) + _encode_general_name_preallocated( + backend, access_description.access_location, ad.location + ) + ad.method = method + res = backend._lib.sk_ACCESS_DESCRIPTION_push(aia, ad) + backend.openssl_assert(res >= 1) + + return aia + + +def _encode_general_names(backend, names): + general_names = backend._lib.GENERAL_NAMES_new() + backend.openssl_assert(general_names != backend._ffi.NULL) + for name in names: + gn = _encode_general_name(backend, name) + res = backend._lib.sk_GENERAL_NAME_push(general_names, gn) + backend.openssl_assert(res != 0) + + return general_names + + +def _encode_alt_name(backend, san): + general_names = _encode_general_names(backend, san) + general_names = backend._ffi.gc( + general_names, backend._lib.GENERAL_NAMES_free + ) + return general_names + + +def _encode_subject_key_identifier(backend, ski): + return _encode_asn1_str_gc(backend, ski.digest) + + +def _encode_general_name(backend, name): + gn = backend._lib.GENERAL_NAME_new() + _encode_general_name_preallocated(backend, name, gn) + return gn + + +def _encode_general_name_preallocated(backend, name, gn): + if isinstance(name, x509.DNSName): + backend.openssl_assert(gn != backend._ffi.NULL) + gn.type = backend._lib.GEN_DNS + + ia5 = backend._lib.ASN1_IA5STRING_new() + backend.openssl_assert(ia5 != backend._ffi.NULL) + # ia5strings are supposed to be ITU T.50 but to allow round-tripping + # of broken certs that encode utf8 we'll encode utf8 here too. + value = name.value.encode("utf8") + + res = backend._lib.ASN1_STRING_set(ia5, value, len(value)) + backend.openssl_assert(res == 1) + gn.d.dNSName = ia5 + elif isinstance(name, x509.RegisteredID): + backend.openssl_assert(gn != backend._ffi.NULL) + gn.type = backend._lib.GEN_RID + obj = backend._lib.OBJ_txt2obj( + name.value.dotted_string.encode("ascii"), 1 + ) + backend.openssl_assert(obj != backend._ffi.NULL) + gn.d.registeredID = obj + elif isinstance(name, x509.DirectoryName): + backend.openssl_assert(gn != backend._ffi.NULL) + dir_name = _encode_name(backend, name.value) + gn.type = backend._lib.GEN_DIRNAME + gn.d.directoryName = dir_name + elif isinstance(name, x509.IPAddress): + backend.openssl_assert(gn != backend._ffi.NULL) + if isinstance(name.value, ipaddress.IPv4Network): + packed = name.value.network_address.packed + utils.int_to_bytes( + ((1 << 32) - name.value.num_addresses), 4 + ) + elif isinstance(name.value, ipaddress.IPv6Network): + packed = name.value.network_address.packed + utils.int_to_bytes( + (1 << 128) - name.value.num_addresses, 16 + ) + else: + packed = name.value.packed + ipaddr = _encode_asn1_str(backend, packed) + gn.type = backend._lib.GEN_IPADD + gn.d.iPAddress = ipaddr + elif isinstance(name, x509.OtherName): + backend.openssl_assert(gn != backend._ffi.NULL) + other_name = backend._lib.OTHERNAME_new() + backend.openssl_assert(other_name != backend._ffi.NULL) + + type_id = backend._lib.OBJ_txt2obj( + name.type_id.dotted_string.encode("ascii"), 1 + ) + backend.openssl_assert(type_id != backend._ffi.NULL) + data = backend._ffi.new("unsigned char[]", name.value) + data_ptr_ptr = backend._ffi.new("unsigned char **") + data_ptr_ptr[0] = data + value = backend._lib.d2i_ASN1_TYPE( + backend._ffi.NULL, data_ptr_ptr, len(name.value) + ) + if value == backend._ffi.NULL: + backend._consume_errors() + raise ValueError("Invalid ASN.1 data") + other_name.type_id = type_id + other_name.value = value + gn.type = backend._lib.GEN_OTHERNAME + gn.d.otherName = other_name + elif isinstance(name, x509.RFC822Name): + backend.openssl_assert(gn != backend._ffi.NULL) + # ia5strings are supposed to be ITU T.50 but to allow round-tripping + # of broken certs that encode utf8 we'll encode utf8 here too. + data = name.value.encode("utf8") + asn1_str = _encode_asn1_str(backend, data) + gn.type = backend._lib.GEN_EMAIL + gn.d.rfc822Name = asn1_str + elif isinstance(name, x509.UniformResourceIdentifier): + backend.openssl_assert(gn != backend._ffi.NULL) + # ia5strings are supposed to be ITU T.50 but to allow round-tripping + # of broken certs that encode utf8 we'll encode utf8 here too. + data = name.value.encode("utf8") + asn1_str = _encode_asn1_str(backend, data) + gn.type = backend._lib.GEN_URI + gn.d.uniformResourceIdentifier = asn1_str + else: + raise ValueError("{} is an unknown GeneralName type".format(name)) + + +def _encode_extended_key_usage(backend, extended_key_usage): + eku = backend._lib.sk_ASN1_OBJECT_new_null() + eku = backend._ffi.gc(eku, backend._lib.sk_ASN1_OBJECT_free) + for oid in extended_key_usage: + obj = _txt2obj(backend, oid.dotted_string) + res = backend._lib.sk_ASN1_OBJECT_push(eku, obj) + backend.openssl_assert(res >= 1) + + return eku + + +_CRLREASONFLAGS = { + x509.ReasonFlags.key_compromise: 1, + x509.ReasonFlags.ca_compromise: 2, + x509.ReasonFlags.affiliation_changed: 3, + x509.ReasonFlags.superseded: 4, + x509.ReasonFlags.cessation_of_operation: 5, + x509.ReasonFlags.certificate_hold: 6, + x509.ReasonFlags.privilege_withdrawn: 7, + x509.ReasonFlags.aa_compromise: 8, +} + + +def _encode_reasonflags(backend, reasons): + bitmask = backend._lib.ASN1_BIT_STRING_new() + backend.openssl_assert(bitmask != backend._ffi.NULL) + for reason in reasons: + res = backend._lib.ASN1_BIT_STRING_set_bit( + bitmask, _CRLREASONFLAGS[reason], 1 + ) + backend.openssl_assert(res == 1) + + return bitmask + + +def _encode_full_name(backend, full_name): + dpn = backend._lib.DIST_POINT_NAME_new() + backend.openssl_assert(dpn != backend._ffi.NULL) + dpn.type = _DISTPOINT_TYPE_FULLNAME + dpn.name.fullname = _encode_general_names(backend, full_name) + return dpn + + +def _encode_relative_name(backend, relative_name): + dpn = backend._lib.DIST_POINT_NAME_new() + backend.openssl_assert(dpn != backend._ffi.NULL) + dpn.type = _DISTPOINT_TYPE_RELATIVENAME + dpn.name.relativename = _encode_sk_name_entry(backend, relative_name) + return dpn + + +def _encode_cdps_freshest_crl(backend, cdps): + cdp = backend._lib.sk_DIST_POINT_new_null() + cdp = backend._ffi.gc(cdp, backend._lib.sk_DIST_POINT_free) + for point in cdps: + dp = backend._lib.DIST_POINT_new() + backend.openssl_assert(dp != backend._ffi.NULL) + + if point.reasons: + dp.reasons = _encode_reasonflags(backend, point.reasons) + + if point.full_name: + dp.distpoint = _encode_full_name(backend, point.full_name) + + if point.relative_name: + dp.distpoint = _encode_relative_name(backend, point.relative_name) + + if point.crl_issuer: + dp.CRLissuer = _encode_general_names(backend, point.crl_issuer) + + res = backend._lib.sk_DIST_POINT_push(cdp, dp) + backend.openssl_assert(res >= 1) + + return cdp + + +def _encode_name_constraints(backend, name_constraints): + nc = backend._lib.NAME_CONSTRAINTS_new() + backend.openssl_assert(nc != backend._ffi.NULL) + nc = backend._ffi.gc(nc, backend._lib.NAME_CONSTRAINTS_free) + permitted = _encode_general_subtree( + backend, name_constraints.permitted_subtrees + ) + nc.permittedSubtrees = permitted + excluded = _encode_general_subtree( + backend, name_constraints.excluded_subtrees + ) + nc.excludedSubtrees = excluded + + return nc + + +def _encode_policy_constraints(backend, policy_constraints): + pc = backend._lib.POLICY_CONSTRAINTS_new() + backend.openssl_assert(pc != backend._ffi.NULL) + pc = backend._ffi.gc(pc, backend._lib.POLICY_CONSTRAINTS_free) + if policy_constraints.require_explicit_policy is not None: + pc.requireExplicitPolicy = _encode_asn1_int( + backend, policy_constraints.require_explicit_policy + ) + + if policy_constraints.inhibit_policy_mapping is not None: + pc.inhibitPolicyMapping = _encode_asn1_int( + backend, policy_constraints.inhibit_policy_mapping + ) + + return pc + + +def _encode_general_subtree(backend, subtrees): + if subtrees is None: + return backend._ffi.NULL + else: + general_subtrees = backend._lib.sk_GENERAL_SUBTREE_new_null() + for name in subtrees: + gs = backend._lib.GENERAL_SUBTREE_new() + gs.base = _encode_general_name(backend, name) + res = backend._lib.sk_GENERAL_SUBTREE_push(general_subtrees, gs) + assert res >= 1 + + return general_subtrees + + +def _encode_nonce(backend, nonce): + return _encode_asn1_str_gc(backend, nonce.nonce) + + +_EXTENSION_ENCODE_HANDLERS = { + ExtensionOID.BASIC_CONSTRAINTS: _encode_basic_constraints, + ExtensionOID.SUBJECT_KEY_IDENTIFIER: _encode_subject_key_identifier, + ExtensionOID.KEY_USAGE: _encode_key_usage, + ExtensionOID.SUBJECT_ALTERNATIVE_NAME: _encode_alt_name, + ExtensionOID.ISSUER_ALTERNATIVE_NAME: _encode_alt_name, + ExtensionOID.EXTENDED_KEY_USAGE: _encode_extended_key_usage, + ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _encode_authority_key_identifier, + ExtensionOID.CERTIFICATE_POLICIES: _encode_certificate_policies, + ExtensionOID.AUTHORITY_INFORMATION_ACCESS: _encode_information_access, + ExtensionOID.SUBJECT_INFORMATION_ACCESS: _encode_information_access, + ExtensionOID.CRL_DISTRIBUTION_POINTS: _encode_cdps_freshest_crl, + ExtensionOID.FRESHEST_CRL: _encode_cdps_freshest_crl, + ExtensionOID.INHIBIT_ANY_POLICY: _encode_inhibit_any_policy, + ExtensionOID.OCSP_NO_CHECK: _encode_ocsp_nocheck, + ExtensionOID.NAME_CONSTRAINTS: _encode_name_constraints, + ExtensionOID.POLICY_CONSTRAINTS: _encode_policy_constraints, +} + +_CRL_EXTENSION_ENCODE_HANDLERS = { + ExtensionOID.ISSUER_ALTERNATIVE_NAME: _encode_alt_name, + ExtensionOID.AUTHORITY_KEY_IDENTIFIER: _encode_authority_key_identifier, + ExtensionOID.AUTHORITY_INFORMATION_ACCESS: _encode_information_access, + ExtensionOID.CRL_NUMBER: _encode_crl_number_delta_crl_indicator, + ExtensionOID.DELTA_CRL_INDICATOR: _encode_crl_number_delta_crl_indicator, + ExtensionOID.ISSUING_DISTRIBUTION_POINT: _encode_issuing_dist_point, + ExtensionOID.FRESHEST_CRL: _encode_cdps_freshest_crl, +} + +_CRL_ENTRY_EXTENSION_ENCODE_HANDLERS = { + CRLEntryExtensionOID.CERTIFICATE_ISSUER: _encode_alt_name, + CRLEntryExtensionOID.CRL_REASON: _encode_crl_reason, + CRLEntryExtensionOID.INVALIDITY_DATE: _encode_invalidity_date, +} + +_OCSP_REQUEST_EXTENSION_ENCODE_HANDLERS = { + OCSPExtensionOID.NONCE: _encode_nonce, +} + +_OCSP_BASICRESP_EXTENSION_ENCODE_HANDLERS = { + OCSPExtensionOID.NONCE: _encode_nonce, +} diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/hashes.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/hashes.py new file mode 100644 index 0000000..4403399 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/hashes.py @@ -0,0 +1,82 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + + +from cryptography import utils +from cryptography.exceptions import UnsupportedAlgorithm, _Reasons +from cryptography.hazmat.primitives import hashes + + +@utils.register_interface(hashes.HashContext) +class _HashContext(object): + def __init__(self, backend, algorithm, ctx=None): + self._algorithm = algorithm + + self._backend = backend + + if ctx is None: + ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new() + ctx = self._backend._ffi.gc( + ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free + ) + evp_md = self._backend._evp_md_from_algorithm(algorithm) + if evp_md == self._backend._ffi.NULL: + raise UnsupportedAlgorithm( + "{} is not a supported hash on this backend.".format( + algorithm.name + ), + _Reasons.UNSUPPORTED_HASH, + ) + res = self._backend._lib.EVP_DigestInit_ex( + ctx, evp_md, self._backend._ffi.NULL + ) + self._backend.openssl_assert(res != 0) + + self._ctx = ctx + + algorithm = utils.read_only_property("_algorithm") + + def copy(self): + copied_ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new() + copied_ctx = self._backend._ffi.gc( + copied_ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free + ) + res = self._backend._lib.EVP_MD_CTX_copy_ex(copied_ctx, self._ctx) + self._backend.openssl_assert(res != 0) + return _HashContext(self._backend, self.algorithm, ctx=copied_ctx) + + def update(self, data): + data_ptr = self._backend._ffi.from_buffer(data) + res = self._backend._lib.EVP_DigestUpdate( + self._ctx, data_ptr, len(data) + ) + self._backend.openssl_assert(res != 0) + + def finalize(self): + if isinstance(self.algorithm, hashes.ExtendableOutputFunction): + # extendable output functions use a different finalize + return self._finalize_xof() + else: + buf = self._backend._ffi.new( + "unsigned char[]", self._backend._lib.EVP_MAX_MD_SIZE + ) + outlen = self._backend._ffi.new("unsigned int *") + res = self._backend._lib.EVP_DigestFinal_ex(self._ctx, buf, outlen) + self._backend.openssl_assert(res != 0) + self._backend.openssl_assert( + outlen[0] == self.algorithm.digest_size + ) + return self._backend._ffi.buffer(buf)[: outlen[0]] + + def _finalize_xof(self): + buf = self._backend._ffi.new( + "unsigned char[]", self.algorithm.digest_size + ) + res = self._backend._lib.EVP_DigestFinalXOF( + self._ctx, buf, self.algorithm.digest_size + ) + self._backend.openssl_assert(res != 0) + return self._backend._ffi.buffer(buf)[: self.algorithm.digest_size] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/hmac.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/hmac.py new file mode 100644 index 0000000..5024223 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/hmac.py @@ -0,0 +1,78 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + + +from cryptography import utils +from cryptography.exceptions import ( + InvalidSignature, + UnsupportedAlgorithm, + _Reasons, +) +from cryptography.hazmat.primitives import constant_time, hashes + + +@utils.register_interface(hashes.HashContext) +class _HMACContext(object): + def __init__(self, backend, key, algorithm, ctx=None): + self._algorithm = algorithm + self._backend = backend + + if ctx is None: + ctx = self._backend._lib.Cryptography_HMAC_CTX_new() + self._backend.openssl_assert(ctx != self._backend._ffi.NULL) + ctx = self._backend._ffi.gc( + ctx, self._backend._lib.Cryptography_HMAC_CTX_free + ) + evp_md = self._backend._evp_md_from_algorithm(algorithm) + if evp_md == self._backend._ffi.NULL: + raise UnsupportedAlgorithm( + "{} is not a supported hash on this backend".format( + algorithm.name + ), + _Reasons.UNSUPPORTED_HASH, + ) + key_ptr = self._backend._ffi.from_buffer(key) + res = self._backend._lib.HMAC_Init_ex( + ctx, key_ptr, len(key), evp_md, self._backend._ffi.NULL + ) + self._backend.openssl_assert(res != 0) + + self._ctx = ctx + self._key = key + + algorithm = utils.read_only_property("_algorithm") + + def copy(self): + copied_ctx = self._backend._lib.Cryptography_HMAC_CTX_new() + self._backend.openssl_assert(copied_ctx != self._backend._ffi.NULL) + copied_ctx = self._backend._ffi.gc( + copied_ctx, self._backend._lib.Cryptography_HMAC_CTX_free + ) + res = self._backend._lib.HMAC_CTX_copy(copied_ctx, self._ctx) + self._backend.openssl_assert(res != 0) + return _HMACContext( + self._backend, self._key, self.algorithm, ctx=copied_ctx + ) + + def update(self, data): + data_ptr = self._backend._ffi.from_buffer(data) + res = self._backend._lib.HMAC_Update(self._ctx, data_ptr, len(data)) + self._backend.openssl_assert(res != 0) + + def finalize(self): + buf = self._backend._ffi.new( + "unsigned char[]", self._backend._lib.EVP_MAX_MD_SIZE + ) + outlen = self._backend._ffi.new("unsigned int *") + res = self._backend._lib.HMAC_Final(self._ctx, buf, outlen) + self._backend.openssl_assert(res != 0) + self._backend.openssl_assert(outlen[0] == self.algorithm.digest_size) + return self._backend._ffi.buffer(buf)[: outlen[0]] + + def verify(self, signature): + digest = self.finalize() + if not constant_time.bytes_eq(digest, signature): + raise InvalidSignature("Signature did not match digest.") diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/ocsp.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/ocsp.py new file mode 100644 index 0000000..50c02e7 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/ocsp.py @@ -0,0 +1,401 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import functools + +from cryptography import utils, x509 +from cryptography.exceptions import UnsupportedAlgorithm +from cryptography.hazmat.backends.openssl.decode_asn1 import ( + _CRL_ENTRY_REASON_CODE_TO_ENUM, + _asn1_integer_to_int, + _asn1_string_to_bytes, + _decode_x509_name, + _obj2txt, + _parse_asn1_generalized_time, +) +from cryptography.hazmat.backends.openssl.x509 import _Certificate +from cryptography.hazmat.primitives import serialization +from cryptography.x509.ocsp import ( + OCSPCertStatus, + OCSPRequest, + OCSPResponse, + OCSPResponseStatus, + _CERT_STATUS_TO_ENUM, + _OIDS_TO_HASH, + _RESPONSE_STATUS_TO_ENUM, +) + + +def _requires_successful_response(func): + @functools.wraps(func) + def wrapper(self, *args): + if self.response_status != OCSPResponseStatus.SUCCESSFUL: + raise ValueError( + "OCSP response status is not successful so the property " + "has no value" + ) + else: + return func(self, *args) + + return wrapper + + +def _issuer_key_hash(backend, cert_id): + key_hash = backend._ffi.new("ASN1_OCTET_STRING **") + res = backend._lib.OCSP_id_get0_info( + backend._ffi.NULL, + backend._ffi.NULL, + key_hash, + backend._ffi.NULL, + cert_id, + ) + backend.openssl_assert(res == 1) + backend.openssl_assert(key_hash[0] != backend._ffi.NULL) + return _asn1_string_to_bytes(backend, key_hash[0]) + + +def _issuer_name_hash(backend, cert_id): + name_hash = backend._ffi.new("ASN1_OCTET_STRING **") + res = backend._lib.OCSP_id_get0_info( + name_hash, + backend._ffi.NULL, + backend._ffi.NULL, + backend._ffi.NULL, + cert_id, + ) + backend.openssl_assert(res == 1) + backend.openssl_assert(name_hash[0] != backend._ffi.NULL) + return _asn1_string_to_bytes(backend, name_hash[0]) + + +def _serial_number(backend, cert_id): + num = backend._ffi.new("ASN1_INTEGER **") + res = backend._lib.OCSP_id_get0_info( + backend._ffi.NULL, backend._ffi.NULL, backend._ffi.NULL, num, cert_id + ) + backend.openssl_assert(res == 1) + backend.openssl_assert(num[0] != backend._ffi.NULL) + return _asn1_integer_to_int(backend, num[0]) + + +def _hash_algorithm(backend, cert_id): + asn1obj = backend._ffi.new("ASN1_OBJECT **") + res = backend._lib.OCSP_id_get0_info( + backend._ffi.NULL, + asn1obj, + backend._ffi.NULL, + backend._ffi.NULL, + cert_id, + ) + backend.openssl_assert(res == 1) + backend.openssl_assert(asn1obj[0] != backend._ffi.NULL) + oid = _obj2txt(backend, asn1obj[0]) + try: + return _OIDS_TO_HASH[oid] + except KeyError: + raise UnsupportedAlgorithm( + "Signature algorithm OID: {} not recognized".format(oid) + ) + + +@utils.register_interface(OCSPResponse) +class _OCSPResponse(object): + def __init__(self, backend, ocsp_response): + self._backend = backend + self._ocsp_response = ocsp_response + status = self._backend._lib.OCSP_response_status(self._ocsp_response) + self._backend.openssl_assert(status in _RESPONSE_STATUS_TO_ENUM) + self._status = _RESPONSE_STATUS_TO_ENUM[status] + if self._status is OCSPResponseStatus.SUCCESSFUL: + basic = self._backend._lib.OCSP_response_get1_basic( + self._ocsp_response + ) + self._backend.openssl_assert(basic != self._backend._ffi.NULL) + self._basic = self._backend._ffi.gc( + basic, self._backend._lib.OCSP_BASICRESP_free + ) + num_resp = self._backend._lib.OCSP_resp_count(self._basic) + if num_resp != 1: + raise ValueError( + "OCSP response contains more than one SINGLERESP structure" + ", which this library does not support. " + "{} found".format(num_resp) + ) + self._single = self._backend._lib.OCSP_resp_get0(self._basic, 0) + self._backend.openssl_assert( + self._single != self._backend._ffi.NULL + ) + self._cert_id = self._backend._lib.OCSP_SINGLERESP_get0_id( + self._single + ) + self._backend.openssl_assert( + self._cert_id != self._backend._ffi.NULL + ) + + response_status = utils.read_only_property("_status") + + @property + @_requires_successful_response + def signature_algorithm_oid(self): + alg = self._backend._lib.OCSP_resp_get0_tbs_sigalg(self._basic) + self._backend.openssl_assert(alg != self._backend._ffi.NULL) + oid = _obj2txt(self._backend, alg.algorithm) + return x509.ObjectIdentifier(oid) + + @property + @_requires_successful_response + def signature_hash_algorithm(self): + oid = self.signature_algorithm_oid + try: + return x509._SIG_OIDS_TO_HASH[oid] + except KeyError: + raise UnsupportedAlgorithm( + "Signature algorithm OID:{} not recognized".format(oid) + ) + + @property + @_requires_successful_response + def signature(self): + sig = self._backend._lib.OCSP_resp_get0_signature(self._basic) + self._backend.openssl_assert(sig != self._backend._ffi.NULL) + return _asn1_string_to_bytes(self._backend, sig) + + @property + @_requires_successful_response + def tbs_response_bytes(self): + respdata = self._backend._lib.OCSP_resp_get0_respdata(self._basic) + self._backend.openssl_assert(respdata != self._backend._ffi.NULL) + pp = self._backend._ffi.new("unsigned char **") + res = self._backend._lib.i2d_OCSP_RESPDATA(respdata, pp) + self._backend.openssl_assert(pp[0] != self._backend._ffi.NULL) + pp = self._backend._ffi.gc( + pp, lambda pointer: self._backend._lib.OPENSSL_free(pointer[0]) + ) + self._backend.openssl_assert(res > 0) + return self._backend._ffi.buffer(pp[0], res)[:] + + @property + @_requires_successful_response + def certificates(self): + sk_x509 = self._backend._lib.OCSP_resp_get0_certs(self._basic) + num = self._backend._lib.sk_X509_num(sk_x509) + certs = [] + for i in range(num): + x509 = self._backend._lib.sk_X509_value(sk_x509, i) + self._backend.openssl_assert(x509 != self._backend._ffi.NULL) + cert = _Certificate(self._backend, x509) + # We need to keep the OCSP response that the certificate came from + # alive until the Certificate object itself goes out of scope, so + # we give it a private reference. + cert._ocsp_resp = self + certs.append(cert) + + return certs + + @property + @_requires_successful_response + def responder_key_hash(self): + _, asn1_string = self._responder_key_name() + if asn1_string == self._backend._ffi.NULL: + return None + else: + return _asn1_string_to_bytes(self._backend, asn1_string) + + @property + @_requires_successful_response + def responder_name(self): + x509_name, _ = self._responder_key_name() + if x509_name == self._backend._ffi.NULL: + return None + else: + return _decode_x509_name(self._backend, x509_name) + + def _responder_key_name(self): + asn1_string = self._backend._ffi.new("ASN1_OCTET_STRING **") + x509_name = self._backend._ffi.new("X509_NAME **") + res = self._backend._lib.OCSP_resp_get0_id( + self._basic, asn1_string, x509_name + ) + self._backend.openssl_assert(res == 1) + return x509_name[0], asn1_string[0] + + @property + @_requires_successful_response + def produced_at(self): + produced_at = self._backend._lib.OCSP_resp_get0_produced_at( + self._basic + ) + return _parse_asn1_generalized_time(self._backend, produced_at) + + @property + @_requires_successful_response + def certificate_status(self): + status = self._backend._lib.OCSP_single_get0_status( + self._single, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + ) + self._backend.openssl_assert(status in _CERT_STATUS_TO_ENUM) + return _CERT_STATUS_TO_ENUM[status] + + @property + @_requires_successful_response + def revocation_time(self): + if self.certificate_status is not OCSPCertStatus.REVOKED: + return None + + asn1_time = self._backend._ffi.new("ASN1_GENERALIZEDTIME **") + self._backend._lib.OCSP_single_get0_status( + self._single, + self._backend._ffi.NULL, + asn1_time, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + ) + self._backend.openssl_assert(asn1_time[0] != self._backend._ffi.NULL) + return _parse_asn1_generalized_time(self._backend, asn1_time[0]) + + @property + @_requires_successful_response + def revocation_reason(self): + if self.certificate_status is not OCSPCertStatus.REVOKED: + return None + + reason_ptr = self._backend._ffi.new("int *") + self._backend._lib.OCSP_single_get0_status( + self._single, + reason_ptr, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + ) + # If no reason is encoded OpenSSL returns -1 + if reason_ptr[0] == -1: + return None + else: + self._backend.openssl_assert( + reason_ptr[0] in _CRL_ENTRY_REASON_CODE_TO_ENUM + ) + return _CRL_ENTRY_REASON_CODE_TO_ENUM[reason_ptr[0]] + + @property + @_requires_successful_response + def this_update(self): + asn1_time = self._backend._ffi.new("ASN1_GENERALIZEDTIME **") + self._backend._lib.OCSP_single_get0_status( + self._single, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + asn1_time, + self._backend._ffi.NULL, + ) + self._backend.openssl_assert(asn1_time[0] != self._backend._ffi.NULL) + return _parse_asn1_generalized_time(self._backend, asn1_time[0]) + + @property + @_requires_successful_response + def next_update(self): + asn1_time = self._backend._ffi.new("ASN1_GENERALIZEDTIME **") + self._backend._lib.OCSP_single_get0_status( + self._single, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + asn1_time, + ) + if asn1_time[0] != self._backend._ffi.NULL: + return _parse_asn1_generalized_time(self._backend, asn1_time[0]) + else: + return None + + @property + @_requires_successful_response + def issuer_key_hash(self): + return _issuer_key_hash(self._backend, self._cert_id) + + @property + @_requires_successful_response + def issuer_name_hash(self): + return _issuer_name_hash(self._backend, self._cert_id) + + @property + @_requires_successful_response + def hash_algorithm(self): + return _hash_algorithm(self._backend, self._cert_id) + + @property + @_requires_successful_response + def serial_number(self): + return _serial_number(self._backend, self._cert_id) + + @utils.cached_property + @_requires_successful_response + def extensions(self): + return self._backend._ocsp_basicresp_ext_parser.parse(self._basic) + + @utils.cached_property + @_requires_successful_response + def single_extensions(self): + return self._backend._ocsp_singleresp_ext_parser.parse(self._single) + + def public_bytes(self, encoding): + if encoding is not serialization.Encoding.DER: + raise ValueError("The only allowed encoding value is Encoding.DER") + + bio = self._backend._create_mem_bio_gc() + res = self._backend._lib.i2d_OCSP_RESPONSE_bio( + bio, self._ocsp_response + ) + self._backend.openssl_assert(res > 0) + return self._backend._read_mem_bio(bio) + + +@utils.register_interface(OCSPRequest) +class _OCSPRequest(object): + def __init__(self, backend, ocsp_request): + if backend._lib.OCSP_request_onereq_count(ocsp_request) > 1: + raise NotImplementedError( + "OCSP request contains more than one request" + ) + self._backend = backend + self._ocsp_request = ocsp_request + self._request = self._backend._lib.OCSP_request_onereq_get0( + self._ocsp_request, 0 + ) + self._backend.openssl_assert(self._request != self._backend._ffi.NULL) + self._cert_id = self._backend._lib.OCSP_onereq_get0_id(self._request) + self._backend.openssl_assert(self._cert_id != self._backend._ffi.NULL) + + @property + def issuer_key_hash(self): + return _issuer_key_hash(self._backend, self._cert_id) + + @property + def issuer_name_hash(self): + return _issuer_name_hash(self._backend, self._cert_id) + + @property + def serial_number(self): + return _serial_number(self._backend, self._cert_id) + + @property + def hash_algorithm(self): + return _hash_algorithm(self._backend, self._cert_id) + + @utils.cached_property + def extensions(self): + return self._backend._ocsp_req_ext_parser.parse(self._ocsp_request) + + def public_bytes(self, encoding): + if encoding is not serialization.Encoding.DER: + raise ValueError("The only allowed encoding value is Encoding.DER") + + bio = self._backend._create_mem_bio_gc() + res = self._backend._lib.i2d_OCSP_REQUEST_bio(bio, self._ocsp_request) + self._backend.openssl_assert(res > 0) + return self._backend._read_mem_bio(bio) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/poly1305.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/poly1305.py new file mode 100644 index 0000000..17493ca --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/poly1305.py @@ -0,0 +1,65 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + + +from cryptography.exceptions import InvalidSignature +from cryptography.hazmat.primitives import constant_time + + +_POLY1305_TAG_SIZE = 16 +_POLY1305_KEY_SIZE = 32 + + +class _Poly1305Context(object): + def __init__(self, backend, key): + self._backend = backend + + key_ptr = self._backend._ffi.from_buffer(key) + # This function copies the key into OpenSSL-owned memory so we don't + # need to retain it ourselves + evp_pkey = self._backend._lib.EVP_PKEY_new_raw_private_key( + self._backend._lib.NID_poly1305, + self._backend._ffi.NULL, + key_ptr, + len(key), + ) + self._backend.openssl_assert(evp_pkey != self._backend._ffi.NULL) + self._evp_pkey = self._backend._ffi.gc( + evp_pkey, self._backend._lib.EVP_PKEY_free + ) + ctx = self._backend._lib.Cryptography_EVP_MD_CTX_new() + self._backend.openssl_assert(ctx != self._backend._ffi.NULL) + self._ctx = self._backend._ffi.gc( + ctx, self._backend._lib.Cryptography_EVP_MD_CTX_free + ) + res = self._backend._lib.EVP_DigestSignInit( + self._ctx, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + self._evp_pkey, + ) + self._backend.openssl_assert(res == 1) + + def update(self, data): + data_ptr = self._backend._ffi.from_buffer(data) + res = self._backend._lib.EVP_DigestSignUpdate( + self._ctx, data_ptr, len(data) + ) + self._backend.openssl_assert(res != 0) + + def finalize(self): + buf = self._backend._ffi.new("unsigned char[]", _POLY1305_TAG_SIZE) + outlen = self._backend._ffi.new("size_t *") + res = self._backend._lib.EVP_DigestSignFinal(self._ctx, buf, outlen) + self._backend.openssl_assert(res != 0) + self._backend.openssl_assert(outlen[0] == _POLY1305_TAG_SIZE) + return self._backend._ffi.buffer(buf)[: outlen[0]] + + def verify(self, tag): + mac = self.finalize() + if not constant_time.bytes_eq(mac, tag): + raise InvalidSignature("Value did not match computed tag.") diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/rsa.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/rsa.py new file mode 100644 index 0000000..de29977 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/rsa.py @@ -0,0 +1,465 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography import utils +from cryptography.exceptions import ( + InvalidSignature, + UnsupportedAlgorithm, + _Reasons, +) +from cryptography.hazmat.backends.openssl.utils import ( + _calculate_digest_and_algorithm, + _check_not_prehashed, + _warn_sign_verify_deprecated, +) +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric import ( + AsymmetricSignatureContext, + AsymmetricVerificationContext, + rsa, +) +from cryptography.hazmat.primitives.asymmetric.padding import ( + AsymmetricPadding, + MGF1, + OAEP, + PKCS1v15, + PSS, + calculate_max_pss_salt_length, +) +from cryptography.hazmat.primitives.asymmetric.rsa import ( + RSAPrivateKeyWithSerialization, + RSAPublicKeyWithSerialization, +) + + +def _get_rsa_pss_salt_length(pss, key, hash_algorithm): + salt = pss._salt_length + + if salt is MGF1.MAX_LENGTH or salt is PSS.MAX_LENGTH: + return calculate_max_pss_salt_length(key, hash_algorithm) + else: + return salt + + +def _enc_dec_rsa(backend, key, data, padding): + if not isinstance(padding, AsymmetricPadding): + raise TypeError("Padding must be an instance of AsymmetricPadding.") + + if isinstance(padding, PKCS1v15): + padding_enum = backend._lib.RSA_PKCS1_PADDING + elif isinstance(padding, OAEP): + padding_enum = backend._lib.RSA_PKCS1_OAEP_PADDING + + if not isinstance(padding._mgf, MGF1): + raise UnsupportedAlgorithm( + "Only MGF1 is supported by this backend.", + _Reasons.UNSUPPORTED_MGF, + ) + + if not backend.rsa_padding_supported(padding): + raise UnsupportedAlgorithm( + "This combination of padding and hash algorithm is not " + "supported by this backend.", + _Reasons.UNSUPPORTED_PADDING, + ) + + else: + raise UnsupportedAlgorithm( + "{} is not supported by this backend.".format(padding.name), + _Reasons.UNSUPPORTED_PADDING, + ) + + return _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum, padding) + + +def _enc_dec_rsa_pkey_ctx(backend, key, data, padding_enum, padding): + if isinstance(key, _RSAPublicKey): + init = backend._lib.EVP_PKEY_encrypt_init + crypt = backend._lib.EVP_PKEY_encrypt + else: + init = backend._lib.EVP_PKEY_decrypt_init + crypt = backend._lib.EVP_PKEY_decrypt + + pkey_ctx = backend._lib.EVP_PKEY_CTX_new(key._evp_pkey, backend._ffi.NULL) + backend.openssl_assert(pkey_ctx != backend._ffi.NULL) + pkey_ctx = backend._ffi.gc(pkey_ctx, backend._lib.EVP_PKEY_CTX_free) + res = init(pkey_ctx) + backend.openssl_assert(res == 1) + res = backend._lib.EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, padding_enum) + backend.openssl_assert(res > 0) + buf_size = backend._lib.EVP_PKEY_size(key._evp_pkey) + backend.openssl_assert(buf_size > 0) + if isinstance(padding, OAEP) and backend._lib.Cryptography_HAS_RSA_OAEP_MD: + mgf1_md = backend._evp_md_non_null_from_algorithm( + padding._mgf._algorithm + ) + res = backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1_md) + backend.openssl_assert(res > 0) + oaep_md = backend._evp_md_non_null_from_algorithm(padding._algorithm) + res = backend._lib.EVP_PKEY_CTX_set_rsa_oaep_md(pkey_ctx, oaep_md) + backend.openssl_assert(res > 0) + + if ( + isinstance(padding, OAEP) + and padding._label is not None + and len(padding._label) > 0 + ): + # set0_rsa_oaep_label takes ownership of the char * so we need to + # copy it into some new memory + labelptr = backend._lib.OPENSSL_malloc(len(padding._label)) + backend.openssl_assert(labelptr != backend._ffi.NULL) + backend._ffi.memmove(labelptr, padding._label, len(padding._label)) + res = backend._lib.EVP_PKEY_CTX_set0_rsa_oaep_label( + pkey_ctx, labelptr, len(padding._label) + ) + backend.openssl_assert(res == 1) + + outlen = backend._ffi.new("size_t *", buf_size) + buf = backend._ffi.new("unsigned char[]", buf_size) + # Everything from this line onwards is written with the goal of being as + # constant-time as is practical given the constraints of Python and our + # API. See Bleichenbacher's '98 attack on RSA, and its many many variants. + # As such, you should not attempt to change this (particularly to "clean it + # up") without understanding why it was written this way (see + # Chesterton's Fence), and without measuring to verify you have not + # introduced observable time differences. + res = crypt(pkey_ctx, buf, outlen, data, len(data)) + resbuf = backend._ffi.buffer(buf)[: outlen[0]] + backend._lib.ERR_clear_error() + if res <= 0: + raise ValueError("Encryption/decryption failed.") + return resbuf + + +def _rsa_sig_determine_padding(backend, key, padding, algorithm): + if not isinstance(padding, AsymmetricPadding): + raise TypeError("Expected provider of AsymmetricPadding.") + + pkey_size = backend._lib.EVP_PKEY_size(key._evp_pkey) + backend.openssl_assert(pkey_size > 0) + + if isinstance(padding, PKCS1v15): + padding_enum = backend._lib.RSA_PKCS1_PADDING + elif isinstance(padding, PSS): + if not isinstance(padding._mgf, MGF1): + raise UnsupportedAlgorithm( + "Only MGF1 is supported by this backend.", + _Reasons.UNSUPPORTED_MGF, + ) + + # Size of key in bytes - 2 is the maximum + # PSS signature length (salt length is checked later) + if pkey_size - algorithm.digest_size - 2 < 0: + raise ValueError( + "Digest too large for key size. Use a larger " + "key or different digest." + ) + + padding_enum = backend._lib.RSA_PKCS1_PSS_PADDING + else: + raise UnsupportedAlgorithm( + "{} is not supported by this backend.".format(padding.name), + _Reasons.UNSUPPORTED_PADDING, + ) + + return padding_enum + + +def _rsa_sig_setup(backend, padding, algorithm, key, data, init_func): + padding_enum = _rsa_sig_determine_padding(backend, key, padding, algorithm) + evp_md = backend._evp_md_non_null_from_algorithm(algorithm) + pkey_ctx = backend._lib.EVP_PKEY_CTX_new(key._evp_pkey, backend._ffi.NULL) + backend.openssl_assert(pkey_ctx != backend._ffi.NULL) + pkey_ctx = backend._ffi.gc(pkey_ctx, backend._lib.EVP_PKEY_CTX_free) + res = init_func(pkey_ctx) + backend.openssl_assert(res == 1) + res = backend._lib.EVP_PKEY_CTX_set_signature_md(pkey_ctx, evp_md) + if res == 0: + backend._consume_errors() + raise UnsupportedAlgorithm( + "{} is not supported by this backend for RSA signing.".format( + algorithm.name + ), + _Reasons.UNSUPPORTED_HASH, + ) + res = backend._lib.EVP_PKEY_CTX_set_rsa_padding(pkey_ctx, padding_enum) + backend.openssl_assert(res > 0) + if isinstance(padding, PSS): + res = backend._lib.EVP_PKEY_CTX_set_rsa_pss_saltlen( + pkey_ctx, _get_rsa_pss_salt_length(padding, key, algorithm) + ) + backend.openssl_assert(res > 0) + + mgf1_md = backend._evp_md_non_null_from_algorithm( + padding._mgf._algorithm + ) + res = backend._lib.EVP_PKEY_CTX_set_rsa_mgf1_md(pkey_ctx, mgf1_md) + backend.openssl_assert(res > 0) + + return pkey_ctx + + +def _rsa_sig_sign(backend, padding, algorithm, private_key, data): + pkey_ctx = _rsa_sig_setup( + backend, + padding, + algorithm, + private_key, + data, + backend._lib.EVP_PKEY_sign_init, + ) + buflen = backend._ffi.new("size_t *") + res = backend._lib.EVP_PKEY_sign( + pkey_ctx, backend._ffi.NULL, buflen, data, len(data) + ) + backend.openssl_assert(res == 1) + buf = backend._ffi.new("unsigned char[]", buflen[0]) + res = backend._lib.EVP_PKEY_sign(pkey_ctx, buf, buflen, data, len(data)) + if res != 1: + errors = backend._consume_errors_with_text() + raise ValueError( + "Digest or salt length too long for key size. Use a larger key " + "or shorter salt length if you are specifying a PSS salt", + errors, + ) + + return backend._ffi.buffer(buf)[:] + + +def _rsa_sig_verify(backend, padding, algorithm, public_key, signature, data): + pkey_ctx = _rsa_sig_setup( + backend, + padding, + algorithm, + public_key, + data, + backend._lib.EVP_PKEY_verify_init, + ) + res = backend._lib.EVP_PKEY_verify( + pkey_ctx, signature, len(signature), data, len(data) + ) + # The previous call can return negative numbers in the event of an + # error. This is not a signature failure but we need to fail if it + # occurs. + backend.openssl_assert(res >= 0) + if res == 0: + backend._consume_errors() + raise InvalidSignature + + +@utils.register_interface(AsymmetricSignatureContext) +class _RSASignatureContext(object): + def __init__(self, backend, private_key, padding, algorithm): + self._backend = backend + self._private_key = private_key + + # We now call _rsa_sig_determine_padding in _rsa_sig_setup. However + # we need to make a pointless call to it here so we maintain the + # API of erroring on init with this context if the values are invalid. + _rsa_sig_determine_padding(backend, private_key, padding, algorithm) + self._padding = padding + self._algorithm = algorithm + self._hash_ctx = hashes.Hash(self._algorithm, self._backend) + + def update(self, data): + self._hash_ctx.update(data) + + def finalize(self): + return _rsa_sig_sign( + self._backend, + self._padding, + self._algorithm, + self._private_key, + self._hash_ctx.finalize(), + ) + + +@utils.register_interface(AsymmetricVerificationContext) +class _RSAVerificationContext(object): + def __init__(self, backend, public_key, signature, padding, algorithm): + self._backend = backend + self._public_key = public_key + self._signature = signature + self._padding = padding + # We now call _rsa_sig_determine_padding in _rsa_sig_setup. However + # we need to make a pointless call to it here so we maintain the + # API of erroring on init with this context if the values are invalid. + _rsa_sig_determine_padding(backend, public_key, padding, algorithm) + + padding = padding + self._algorithm = algorithm + self._hash_ctx = hashes.Hash(self._algorithm, self._backend) + + def update(self, data): + self._hash_ctx.update(data) + + def verify(self): + return _rsa_sig_verify( + self._backend, + self._padding, + self._algorithm, + self._public_key, + self._signature, + self._hash_ctx.finalize(), + ) + + +@utils.register_interface(RSAPrivateKeyWithSerialization) +class _RSAPrivateKey(object): + def __init__(self, backend, rsa_cdata, evp_pkey): + res = backend._lib.RSA_check_key(rsa_cdata) + if res != 1: + errors = backend._consume_errors_with_text() + raise ValueError("Invalid private key", errors) + + # Blinding is on by default in many versions of OpenSSL, but let's + # just be conservative here. + res = backend._lib.RSA_blinding_on(rsa_cdata, backend._ffi.NULL) + backend.openssl_assert(res == 1) + + self._backend = backend + self._rsa_cdata = rsa_cdata + self._evp_pkey = evp_pkey + + n = self._backend._ffi.new("BIGNUM **") + self._backend._lib.RSA_get0_key( + self._rsa_cdata, + n, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + ) + self._backend.openssl_assert(n[0] != self._backend._ffi.NULL) + self._key_size = self._backend._lib.BN_num_bits(n[0]) + + key_size = utils.read_only_property("_key_size") + + def signer(self, padding, algorithm): + _warn_sign_verify_deprecated() + _check_not_prehashed(algorithm) + return _RSASignatureContext(self._backend, self, padding, algorithm) + + def decrypt(self, ciphertext, padding): + key_size_bytes = (self.key_size + 7) // 8 + if key_size_bytes != len(ciphertext): + raise ValueError("Ciphertext length must be equal to key size.") + + return _enc_dec_rsa(self._backend, self, ciphertext, padding) + + def public_key(self): + ctx = self._backend._lib.RSAPublicKey_dup(self._rsa_cdata) + self._backend.openssl_assert(ctx != self._backend._ffi.NULL) + ctx = self._backend._ffi.gc(ctx, self._backend._lib.RSA_free) + evp_pkey = self._backend._rsa_cdata_to_evp_pkey(ctx) + return _RSAPublicKey(self._backend, ctx, evp_pkey) + + def private_numbers(self): + n = self._backend._ffi.new("BIGNUM **") + e = self._backend._ffi.new("BIGNUM **") + d = self._backend._ffi.new("BIGNUM **") + p = self._backend._ffi.new("BIGNUM **") + q = self._backend._ffi.new("BIGNUM **") + dmp1 = self._backend._ffi.new("BIGNUM **") + dmq1 = self._backend._ffi.new("BIGNUM **") + iqmp = self._backend._ffi.new("BIGNUM **") + self._backend._lib.RSA_get0_key(self._rsa_cdata, n, e, d) + self._backend.openssl_assert(n[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(e[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(d[0] != self._backend._ffi.NULL) + self._backend._lib.RSA_get0_factors(self._rsa_cdata, p, q) + self._backend.openssl_assert(p[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(q[0] != self._backend._ffi.NULL) + self._backend._lib.RSA_get0_crt_params( + self._rsa_cdata, dmp1, dmq1, iqmp + ) + self._backend.openssl_assert(dmp1[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(dmq1[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(iqmp[0] != self._backend._ffi.NULL) + return rsa.RSAPrivateNumbers( + p=self._backend._bn_to_int(p[0]), + q=self._backend._bn_to_int(q[0]), + d=self._backend._bn_to_int(d[0]), + dmp1=self._backend._bn_to_int(dmp1[0]), + dmq1=self._backend._bn_to_int(dmq1[0]), + iqmp=self._backend._bn_to_int(iqmp[0]), + public_numbers=rsa.RSAPublicNumbers( + e=self._backend._bn_to_int(e[0]), + n=self._backend._bn_to_int(n[0]), + ), + ) + + def private_bytes(self, encoding, format, encryption_algorithm): + return self._backend._private_key_bytes( + encoding, + format, + encryption_algorithm, + self, + self._evp_pkey, + self._rsa_cdata, + ) + + def sign(self, data, padding, algorithm): + data, algorithm = _calculate_digest_and_algorithm( + self._backend, data, algorithm + ) + return _rsa_sig_sign(self._backend, padding, algorithm, self, data) + + +@utils.register_interface(RSAPublicKeyWithSerialization) +class _RSAPublicKey(object): + def __init__(self, backend, rsa_cdata, evp_pkey): + self._backend = backend + self._rsa_cdata = rsa_cdata + self._evp_pkey = evp_pkey + + n = self._backend._ffi.new("BIGNUM **") + self._backend._lib.RSA_get0_key( + self._rsa_cdata, + n, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + ) + self._backend.openssl_assert(n[0] != self._backend._ffi.NULL) + self._key_size = self._backend._lib.BN_num_bits(n[0]) + + key_size = utils.read_only_property("_key_size") + + def verifier(self, signature, padding, algorithm): + _warn_sign_verify_deprecated() + utils._check_bytes("signature", signature) + + _check_not_prehashed(algorithm) + return _RSAVerificationContext( + self._backend, self, signature, padding, algorithm + ) + + def encrypt(self, plaintext, padding): + return _enc_dec_rsa(self._backend, self, plaintext, padding) + + def public_numbers(self): + n = self._backend._ffi.new("BIGNUM **") + e = self._backend._ffi.new("BIGNUM **") + self._backend._lib.RSA_get0_key( + self._rsa_cdata, n, e, self._backend._ffi.NULL + ) + self._backend.openssl_assert(n[0] != self._backend._ffi.NULL) + self._backend.openssl_assert(e[0] != self._backend._ffi.NULL) + return rsa.RSAPublicNumbers( + e=self._backend._bn_to_int(e[0]), + n=self._backend._bn_to_int(n[0]), + ) + + def public_bytes(self, encoding, format): + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, self._rsa_cdata + ) + + def verify(self, signature, data, padding, algorithm): + data, algorithm = _calculate_digest_and_algorithm( + self._backend, data, algorithm + ) + return _rsa_sig_verify( + self._backend, padding, algorithm, self, signature, data + ) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/utils.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/utils.py new file mode 100644 index 0000000..ec0b947 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/utils.py @@ -0,0 +1,65 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import warnings + +from cryptography import utils +from cryptography.hazmat.primitives import hashes +from cryptography.hazmat.primitives.asymmetric.utils import Prehashed + + +def _evp_pkey_derive(backend, evp_pkey, peer_public_key): + ctx = backend._lib.EVP_PKEY_CTX_new(evp_pkey, backend._ffi.NULL) + backend.openssl_assert(ctx != backend._ffi.NULL) + ctx = backend._ffi.gc(ctx, backend._lib.EVP_PKEY_CTX_free) + res = backend._lib.EVP_PKEY_derive_init(ctx) + backend.openssl_assert(res == 1) + res = backend._lib.EVP_PKEY_derive_set_peer(ctx, peer_public_key._evp_pkey) + backend.openssl_assert(res == 1) + keylen = backend._ffi.new("size_t *") + res = backend._lib.EVP_PKEY_derive(ctx, backend._ffi.NULL, keylen) + backend.openssl_assert(res == 1) + backend.openssl_assert(keylen[0] > 0) + buf = backend._ffi.new("unsigned char[]", keylen[0]) + res = backend._lib.EVP_PKEY_derive(ctx, buf, keylen) + if res != 1: + raise ValueError("Null shared key derived from public/private pair.") + + return backend._ffi.buffer(buf, keylen[0])[:] + + +def _calculate_digest_and_algorithm(backend, data, algorithm): + if not isinstance(algorithm, Prehashed): + hash_ctx = hashes.Hash(algorithm, backend) + hash_ctx.update(data) + data = hash_ctx.finalize() + else: + algorithm = algorithm._algorithm + + if len(data) != algorithm.digest_size: + raise ValueError( + "The provided data must be the same length as the hash " + "algorithm's digest size." + ) + + return (data, algorithm) + + +def _check_not_prehashed(signature_algorithm): + if isinstance(signature_algorithm, Prehashed): + raise TypeError( + "Prehashed is only supported in the sign and verify methods. " + "It cannot be used with signer or verifier." + ) + + +def _warn_sign_verify_deprecated(): + warnings.warn( + "signer and verifier have been deprecated. Please use sign " + "and verify instead.", + utils.PersistentlyDeprecated2017, + stacklevel=3, + ) diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/x25519.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/x25519.py new file mode 100644 index 0000000..4971c54 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/x25519.py @@ -0,0 +1,123 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography import utils +from cryptography.hazmat.backends.openssl.utils import _evp_pkey_derive +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric.x25519 import ( + X25519PrivateKey, + X25519PublicKey, +) + + +_X25519_KEY_SIZE = 32 + + +@utils.register_interface(X25519PublicKey) +class _X25519PublicKey(object): + def __init__(self, backend, evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_bytes(self, encoding, format): + if ( + encoding is serialization.Encoding.Raw + or format is serialization.PublicFormat.Raw + ): + if ( + encoding is not serialization.Encoding.Raw + or format is not serialization.PublicFormat.Raw + ): + raise ValueError( + "When using Raw both encoding and format must be Raw" + ) + + return self._raw_public_bytes() + + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, None + ) + + def _raw_public_bytes(self): + ucharpp = self._backend._ffi.new("unsigned char **") + res = self._backend._lib.EVP_PKEY_get1_tls_encodedpoint( + self._evp_pkey, ucharpp + ) + self._backend.openssl_assert(res == 32) + self._backend.openssl_assert(ucharpp[0] != self._backend._ffi.NULL) + data = self._backend._ffi.gc( + ucharpp[0], self._backend._lib.OPENSSL_free + ) + return self._backend._ffi.buffer(data, res)[:] + + +@utils.register_interface(X25519PrivateKey) +class _X25519PrivateKey(object): + def __init__(self, backend, evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_key(self): + bio = self._backend._create_mem_bio_gc() + res = self._backend._lib.i2d_PUBKEY_bio(bio, self._evp_pkey) + self._backend.openssl_assert(res == 1) + evp_pkey = self._backend._lib.d2i_PUBKEY_bio( + bio, self._backend._ffi.NULL + ) + self._backend.openssl_assert(evp_pkey != self._backend._ffi.NULL) + evp_pkey = self._backend._ffi.gc( + evp_pkey, self._backend._lib.EVP_PKEY_free + ) + return _X25519PublicKey(self._backend, evp_pkey) + + def exchange(self, peer_public_key): + if not isinstance(peer_public_key, X25519PublicKey): + raise TypeError("peer_public_key must be X25519PublicKey.") + + return _evp_pkey_derive(self._backend, self._evp_pkey, peer_public_key) + + def private_bytes(self, encoding, format, encryption_algorithm): + if ( + encoding is serialization.Encoding.Raw + or format is serialization.PublicFormat.Raw + ): + if ( + format is not serialization.PrivateFormat.Raw + or encoding is not serialization.Encoding.Raw + or not isinstance( + encryption_algorithm, serialization.NoEncryption + ) + ): + raise ValueError( + "When using Raw both encoding and format must be Raw " + "and encryption_algorithm must be NoEncryption()" + ) + + return self._raw_private_bytes() + + return self._backend._private_key_bytes( + encoding, format, encryption_algorithm, self, self._evp_pkey, None + ) + + def _raw_private_bytes(self): + # When we drop support for CRYPTOGRAPHY_OPENSSL_LESS_THAN_111 we can + # switch this to EVP_PKEY_new_raw_private_key + # The trick we use here is serializing to a PKCS8 key and just + # using the last 32 bytes, which is the key itself. + bio = self._backend._create_mem_bio_gc() + res = self._backend._lib.i2d_PKCS8PrivateKey_bio( + bio, + self._evp_pkey, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + 0, + self._backend._ffi.NULL, + self._backend._ffi.NULL, + ) + self._backend.openssl_assert(res == 1) + pkcs8 = self._backend._read_mem_bio(bio) + self._backend.openssl_assert(len(pkcs8) == 48) + return pkcs8[-_X25519_KEY_SIZE:] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/x448.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/x448.py new file mode 100644 index 0000000..7ebcdf8 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/x448.py @@ -0,0 +1,107 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +from cryptography import utils +from cryptography.hazmat.backends.openssl.utils import _evp_pkey_derive +from cryptography.hazmat.primitives import serialization +from cryptography.hazmat.primitives.asymmetric.x448 import ( + X448PrivateKey, + X448PublicKey, +) + +_X448_KEY_SIZE = 56 + + +@utils.register_interface(X448PublicKey) +class _X448PublicKey(object): + def __init__(self, backend, evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_bytes(self, encoding, format): + if ( + encoding is serialization.Encoding.Raw + or format is serialization.PublicFormat.Raw + ): + if ( + encoding is not serialization.Encoding.Raw + or format is not serialization.PublicFormat.Raw + ): + raise ValueError( + "When using Raw both encoding and format must be Raw" + ) + + return self._raw_public_bytes() + + return self._backend._public_key_bytes( + encoding, format, self, self._evp_pkey, None + ) + + def _raw_public_bytes(self): + buf = self._backend._ffi.new("unsigned char []", _X448_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _X448_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _X448_KEY_SIZE) + return self._backend._ffi.buffer(buf, _X448_KEY_SIZE)[:] + + +@utils.register_interface(X448PrivateKey) +class _X448PrivateKey(object): + def __init__(self, backend, evp_pkey): + self._backend = backend + self._evp_pkey = evp_pkey + + def public_key(self): + buf = self._backend._ffi.new("unsigned char []", _X448_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _X448_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_public_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _X448_KEY_SIZE) + return self._backend.x448_load_public_bytes(buf) + + def exchange(self, peer_public_key): + if not isinstance(peer_public_key, X448PublicKey): + raise TypeError("peer_public_key must be X448PublicKey.") + + return _evp_pkey_derive(self._backend, self._evp_pkey, peer_public_key) + + def private_bytes(self, encoding, format, encryption_algorithm): + if ( + encoding is serialization.Encoding.Raw + or format is serialization.PublicFormat.Raw + ): + if ( + format is not serialization.PrivateFormat.Raw + or encoding is not serialization.Encoding.Raw + or not isinstance( + encryption_algorithm, serialization.NoEncryption + ) + ): + raise ValueError( + "When using Raw both encoding and format must be Raw " + "and encryption_algorithm must be NoEncryption()" + ) + + return self._raw_private_bytes() + + return self._backend._private_key_bytes( + encoding, format, encryption_algorithm, self, self._evp_pkey, None + ) + + def _raw_private_bytes(self): + buf = self._backend._ffi.new("unsigned char []", _X448_KEY_SIZE) + buflen = self._backend._ffi.new("size_t *", _X448_KEY_SIZE) + res = self._backend._lib.EVP_PKEY_get_raw_private_key( + self._evp_pkey, buf, buflen + ) + self._backend.openssl_assert(res == 1) + self._backend.openssl_assert(buflen[0] == _X448_KEY_SIZE) + return self._backend._ffi.buffer(buf, _X448_KEY_SIZE)[:] diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/x509.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/x509.py new file mode 100644 index 0000000..4d0dac7 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/backends/openssl/x509.py @@ -0,0 +1,587 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function + +import datetime +import operator + +from cryptography import utils, x509 +from cryptography.exceptions import UnsupportedAlgorithm +from cryptography.hazmat.backends.openssl.decode_asn1 import ( + _asn1_integer_to_int, + _asn1_string_to_bytes, + _decode_x509_name, + _obj2txt, + _parse_asn1_time, +) +from cryptography.hazmat.backends.openssl.encode_asn1 import ( + _encode_asn1_int_gc, + _txt2obj_gc, +) +from cryptography.hazmat.primitives import hashes, serialization +from cryptography.hazmat.primitives.asymmetric import dsa, ec, rsa +from cryptography.x509.name import _ASN1Type + + +@utils.register_interface(x509.Certificate) +class _Certificate(object): + def __init__(self, backend, x509_cert): + self._backend = backend + self._x509 = x509_cert + + version = self._backend._lib.X509_get_version(self._x509) + if version == 0: + self._version = x509.Version.v1 + elif version == 2: + self._version = x509.Version.v3 + else: + raise x509.InvalidVersion( + "{} is not a valid X509 version".format(version), version + ) + + def __repr__(self): + return "".format(self.subject) + + def __eq__(self, other): + if not isinstance(other, x509.Certificate): + return NotImplemented + + res = self._backend._lib.X509_cmp(self._x509, other._x509) + return res == 0 + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(self.public_bytes(serialization.Encoding.DER)) + + def __deepcopy__(self, memo): + return self + + def fingerprint(self, algorithm): + h = hashes.Hash(algorithm, self._backend) + h.update(self.public_bytes(serialization.Encoding.DER)) + return h.finalize() + + version = utils.read_only_property("_version") + + @property + def serial_number(self): + asn1_int = self._backend._lib.X509_get_serialNumber(self._x509) + self._backend.openssl_assert(asn1_int != self._backend._ffi.NULL) + return _asn1_integer_to_int(self._backend, asn1_int) + + def public_key(self): + pkey = self._backend._lib.X509_get_pubkey(self._x509) + if pkey == self._backend._ffi.NULL: + # Remove errors from the stack. + self._backend._consume_errors() + raise ValueError("Certificate public key is of an unknown type") + + pkey = self._backend._ffi.gc(pkey, self._backend._lib.EVP_PKEY_free) + + return self._backend._evp_pkey_to_public_key(pkey) + + @property + def not_valid_before(self): + asn1_time = self._backend._lib.X509_getm_notBefore(self._x509) + return _parse_asn1_time(self._backend, asn1_time) + + @property + def not_valid_after(self): + asn1_time = self._backend._lib.X509_getm_notAfter(self._x509) + return _parse_asn1_time(self._backend, asn1_time) + + @property + def issuer(self): + issuer = self._backend._lib.X509_get_issuer_name(self._x509) + self._backend.openssl_assert(issuer != self._backend._ffi.NULL) + return _decode_x509_name(self._backend, issuer) + + @property + def subject(self): + subject = self._backend._lib.X509_get_subject_name(self._x509) + self._backend.openssl_assert(subject != self._backend._ffi.NULL) + return _decode_x509_name(self._backend, subject) + + @property + def signature_hash_algorithm(self): + oid = self.signature_algorithm_oid + try: + return x509._SIG_OIDS_TO_HASH[oid] + except KeyError: + raise UnsupportedAlgorithm( + "Signature algorithm OID:{} not recognized".format(oid) + ) + + @property + def signature_algorithm_oid(self): + alg = self._backend._ffi.new("X509_ALGOR **") + self._backend._lib.X509_get0_signature( + self._backend._ffi.NULL, alg, self._x509 + ) + self._backend.openssl_assert(alg[0] != self._backend._ffi.NULL) + oid = _obj2txt(self._backend, alg[0].algorithm) + return x509.ObjectIdentifier(oid) + + @utils.cached_property + def extensions(self): + return self._backend._certificate_extension_parser.parse(self._x509) + + @property + def signature(self): + sig = self._backend._ffi.new("ASN1_BIT_STRING **") + self._backend._lib.X509_get0_signature( + sig, self._backend._ffi.NULL, self._x509 + ) + self._backend.openssl_assert(sig[0] != self._backend._ffi.NULL) + return _asn1_string_to_bytes(self._backend, sig[0]) + + @property + def tbs_certificate_bytes(self): + pp = self._backend._ffi.new("unsigned char **") + res = self._backend._lib.i2d_re_X509_tbs(self._x509, pp) + self._backend.openssl_assert(res > 0) + pp = self._backend._ffi.gc( + pp, lambda pointer: self._backend._lib.OPENSSL_free(pointer[0]) + ) + return self._backend._ffi.buffer(pp[0], res)[:] + + def public_bytes(self, encoding): + bio = self._backend._create_mem_bio_gc() + if encoding is serialization.Encoding.PEM: + res = self._backend._lib.PEM_write_bio_X509(bio, self._x509) + elif encoding is serialization.Encoding.DER: + res = self._backend._lib.i2d_X509_bio(bio, self._x509) + else: + raise TypeError("encoding must be an item from the Encoding enum") + + self._backend.openssl_assert(res == 1) + return self._backend._read_mem_bio(bio) + + +@utils.register_interface(x509.RevokedCertificate) +class _RevokedCertificate(object): + def __init__(self, backend, crl, x509_revoked): + self._backend = backend + # The X509_REVOKED_value is a X509_REVOKED * that has + # no reference counting. This means when X509_CRL_free is + # called then the CRL and all X509_REVOKED * are freed. Since + # you can retain a reference to a single revoked certificate + # and let the CRL fall out of scope we need to retain a + # private reference to the CRL inside the RevokedCertificate + # object to prevent the gc from being called inappropriately. + self._crl = crl + self._x509_revoked = x509_revoked + + @property + def serial_number(self): + asn1_int = self._backend._lib.X509_REVOKED_get0_serialNumber( + self._x509_revoked + ) + self._backend.openssl_assert(asn1_int != self._backend._ffi.NULL) + return _asn1_integer_to_int(self._backend, asn1_int) + + @property + def revocation_date(self): + return _parse_asn1_time( + self._backend, + self._backend._lib.X509_REVOKED_get0_revocationDate( + self._x509_revoked + ), + ) + + @utils.cached_property + def extensions(self): + return self._backend._revoked_cert_extension_parser.parse( + self._x509_revoked + ) + + +@utils.register_interface(x509.CertificateRevocationList) +class _CertificateRevocationList(object): + def __init__(self, backend, x509_crl): + self._backend = backend + self._x509_crl = x509_crl + + def __eq__(self, other): + if not isinstance(other, x509.CertificateRevocationList): + return NotImplemented + + res = self._backend._lib.X509_CRL_cmp(self._x509_crl, other._x509_crl) + return res == 0 + + def __ne__(self, other): + return not self == other + + def fingerprint(self, algorithm): + h = hashes.Hash(algorithm, self._backend) + bio = self._backend._create_mem_bio_gc() + res = self._backend._lib.i2d_X509_CRL_bio(bio, self._x509_crl) + self._backend.openssl_assert(res == 1) + der = self._backend._read_mem_bio(bio) + h.update(der) + return h.finalize() + + @utils.cached_property + def _sorted_crl(self): + # X509_CRL_get0_by_serial sorts in place, which breaks a variety of + # things we don't want to break (like iteration and the signature). + # Let's dupe it and sort that instead. + dup = self._backend._lib.X509_CRL_dup(self._x509_crl) + self._backend.openssl_assert(dup != self._backend._ffi.NULL) + dup = self._backend._ffi.gc(dup, self._backend._lib.X509_CRL_free) + return dup + + def get_revoked_certificate_by_serial_number(self, serial_number): + revoked = self._backend._ffi.new("X509_REVOKED **") + asn1_int = _encode_asn1_int_gc(self._backend, serial_number) + res = self._backend._lib.X509_CRL_get0_by_serial( + self._sorted_crl, revoked, asn1_int + ) + if res == 0: + return None + else: + self._backend.openssl_assert(revoked[0] != self._backend._ffi.NULL) + return _RevokedCertificate( + self._backend, self._sorted_crl, revoked[0] + ) + + @property + def signature_hash_algorithm(self): + oid = self.signature_algorithm_oid + try: + return x509._SIG_OIDS_TO_HASH[oid] + except KeyError: + raise UnsupportedAlgorithm( + "Signature algorithm OID:{} not recognized".format(oid) + ) + + @property + def signature_algorithm_oid(self): + alg = self._backend._ffi.new("X509_ALGOR **") + self._backend._lib.X509_CRL_get0_signature( + self._x509_crl, self._backend._ffi.NULL, alg + ) + self._backend.openssl_assert(alg[0] != self._backend._ffi.NULL) + oid = _obj2txt(self._backend, alg[0].algorithm) + return x509.ObjectIdentifier(oid) + + @property + def issuer(self): + issuer = self._backend._lib.X509_CRL_get_issuer(self._x509_crl) + self._backend.openssl_assert(issuer != self._backend._ffi.NULL) + return _decode_x509_name(self._backend, issuer) + + @property + def next_update(self): + nu = self._backend._lib.X509_CRL_get_nextUpdate(self._x509_crl) + self._backend.openssl_assert(nu != self._backend._ffi.NULL) + return _parse_asn1_time(self._backend, nu) + + @property + def last_update(self): + lu = self._backend._lib.X509_CRL_get_lastUpdate(self._x509_crl) + self._backend.openssl_assert(lu != self._backend._ffi.NULL) + return _parse_asn1_time(self._backend, lu) + + @property + def signature(self): + sig = self._backend._ffi.new("ASN1_BIT_STRING **") + self._backend._lib.X509_CRL_get0_signature( + self._x509_crl, sig, self._backend._ffi.NULL + ) + self._backend.openssl_assert(sig[0] != self._backend._ffi.NULL) + return _asn1_string_to_bytes(self._backend, sig[0]) + + @property + def tbs_certlist_bytes(self): + pp = self._backend._ffi.new("unsigned char **") + res = self._backend._lib.i2d_re_X509_CRL_tbs(self._x509_crl, pp) + self._backend.openssl_assert(res > 0) + pp = self._backend._ffi.gc( + pp, lambda pointer: self._backend._lib.OPENSSL_free(pointer[0]) + ) + return self._backend._ffi.buffer(pp[0], res)[:] + + def public_bytes(self, encoding): + bio = self._backend._create_mem_bio_gc() + if encoding is serialization.Encoding.PEM: + res = self._backend._lib.PEM_write_bio_X509_CRL( + bio, self._x509_crl + ) + elif encoding is serialization.Encoding.DER: + res = self._backend._lib.i2d_X509_CRL_bio(bio, self._x509_crl) + else: + raise TypeError("encoding must be an item from the Encoding enum") + + self._backend.openssl_assert(res == 1) + return self._backend._read_mem_bio(bio) + + def _revoked_cert(self, idx): + revoked = self._backend._lib.X509_CRL_get_REVOKED(self._x509_crl) + r = self._backend._lib.sk_X509_REVOKED_value(revoked, idx) + self._backend.openssl_assert(r != self._backend._ffi.NULL) + return _RevokedCertificate(self._backend, self, r) + + def __iter__(self): + for i in range(len(self)): + yield self._revoked_cert(i) + + def __getitem__(self, idx): + if isinstance(idx, slice): + start, stop, step = idx.indices(len(self)) + return [self._revoked_cert(i) for i in range(start, stop, step)] + else: + idx = operator.index(idx) + if idx < 0: + idx += len(self) + if not 0 <= idx < len(self): + raise IndexError + return self._revoked_cert(idx) + + def __len__(self): + revoked = self._backend._lib.X509_CRL_get_REVOKED(self._x509_crl) + if revoked == self._backend._ffi.NULL: + return 0 + else: + return self._backend._lib.sk_X509_REVOKED_num(revoked) + + @utils.cached_property + def extensions(self): + return self._backend._crl_extension_parser.parse(self._x509_crl) + + def is_signature_valid(self, public_key): + if not isinstance( + public_key, + (dsa.DSAPublicKey, rsa.RSAPublicKey, ec.EllipticCurvePublicKey), + ): + raise TypeError( + "Expecting one of DSAPublicKey, RSAPublicKey," + " or EllipticCurvePublicKey." + ) + res = self._backend._lib.X509_CRL_verify( + self._x509_crl, public_key._evp_pkey + ) + + if res != 1: + self._backend._consume_errors() + return False + + return True + + +@utils.register_interface(x509.CertificateSigningRequest) +class _CertificateSigningRequest(object): + def __init__(self, backend, x509_req): + self._backend = backend + self._x509_req = x509_req + + def __eq__(self, other): + if not isinstance(other, _CertificateSigningRequest): + return NotImplemented + + self_bytes = self.public_bytes(serialization.Encoding.DER) + other_bytes = other.public_bytes(serialization.Encoding.DER) + return self_bytes == other_bytes + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash(self.public_bytes(serialization.Encoding.DER)) + + def public_key(self): + pkey = self._backend._lib.X509_REQ_get_pubkey(self._x509_req) + self._backend.openssl_assert(pkey != self._backend._ffi.NULL) + pkey = self._backend._ffi.gc(pkey, self._backend._lib.EVP_PKEY_free) + return self._backend._evp_pkey_to_public_key(pkey) + + @property + def subject(self): + subject = self._backend._lib.X509_REQ_get_subject_name(self._x509_req) + self._backend.openssl_assert(subject != self._backend._ffi.NULL) + return _decode_x509_name(self._backend, subject) + + @property + def signature_hash_algorithm(self): + oid = self.signature_algorithm_oid + try: + return x509._SIG_OIDS_TO_HASH[oid] + except KeyError: + raise UnsupportedAlgorithm( + "Signature algorithm OID:{} not recognized".format(oid) + ) + + @property + def signature_algorithm_oid(self): + alg = self._backend._ffi.new("X509_ALGOR **") + self._backend._lib.X509_REQ_get0_signature( + self._x509_req, self._backend._ffi.NULL, alg + ) + self._backend.openssl_assert(alg[0] != self._backend._ffi.NULL) + oid = _obj2txt(self._backend, alg[0].algorithm) + return x509.ObjectIdentifier(oid) + + @utils.cached_property + def extensions(self): + x509_exts = self._backend._lib.X509_REQ_get_extensions(self._x509_req) + x509_exts = self._backend._ffi.gc( + x509_exts, + lambda x: self._backend._lib.sk_X509_EXTENSION_pop_free( + x, + self._backend._ffi.addressof( + self._backend._lib._original_lib, "X509_EXTENSION_free" + ), + ), + ) + return self._backend._csr_extension_parser.parse(x509_exts) + + def public_bytes(self, encoding): + bio = self._backend._create_mem_bio_gc() + if encoding is serialization.Encoding.PEM: + res = self._backend._lib.PEM_write_bio_X509_REQ( + bio, self._x509_req + ) + elif encoding is serialization.Encoding.DER: + res = self._backend._lib.i2d_X509_REQ_bio(bio, self._x509_req) + else: + raise TypeError("encoding must be an item from the Encoding enum") + + self._backend.openssl_assert(res == 1) + return self._backend._read_mem_bio(bio) + + @property + def tbs_certrequest_bytes(self): + pp = self._backend._ffi.new("unsigned char **") + res = self._backend._lib.i2d_re_X509_REQ_tbs(self._x509_req, pp) + self._backend.openssl_assert(res > 0) + pp = self._backend._ffi.gc( + pp, lambda pointer: self._backend._lib.OPENSSL_free(pointer[0]) + ) + return self._backend._ffi.buffer(pp[0], res)[:] + + @property + def signature(self): + sig = self._backend._ffi.new("ASN1_BIT_STRING **") + self._backend._lib.X509_REQ_get0_signature( + self._x509_req, sig, self._backend._ffi.NULL + ) + self._backend.openssl_assert(sig[0] != self._backend._ffi.NULL) + return _asn1_string_to_bytes(self._backend, sig[0]) + + @property + def is_signature_valid(self): + pkey = self._backend._lib.X509_REQ_get_pubkey(self._x509_req) + self._backend.openssl_assert(pkey != self._backend._ffi.NULL) + pkey = self._backend._ffi.gc(pkey, self._backend._lib.EVP_PKEY_free) + res = self._backend._lib.X509_REQ_verify(self._x509_req, pkey) + + if res != 1: + self._backend._consume_errors() + return False + + return True + + def get_attribute_for_oid(self, oid): + obj = _txt2obj_gc(self._backend, oid.dotted_string) + pos = self._backend._lib.X509_REQ_get_attr_by_OBJ( + self._x509_req, obj, -1 + ) + if pos == -1: + raise x509.AttributeNotFound( + "No {} attribute was found".format(oid), oid + ) + + attr = self._backend._lib.X509_REQ_get_attr(self._x509_req, pos) + self._backend.openssl_assert(attr != self._backend._ffi.NULL) + # We don't support multiple valued attributes for now. + self._backend.openssl_assert( + self._backend._lib.X509_ATTRIBUTE_count(attr) == 1 + ) + asn1_type = self._backend._lib.X509_ATTRIBUTE_get0_type(attr, 0) + self._backend.openssl_assert(asn1_type != self._backend._ffi.NULL) + # We need this to ensure that our C type cast is safe. + # Also this should always be a sane string type, but we'll see if + # that is true in the real world... + if asn1_type.type not in ( + _ASN1Type.UTF8String.value, + _ASN1Type.PrintableString.value, + _ASN1Type.IA5String.value, + ): + raise ValueError( + "OID {} has a disallowed ASN.1 type: {}".format( + oid, asn1_type.type + ) + ) + + data = self._backend._lib.X509_ATTRIBUTE_get0_data( + attr, 0, asn1_type.type, self._backend._ffi.NULL + ) + self._backend.openssl_assert(data != self._backend._ffi.NULL) + # This cast is safe iff we assert on the type above to ensure + # that it is always a type of ASN1_STRING + data = self._backend._ffi.cast("ASN1_STRING *", data) + return _asn1_string_to_bytes(self._backend, data) + + +@utils.register_interface( + x509.certificate_transparency.SignedCertificateTimestamp +) +class _SignedCertificateTimestamp(object): + def __init__(self, backend, sct_list, sct): + self._backend = backend + # Keep the SCT_LIST that this SCT came from alive. + self._sct_list = sct_list + self._sct = sct + + @property + def version(self): + version = self._backend._lib.SCT_get_version(self._sct) + assert version == self._backend._lib.SCT_VERSION_V1 + return x509.certificate_transparency.Version.v1 + + @property + def log_id(self): + out = self._backend._ffi.new("unsigned char **") + log_id_length = self._backend._lib.SCT_get0_log_id(self._sct, out) + assert log_id_length >= 0 + return self._backend._ffi.buffer(out[0], log_id_length)[:] + + @property + def timestamp(self): + timestamp = self._backend._lib.SCT_get_timestamp(self._sct) + milliseconds = timestamp % 1000 + return datetime.datetime.utcfromtimestamp(timestamp // 1000).replace( + microsecond=milliseconds * 1000 + ) + + @property + def entry_type(self): + entry_type = self._backend._lib.SCT_get_log_entry_type(self._sct) + # We currently only support loading SCTs from the X.509 extension, so + # we only have precerts. + assert entry_type == self._backend._lib.CT_LOG_ENTRY_TYPE_PRECERT + return x509.certificate_transparency.LogEntryType.PRE_CERTIFICATE + + @property + def _signature(self): + ptrptr = self._backend._ffi.new("unsigned char **") + res = self._backend._lib.SCT_get0_signature(self._sct, ptrptr) + self._backend.openssl_assert(res > 0) + self._backend.openssl_assert(ptrptr[0] != self._backend._ffi.NULL) + return self._backend._ffi.buffer(ptrptr[0], res)[:] + + def __hash__(self): + return hash(self._signature) + + def __eq__(self, other): + if not isinstance(other, _SignedCertificateTimestamp): + return NotImplemented + + return self._signature == other._signature + + def __ne__(self, other): + return not self == other diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/bindings/__init__.py b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/bindings/__init__.py new file mode 100644 index 0000000..4b54088 --- /dev/null +++ b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/bindings/__init__.py @@ -0,0 +1,5 @@ +# This file is dual licensed under the terms of the Apache License, Version +# 2.0, and the BSD License. See the LICENSE file in the root of this repository +# for complete details. + +from __future__ import absolute_import, division, print_function diff --git a/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/bindings/_openssl.abi3.so b/flask-facebok-google-twitter-login/env/lib/python3.8/site-packages/cryptography/hazmat/bindings/_openssl.abi3.so new file mode 100755 index 0000000000000000000000000000000000000000..66bd3426f224e3bde0a0585c3fac67510d0490e3 GIT binary patch literal 7050912 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
    YYu}^WRl|1|F#1g%4Dp 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

    )}y-sirHdV6sv)}oc(FB}e7nkMwX0?0&$ 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

    DQRDUCFq2b~It17JFsk50_fb^U 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 z zFjtC365%b5DX(>LCMh(EL44jP&K%~H3}HDA&1)$u0+JLASdJo|cNx3^OR=(#mrJ&a zaU})&cnG#YlN36zf#MpJ{EJvhN8%S1aZKsdj?+RGzldfKIEw(=sk!H=CyWn@TD_q` zRFvC_V4W-{sQxJ3(fW|-f3Ah>@ZO}Ap?c|ygPW1PX-(trh%h7C`-+PW$x4$q82|7@ zGyaD%{(rzX{x;g-pBKEX%fhGLgK~FL-*;JLlRu!i)O=E3k2hFI`Zbe*DewmhPb+n% zO5JJpKmL9=eyrMEBMIN!t9ELh(kH@ve6Hcc-Mv%$S_=L}<>o^UXmu9lT3Ri?M&Q<6 zhd3jgi6Wb=jtmApyayhv}A+Y4(rw6t&NUIcDBD#><VZaigaHx&%`u2f*V@UgTmd=Ch7>&gyyyehS0#dVr@m^u} z7mW3MI>YQnt`Lt6L@l3Bd;dH~W7$lm+RJH57#s1qdyOOF^mnB|l@2`${4>Y#q)^5P z>c>S5o%ChWVIh;F^=5znqH%366sLwW{aHvk-k!*}EhJYkd?fy%WLB$ndT8cD&tc zrbhQuNNmuiq%oDntY=?v0_m@3g{=Hm{J%kM^ZPAE{tg-Gx2;2{>lyMIku6z4hEV-n zfvVry>j3m$0=-?J0JSB*tFlx2boHM#slykJT(fz2^g$0~dVqPO`}lHgY_y_{~jJ?=B6QD<|Y{_pIo*XH3Zb)c9>eEnt{U zq1hsMlX2=J4voKCb2hl_-@?|vEP^W%cT0orHNa%vJA?N0y-FnHIkI-{T}92@Bg(<# z1eD}>y3Gs$uFUHYuSUrxPw9>cu4j3^nZLS(a=PRe_eF4XU-D)?O3mQ%Jzi&ZaihG2 zqxcE*%>|9Z33s1*k1U|i3U#`KrACQL!B{90lE+@WuPyaBgI_g=t&H~XyD)>Paeghx$BcZId?W!y_&`A*!fWxr9ca(o)LFlqsFaK`Vo~J2u7NB z$QGe`Tvz#H#c-ZP_a_Gj_i=wU$sa598dtP~{?Kzc>H9zSmu2p_2*cmUx8wUay2qR@ zzp_{B5YD{cFON5w@R?yAILb)pJ);ic4&{w5_Ou(=WjNt3aXk+~mR6YgB3;{o())Zv zdf7LmkNk%8N#BqjyvK78{N`6dQ?rg882|Z;z9D__H>7I~{<`v;Qt3<9+RuRgOEz@~ zZ|xBFI)rz12y3{uk0;*pim=B?jW2WkIU~%1pB83Y#10cDuWlFZ_w@}k&~CGea$y-Z zy-!+t{{y6#rKLv>kUlakef$B^C#9uNJ3#u3wDegW(own?`uZRW)(Lf5u}JtULi9~b z7eC2JU!0jPR+Et~`ljWt@0i|{nJ%7_kzYh7KLVS@M?_B#Z|x8k(bLmK^z^WZt}t{8 zr|<90o-b{`(=b|qiGC*xU{i6?RBb9U;KkQ?r>f1nZlDxOu_L|D|6#UV?DSS`J2Q)& z7e1NX+{gJgoUKFtj`iyfZsO!yV49;MiSOJ?u4v+qRp1ber}#kKfvaAY=Y8}L6}1di zOR}N^-l=?-E!P+_c)i)nPPib_k~@@;{xeVd+4&-QFfw@yXcts};W+cZBpG2aG5Ba9 znCN#BHG4;!&9Hr!G@kp}`)ATJU)YWh{+OWIJAFh}Z#J#1-7#wtej7g`p&~x$b*~=8 z2CTR#ssP7BPYO@EW)N%r@3eR)j+E;+a|*8v8VJHF!T%{~|E@syV-3LiK|{hoa`3?(fS>H`@oP9HH6oe5A?tOzrYTsQz@DZDE)z32XEkaJeIek3}{L==#%G{?Jl2|xq=Z1;tV;<<}RR477-*17~kR?5&;Rn{_IcQVk`w~$m(J?Ql;d(LB?f`E88|CrUZ zx8UBpRKweDMSn(dwqHe%sM}u`4rj2_0Y`N*{H(l)XO#=QoqrHIv4Mt)AOAVmkQ2Ab z;lwoL?+?9WAEfK!gLl0P8U85ELiO_A;XuL(UC1R1{O|pn`mIs}9I~EK_d}L#{d)S1 z@g5q#udP8lXfR$&v_$G$U|a8p&fXV)qFOiSb&Z(A<(#?28*k8ZYL8^pgz9DU*P(pB zmlECQQJhyn`N=WBTKQJv!oss(N#QfD9iL+akNa#NUgN391Vg*_ecBs!?|%vfV~mRF9nG}EYH*r+{8xg14Lf$8mfXq_PIqLW|4RI z1H?)ZRjx^CAJ`1l&!jfnNvUe6{8TFUJ|Al|QFmDRg>h~aXbc~N>))M^PTfx zV~*v1$U|JqiBtc8fOXFm%+qn9vC+wUQfe61s=mdc>V2@Hq-k-#zvwDYV(|R88RG8C zUi=X|MQ$WDo_iIsnj%*THa>U?LDRRx2z$H!rpYn*a^-9(r@Jt_j1Su5^#&K+Vs#c= z4OsQwd}rYb(#&&yW~UlXOm1UhcafaxE>j*ff}O~PX7mlVPv1Hd2I2jQ znyj6wbO><)F$Q>9?e)8i4Q6s5kD($M7&d|?WZ`9 zvBmzo9;C7&1JM=5j%oPRAl9$`R68$rO!B?e(vQ}-SbBDpX2~dB8?1-bKYS|nQYZU1t?-IR*cRj-cH&USOYtVj&c*0qR&%D2GghAqMuB%+uC zq?`HR#6z@68)bpKT`~Eqh9hmp$H{2Mb0N9> zYY(+njWYPEH|dO`zi2!k3$z`VR|f+b)-{vN-Vju_DA9k(ygu0YJy&o?8#v?4m5%PA zvX>*YK+4MdOp}sl8+OmQ#T{TTzEkt>VB>htk0|#U^s!_(%w(ARxfsx6-T?23;4NxN{~XUfgD8cL5@3Ar z=>*My)`_Cm%xWG@^!o{sEchRK*^B8;w*~kGTAdA_JlWJRQ48F}`<2^_;@2*l|V`;{B03 z1|#CNZEEhO}+X$Q)J?Q)3$LCqH z{O2Tp{EnwKtrPTYtwsTq_}k_)xwEjty8z_Oj)1t|5a*p_r7k-3L$B&yF_^*gh&O!C zJB38!YZlnUvCOSxPUK*EWb{E=npuboBn`cYCLOs z_wF?Ef8`N$)r910XKYU!k2=3;r#||?G8&W?Q@yWq9(3-i7_j0x``#R;Vg3n-pe%Dz1 zfP>R^^ZHVTlzzdy)Qc!GUO4y0lioj%ADIh#_c%nM8b45KD{@3Q19^?b#;q3`(`b9v&tfO{hL{* zokOt((|7cQkbIM1l<}swjeQ**_ic5EfuP@lZA+jRBPvbrnyO#&?kA11owNg1wQupB zQ0=N=@-FY$Lp8g%H0nU!yUC!n1u5eQu<x@9`Li zQ5w8UKLA&HX@v055WW~xB9pI!b~hG0Ig;kEaWC%;yYt4G7B`${;`)^;E7Y{!~b>ygoLv>WnKYzh5;c`?AXKRL$x1^U9;EaGzD#!}tYFp5UeA zyFlms&IvuUq;PKPl~vPJd5nSMrK4ojfRcHyIPdfpn{u^|;gec}b%<=GI*gF-(*|!Pt)o3h^G##TK=HnZCQbYKonC}; z{9_071w}NjA;eE(dOyB?JjKk7>~}s9^yAZ{s~?{mWn?nD-4|Wh1&nZ4Y8%cmj`h`y zL+g3ltx^Ru7HngUe9tpN1Daz!XgvD|<}L?ub@%d@&NL;zJ-4mxK@2H>L7X}Cf5;?m z@m{^Dt!?lk5Ox-7KgnL+S*ZOdPB}yKzBCE*#}JMttaBW^Plc+#%yX(wWL}o85A9x_ zeCh!UxK4_zL5vrk5?f_FM|#;%4q$e?1(2dJ_sIT<5+?jD2Q-^XFAg z32&X5m?jVkV)~evwP`VBCT43|%t#ZnD=lV{i4hwM%HggdbrqyyZY{1d@I=ZQS77|} zZ;9d)#IzmnAB%zVZo`5_5|0AL0aj^KqX6WLODj~Tce`f!5!<{^-|4E2LATc9XejD4 zHPjpFm+%kj3it=>!@T99Wyap2%uM8Wn8C>q3_#;GUa3?2JZ}PKY-X)N4cofRoMKlb z26ZjnU9!}>sL%GcktPzC78iM6-AKT6_4_k2tb z2u*Rj9nBTiPRT)v;;_{{+E`g8zeiZTUorV5y_Pc0uVDz~1hYcPzVons-dG<%_8|;| zUdhkRz7{WLA2ugDe-e3s*_>=9j`Q>(SvruIo0rTc6YslaUx&gDF8F;z`qwzyXdDjUs=@HF6k;<36+kyh!puj49Slq4n z0Vdu+lW!>IG)l-K&JV7?oC%@tqF4`JSwdgr5v_Hx`kA$b_O zLPQJ7mD;_Kvq@YXq8;(1D%M?HblZZ2h-fECQ058AjqEjj{n4lfWA0D{W$3$_V_9`x zrSIS*TIOWZ>#b%`@|`OSm1UI2o^lvbtviJ`@?0ReQ~2D1ET={Vnx6CDZBp+!HBuAX z*##9>ni*Mnsv+smu*fi!7->K9yy5x?I!!zvn z&^X>rp85QlStB_9x4wTvfv;xsR39=s#sl(PBah6Ryf|HlGD^LBot!r7Rzc-qs9Gqe z@VlsrobXmC#(S$_{~64k-U;k&fgg%m3YU%&AwD&lF5bu!wq*I9;@6|x>Jwx1eAdDt~xkX%Sahxvtx zPugx6eL(!^F{8rqE{Of?cJm_5I|@eNka5Wlj6iVWv?9`+EHJOBZa^Y~t2R|Mdj-*w zrV6+HYiT%sVNQG)z8%lWtH|EqEZIU5DSl4R5v7|d@V(_eUoLcAd{wQod8vvGRm6;zZo z$Hx{qOE!n&V|&rI_}JoT_PPo%avt5lM!~5$(bT&%()rP}!d(>~+Z$YkCA|xx zYfXkj$PjjxtXGbT68v%T{|1|VLxsCEKK7)F(q}8OUn37$*OPC($@f7Qlh2f2QL+}? zZ3+5{CVC!GQMxW#`WmF@L$=k?(zVgjbtBx@MmUeYis}@9$mAzwSw(Xz4cs)srHurV zP;(8f>km#%(D<5OMqgh?r|J zJvb339+-&lu_FPCG}0Y}h?5RX#DA0jYlt|_C*q}sh*x$X;$37uC=q8IfQWM~wgKrn z5HWUOB3@!MeIpTP9his%Z3_=X#Cyd7q2ug;j(5}$(Sejlm_{C$ly^v}e*kLk$@%&z zd50{J4@}UPY}T(MX#8HYttfr1oun0bT47!q8{xm$5|%}nmlbAS!hkg|M`&J}>j>fa zExJ}FqAs|{Gaac4&n^RquF^A~ay5rK_T)&!*4T!zqH40}=X;$H_&b zb(GGOB^PXZZ8W=?xW5w@&0cCI{5CeM6tUD!co<=mmW+xL82g&Ixwrwhhk0u~cOEqg z?wU2^q4Ug=Qc<#$wSnSowq+w=zxO^(1<-ngIPe>kE-vw!q11z9r70p54)@^IsyAA) zc0{6Q=ZeziNa<2K*>I>knka<4t8IhV8Eof~ofS05MGsrfb!S0sC#bRa{WCHMmSkjmM9roNiD7O18P7r2->%2Q)OH2(#+Sxm+~J(AB- zI6Tc>(bzqPOV)==mbNZO-Y{ZVxP&)!mxf9{NS=x$V4)2%0R^`8+UVaDs+k$dB;D4-fU$j5| z!~OVl{I4`|2f)A9BvhGpwU=-3|3grII{vHM;nVT|D82j+`0Kz_`-ZgsG5y~sBcA>* zcbCzt$@BgAbo}c~oR7ah4w7Majp%!SMmdJQ2LF~IJ{|v$O=Mbo%NeK;;5!J&fxSk6 zf4RFMRI)iaz$BH~an0x{S)06osMLPI$8%G-WK~ix`^aBGf!wI?6pE|)@mO(b#F zUUab2Lh-U3S)3My;sp*fi5EuQCg)jqeYwB zYXP`rq0a(hu};^g0QQCIDsguBsZ*EeHNyRJgu6#4`+cH#A}omPc{P&g`@BY? zKsd^Xf-Wh&wZAQjRDZVDe{`HIMHPvt!>(jsS7-j~=ny#zURQvkYI5Ht5guuN-{|4h zk9zUk^dq~mvI=)2J*0l*NgmseLH{bUPbB*z)34Ymu#c8STLgXEY-;uy>8JZ2DT34m6s+{))c-5=w-0 zEA36)>qL14D)nw3@ctFy9 z5bsBJ1Qwd+_vTkQLA)t)8l#Y~@)LeGf=li3k?JoX^zoL^d5$6UeTL9lwW^cZtYLX& zb){Tjh$OCQi{M+XtnTOh{eYA7bK2_0w$+8O7a#@sKQWesWM17lgm`cGEJ7awel34J zyd%no>hz_+vmM9topP@M+O; z(z?7_gA$P)NtDjg>=n9QjAO%)v%1_pCr2Ahccb$JXR|Eo&CV0s*_IZnr)WM_I<53c zL3v$Haj0%~adxO~VsWQX-RR=Zp}JUcPN*(goLf#@mrz}}7|))Wop5ZGX05Hk7O%3Y zLdB~}YEbdi(t6J#gFMX2ke((ner)TKHRw=F+mio8U&6+ZuMK>a?oMtu5vz!hg;|BG zFJo5gzK|>=CgMJu>|_4Eko*>Z10p5|5a4|Uqo@gu8DSqg*OMZF0;_i@o=u-kf>qQ? zI*KOx9<9+{V6`{ejY~Q<@(bEKxOdl3d|Zyy$e1x&vmlHNoK^4uMu*`CIkZS$QT<-o z?3BO^ylo#E3c>P2ZdXXf6biY+bDSrJwuS1to*FJbqORQfg^3RMBz9tC@+wu}JTZ#l zwIVy3{TZGXohM4`dQ@-iTKaL_n6`=mZ#w3dm|hiuAidKRJ1k9M*dB+DZ)Y|rXvdYN z9p@gX9jnvYVOo&cj$;qj4q9+3-kHnQ9J3eA*QK?k?9@_PQpUo-v=wOW zWq>A65qu)I{Lr55_Y;h6O4EFM5zn)pn`7uhj|<=) zRMQv7gYB}XkxMu~v)XfiWK?hG0Sn%^h|oXqW`>CK0=4yp4_uv7>~_=NZp9{!hZIC( zzPEEDsTBjZRNgH^E}ouYZn>Rk zbpN!`5!9gugxnv8U=FP>w|9xTf8{*kG{2SS9_BnTE*m$ShlQOdrgjQ7zl#yx6b9|M z&Y}F5?C12H=J)d4tKojbbMsg50q8|t@IcZ0UVfwEJm8&&LS6==j*VL%cAo{u-l2JKE24R;DW~}@@{T7-ey?mK1-@QtdA+>Ekzo1 zz_PFEGUd{R7xs6SfcmQjwPaU!?4bM?!|pnv)tu})Z<{S`joVC>?wm5>LN;$GAB0xZ z2cU3a*u)#u@>jXssT&(Hcn}R@q5ReEy5=2S6?!{Agaa(Fafe0o*MQAPX9<6nh18^0 zNa2OuH{5eZ=fB1_Nwl(kr6ls&*3(}T^WSin38k^)NeX(7JZprJd-Wt`u+aIN+%>kN zE+x|Mo>$!s?yzYF$o365FEgY#=Ss!$&!UZ8yc zcALWP0;zO}^&^+Md))=n*7zerLz*t!mhavnB}^#4$@M}|njG!jnBNl0|G?c8cApnH zw)#kiU88i#_uR(2l+|GMhV3a^x_irF5)8hS7k2N^>T?iGg$CH(4@3uSr6Ez287D$; zZ`j@F-XYyb&{sQ!l|{hlKR`2oulphxHSaVdz^C75?nYW7iYS^P7T_s;NVt$h#+1q7jjo}(X8M195W>eRrt_iuD z?bV#$RP5o(DVmY>u?rRdv@{0N!7D)z0BBuBeX^Wuw;Ve}Id=F>WDjCGs+%=NSO2n! zzy+M_Ik9Cs1n2Cn&)fAl!JBltQM=iRpd2}donYRcO}2S%C`TK^_8_ay_->##^C0M5 zbO7}H{j0%GYN$=Z^8XsYpLMGkus8O-ifXog@v?%7>Smts3+?5*Cx5?8{u|lKw2QrF zd@Sd6?%1689joXtcUWHhmgVa0iS8Zx>l!B|oXb`b$ZE-b^B-r*=0Zz6{n?VcvP1YU z9m2PD2;YzqHkM7pS9GPI@AwIe3aGIz@JGn*^?&`0viwPtIaAQ?m*<5A}kN`@;mi)fw-e;0Y#JUCuf8+;h%tv)^Ks_4)Sx;}V1RO#9;eA(CJ6h52tDmhZXL%J>TIXcS{C+c4g@8rKgo;XPfbc3&X9wz-!Pou%z6p>CX>yyr77VF0 zR3v4bB-c-_*v=J7J*?6(fot(sYxo9Ofkp9{S2Y;&I5|o76`%5IV>4;`VR4MM;YzxK zWZ>dcf0j>t$MX#w+-8%d#3v^rsdSL9{`vF9P;kfiOl5!b$@6*B0C~{pp?*pIk7RJ z_9^^Hxc78#XyvEpdP6rZB%^k-#KX6p>J44IfTw2(#SyADdU`|SOJxP;ShX@mGDXy6 z@x_ErP)<0O@-^KI{dzby;~%U2nXLQJ3;)sG8-Arfy=w^h-|EMId=>fQNDH;@7f>F@w4nGRnCAjA31Kq@V} zQnzf3ZdplG%NF!V%i?L7e3=ThB>nMgf24h{gq948w687nTqW&m>T6%XzU@D8lf-M5 zb9>guC0%VX#Jn`>XEVnN-?5xT``fP!ElVHf9VXy>6qKQFES1IQ*%h$g43wv>iv4x9 zN;!2K?AwohI33qo-hOa8s+npX*9U>6Gnpb^;0g<0`(IC?Ek@&v?(^mXn0FQ zR~QWk^i!G9U}u?-Puggx(9cQoe20GKuhHPs&++p72mM?o&!6h&74n>ou8?wiC>gJN&ZthzkUK)&Or8GfmO)j-7EOt)cAMl@_r%s^DO)e6n^?Dg%6qe ztKgp#D>UM*apXbya|FNC!aqosGhn}7;Wrr#-xK^-HGWvPr%3SAE&RWd6)62OAR%p7 z+VqB>*4WE*>1Y24_P#pxb@igU35@*^kWfFTVBe>)xi43Jt6=}d!mbhQ^nVC8EzcF~ zazLSJy6y&1;)DzJ`|0}q)$;y**89Wc{p>sBeR}F7sc@WN2TGq7w6{I1!{FE#bUWRE z-2O{TC8vM_lwV}S4n`3C`9PtB7x5$iLND=Zcs+}R_sgyC`~xp`0T-K&pOY1^9{?mI z^#@Y3Ut@pPrM`2cU~jds?tV3SMgRz{)Hy0mbTtyvvqO+1vb?2P#1I z^uq#(?K&7rO#b$gy+-i2BWevPpBukx=SEt{@Zf$ zkSi~9!E5N{gu}fK8e$WVR&~AOBhP^5^xc|w9c}`)#h39pgRUWlN*%iT z(>t}9qZ@}PRGL_W%6TE}I-oL)h7v{vZ}v2`9;|P~=zc>P)r7wHH*sp~2-V9yAKD9d zu#Myj@DQEa_p9Eq=$1OFYG23sfz}VJ?ZBPljpW8{PK}LndlcUx87PSg7T_f1Q_SqV zXKdO}#e0V6@)D1aSv*Xl(zV?AIs43@Ss=%dxw5fx2a4RvF{%o3!qjo0NeDbE^Un-$ zyCS_vEUi;jd|b%0hqLByIcCeu{yp7tk-Sgz-%9jRHP$IBev-YR*{}!I74(9LsmorV zLmJ+3%yQgd{BV=8_MPx;n%LD#H^@GX{b$uklXi*bB(OrN@2#T~xnP@q4y91ww{D$(;xB$!@%Vn|HmT|5(?%e#-=ewAE1B}o^nToJ=AQ`$iUBB7|K~IrgwC%J1YLg_Pms21 zUB4JWXNKnJ`c-4dyPCZ94)8**LG}OSFWQf@v0RlhHXY3H6PL(xFM}JLCeo{vUTUAy z7uF0fGh;&&W76Z_@KVD3xgQrO*f`BKs8IL0Y~MNkWxN9Z&LZ=+9YNzUg0H+~*+cYldn__M0F@mQ-k!)DaN(%WIk5|0HWY zUUe~{?+RS}J@5{s^<#fUPPp|Vna)lCie3?dEKn?x!2)-n3j6Y%o~vE{6YhWswJysw z113voK~irK#?g-I-UY?I3kpKV2|C4RLwKX(?>W{TqMF9}{Mj&%KauYlCEv3zQ@+RQ zt9o*oPV3(1Z==Xe1MtrtmG4*h?N3F?ch!yKK-K-b7o3;MNQP=I21ftpb9ik}rYa+= zELWb>^)nL5=lXp-FY12(E>Dqm)=Rxtt9r!|HfH6~Bqq=x`Ov=PA=XC&s0fFsiRZ>+ zIMdy`U*rMyWICQkQ^U@saFT}rX^AUo{jF5Q*yKtbyBGlx{;p*mn{!XB*K;d7o;-2S zANrwuWrci|F3+61OHn%0KU2B4N93(Q7Cp*pqDqx3q1C<>M`+(@t9>s@oBP{$D|ymB&j+e~A{pvdQZUp>BEDL6P{A%BpL0@Mpu_{E5ti2f+_rnW5rw1QnCh^Hr@EY2FaF zB`*IdO~L$~V!shA9a=RkidGXx1L7T_WaBB3eN;awH|h<^wn*SdQ-=-CUc>i9-rn5) zxwo5n+gO|FJw3&!Z>8zp(+iD;-Mj;Bjxp*R$)-uK^P*-qQg@m0LD`(nzB4ZWh7 z7{ymOj12{4^(Q^|2PbYHmux&zND;2aS6|WpyhjVTU!i@x#b1LCg`+I&fbKVYOH60eT>-~PHD0EFK`}nw z`pltBx4ps1&{)kf>R0k1R?~hYrM)z$X;;d;Q0-cBzd5K)3-1t9yRMIQdyd!5VrvrB zmaQ1UF*7ewT{RK&8MC3&XqZRs(e2BPn$I|QY)Dot<#lOu_)mY(^HR+l$2t-G8)Zgq z5YY=dKIRkV(Z{LGBO#Va{%&jCN;yJVB*=l3bE{R(VEE51xcBq|qd^o}YH%CA#uJ86 z__iDMw=iD8s_iRIGj??}y}yHu4V~8TT^ErDtnsT9yg_|sth!pD(fwsK<|Cg+f7i(HO+aY2=-sT(+by4`L;~yc zDnoo;44?NB<@Saz2UXK2IX``c%@67XR0}J6Y>c_*8!LNa`8DeQi*l6wu(Bsc0fGRm zExo2UY}@aFNaIeYnMmgP3Q%AorMNq9OozY4LT|X)XO>-5B=s$?dh(6(J8nz2Pg_Pf?r+5(i zzz4J0d#UYzR(HE>{}l#PG$#Btx<=FQ3wg5ohy5Xu4aNWdoQgFW+4-wYs%1!;t4xVP zP2<(>`q5dGM&O}P?&adDxG9vwuLLj1RB1F;u+=BPQL)GaJSZmhD|zs@ZAhXiAv?rh zcEe~FjuoDKNkzbDX5G6`bO}cjy#ZTjoZ#46iwB{&0+)r}$DvWOKb9WVVg4__QhP(o zl#mjUmauC=;0k@8kR;Yj1-JwQ7n{Az(9kMf(o-r^Y)nO~fc{&Ty5|c0?!#88 z*1MrnRi@{=uDNaIwOR*atlImzs)uQ`a_bYN+R(42Dm}oJ5ru=YzY{OzyH2+2VQC*C z{>T-CCq2S7zoH4?o8A5{(X52x@b#2pUe50!dd|n8P5g>t;6;`0*ic3zLf`(4a?AfW z@w!y`s$dDHQ-&C#6U16yK?&?=PDVftl5c6yTCKjkSIE(TUcP*k?x`784w9@#Y(4jd z{(`m$neZEtPN3DISt&Mce2+=kfhOt;1r(Oi;APX0*JiVh#nfcYgpI6;T}# zn?M2h&tAYT&kVev*B%bGbAD}Y8?O>9kVS6Gqx7MQw;K&ne|S)?c1u z-BQ6*G&vgYBEh=@JVj<_ZyKPFVpk*jsA8p#IxRv#;7%yx5u;vCv)qB_WpE|**bS(2 z&_Occ*%W=l#EQ`!xH&UqT!X^Dd!c8cNQKy}xcqNb`a2ynMSp~fP3e!mjLKeJXs%rT z;q_?T`y7nr`^5dbQMMo(ZsSj+zivH9yZ;==8sm)tj>npAhJKB8dL=Vjwy53@Y!J{L z9jabwgbnY2PDM)EXjbUQoPdeKN~Y5TOz=iI4q%G*9uQ%^BlK|wNy%I+eIU!-Z95m5 z#+4vS-1Q$-U**R79Kt3gs){Q8Z-q)J`P<)VXp+1nqdtT8RqT@nDsTmH^)K0E@?$){ z(N(g^c)TfTqfuW1l8dN@rnfu8SbaGuD6MP@4|d+ZhI=*Q<4!n?`Dt;43TZa7;^Vki zhH|#oec<+oOz-|q;(Qq@UL7*R(71x37~oeCaC48bTI>b@y5npGX+wax9plHwHLIp|FkaU4uq9ExSk|B_EAkMgqg7_gq zKi5m2!2E~qm!W1x?hD<(XlpinFJg*CcOC0i(r~p~8ZZyv-N!t<46hJq<8`1r)-?#8 zY?TJ!{Y~(CV-%iTR}zu$*2_JZx?+EP9t{Zy;v4B`d*k!MM>y!R z9o#7Bzt`oy1a_eutmn9s!iu#z~=heUD zgRkqoH>%zb-lyIxRlU(B&q|+dIVY)mfVzL%vPobI_x?#`_HSXFl?*7Vm3bAt+W(5dTHk{lc{c{i zg-u+;aI0gToOw9b=TeXESJT+Aqr#8d#AegmW^*TRbggVs=OP&PHHTvhci_0W(|f>h zPLkm@IoDAa}Bs)*3+do%`HTK-=M5cou@eT9s-{lQ%l7;@3 z=d_ip`~LKGJ9{lDS4xApUmE_EgPEzysQV|8S`Q!rw7+1jhsH@DQGYz8VH5SkWN8|q zJQ|gB9UOc3UFOGfpz3y=e*UKpGal#Neu)+e9jJxXB%-Cc9>I#L{)@MDe>?pLFlXN) z;{Byc-XZ8i<1DEg$?OtcD`Q^wG2wD@xb+GBYYP#ecQ4%Bc%yFN9LkcgBgg3k*-Apt z8*d_OHm#pXp5iv)-QCrHxJ zHvi-tR~tm0K@Swj-rrrpH~YKVFOlzc`I-B%CRUFwKY=< z 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∓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

    kHV;%Sx)?3$7uTYR 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

    P|O|UjMavsF%5( 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