README.md edited
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,537 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
# pylint: disable=missing-module-docstring, redefined-builtin
|
||||
import json
|
||||
from base64 import b64decode
|
||||
from collections.abc import Sequence
|
||||
from typing import TYPE_CHECKING, Optional, no_type_check
|
||||
|
||||
try:
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
from cryptography.hazmat.primitives.asymmetric.padding import MGF1, OAEP
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher
|
||||
from cryptography.hazmat.primitives.ciphers.algorithms import AES
|
||||
from cryptography.hazmat.primitives.ciphers.modes import CBC
|
||||
from cryptography.hazmat.primitives.hashes import SHA1, SHA256, SHA512, Hash
|
||||
|
||||
CRYPTO_INSTALLED = True
|
||||
except ImportError:
|
||||
default_backend = None # type: ignore[assignment]
|
||||
MGF1, OAEP, Cipher, AES, CBC = (None, None, None, None, None) # type: ignore[misc,assignment]
|
||||
SHA1, SHA256, SHA512, Hash = (None, None, None, None) # type: ignore[misc,assignment]
|
||||
|
||||
CRYPTO_INSTALLED = False
|
||||
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.strings import TextEncoding
|
||||
from telegram._utils.types import JSONDict
|
||||
from telegram.error import PassportDecryptionError
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot
|
||||
|
||||
|
||||
@no_type_check
|
||||
def decrypt(secret, hash, data):
|
||||
"""
|
||||
Decrypt per telegram docs at https://core.telegram.org/passport.
|
||||
|
||||
Args:
|
||||
secret (:obj:`str` or :obj:`bytes`): The encryption secret, either as bytes or as a
|
||||
base64 encoded string.
|
||||
hash (:obj:`str` or :obj:`bytes`): The hash, either as bytes or as a
|
||||
base64 encoded string.
|
||||
data (:obj:`str` or :obj:`bytes`): The data to decrypt, either as bytes or as a
|
||||
base64 encoded string.
|
||||
file (:obj:`bool`): Force data to be treated as raw data, instead of trying to
|
||||
b64decode it.
|
||||
|
||||
Raises:
|
||||
:class:`PassportDecryptionError`: Given hash does not match hash of decrypted data.
|
||||
|
||||
Returns:
|
||||
:obj:`bytes`: The decrypted data as bytes.
|
||||
|
||||
"""
|
||||
if not CRYPTO_INSTALLED:
|
||||
raise RuntimeError(
|
||||
"To use Telegram Passports, PTB must be installed via `pip install "
|
||||
'"python-telegram-bot[passport]"`.'
|
||||
)
|
||||
# Make a SHA512 hash of secret + update
|
||||
digest = Hash(SHA512(), backend=default_backend())
|
||||
digest.update(secret + hash)
|
||||
secret_hash_hash = digest.finalize()
|
||||
# First 32 chars is our key, next 16 is the initialisation vector
|
||||
key, init_vector = secret_hash_hash[:32], secret_hash_hash[32 : 32 + 16]
|
||||
# Init a AES-CBC cipher and decrypt the data
|
||||
cipher = Cipher(AES(key), CBC(init_vector), backend=default_backend())
|
||||
decryptor = cipher.decryptor()
|
||||
data = decryptor.update(data) + decryptor.finalize()
|
||||
# Calculate SHA256 hash of the decrypted data
|
||||
digest = Hash(SHA256(), backend=default_backend())
|
||||
digest.update(data)
|
||||
data_hash = digest.finalize()
|
||||
# If the newly calculated hash did not match the one telegram gave us
|
||||
if data_hash != hash:
|
||||
# Raise a error that is caught inside telegram.PassportData and transformed into a warning
|
||||
raise PassportDecryptionError(f"Hashes are not equal! {data_hash} != {hash}")
|
||||
# Return data without padding
|
||||
return data[data[0] :]
|
||||
|
||||
|
||||
@no_type_check
|
||||
def decrypt_json(secret, hash, data):
|
||||
"""Decrypts data using secret and hash and then decodes utf-8 string and loads json"""
|
||||
return json.loads(decrypt(secret, hash, data).decode(TextEncoding.UTF_8))
|
||||
|
||||
|
||||
class EncryptedCredentials(TelegramObject):
|
||||
"""Contains data required for decrypting and authenticating EncryptedPassportElement. See the
|
||||
Telegram Passport Documentation for a complete description of the data decryption and
|
||||
authentication processes.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`data`, :attr:`hash` and :attr:`secret` are equal.
|
||||
|
||||
Note:
|
||||
This object is decrypted only when originating from
|
||||
:attr:`telegram.PassportData.decrypted_credentials`.
|
||||
|
||||
Args:
|
||||
data (:class:`telegram.Credentials` | :obj:`str`): Decrypted data with unique user's
|
||||
nonce, data hashes and secrets used for EncryptedPassportElement decryption and
|
||||
authentication or base64 encrypted data.
|
||||
hash (:obj:`str`): Base64-encoded data hash for data authentication.
|
||||
secret (:obj:`str`): Decrypted or encrypted secret used for decryption.
|
||||
|
||||
Attributes:
|
||||
data (:class:`telegram.Credentials` | :obj:`str`): Decrypted data with unique user's
|
||||
nonce, data hashes and secrets used for EncryptedPassportElement decryption and
|
||||
authentication or base64 encrypted data.
|
||||
hash (:obj:`str`): Base64-encoded data hash for data authentication.
|
||||
secret (:obj:`str`): Decrypted or encrypted secret used for decryption.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"_decrypted_data",
|
||||
"_decrypted_secret",
|
||||
"data",
|
||||
"hash",
|
||||
"secret",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
data: str,
|
||||
hash: str,
|
||||
secret: str,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
# Required
|
||||
self.data: str = data
|
||||
self.hash: str = hash
|
||||
self.secret: str = secret
|
||||
|
||||
self._id_attrs = (self.data, self.hash, self.secret)
|
||||
|
||||
self._decrypted_secret: Optional[bytes] = None
|
||||
self._decrypted_data: Optional[Credentials] = None
|
||||
|
||||
self._freeze()
|
||||
|
||||
@property
|
||||
def decrypted_secret(self) -> bytes:
|
||||
"""
|
||||
:obj:`bytes`: Lazily decrypt and return secret.
|
||||
|
||||
Raises:
|
||||
telegram.error.PassportDecryptionError: Decryption failed. Usually due to bad
|
||||
private/public key but can also suggest malformed/tampered data.
|
||||
"""
|
||||
if self._decrypted_secret is None:
|
||||
if not CRYPTO_INSTALLED:
|
||||
raise RuntimeError(
|
||||
"To use Telegram Passports, PTB must be installed via `pip install "
|
||||
'"python-telegram-bot[passport]"`.'
|
||||
)
|
||||
# Try decrypting according to step 1 at
|
||||
# https://core.telegram.org/passport#decrypting-data
|
||||
# We make sure to base64 decode the secret first.
|
||||
# Telegram says to use OAEP padding so we do that. The Mask Generation Function
|
||||
# is the default for OAEP, the algorithm is the default for PHP which is what
|
||||
# Telegram's backend servers run.
|
||||
try:
|
||||
self._decrypted_secret = self.get_bot().private_key.decrypt( # type: ignore
|
||||
b64decode(self.secret),
|
||||
OAEP(mgf=MGF1(algorithm=SHA1()), algorithm=SHA1(), label=None), # skipcq
|
||||
)
|
||||
except ValueError as exception:
|
||||
# If decryption fails raise exception
|
||||
raise PassportDecryptionError(exception) from exception
|
||||
return self._decrypted_secret
|
||||
|
||||
@property
|
||||
def decrypted_data(self) -> "Credentials":
|
||||
"""
|
||||
:class:`telegram.Credentials`: Lazily decrypt and return credentials data. This object
|
||||
also contains the user specified nonce as
|
||||
`decrypted_data.nonce`.
|
||||
|
||||
Raises:
|
||||
telegram.error.PassportDecryptionError: Decryption failed. Usually due to bad
|
||||
private/public key but can also suggest malformed/tampered data.
|
||||
"""
|
||||
if self._decrypted_data is None:
|
||||
self._decrypted_data = Credentials.de_json(
|
||||
decrypt_json(self.decrypted_secret, b64decode(self.hash), b64decode(self.data)),
|
||||
self.get_bot(),
|
||||
)
|
||||
return self._decrypted_data # type: ignore[return-value]
|
||||
|
||||
|
||||
class Credentials(TelegramObject):
|
||||
"""
|
||||
Attributes:
|
||||
secure_data (:class:`telegram.SecureData`): Credentials for encrypted data
|
||||
nonce (:obj:`str`): Bot-specified nonce
|
||||
"""
|
||||
|
||||
__slots__ = ("nonce", "secure_data")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
secure_data: "SecureData",
|
||||
nonce: str,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
# Required
|
||||
self.secure_data: SecureData = secure_data
|
||||
self.nonce: str = nonce
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["Credentials"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["secure_data"] = SecureData.de_json(data.get("secure_data"), bot=bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
|
||||
class SecureData(TelegramObject):
|
||||
"""
|
||||
This object represents the credentials that were used to decrypt the encrypted data.
|
||||
All fields are optional and depend on fields that were requested.
|
||||
|
||||
Args:
|
||||
personal_details (:class:`telegram.SecureValue`, optional): Credentials for encrypted
|
||||
personal details.
|
||||
passport (:class:`telegram.SecureValue`, optional): Credentials for encrypted passport.
|
||||
internal_passport (:class:`telegram.SecureValue`, optional): Credentials for encrypted
|
||||
internal passport.
|
||||
driver_license (:class:`telegram.SecureValue`, optional): Credentials for encrypted
|
||||
driver license.
|
||||
identity_card (:class:`telegram.SecureValue`, optional): Credentials for encrypted ID card
|
||||
address (:class:`telegram.SecureValue`, optional): Credentials for encrypted
|
||||
residential address.
|
||||
utility_bill (:class:`telegram.SecureValue`, optional): Credentials for encrypted
|
||||
utility bill.
|
||||
bank_statement (:class:`telegram.SecureValue`, optional): Credentials for encrypted
|
||||
bank statement.
|
||||
rental_agreement (:class:`telegram.SecureValue`, optional): Credentials for encrypted
|
||||
rental agreement.
|
||||
passport_registration (:class:`telegram.SecureValue`, optional): Credentials for encrypted
|
||||
registration from internal passport.
|
||||
temporary_registration (:class:`telegram.SecureValue`, optional): Credentials for encrypted
|
||||
temporary registration.
|
||||
|
||||
Attributes:
|
||||
personal_details (:class:`telegram.SecureValue`): Optional. Credentials for encrypted
|
||||
personal details.
|
||||
passport (:class:`telegram.SecureValue`): Optional. Credentials for encrypted passport.
|
||||
internal_passport (:class:`telegram.SecureValue`): Optional. Credentials for encrypted
|
||||
internal passport.
|
||||
driver_license (:class:`telegram.SecureValue`): Optional. Credentials for encrypted
|
||||
driver license.
|
||||
identity_card (:class:`telegram.SecureValue`): Optional. Credentials for encrypted ID card
|
||||
address (:class:`telegram.SecureValue`): Optional. Credentials for encrypted
|
||||
residential address.
|
||||
utility_bill (:class:`telegram.SecureValue`): Optional. Credentials for encrypted
|
||||
utility bill.
|
||||
bank_statement (:class:`telegram.SecureValue`): Optional. Credentials for encrypted
|
||||
bank statement.
|
||||
rental_agreement (:class:`telegram.SecureValue`): Optional. Credentials for encrypted
|
||||
rental agreement.
|
||||
passport_registration (:class:`telegram.SecureValue`): Optional. Credentials for encrypted
|
||||
registration from internal passport.
|
||||
temporary_registration (:class:`telegram.SecureValue`): Optional. Credentials for encrypted
|
||||
temporary registration.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"address",
|
||||
"bank_statement",
|
||||
"driver_license",
|
||||
"identity_card",
|
||||
"internal_passport",
|
||||
"passport",
|
||||
"passport_registration",
|
||||
"personal_details",
|
||||
"rental_agreement",
|
||||
"temporary_registration",
|
||||
"utility_bill",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
personal_details: Optional["SecureValue"] = None,
|
||||
passport: Optional["SecureValue"] = None,
|
||||
internal_passport: Optional["SecureValue"] = None,
|
||||
driver_license: Optional["SecureValue"] = None,
|
||||
identity_card: Optional["SecureValue"] = None,
|
||||
address: Optional["SecureValue"] = None,
|
||||
utility_bill: Optional["SecureValue"] = None,
|
||||
bank_statement: Optional["SecureValue"] = None,
|
||||
rental_agreement: Optional["SecureValue"] = None,
|
||||
passport_registration: Optional["SecureValue"] = None,
|
||||
temporary_registration: Optional["SecureValue"] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
|
||||
# Optionals
|
||||
self.temporary_registration: Optional[SecureValue] = temporary_registration
|
||||
self.passport_registration: Optional[SecureValue] = passport_registration
|
||||
self.rental_agreement: Optional[SecureValue] = rental_agreement
|
||||
self.bank_statement: Optional[SecureValue] = bank_statement
|
||||
self.utility_bill: Optional[SecureValue] = utility_bill
|
||||
self.address: Optional[SecureValue] = address
|
||||
self.identity_card: Optional[SecureValue] = identity_card
|
||||
self.driver_license: Optional[SecureValue] = driver_license
|
||||
self.internal_passport: Optional[SecureValue] = internal_passport
|
||||
self.passport: Optional[SecureValue] = passport
|
||||
self.personal_details: Optional[SecureValue] = personal_details
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["SecureData"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["temporary_registration"] = SecureValue.de_json(
|
||||
data.get("temporary_registration"), bot=bot
|
||||
)
|
||||
data["passport_registration"] = SecureValue.de_json(
|
||||
data.get("passport_registration"), bot=bot
|
||||
)
|
||||
data["rental_agreement"] = SecureValue.de_json(data.get("rental_agreement"), bot=bot)
|
||||
data["bank_statement"] = SecureValue.de_json(data.get("bank_statement"), bot=bot)
|
||||
data["utility_bill"] = SecureValue.de_json(data.get("utility_bill"), bot=bot)
|
||||
data["address"] = SecureValue.de_json(data.get("address"), bot=bot)
|
||||
data["identity_card"] = SecureValue.de_json(data.get("identity_card"), bot=bot)
|
||||
data["driver_license"] = SecureValue.de_json(data.get("driver_license"), bot=bot)
|
||||
data["internal_passport"] = SecureValue.de_json(data.get("internal_passport"), bot=bot)
|
||||
data["passport"] = SecureValue.de_json(data.get("passport"), bot=bot)
|
||||
data["personal_details"] = SecureValue.de_json(data.get("personal_details"), bot=bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
|
||||
class SecureValue(TelegramObject):
|
||||
"""
|
||||
This object represents the credentials that were used to decrypt the encrypted value.
|
||||
All fields are optional and depend on the type of field.
|
||||
|
||||
Args:
|
||||
data (:class:`telegram.DataCredentials`, optional): Credentials for encrypted Telegram
|
||||
Passport data. Available for "personal_details", "passport", "driver_license",
|
||||
"identity_card", "identity_passport" and "address" types.
|
||||
front_side (:class:`telegram.FileCredentials`, optional): Credentials for encrypted
|
||||
document's front side. Available for "passport", "driver_license", "identity_card"
|
||||
and "internal_passport".
|
||||
reverse_side (:class:`telegram.FileCredentials`, optional): Credentials for encrypted
|
||||
document's reverse side. Available for "driver_license" and "identity_card".
|
||||
selfie (:class:`telegram.FileCredentials`, optional): Credentials for encrypted selfie
|
||||
of the user with a document. Can be available for "passport", "driver_license",
|
||||
"identity_card" and "internal_passport".
|
||||
translation (list[:class:`telegram.FileCredentials`], optional): Credentials for an
|
||||
encrypted translation of the document. Available for "passport", "driver_license",
|
||||
"identity_card", "internal_passport", "utility_bill", "bank_statement",
|
||||
"rental_agreement", "passport_registration" and "temporary_registration".
|
||||
files (list[:class:`telegram.FileCredentials`], optional): Credentials for encrypted
|
||||
files. Available for "utility_bill", "bank_statement", "rental_agreement",
|
||||
"passport_registration" and "temporary_registration" types.
|
||||
|
||||
Attributes:
|
||||
data (:class:`telegram.DataCredentials`): Optional. Credentials for encrypted Telegram
|
||||
Passport data. Available for "personal_details", "passport", "driver_license",
|
||||
"identity_card", "identity_passport" and "address" types.
|
||||
front_side (:class:`telegram.FileCredentials`): Optional. Credentials for encrypted
|
||||
document's front side. Available for "passport", "driver_license", "identity_card"
|
||||
and "internal_passport".
|
||||
reverse_side (:class:`telegram.FileCredentials`): Optional. Credentials for encrypted
|
||||
document's reverse side. Available for "driver_license" and "identity_card".
|
||||
selfie (:class:`telegram.FileCredentials`): Optional. Credentials for encrypted selfie
|
||||
of the user with a document. Can be available for "passport", "driver_license",
|
||||
"identity_card" and "internal_passport".
|
||||
translation (tuple[:class:`telegram.FileCredentials`]): Optional. Credentials for an
|
||||
encrypted translation of the document. Available for "passport", "driver_license",
|
||||
"identity_card", "internal_passport", "utility_bill", "bank_statement",
|
||||
"rental_agreement", "passport_registration" and "temporary_registration".
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
|tupleclassattrs|
|
||||
|
||||
files (tuple[:class:`telegram.FileCredentials`]): Optional. Credentials for encrypted
|
||||
files. Available for "utility_bill", "bank_statement", "rental_agreement",
|
||||
"passport_registration" and "temporary_registration" types.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
|
||||
* |tupleclassattrs|
|
||||
* |alwaystuple|
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("data", "files", "front_side", "reverse_side", "selfie", "translation")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
data: Optional["DataCredentials"] = None,
|
||||
front_side: Optional["FileCredentials"] = None,
|
||||
reverse_side: Optional["FileCredentials"] = None,
|
||||
selfie: Optional["FileCredentials"] = None,
|
||||
files: Optional[Sequence["FileCredentials"]] = None,
|
||||
translation: Optional[Sequence["FileCredentials"]] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.data: Optional[DataCredentials] = data
|
||||
self.front_side: Optional[FileCredentials] = front_side
|
||||
self.reverse_side: Optional[FileCredentials] = reverse_side
|
||||
self.selfie: Optional[FileCredentials] = selfie
|
||||
self.files: tuple[FileCredentials, ...] = parse_sequence_arg(files)
|
||||
self.translation: tuple[FileCredentials, ...] = parse_sequence_arg(translation)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["SecureValue"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["data"] = DataCredentials.de_json(data.get("data"), bot=bot)
|
||||
data["front_side"] = FileCredentials.de_json(data.get("front_side"), bot=bot)
|
||||
data["reverse_side"] = FileCredentials.de_json(data.get("reverse_side"), bot=bot)
|
||||
data["selfie"] = FileCredentials.de_json(data.get("selfie"), bot=bot)
|
||||
data["files"] = FileCredentials.de_list(data.get("files"), bot=bot)
|
||||
data["translation"] = FileCredentials.de_list(data.get("translation"), bot=bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
|
||||
class _CredentialsBase(TelegramObject):
|
||||
"""Base class for DataCredentials and FileCredentials."""
|
||||
|
||||
__slots__ = ("data_hash", "file_hash", "hash", "secret")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
hash: str,
|
||||
secret: str,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
with self._unfrozen():
|
||||
self.hash: str = hash
|
||||
self.secret: str = secret
|
||||
|
||||
# Aliases just to be sure
|
||||
self.file_hash: str = self.hash
|
||||
self.data_hash: str = self.hash
|
||||
|
||||
|
||||
class DataCredentials(_CredentialsBase):
|
||||
"""
|
||||
These credentials can be used to decrypt encrypted data from the data field in
|
||||
EncryptedPassportData.
|
||||
|
||||
Args:
|
||||
data_hash (:obj:`str`): Checksum of encrypted data
|
||||
secret (:obj:`str`): Secret of encrypted data
|
||||
|
||||
Attributes:
|
||||
hash (:obj:`str`): Checksum of encrypted data
|
||||
secret (:obj:`str`): Secret of encrypted data
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
def __init__(self, data_hash: str, secret: str, *, api_kwargs: Optional[JSONDict] = None):
|
||||
super().__init__(hash=data_hash, secret=secret, api_kwargs=api_kwargs)
|
||||
self._freeze()
|
||||
|
||||
|
||||
class FileCredentials(_CredentialsBase):
|
||||
"""
|
||||
These credentials can be used to decrypt encrypted files from the front_side,
|
||||
reverse_side, selfie and files fields in EncryptedPassportData.
|
||||
|
||||
Args:
|
||||
file_hash (:obj:`str`): Checksum of encrypted file
|
||||
secret (:obj:`str`): Secret of encrypted file
|
||||
|
||||
Attributes:
|
||||
hash (:obj:`str`): Checksum of encrypted file
|
||||
secret (:obj:`str`): Secret of encrypted file
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
def __init__(self, file_hash: str, secret: str, *, api_kwargs: Optional[JSONDict] = None):
|
||||
super().__init__(hash=file_hash, secret=secret, api_kwargs=api_kwargs)
|
||||
self._freeze()
|
||||
186
.venv/lib/python3.10/site-packages/telegram/_passport/data.py
Normal file
186
.venv/lib/python3.10/site-packages/telegram/_passport/data.py
Normal file
@@ -0,0 +1,186 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
# pylint: disable=missing-module-docstring
|
||||
from typing import Optional
|
||||
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
|
||||
class PersonalDetails(TelegramObject):
|
||||
"""
|
||||
This object represents personal details.
|
||||
|
||||
Args:
|
||||
first_name (:obj:`str`): First Name.
|
||||
middle_name (:obj:`str`): Optional. First Name.
|
||||
last_name (:obj:`str`): Last Name.
|
||||
birth_date (:obj:`str`): Date of birth in DD.MM.YYYY format.
|
||||
gender (:obj:`str`): Gender, male or female.
|
||||
country_code (:obj:`str`): Citizenship (ISO 3166-1 alpha-2 country code).
|
||||
residence_country_code (:obj:`str`): Country of residence (ISO 3166-1 alpha-2 country
|
||||
code).
|
||||
first_name_native (:obj:`str`): First Name in the language of the user's country of
|
||||
residence.
|
||||
middle_name_native (:obj:`str`): Optional. Middle Name in the language of the user's
|
||||
country of residence.
|
||||
last_name_native (:obj:`str`): Last Name in the language of the user's country of
|
||||
residence.
|
||||
|
||||
Attributes:
|
||||
first_name (:obj:`str`): First Name.
|
||||
middle_name (:obj:`str`): Optional. First Name.
|
||||
last_name (:obj:`str`): Last Name.
|
||||
birth_date (:obj:`str`): Date of birth in DD.MM.YYYY format.
|
||||
gender (:obj:`str`): Gender, male or female.
|
||||
country_code (:obj:`str`): Citizenship (ISO 3166-1 alpha-2 country code).
|
||||
residence_country_code (:obj:`str`): Country of residence (ISO 3166-1 alpha-2 country
|
||||
code).
|
||||
first_name_native (:obj:`str`): First Name in the language of the user's country of
|
||||
residence.
|
||||
middle_name_native (:obj:`str`): Optional. Middle Name in the language of the user's
|
||||
country of residence.
|
||||
last_name_native (:obj:`str`): Last Name in the language of the user's country of
|
||||
residence.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"birth_date",
|
||||
"country_code",
|
||||
"first_name",
|
||||
"first_name_native",
|
||||
"gender",
|
||||
"last_name",
|
||||
"last_name_native",
|
||||
"middle_name",
|
||||
"middle_name_native",
|
||||
"residence_country_code",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
first_name: str,
|
||||
last_name: str,
|
||||
birth_date: str,
|
||||
gender: str,
|
||||
country_code: str,
|
||||
residence_country_code: str,
|
||||
first_name_native: Optional[str] = None,
|
||||
last_name_native: Optional[str] = None,
|
||||
middle_name: Optional[str] = None,
|
||||
middle_name_native: Optional[str] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
# Required
|
||||
self.first_name: str = first_name
|
||||
self.last_name: str = last_name
|
||||
self.middle_name: Optional[str] = middle_name
|
||||
self.birth_date: str = birth_date
|
||||
self.gender: str = gender
|
||||
self.country_code: str = country_code
|
||||
self.residence_country_code: str = residence_country_code
|
||||
self.first_name_native: Optional[str] = first_name_native
|
||||
self.last_name_native: Optional[str] = last_name_native
|
||||
self.middle_name_native: Optional[str] = middle_name_native
|
||||
|
||||
self._freeze()
|
||||
|
||||
|
||||
class ResidentialAddress(TelegramObject):
|
||||
"""
|
||||
This object represents a residential address.
|
||||
|
||||
Args:
|
||||
street_line1 (:obj:`str`): First line for the address.
|
||||
street_line2 (:obj:`str`): Optional. Second line for the address.
|
||||
city (:obj:`str`): City.
|
||||
state (:obj:`str`): Optional. State.
|
||||
country_code (:obj:`str`): ISO 3166-1 alpha-2 country code.
|
||||
post_code (:obj:`str`): Address post code.
|
||||
|
||||
Attributes:
|
||||
street_line1 (:obj:`str`): First line for the address.
|
||||
street_line2 (:obj:`str`): Optional. Second line for the address.
|
||||
city (:obj:`str`): City.
|
||||
state (:obj:`str`): Optional. State.
|
||||
country_code (:obj:`str`): ISO 3166-1 alpha-2 country code.
|
||||
post_code (:obj:`str`): Address post code.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"city",
|
||||
"country_code",
|
||||
"post_code",
|
||||
"state",
|
||||
"street_line1",
|
||||
"street_line2",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
street_line1: str,
|
||||
street_line2: str,
|
||||
city: str,
|
||||
state: str,
|
||||
country_code: str,
|
||||
post_code: str,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
# Required
|
||||
self.street_line1: str = street_line1
|
||||
self.street_line2: str = street_line2
|
||||
self.city: str = city
|
||||
self.state: str = state
|
||||
self.country_code: str = country_code
|
||||
self.post_code: str = post_code
|
||||
|
||||
self._freeze()
|
||||
|
||||
|
||||
class IdDocumentData(TelegramObject):
|
||||
"""
|
||||
This object represents the data of an identity document.
|
||||
|
||||
Args:
|
||||
document_no (:obj:`str`): Document number.
|
||||
expiry_date (:obj:`str`): Optional. Date of expiry, in DD.MM.YYYY format.
|
||||
|
||||
Attributes:
|
||||
document_no (:obj:`str`): Document number.
|
||||
expiry_date (:obj:`str`): Optional. Date of expiry, in DD.MM.YYYY format.
|
||||
"""
|
||||
|
||||
__slots__ = ("document_no", "expiry_date")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
document_no: str,
|
||||
expiry_date: str,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
self.document_no: str = document_no
|
||||
self.expiry_date: str = expiry_date
|
||||
|
||||
self._freeze()
|
||||
@@ -0,0 +1,282 @@
|
||||
#!/usr/bin/env python
|
||||
# flake8: noqa: E501
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a Telegram EncryptedPassportElement."""
|
||||
from base64 import b64decode
|
||||
from collections.abc import Sequence
|
||||
from typing import TYPE_CHECKING, Optional, Union
|
||||
|
||||
from telegram._passport.credentials import decrypt_json
|
||||
from telegram._passport.data import IdDocumentData, PersonalDetails, ResidentialAddress
|
||||
from telegram._passport.passportfile import PassportFile
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, Credentials
|
||||
|
||||
|
||||
class EncryptedPassportElement(TelegramObject):
|
||||
"""
|
||||
Contains information about documents or other Telegram Passport elements shared with the bot
|
||||
by the user. The data has been automatically decrypted by python-telegram-bot.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`type`, :attr:`data`, :attr:`phone_number`, :attr:`email`,
|
||||
:attr:`files`, :attr:`front_side`, :attr:`reverse_side` and :attr:`selfie` are equal.
|
||||
|
||||
Note:
|
||||
This object is decrypted only when originating from
|
||||
:attr:`telegram.PassportData.decrypted_data`.
|
||||
|
||||
Args:
|
||||
type (:obj:`str`): Element type. One of "personal_details", "passport", "driver_license",
|
||||
"identity_card", "internal_passport", "address", "utility_bill", "bank_statement",
|
||||
"rental_agreement", "passport_registration", "temporary_registration", "phone_number",
|
||||
"email".
|
||||
hash (:obj:`str`): Base64-encoded element hash for using in
|
||||
:class:`telegram.PassportElementErrorUnspecified`.
|
||||
data (:class:`telegram.PersonalDetails` | :class:`telegram.IdDocumentData` | \
|
||||
:class:`telegram.ResidentialAddress` | :obj:`str`, optional):
|
||||
Decrypted or encrypted data; available only for "personal_details", "passport",
|
||||
"driver_license", "identity_card", "internal_passport" and "address" types.
|
||||
phone_number (:obj:`str`, optional): User's verified phone number; available only for
|
||||
"phone_number" type.
|
||||
email (:obj:`str`, optional): User's verified email address; available only for "email"
|
||||
type.
|
||||
files (Sequence[:class:`telegram.PassportFile`], optional): Array of encrypted/decrypted
|
||||
files with documents provided by the user; available only for "utility_bill",
|
||||
"bank_statement", "rental_agreement", "passport_registration" and
|
||||
"temporary_registration" types.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
|sequenceclassargs|
|
||||
|
||||
front_side (:class:`telegram.PassportFile`, optional): Encrypted/decrypted file with the
|
||||
front side of the document, provided by the user; Available only for "passport",
|
||||
"driver_license", "identity_card" and "internal_passport".
|
||||
reverse_side (:class:`telegram.PassportFile`, optional): Encrypted/decrypted file with the
|
||||
reverse side of the document, provided by the user; Available only for
|
||||
"driver_license" and "identity_card".
|
||||
selfie (:class:`telegram.PassportFile`, optional): Encrypted/decrypted file with the
|
||||
selfie of the user holding a document, provided by the user; available if requested for
|
||||
"passport", "driver_license", "identity_card" and "internal_passport".
|
||||
translation (Sequence[:class:`telegram.PassportFile`], optional): Array of
|
||||
encrypted/decrypted files with translated versions of documents provided by the user;
|
||||
available if requested requested for "passport", "driver_license", "identity_card",
|
||||
"internal_passport", "utility_bill", "bank_statement", "rental_agreement",
|
||||
"passport_registration" and "temporary_registration" types.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
|sequenceclassargs|
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): Element type. One of "personal_details", "passport", "driver_license",
|
||||
"identity_card", "internal_passport", "address", "utility_bill", "bank_statement",
|
||||
"rental_agreement", "passport_registration", "temporary_registration", "phone_number",
|
||||
"email".
|
||||
hash (:obj:`str`): Base64-encoded element hash for using in
|
||||
:class:`telegram.PassportElementErrorUnspecified`.
|
||||
data (:class:`telegram.PersonalDetails` | :class:`telegram.IdDocumentData` | \
|
||||
:class:`telegram.ResidentialAddress` | :obj:`str`):
|
||||
Optional. Decrypted or encrypted data; available only for "personal_details",
|
||||
"passport", "driver_license", "identity_card", "internal_passport" and "address" types.
|
||||
phone_number (:obj:`str`): Optional. User's verified phone number; available only for
|
||||
"phone_number" type.
|
||||
email (:obj:`str`): Optional. User's verified email address; available only for "email"
|
||||
type.
|
||||
files (tuple[:class:`telegram.PassportFile`]): Optional. Array of encrypted/decrypted
|
||||
files with documents provided by the user; available only for "utility_bill",
|
||||
"bank_statement", "rental_agreement", "passport_registration" and
|
||||
"temporary_registration" types.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
|
||||
* |tupleclassattrs|
|
||||
* |alwaystuple|
|
||||
|
||||
front_side (:class:`telegram.PassportFile`): Optional. Encrypted/decrypted file with the
|
||||
front side of the document, provided by the user; available only for "passport",
|
||||
"driver_license", "identity_card" and "internal_passport".
|
||||
reverse_side (:class:`telegram.PassportFile`): Optional. Encrypted/decrypted file with the
|
||||
reverse side of the document, provided by the user; available only for "driver_license"
|
||||
and "identity_card".
|
||||
selfie (:class:`telegram.PassportFile`): Optional. Encrypted/decrypted file with the
|
||||
selfie of the user holding a document, provided by the user; available if requested for
|
||||
"passport", "driver_license", "identity_card" and "internal_passport".
|
||||
translation (tuple[:class:`telegram.PassportFile`]): Optional. Array of
|
||||
encrypted/decrypted files with translated versions of documents provided by the user;
|
||||
available if requested for "passport", "driver_license", "identity_card",
|
||||
"internal_passport", "utility_bill", "bank_statement", "rental_agreement",
|
||||
"passport_registration" and "temporary_registration" types.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
|
||||
* |tupleclassattrs|
|
||||
* |alwaystuple|
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"data",
|
||||
"email",
|
||||
"files",
|
||||
"front_side",
|
||||
"hash",
|
||||
"phone_number",
|
||||
"reverse_side",
|
||||
"selfie",
|
||||
"translation",
|
||||
"type",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
type: str, # pylint: disable=redefined-builtin
|
||||
hash: str, # pylint: disable=redefined-builtin
|
||||
data: Optional[Union[PersonalDetails, IdDocumentData, ResidentialAddress]] = None,
|
||||
phone_number: Optional[str] = None,
|
||||
email: Optional[str] = None,
|
||||
files: Optional[Sequence[PassportFile]] = None,
|
||||
front_side: Optional[PassportFile] = None,
|
||||
reverse_side: Optional[PassportFile] = None,
|
||||
selfie: Optional[PassportFile] = None,
|
||||
translation: Optional[Sequence[PassportFile]] = None,
|
||||
# TODO: Remove the credentials argument in 22.0 or later
|
||||
credentials: Optional[ # pylint: disable=unused-argument # noqa: ARG002
|
||||
"Credentials"
|
||||
] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
|
||||
# Required
|
||||
self.type: str = type
|
||||
# Optionals
|
||||
self.data: Optional[Union[PersonalDetails, IdDocumentData, ResidentialAddress]] = data
|
||||
self.phone_number: Optional[str] = phone_number
|
||||
self.email: Optional[str] = email
|
||||
self.files: tuple[PassportFile, ...] = parse_sequence_arg(files)
|
||||
self.front_side: Optional[PassportFile] = front_side
|
||||
self.reverse_side: Optional[PassportFile] = reverse_side
|
||||
self.selfie: Optional[PassportFile] = selfie
|
||||
self.translation: tuple[PassportFile, ...] = parse_sequence_arg(translation)
|
||||
self.hash: str = hash
|
||||
|
||||
self._id_attrs = (
|
||||
self.type,
|
||||
self.data,
|
||||
self.phone_number,
|
||||
self.email,
|
||||
self.files,
|
||||
self.front_side,
|
||||
self.reverse_side,
|
||||
self.selfie,
|
||||
)
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["EncryptedPassportElement"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["files"] = PassportFile.de_list(data.get("files"), bot) or None
|
||||
data["front_side"] = PassportFile.de_json(data.get("front_side"), bot)
|
||||
data["reverse_side"] = PassportFile.de_json(data.get("reverse_side"), bot)
|
||||
data["selfie"] = PassportFile.de_json(data.get("selfie"), bot)
|
||||
data["translation"] = PassportFile.de_list(data.get("translation"), bot) or None
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@classmethod
|
||||
def de_json_decrypted(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"], credentials: "Credentials"
|
||||
) -> Optional["EncryptedPassportElement"]:
|
||||
"""Variant of :meth:`telegram.TelegramObject.de_json` that also takes into account
|
||||
passport credentials.
|
||||
|
||||
Args:
|
||||
data (dict[:obj:`str`, ...]): The JSON data.
|
||||
bot (:class:`telegram.Bot` | :obj:`None`): The bot associated with these object.
|
||||
May be :obj:`None`, in which case shortcut methods will not be available.
|
||||
|
||||
.. versionchanged:: 21.4
|
||||
:paramref:`bot` is now optional and defaults to :obj:`None`
|
||||
|
||||
.. deprecated:: 21.4
|
||||
This argument will be converted to an optional argument in future versions.
|
||||
credentials (:class:`telegram.FileCredentials`): The credentials
|
||||
|
||||
Returns:
|
||||
:class:`telegram.EncryptedPassportElement`:
|
||||
|
||||
"""
|
||||
if not data:
|
||||
return None
|
||||
|
||||
if data["type"] not in ("phone_number", "email"):
|
||||
secure_data = getattr(credentials.secure_data, data["type"])
|
||||
|
||||
if secure_data.data is not None:
|
||||
# If not already decrypted
|
||||
if not isinstance(data["data"], dict):
|
||||
data["data"] = decrypt_json(
|
||||
b64decode(secure_data.data.secret),
|
||||
b64decode(secure_data.data.hash),
|
||||
b64decode(data["data"]),
|
||||
)
|
||||
if data["type"] == "personal_details":
|
||||
data["data"] = PersonalDetails.de_json(data["data"], bot=bot)
|
||||
elif data["type"] in (
|
||||
"passport",
|
||||
"internal_passport",
|
||||
"driver_license",
|
||||
"identity_card",
|
||||
):
|
||||
data["data"] = IdDocumentData.de_json(data["data"], bot=bot)
|
||||
elif data["type"] == "address":
|
||||
data["data"] = ResidentialAddress.de_json(data["data"], bot=bot)
|
||||
|
||||
data["files"] = (
|
||||
PassportFile.de_list_decrypted(data.get("files"), bot, secure_data.files) or None
|
||||
)
|
||||
data["front_side"] = PassportFile.de_json_decrypted(
|
||||
data.get("front_side"), bot, secure_data.front_side
|
||||
)
|
||||
data["reverse_side"] = PassportFile.de_json_decrypted(
|
||||
data.get("reverse_side"), bot, secure_data.reverse_side
|
||||
)
|
||||
data["selfie"] = PassportFile.de_json_decrypted(
|
||||
data.get("selfie"), bot, secure_data.selfie
|
||||
)
|
||||
data["translation"] = (
|
||||
PassportFile.de_list_decrypted(
|
||||
data.get("translation"), bot, secure_data.translation
|
||||
)
|
||||
or None
|
||||
)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
@@ -0,0 +1,132 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""Contains information about Telegram Passport data shared with the bot by the user."""
|
||||
from collections.abc import Sequence
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from telegram._passport.credentials import EncryptedCredentials
|
||||
from telegram._passport.encryptedpassportelement import EncryptedPassportElement
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.argumentparsing import parse_sequence_arg
|
||||
from telegram._utils.types import JSONDict
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, Credentials
|
||||
|
||||
|
||||
class PassportData(TelegramObject):
|
||||
"""Contains information about Telegram Passport data shared with the bot by the user.
|
||||
|
||||
Note:
|
||||
To be able to decrypt this object, you must pass your ``private_key`` to either
|
||||
:class:`telegram.ext.Updater` or :class:`telegram.Bot`. Decrypted data is then found in
|
||||
:attr:`decrypted_data` and the payload can be found in :attr:`decrypted_credentials`'s
|
||||
attribute :attr:`telegram.Credentials.nonce`.
|
||||
|
||||
Args:
|
||||
data (Sequence[:class:`telegram.EncryptedPassportElement`]): Array with encrypted
|
||||
information about documents and other Telegram Passport elements that was shared with
|
||||
the bot.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
|sequenceclassargs|
|
||||
|
||||
credentials (:class:`telegram.EncryptedCredentials`)): Encrypted credentials.
|
||||
|
||||
Attributes:
|
||||
data (tuple[:class:`telegram.EncryptedPassportElement`]): Array with encrypted
|
||||
information about documents and other Telegram Passport elements that was shared with
|
||||
the bot.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
|tupleclassattrs|
|
||||
|
||||
credentials (:class:`telegram.EncryptedCredentials`): Encrypted credentials.
|
||||
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("_decrypted_data", "credentials", "data")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
data: Sequence[EncryptedPassportElement],
|
||||
credentials: EncryptedCredentials,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
|
||||
self.data: tuple[EncryptedPassportElement, ...] = parse_sequence_arg(data)
|
||||
self.credentials: EncryptedCredentials = credentials
|
||||
|
||||
self._decrypted_data: Optional[tuple[EncryptedPassportElement]] = None
|
||||
self._id_attrs = tuple([x.type for x in data] + [credentials.hash])
|
||||
|
||||
self._freeze()
|
||||
|
||||
@classmethod
|
||||
def de_json(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"] = None
|
||||
) -> Optional["PassportData"]:
|
||||
"""See :meth:`telegram.TelegramObject.de_json`."""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["data"] = EncryptedPassportElement.de_list(data.get("data"), bot)
|
||||
data["credentials"] = EncryptedCredentials.de_json(data.get("credentials"), bot)
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@property
|
||||
def decrypted_data(self) -> tuple[EncryptedPassportElement, ...]:
|
||||
"""
|
||||
tuple[:class:`telegram.EncryptedPassportElement`]: Lazily decrypt and return information
|
||||
about documents and other Telegram Passport elements which were shared with the bot.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
Returns a tuple instead of a list.
|
||||
|
||||
Raises:
|
||||
telegram.error.PassportDecryptionError: Decryption failed. Usually due to bad
|
||||
private/public key but can also suggest malformed/tampered data.
|
||||
"""
|
||||
if self._decrypted_data is None:
|
||||
self._decrypted_data = tuple( # type: ignore[assignment]
|
||||
EncryptedPassportElement.de_json_decrypted(
|
||||
element.to_dict(), self.get_bot(), self.decrypted_credentials
|
||||
)
|
||||
for element in self.data
|
||||
)
|
||||
return self._decrypted_data # type: ignore[return-value]
|
||||
|
||||
@property
|
||||
def decrypted_credentials(self) -> "Credentials":
|
||||
"""
|
||||
:class:`telegram.Credentials`: Lazily decrypt and return credentials that were used
|
||||
to decrypt the data. This object also contains the user specified payload as
|
||||
`decrypted_data.payload`.
|
||||
|
||||
Raises:
|
||||
telegram.error.PassportDecryptionError: Decryption failed. Usually due to bad
|
||||
private/public key but can also suggest malformed/tampered data.
|
||||
"""
|
||||
return self.credentials.decrypted_data
|
||||
@@ -0,0 +1,474 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
# pylint: disable=redefined-builtin
|
||||
"""This module contains the classes that represent Telegram PassportElementError."""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.types import JSONDict
|
||||
from telegram._utils.warnings import warn
|
||||
from telegram.warnings import PTBDeprecationWarning
|
||||
|
||||
|
||||
class PassportElementError(TelegramObject):
|
||||
"""Baseclass for the PassportElementError* classes.
|
||||
|
||||
This object represents an error in the Telegram Passport element which was submitted that
|
||||
should be resolved by the user.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`source` and :attr:`type` are equal.
|
||||
|
||||
Args:
|
||||
source (:obj:`str`): Error source.
|
||||
type (:obj:`str`): The section of the user's Telegram Passport which has the error.
|
||||
message (:obj:`str`): Error message.
|
||||
|
||||
Attributes:
|
||||
source (:obj:`str`): Error source.
|
||||
type (:obj:`str`): The section of the user's Telegram Passport which has the error.
|
||||
message (:obj:`str`): Error message.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("message", "source", "type")
|
||||
|
||||
def __init__(
|
||||
self, source: str, type: str, message: str, *, api_kwargs: Optional[JSONDict] = None
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
# Required
|
||||
self.source: str = str(source)
|
||||
self.type: str = str(type)
|
||||
self.message: str = str(message)
|
||||
|
||||
self._id_attrs = (self.source, self.type)
|
||||
|
||||
self._freeze()
|
||||
|
||||
|
||||
class PassportElementErrorDataField(PassportElementError):
|
||||
"""
|
||||
Represents an issue in one of the data fields that was provided by the user. The error is
|
||||
considered resolved when the field's value changes.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`~telegram.PassportElementError.source`, :attr:`type`,
|
||||
:attr:`field_name`, :attr:`data_hash` and :attr:`message` are equal.
|
||||
|
||||
Args:
|
||||
type (:obj:`str`): The section of the user's Telegram Passport which has the error, one of
|
||||
``"personal_details"``, ``"passport"``, ``"driver_license"``, ``"identity_card"``,
|
||||
``"internal_passport"``, ``"address"``.
|
||||
field_name (:obj:`str`): Name of the data field which has the error.
|
||||
data_hash (:obj:`str`): Base64-encoded data hash.
|
||||
message (:obj:`str`): Error message.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): The section of the user's Telegram Passport which has the error, one of
|
||||
``"personal_details"``, ``"passport"``, ``"driver_license"``, ``"identity_card"``,
|
||||
``"internal_passport"``, ``"address"``.
|
||||
field_name (:obj:`str`): Name of the data field which has the error.
|
||||
data_hash (:obj:`str`): Base64-encoded data hash.
|
||||
message (:obj:`str`): Error message.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("data_hash", "field_name")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
type: str,
|
||||
field_name: str,
|
||||
data_hash: str,
|
||||
message: str,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
# Required
|
||||
super().__init__("data", type, message, api_kwargs=api_kwargs)
|
||||
with self._unfrozen():
|
||||
self.field_name: str = field_name
|
||||
self.data_hash: str = data_hash
|
||||
|
||||
self._id_attrs = (
|
||||
self.source,
|
||||
self.type,
|
||||
self.field_name,
|
||||
self.data_hash,
|
||||
self.message,
|
||||
)
|
||||
|
||||
|
||||
class PassportElementErrorFile(PassportElementError):
|
||||
"""
|
||||
Represents an issue with a document scan. The error is considered resolved when the file with
|
||||
the document scan changes.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`~telegram.PassportElementError.source`, :attr:`type`,
|
||||
:attr:`file_hash`, and :attr:`message` are equal.
|
||||
|
||||
Args:
|
||||
type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of
|
||||
``"utility_bill"``, ``"bank_statement"``, ``"rental_agreement"``,
|
||||
``"passport_registration"``, ``"temporary_registration"``.
|
||||
file_hash (:obj:`str`): Base64-encoded file hash.
|
||||
message (:obj:`str`): Error message.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of
|
||||
``"utility_bill"``, ``"bank_statement"``, ``"rental_agreement"``,
|
||||
``"passport_registration"``, ``"temporary_registration"``.
|
||||
file_hash (:obj:`str`): Base64-encoded file hash.
|
||||
message (:obj:`str`): Error message.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("file_hash",)
|
||||
|
||||
def __init__(
|
||||
self, type: str, file_hash: str, message: str, *, api_kwargs: Optional[JSONDict] = None
|
||||
):
|
||||
# Required
|
||||
super().__init__("file", type, message, api_kwargs=api_kwargs)
|
||||
with self._unfrozen():
|
||||
self.file_hash: str = file_hash
|
||||
|
||||
self._id_attrs = (self.source, self.type, self.file_hash, self.message)
|
||||
|
||||
|
||||
class PassportElementErrorFiles(PassportElementError):
|
||||
"""
|
||||
Represents an issue with a list of scans. The error is considered resolved when the list of
|
||||
files with the document scans changes.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`~telegram.PassportElementError.source`, :attr:`type`,
|
||||
:attr:`file_hashes`, and :attr:`message` are equal.
|
||||
|
||||
Args:
|
||||
type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of
|
||||
``"utility_bill"``, ``"bank_statement"``, ``"rental_agreement"``,
|
||||
``"passport_registration"``, ``"temporary_registration"``.
|
||||
file_hashes (list[:obj:`str`]): List of base64-encoded file hashes.
|
||||
message (:obj:`str`): Error message.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of
|
||||
``"utility_bill"``, ``"bank_statement"``, ``"rental_agreement"``,
|
||||
``"passport_registration"``, ``"temporary_registration"``.
|
||||
message (:obj:`str`): Error message.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("_file_hashes",)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
type: str,
|
||||
file_hashes: list[str],
|
||||
message: str,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
# Required
|
||||
super().__init__("files", type, message, api_kwargs=api_kwargs)
|
||||
with self._unfrozen():
|
||||
self._file_hashes: list[str] = file_hashes
|
||||
|
||||
self._id_attrs = (self.source, self.type, self.message, *tuple(file_hashes))
|
||||
|
||||
def to_dict(self, recursive: bool = True) -> JSONDict:
|
||||
"""See :meth:`telegram.TelegramObject.to_dict` for details."""
|
||||
data = super().to_dict(recursive)
|
||||
data["file_hashes"] = self._file_hashes
|
||||
return data
|
||||
|
||||
@property
|
||||
def file_hashes(self) -> list[str]:
|
||||
"""List of base64-encoded file hashes.
|
||||
|
||||
.. deprecated:: 20.6
|
||||
This attribute will return a tuple instead of a list in future major versions.
|
||||
"""
|
||||
warn(
|
||||
PTBDeprecationWarning(
|
||||
"20.6",
|
||||
"The attribute `file_hashes` will return a tuple instead of a list in future major"
|
||||
" versions.",
|
||||
),
|
||||
stacklevel=2,
|
||||
)
|
||||
return self._file_hashes
|
||||
|
||||
|
||||
class PassportElementErrorFrontSide(PassportElementError):
|
||||
"""
|
||||
Represents an issue with the front side of a document. The error is considered resolved when
|
||||
the file with the front side of the document changes.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`~telegram.PassportElementError.source`, :attr:`type`,
|
||||
:attr:`file_hash`, and :attr:`message` are equal.
|
||||
|
||||
Args:
|
||||
type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of
|
||||
``"passport"``, ``"driver_license"``, ``"identity_card"``, ``"internal_passport"``.
|
||||
file_hash (:obj:`str`): Base64-encoded hash of the file with the front side of the
|
||||
document.
|
||||
message (:obj:`str`): Error message.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of
|
||||
``"passport"``, ``"driver_license"``, ``"identity_card"``, ``"internal_passport"``.
|
||||
file_hash (:obj:`str`): Base64-encoded hash of the file with the front side of the
|
||||
document.
|
||||
message (:obj:`str`): Error message.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("file_hash",)
|
||||
|
||||
def __init__(
|
||||
self, type: str, file_hash: str, message: str, *, api_kwargs: Optional[JSONDict] = None
|
||||
):
|
||||
# Required
|
||||
super().__init__("front_side", type, message, api_kwargs=api_kwargs)
|
||||
with self._unfrozen():
|
||||
self.file_hash: str = file_hash
|
||||
|
||||
self._id_attrs = (self.source, self.type, self.file_hash, self.message)
|
||||
|
||||
|
||||
class PassportElementErrorReverseSide(PassportElementError):
|
||||
"""
|
||||
Represents an issue with the reverse side of a document. The error is considered resolved when
|
||||
the file with the reverse side of the document changes.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`~telegram.PassportElementError.source`, :attr:`type`,
|
||||
:attr:`file_hash`, and :attr:`message` are equal.
|
||||
|
||||
Args:
|
||||
type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of
|
||||
``"driver_license"``, ``"identity_card"``.
|
||||
file_hash (:obj:`str`): Base64-encoded hash of the file with the reverse side of the
|
||||
document.
|
||||
message (:obj:`str`): Error message.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of
|
||||
``"driver_license"``, ``"identity_card"``.
|
||||
file_hash (:obj:`str`): Base64-encoded hash of the file with the reverse side of the
|
||||
document.
|
||||
message (:obj:`str`): Error message.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("file_hash",)
|
||||
|
||||
def __init__(
|
||||
self, type: str, file_hash: str, message: str, *, api_kwargs: Optional[JSONDict] = None
|
||||
):
|
||||
# Required
|
||||
super().__init__("reverse_side", type, message, api_kwargs=api_kwargs)
|
||||
with self._unfrozen():
|
||||
self.file_hash: str = file_hash
|
||||
|
||||
self._id_attrs = (self.source, self.type, self.file_hash, self.message)
|
||||
|
||||
|
||||
class PassportElementErrorSelfie(PassportElementError):
|
||||
"""
|
||||
Represents an issue with the selfie with a document. The error is considered resolved when
|
||||
the file with the selfie changes.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`~telegram.PassportElementError.source`, :attr:`type`,
|
||||
:attr:`file_hash`, and :attr:`message` are equal.
|
||||
|
||||
Args:
|
||||
type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of
|
||||
``"passport"``, ``"driver_license"``, ``"identity_card"``, ``"internal_passport"``.
|
||||
file_hash (:obj:`str`): Base64-encoded hash of the file with the selfie.
|
||||
message (:obj:`str`): Error message.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of
|
||||
``"passport"``, ``"driver_license"``, ``"identity_card"``, ``"internal_passport"``.
|
||||
file_hash (:obj:`str`): Base64-encoded hash of the file with the selfie.
|
||||
message (:obj:`str`): Error message.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("file_hash",)
|
||||
|
||||
def __init__(
|
||||
self, type: str, file_hash: str, message: str, *, api_kwargs: Optional[JSONDict] = None
|
||||
):
|
||||
# Required
|
||||
super().__init__("selfie", type, message, api_kwargs=api_kwargs)
|
||||
with self._unfrozen():
|
||||
self.file_hash: str = file_hash
|
||||
|
||||
self._id_attrs = (self.source, self.type, self.file_hash, self.message)
|
||||
|
||||
|
||||
class PassportElementErrorTranslationFile(PassportElementError):
|
||||
"""
|
||||
Represents an issue with one of the files that constitute the translation of a document.
|
||||
The error is considered resolved when the file changes.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`~telegram.PassportElementError.source`, :attr:`type`,
|
||||
:attr:`file_hash`, and :attr:`message` are equal.
|
||||
|
||||
Args:
|
||||
type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue,
|
||||
one of ``"passport"``, ``"driver_license"``, ``"identity_card"``,
|
||||
``"internal_passport"``, ``"utility_bill"``, ``"bank_statement"``,
|
||||
``"rental_agreement"``, ``"passport_registration"``, ``"temporary_registration"``.
|
||||
file_hash (:obj:`str`): Base64-encoded hash of the file.
|
||||
message (:obj:`str`): Error message.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue,
|
||||
one of ``"passport"``, ``"driver_license"``, ``"identity_card"``,
|
||||
``"internal_passport"``, ``"utility_bill"``, ``"bank_statement"``,
|
||||
``"rental_agreement"``, ``"passport_registration"``, ``"temporary_registration"``.
|
||||
file_hash (:obj:`str`): Base64-encoded hash of the file.
|
||||
message (:obj:`str`): Error message.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("file_hash",)
|
||||
|
||||
def __init__(
|
||||
self, type: str, file_hash: str, message: str, *, api_kwargs: Optional[JSONDict] = None
|
||||
):
|
||||
# Required
|
||||
super().__init__("translation_file", type, message, api_kwargs=api_kwargs)
|
||||
with self._unfrozen():
|
||||
self.file_hash: str = file_hash
|
||||
|
||||
self._id_attrs = (self.source, self.type, self.file_hash, self.message)
|
||||
|
||||
|
||||
class PassportElementErrorTranslationFiles(PassportElementError):
|
||||
"""
|
||||
Represents an issue with the translated version of a document. The error is considered
|
||||
resolved when a file with the document translation changes.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`~telegram.PassportElementError.source`, :attr:`type`,
|
||||
:attr:`file_hashes`, and :attr:`message` are equal.
|
||||
|
||||
Args:
|
||||
type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue,
|
||||
one of ``"passport"``, ``"driver_license"``, ``"identity_card"``,
|
||||
``"internal_passport"``, ``"utility_bill"``, ``"bank_statement"``,
|
||||
``"rental_agreement"``, ``"passport_registration"``, ``"temporary_registration"``.
|
||||
file_hashes (list[:obj:`str`]): List of base64-encoded file hashes.
|
||||
message (:obj:`str`): Error message.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue,
|
||||
one of ``"passport"``, ``"driver_license"``, ``"identity_card"``,
|
||||
``"internal_passport"``, ``"utility_bill"``, ``"bank_statement"``,
|
||||
``"rental_agreement"``, ``"passport_registration"``, ``"temporary_registration"``.
|
||||
message (:obj:`str`): Error message.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("_file_hashes",)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
type: str,
|
||||
file_hashes: list[str],
|
||||
message: str,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
# Required
|
||||
super().__init__("translation_files", type, message, api_kwargs=api_kwargs)
|
||||
with self._unfrozen():
|
||||
self._file_hashes: list[str] = file_hashes
|
||||
|
||||
self._id_attrs = (self.source, self.type, self.message, *tuple(file_hashes))
|
||||
|
||||
def to_dict(self, recursive: bool = True) -> JSONDict:
|
||||
"""See :meth:`telegram.TelegramObject.to_dict` for details."""
|
||||
data = super().to_dict(recursive)
|
||||
data["file_hashes"] = self._file_hashes
|
||||
return data
|
||||
|
||||
@property
|
||||
def file_hashes(self) -> list[str]:
|
||||
"""List of base64-encoded file hashes.
|
||||
|
||||
.. deprecated:: 20.6
|
||||
This attribute will return a tuple instead of a list in future major versions.
|
||||
"""
|
||||
warn(
|
||||
PTBDeprecationWarning(
|
||||
"20.6",
|
||||
"The attribute `file_hashes` will return a tuple instead of a list in future major"
|
||||
" versions. See the stability policy:"
|
||||
" https://docs.python-telegram-bot.org/en/stable/stability_policy.html",
|
||||
),
|
||||
stacklevel=2,
|
||||
)
|
||||
return self._file_hashes
|
||||
|
||||
|
||||
class PassportElementErrorUnspecified(PassportElementError):
|
||||
"""
|
||||
Represents an issue in an unspecified place. The error is considered resolved when new
|
||||
data is added.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`~telegram.PassportElementError.source`, :attr:`type`,
|
||||
:attr:`element_hash`, and :attr:`message` are equal.
|
||||
|
||||
Args:
|
||||
type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue.
|
||||
element_hash (:obj:`str`): Base64-encoded element hash.
|
||||
message (:obj:`str`): Error message.
|
||||
|
||||
Attributes:
|
||||
type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue.
|
||||
element_hash (:obj:`str`): Base64-encoded element hash.
|
||||
message (:obj:`str`): Error message.
|
||||
|
||||
"""
|
||||
|
||||
__slots__ = ("element_hash",)
|
||||
|
||||
def __init__(
|
||||
self, type: str, element_hash: str, message: str, *, api_kwargs: Optional[JSONDict] = None
|
||||
):
|
||||
# Required
|
||||
super().__init__("unspecified", type, message, api_kwargs=api_kwargs)
|
||||
with self._unfrozen():
|
||||
self.element_hash: str = element_hash
|
||||
|
||||
self._id_attrs = (self.source, self.type, self.element_hash, self.message)
|
||||
@@ -0,0 +1,227 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2024
|
||||
# Leandro Toledo de Souza <devs@python-telegram-bot.org>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program 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 Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
"""This module contains an object that represents a Encrypted PassportFile."""
|
||||
|
||||
from typing import TYPE_CHECKING, Optional
|
||||
|
||||
from telegram._telegramobject import TelegramObject
|
||||
from telegram._utils.defaultvalue import DEFAULT_NONE
|
||||
from telegram._utils.types import JSONDict, ODVInput
|
||||
from telegram._utils.warnings import warn
|
||||
from telegram.warnings import PTBDeprecationWarning
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from telegram import Bot, File, FileCredentials
|
||||
|
||||
|
||||
class PassportFile(TelegramObject):
|
||||
"""
|
||||
This object represents a file uploaded to Telegram Passport. Currently all Telegram Passport
|
||||
files are in JPEG format when decrypted and don't exceed 10MB.
|
||||
|
||||
Objects of this class are comparable in terms of equality. Two objects of this class are
|
||||
considered equal, if their :attr:`file_unique_id` is equal.
|
||||
|
||||
Args:
|
||||
file_id (:obj:`str`): Identifier for this file, which can be used to download
|
||||
or reuse the file.
|
||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||
is supposed to be the same over time and for different bots.
|
||||
Can't be used to download or reuse the file.
|
||||
file_size (:obj:`int`): File size in bytes.
|
||||
file_date (:obj:`int`): Unix time when the file was uploaded.
|
||||
|
||||
.. deprecated:: 20.6
|
||||
This argument will only accept a datetime instead of an integer in future
|
||||
major versions.
|
||||
|
||||
Attributes:
|
||||
file_id (:obj:`str`): Identifier for this file, which can be used to download
|
||||
or reuse the file.
|
||||
file_unique_id (:obj:`str`): Unique identifier for this file, which
|
||||
is supposed to be the same over time and for different bots.
|
||||
Can't be used to download or reuse the file.
|
||||
file_size (:obj:`int`): File size in bytes.
|
||||
"""
|
||||
|
||||
__slots__ = (
|
||||
"_credentials",
|
||||
"_file_date",
|
||||
"file_id",
|
||||
"file_size",
|
||||
"file_unique_id",
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
file_id: str,
|
||||
file_unique_id: str,
|
||||
file_date: int,
|
||||
file_size: int,
|
||||
credentials: Optional["FileCredentials"] = None,
|
||||
*,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
):
|
||||
super().__init__(api_kwargs=api_kwargs)
|
||||
|
||||
# Required
|
||||
self.file_id: str = file_id
|
||||
self.file_unique_id: str = file_unique_id
|
||||
self.file_size: int = file_size
|
||||
self._file_date: int = file_date
|
||||
# Optionals
|
||||
|
||||
self._credentials: Optional[FileCredentials] = credentials
|
||||
|
||||
self._id_attrs = (self.file_unique_id,)
|
||||
|
||||
self._freeze()
|
||||
|
||||
def to_dict(self, recursive: bool = True) -> JSONDict:
|
||||
"""See :meth:`telegram.TelegramObject.to_dict` for details."""
|
||||
data = super().to_dict(recursive)
|
||||
data["file_date"] = self._file_date
|
||||
return data
|
||||
|
||||
@property
|
||||
def file_date(self) -> int:
|
||||
""":obj:`int`: Unix time when the file was uploaded.
|
||||
|
||||
.. deprecated:: 20.6
|
||||
This attribute will return a datetime instead of a integer in future major versions.
|
||||
"""
|
||||
warn(
|
||||
PTBDeprecationWarning(
|
||||
"20.6",
|
||||
"The attribute `file_date` will return a datetime instead of an integer in future"
|
||||
" major versions.",
|
||||
),
|
||||
stacklevel=2,
|
||||
)
|
||||
return self._file_date
|
||||
|
||||
@classmethod
|
||||
def de_json_decrypted(
|
||||
cls, data: Optional[JSONDict], bot: Optional["Bot"], credentials: "FileCredentials"
|
||||
) -> Optional["PassportFile"]:
|
||||
"""Variant of :meth:`telegram.TelegramObject.de_json` that also takes into account
|
||||
passport credentials.
|
||||
|
||||
Args:
|
||||
data (dict[:obj:`str`, ...]): The JSON data.
|
||||
bot (:class:`telegram.Bot` | :obj:`None`): The bot associated with these object.
|
||||
May be :obj:`None`, in which case shortcut methods will not be available.
|
||||
|
||||
.. versionchanged:: 21.4
|
||||
:paramref:`bot` is now optional and defaults to :obj:`None`
|
||||
|
||||
.. deprecated:: 21.4
|
||||
This argument will be converted to an optional argument in future versions.
|
||||
credentials (:class:`telegram.FileCredentials`): The credentials
|
||||
|
||||
Returns:
|
||||
:class:`telegram.PassportFile`:
|
||||
|
||||
"""
|
||||
data = cls._parse_data(data)
|
||||
|
||||
if not data:
|
||||
return None
|
||||
|
||||
data["credentials"] = credentials
|
||||
|
||||
return super().de_json(data=data, bot=bot)
|
||||
|
||||
@classmethod
|
||||
def de_list_decrypted(
|
||||
cls,
|
||||
data: Optional[list[JSONDict]],
|
||||
bot: Optional["Bot"],
|
||||
credentials: list["FileCredentials"],
|
||||
) -> tuple[Optional["PassportFile"], ...]:
|
||||
"""Variant of :meth:`telegram.TelegramObject.de_list` that also takes into account
|
||||
passport credentials.
|
||||
|
||||
.. versionchanged:: 20.0
|
||||
|
||||
* Returns a tuple instead of a list.
|
||||
* Filters out any :obj:`None` values
|
||||
|
||||
Args:
|
||||
data (list[dict[:obj:`str`, ...]]): The JSON data.
|
||||
bot (:class:`telegram.Bot` | :obj:`None`): The bot associated with these object.
|
||||
May be :obj:`None`, in which case shortcut methods will not be available.
|
||||
|
||||
.. versionchanged:: 21.4
|
||||
:paramref:`bot` is now optional and defaults to :obj:`None`
|
||||
|
||||
.. deprecated:: 21.4
|
||||
This argument will be converted to an optional argument in future versions.
|
||||
credentials (:class:`telegram.FileCredentials`): The credentials
|
||||
|
||||
Returns:
|
||||
tuple[:class:`telegram.PassportFile`]:
|
||||
|
||||
"""
|
||||
if not data:
|
||||
return ()
|
||||
|
||||
return tuple(
|
||||
obj
|
||||
for obj in (
|
||||
cls.de_json_decrypted(passport_file, bot, credentials[i])
|
||||
for i, passport_file in enumerate(data)
|
||||
)
|
||||
if obj is not None
|
||||
)
|
||||
|
||||
async def get_file(
|
||||
self,
|
||||
*,
|
||||
read_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
write_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
connect_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
pool_timeout: ODVInput[float] = DEFAULT_NONE,
|
||||
api_kwargs: Optional[JSONDict] = None,
|
||||
) -> "File":
|
||||
"""
|
||||
Wrapper over :meth:`telegram.Bot.get_file`. Will automatically assign the correct
|
||||
credentials to the returned :class:`telegram.File` if originating from
|
||||
:attr:`telegram.PassportData.decrypted_data`.
|
||||
|
||||
For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`.
|
||||
|
||||
Returns:
|
||||
:class:`telegram.File`
|
||||
|
||||
Raises:
|
||||
:class:`telegram.error.TelegramError`
|
||||
|
||||
"""
|
||||
file = await self.get_bot().get_file(
|
||||
file_id=self.file_id,
|
||||
read_timeout=read_timeout,
|
||||
write_timeout=write_timeout,
|
||||
connect_timeout=connect_timeout,
|
||||
pool_timeout=pool_timeout,
|
||||
api_kwargs=api_kwargs,
|
||||
)
|
||||
if self._credentials:
|
||||
file.set_credentials(self._credentials)
|
||||
return file
|
||||
Reference in New Issue
Block a user