mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2024-12-22 14:35:00 +01:00
Bot api 4.1 (#1198)
* Fix passport decryption failing at random times Sometimes a decrypted secret was being treated as b64 and therefore got decoded even further. Fix by decoding b64 right before call to decrypt so we have better control of when not to do it * Bot api 4.1 Telegram passport 1.1 Added support for middle names. Added support for translations for documents Add errors for translations for documents Added support for requesting names in the language of the user's country of residence Replaced the payload parameter with the new parameter nonce NOTE: Scope stuff is NOT implemented, as we wanna STRONGLY encourage users to use the telegram provided SDKs anyway (and not generate telegram auth links in their bot, but rather on a server) * Minor fixes * Add hash to EncryptedPassportElement For use with PassportElementErrorUnspecified apparently
This commit is contained in:
parent
937be3d2e8
commit
09bdb88822
12 changed files with 550 additions and 101 deletions
|
@ -24,9 +24,9 @@ def msg(bot, update):
|
|||
# If we received any passport data
|
||||
passport_data = update.message.passport_data
|
||||
if passport_data:
|
||||
# If our payload doesn't match what we think, this Update did not originate from us
|
||||
# Ideally you would randomize the payload on the server
|
||||
if passport_data.decrypted_credentials.payload != 'thisisatest':
|
||||
# If our nonce doesn't match what we think, this Update did not originate from us
|
||||
# Ideally you would randomize the nonce on the server
|
||||
if passport_data.decrypted_credentials.nonce != 'thisisatest':
|
||||
return
|
||||
|
||||
# Print the decrypted credential data
|
||||
|
@ -39,7 +39,7 @@ def msg(bot, update):
|
|||
elif data.type == 'email':
|
||||
print('Email: ', data.email)
|
||||
if data.type in ('personal_details', 'passport', 'driver_license', 'identity_card',
|
||||
'identity_passport', 'address'):
|
||||
'internal_passport', 'address'):
|
||||
print(data.type, data.data)
|
||||
if data.type in ('utility_bill', 'bank_statement', 'rental_agreement',
|
||||
'passport_registration', 'temporary_registration'):
|
||||
|
@ -65,6 +65,15 @@ def msg(bot, update):
|
|||
file = data.selfie.get_file()
|
||||
print(data.type, file)
|
||||
file.download()
|
||||
if data.type in ('passport', 'driver_license', 'identity_card',
|
||||
'internal_passport', 'utility_bill', 'bank_statement',
|
||||
'rental_agreement', 'passport_registration',
|
||||
'temporary_registration'):
|
||||
print(data.type, len(data.translation), 'translation')
|
||||
for file in data.translation:
|
||||
actual_file = file.get_file()
|
||||
print(actual_file)
|
||||
actual_file.download()
|
||||
|
||||
|
||||
def error(bot, update, error):
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!/usr/bin/env python
|
||||
''#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2018
|
||||
|
@ -109,7 +109,10 @@ from .passport.passportelementerrors import (PassportElementError,
|
|||
PassportElementErrorFiles,
|
||||
PassportElementErrorFrontSide,
|
||||
PassportElementErrorReverseSide,
|
||||
PassportElementErrorSelfie)
|
||||
PassportElementErrorSelfie,
|
||||
PassportElementErrorTranslationFile,
|
||||
PassportElementErrorTranslationFiles,
|
||||
PassportElementErrorUnspecified)
|
||||
from .passport.credentials import (Credentials,
|
||||
DataCredentials,
|
||||
SecureData,
|
||||
|
@ -148,5 +151,6 @@ __all__ = [
|
|||
'Credentials', 'DataCredentials', 'SecureData', 'FileCredentials', 'IdDocumentData',
|
||||
'PersonalDetails', 'ResidentialAddress', 'InputMediaVideo', 'InputMediaAnimation',
|
||||
'InputMediaAudio', 'InputMediaDocument', 'TelegramDecryptionError',
|
||||
'PassportElementErrorSelfie'
|
||||
'PassportElementErrorSelfie', 'PassportElementErrorTranslationFile',
|
||||
'PassportElementErrorTranslationFiles', 'PassportElementErrorUnspecified'
|
||||
]
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
# 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 File."""
|
||||
from base64 import b64decode
|
||||
from os.path import basename
|
||||
|
||||
from future.backports.urllib import parse as urllib_parse
|
||||
|
@ -107,7 +108,9 @@ class File(TelegramObject):
|
|||
if out:
|
||||
buf = self.bot.request.retrieve(url)
|
||||
if self._credentials:
|
||||
buf = decrypt(self._credentials.secret, self._credentials.hash, buf, file=True)
|
||||
buf = decrypt(b64decode(self._credentials.secret),
|
||||
b64decode(self._credentials.hash),
|
||||
buf)
|
||||
out.write(buf)
|
||||
return out
|
||||
else:
|
||||
|
@ -118,7 +121,9 @@ class File(TelegramObject):
|
|||
|
||||
buf = self.bot.request.retrieve(url, timeout=timeout)
|
||||
if self._credentials:
|
||||
buf = decrypt(self._credentials.secret, self._credentials.hash, buf, file=True)
|
||||
buf = decrypt(b64decode(self._credentials.secret),
|
||||
b64decode(self._credentials.hash),
|
||||
buf)
|
||||
with open(filename, 'wb') as fobj:
|
||||
fobj.write(buf)
|
||||
return filename
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
#
|
||||
# You should have received a copy of the GNU Lesser Public License
|
||||
# along with this program. If not, see [http://www.gnu.org/licenses/].
|
||||
import binascii
|
||||
try:
|
||||
import ujson as json
|
||||
except ImportError:
|
||||
|
@ -44,7 +43,7 @@ class TelegramDecryptionError(TelegramError):
|
|||
"{}".format(message))
|
||||
|
||||
|
||||
def decrypt(secret, hash, data, file=False):
|
||||
def decrypt(secret, hash, data):
|
||||
"""
|
||||
Decrypt per telegram docs at https://core.telegram.org/passport.
|
||||
|
||||
|
@ -65,20 +64,6 @@ def decrypt(secret, hash, data, file=False):
|
|||
:obj:`bytes`: The decrypted data as bytes.
|
||||
|
||||
"""
|
||||
# First make sure that if secret, hash, or data was base64 encoded, to decode it into bytes
|
||||
try:
|
||||
secret = b64decode(secret)
|
||||
except (binascii.Error, TypeError):
|
||||
pass
|
||||
try:
|
||||
hash = b64decode(hash)
|
||||
except (binascii.Error, TypeError):
|
||||
pass
|
||||
if not file:
|
||||
try:
|
||||
data = b64decode(data)
|
||||
except (binascii.Error, TypeError):
|
||||
pass
|
||||
# Make a SHA512 hash of secret + update
|
||||
digest = Hash(SHA512(), backend=default_backend())
|
||||
digest.update(secret + hash)
|
||||
|
@ -113,14 +98,14 @@ class EncryptedCredentials(TelegramObject):
|
|||
|
||||
Attributes:
|
||||
data (:class:`telegram.Credentials` or :obj:`str`): Decrypted data with unique user's
|
||||
payload, data hashes and secrets used for EncryptedPassportElement decryption and
|
||||
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.
|
||||
|
||||
Args:
|
||||
data (:class:`telegram.Credentials` or :obj:`str`): Decrypted data with unique user's
|
||||
payload, data hashes and secrets used for EncryptedPassportElement decryption and
|
||||
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.
|
||||
|
@ -184,8 +169,8 @@ class EncryptedCredentials(TelegramObject):
|
|||
def decrypted_data(self):
|
||||
"""
|
||||
:class:`telegram.Credentials`: Lazily decrypt and return credentials data. This object
|
||||
also contains the user specified payload as
|
||||
`decrypted_data.payload`.
|
||||
also contains the user specified nonce as
|
||||
`decrypted_data.nonce`.
|
||||
|
||||
Raises:
|
||||
telegram.TelegramDecryptionError: Decryption failed. Usually due to bad
|
||||
|
@ -193,8 +178,8 @@ class EncryptedCredentials(TelegramObject):
|
|||
"""
|
||||
if self._decrypted_data is None:
|
||||
self._decrypted_data = Credentials.de_json(decrypt_json(self.decrypted_secret,
|
||||
self.hash,
|
||||
self.data),
|
||||
b64decode(self.hash),
|
||||
b64decode(self.data)),
|
||||
self.bot)
|
||||
return self._decrypted_data
|
||||
|
||||
|
@ -203,13 +188,13 @@ class Credentials(TelegramObject):
|
|||
"""
|
||||
Attributes:
|
||||
secure_data (:class:`telegram.SecureData`): Credentials for encrypted data
|
||||
payload (:obj:`str`): Bot-specified payload
|
||||
nonce (:obj:`str`): Bot-specified nonce
|
||||
"""
|
||||
|
||||
def __init__(self, secure_data, payload, bot=None, **kwargs):
|
||||
def __init__(self, secure_data, nonce, bot=None, **kwargs):
|
||||
# Required
|
||||
self.secure_data = secure_data
|
||||
self.payload = payload
|
||||
self.nonce = nonce
|
||||
|
||||
self.bot = bot
|
||||
|
||||
|
@ -319,7 +304,11 @@ class SecureValue(TelegramObject):
|
|||
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".
|
||||
files (:class:`telegram.Array of FileCredentials`, optional): Credentials for encrypted
|
||||
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.
|
||||
|
||||
|
@ -331,6 +320,7 @@ class SecureValue(TelegramObject):
|
|||
reverse_side=None,
|
||||
selfie=None,
|
||||
files=None,
|
||||
translation=None,
|
||||
bot=None,
|
||||
**kwargs):
|
||||
self.data = data
|
||||
|
@ -338,6 +328,7 @@ class SecureValue(TelegramObject):
|
|||
self.reverse_side = reverse_side
|
||||
self.selfie = selfie
|
||||
self.files = files
|
||||
self.translation = translation
|
||||
|
||||
self.bot = bot
|
||||
|
||||
|
@ -351,6 +342,7 @@ class SecureValue(TelegramObject):
|
|||
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 cls(bot=bot, **data)
|
||||
|
||||
|
@ -358,6 +350,7 @@ class SecureValue(TelegramObject):
|
|||
data = super(SecureValue, self).to_dict()
|
||||
|
||||
data['files'] = [p.to_dict() for p in self.files]
|
||||
data['translation'] = [p.to_dict() for p in self.translation]
|
||||
|
||||
return data
|
||||
|
||||
|
|
|
@ -25,23 +25,33 @@ class PersonalDetails(TelegramObject):
|
|||
|
||||
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 (:obj:`str`): First Name in the language of the user's country of residence.
|
||||
middle_name (:obj:`str`): Optional. Middle Name in the language of the user's country of
|
||||
residence.
|
||||
last_name (:obj:`str`): Last Name in the language of the user's country of residence.
|
||||
"""
|
||||
|
||||
def __init__(self, first_name, last_name, birth_date, gender, country_code,
|
||||
residence_country_code, bot=None, **kwargs):
|
||||
residence_country_code, first_name_native, last_name_native, middle_name=None,
|
||||
middle_name_native=None, bot=None, **kwargs):
|
||||
# Required
|
||||
self.first_name = first_name
|
||||
self.last_name = last_name
|
||||
self.middle_name = middle_name
|
||||
self.birth_date = birth_date
|
||||
self.gender = gender
|
||||
self.country_code = country_code
|
||||
self.residence_country_code = residence_country_code
|
||||
self.first_name_native = first_name_native
|
||||
self.last_name_native = last_name_native
|
||||
self.middle_name_native = middle_name_native
|
||||
|
||||
self.bot = bot
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
# 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 telegram import (TelegramObject, PassportFile, PersonalDetails, IdDocumentData,
|
||||
ResidentialAddress)
|
||||
|
@ -43,15 +44,22 @@ class EncryptedPassportElement(TelegramObject):
|
|||
files (List[:class:`telegram.PassportFile`]): Optional. Array of encrypted/decrypted files
|
||||
with documents provided by the user, available for "utility_bill", "bank_statement",
|
||||
"rental_agreement", "passport_registration" and "temporary_registration" types.
|
||||
front_side (:class:`PassportFile`): Optional. Encrypted/decrypted file with the front side
|
||||
of the document, provided by the user. Available for "passport", "driver_license",
|
||||
"identity_card" and "internal_passport".
|
||||
reverse_side (:class:`PassportFile`): Optional. Encrypted/decrypted file with the reverse
|
||||
side of the document, provided by the user. Available for "driver_license" and
|
||||
"identity_card".
|
||||
selfie (:class:`PassportFile`): Optional. Encrypted/decrypted file with the selfie of the
|
||||
user holding a document, provided by the user; available for "passport",
|
||||
front_side (:class:`telegram.PassportFile`): Optional. Encrypted/decrypted file with the
|
||||
front side of the document, provided by the user. Available 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 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 for "passport",
|
||||
"driver_license", "identity_card" and "internal_passport".
|
||||
translation (List[: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.
|
||||
hash (:obj:`str`): Base64-encoded element hash for using in
|
||||
:class:`telegram.PassportElementErrorUnspecified`.
|
||||
bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods.
|
||||
|
||||
Args:
|
||||
|
@ -69,15 +77,22 @@ class EncryptedPassportElement(TelegramObject):
|
|||
files (List[:class:`telegram.PassportFile`], optional): Array of encrypted/decrypted files
|
||||
with documents provided by the user, available for "utility_bill", "bank_statement",
|
||||
"rental_agreement", "passport_registration" and "temporary_registration" types.
|
||||
front_side (:class:`PassportFile`, optional): Encrypted/decrypted file with the front side
|
||||
of the document, provided by the user. Available for "passport", "driver_license",
|
||||
"identity_card" and "internal_passport".
|
||||
reverse_side (:class:`PassportFile`, optional): Encrypted/decrypted file with the reverse
|
||||
side of the document, provided by the user. Available for "driver_license" and
|
||||
"identity_card".
|
||||
selfie (:class:`PassportFile`, optional): Encrypted/decrypted file with the selfie of the
|
||||
user holding a document, provided by the user; available for "passport",
|
||||
front_side (:class:`telegram.PassportFile`, optional): Encrypted/decrypted file with the
|
||||
front side of the document, provided by the user. Available 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 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 for "passport",
|
||||
"driver_license", "identity_card" and "internal_passport".
|
||||
translation (List[: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.
|
||||
hash (:obj:`str`): Base64-encoded element hash for using in
|
||||
:class:`telegram.PassportElementErrorUnspecified`.
|
||||
bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods.
|
||||
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
|
||||
|
||||
|
@ -95,6 +110,8 @@ class EncryptedPassportElement(TelegramObject):
|
|||
front_side=None,
|
||||
reverse_side=None,
|
||||
selfie=None,
|
||||
translation=None,
|
||||
hash=None,
|
||||
bot=None,
|
||||
credentials=None,
|
||||
**kwargs):
|
||||
|
@ -108,6 +125,8 @@ class EncryptedPassportElement(TelegramObject):
|
|||
self.front_side = front_side
|
||||
self.reverse_side = reverse_side
|
||||
self.selfie = selfie
|
||||
self.translation = translation
|
||||
self.hash = hash
|
||||
|
||||
self._id_attrs = (self.type, self.data, self.phone_number, self.email, self.files,
|
||||
self.front_side, self.reverse_side, self.selfie)
|
||||
|
@ -125,6 +144,7 @@ class EncryptedPassportElement(TelegramObject):
|
|||
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 cls(bot=bot, **data)
|
||||
|
||||
|
@ -141,9 +161,9 @@ class EncryptedPassportElement(TelegramObject):
|
|||
if secure_data.data is not None:
|
||||
# If not already decrypted
|
||||
if not isinstance(data['data'], dict):
|
||||
data['data'] = decrypt_json(secure_data.data.secret,
|
||||
secure_data.data.hash,
|
||||
data['data'])
|
||||
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',
|
||||
|
@ -153,13 +173,15 @@ class EncryptedPassportElement(TelegramObject):
|
|||
data['data'] = ResidentialAddress.de_json(data['data'], bot=bot)
|
||||
|
||||
data['files'] = PassportFile.de_list_decrypted(data.get('files'), bot,
|
||||
secure_data) or None
|
||||
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 cls(bot=bot, **data)
|
||||
|
||||
|
@ -179,5 +201,7 @@ class EncryptedPassportElement(TelegramObject):
|
|||
|
||||
if self.files:
|
||||
data['files'] = [p.to_dict() for p in self.files]
|
||||
if self.translation:
|
||||
data['translation'] = [p.to_dict() for p in self.translation]
|
||||
|
||||
return data
|
||||
|
|
|
@ -250,3 +250,108 @@ class PassportElementErrorSelfie(PassportElementError):
|
|||
self.file_hash = 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.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
type,
|
||||
file_hash,
|
||||
message,
|
||||
**kwargs):
|
||||
# Required
|
||||
super(PassportElementErrorTranslationFile, self).__init__('translation_file',
|
||||
type, message)
|
||||
self.file_hash = 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 change.
|
||||
|
||||
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 file hash.
|
||||
message (:obj:`str`): Error message.
|
||||
|
||||
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.
|
||||
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
type,
|
||||
file_hashes,
|
||||
message,
|
||||
**kwargs):
|
||||
# Required
|
||||
super(PassportElementErrorTranslationFiles, self).__init__('translation_files',
|
||||
type, message)
|
||||
self.file_hashes = file_hashes
|
||||
|
||||
self._id_attrs = ((self.source, self.type, self.message) +
|
||||
tuple([file_hash for file_hash in file_hashes]))
|
||||
|
||||
|
||||
class PassportElementErrorUnspecified(PassportElementError):
|
||||
"""
|
||||
Represents an issue in an unspecified place. The error is considered resolved when new
|
||||
data is added.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
**kwargs (:obj:`dict`): Arbitrary keyword arguments.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
type,
|
||||
element_hash,
|
||||
message,
|
||||
**kwargs):
|
||||
# Required
|
||||
super(PassportElementErrorUnspecified, self).__init__('unspecified', type, message)
|
||||
self.element_hash = element_hash
|
||||
|
||||
self._id_attrs = (self.source, self.type, self.element_hash, self.message)
|
||||
|
|
|
@ -84,7 +84,7 @@ class PassportFile(TelegramObject):
|
|||
if not data:
|
||||
return []
|
||||
|
||||
return [cls.de_json_decrypted(passport_file, bot, credentials.files[i])
|
||||
return [cls.de_json_decrypted(passport_file, bot, credentials[i])
|
||||
for i, passport_file in enumerate(data)]
|
||||
|
||||
def get_file(self, timeout=None, **kwargs):
|
||||
|
|
|
@ -22,29 +22,63 @@ import pytest
|
|||
|
||||
from telegram import (PassportData, PassportFile, Bot, File, PassportElementErrorSelfie,
|
||||
PassportElementErrorDataField, Credentials, TelegramDecryptionError)
|
||||
|
||||
RAW_PASSPORT_DATA = {'data': [{'type': 'personal_details',
|
||||
'data': 'tj3pNwOpN+ZHsyb6F3aJcNmEyPxrOtGTbu3waBlCQDNaQ9oJlkbXpw+HI3y9faq/+TCeB/WsS/2TxRXTKZw4zXvGP2UsfdRkJ2SQq6x+Ffe/oTF9/q8sWp2BwU3hHUOz7ec1/QrdPBhPJjbwSykEBNggPweiBVDZ0x/DWJ0guCkGT9smYGqog1vqlqbIWG7AWcxVy2fpUy9w/zDXjxj5WQ3lRpHJmi46s9xIHobNGGBvWw6/bGBCInMoovgqRCEu1sgz2QXF3wNiUzGFycEzLz7o+1htLys5n8Pdi9MG4RY='},
|
||||
{'type': 'driver_license',
|
||||
'data': 'hOXQ/iHSGRDFXqql3yETA4AiP0mdlwmo9RtGS+Qg9E5okrN/yTcPNtBKb2fLA0posk35bvevN53cyJMHZnxErEFTSw/FQjPyRFdJUyjGNPeu4yOI73uk5eRVLTAlA2G0eN2azzfS/QOBGL19N3pHk9hMTZYPCBTDt89MHhRQS7Z3YWRSzFcFiEhktHv/ezgcg3EWtsUQ8K4J2445uoZzbB8wsQ6RM4ibn08RfjV6dNyVrj8jBGUpCBlA6iY60rFQM+LZ9ByI3OeS53bnIAMQC2rHHbV/wkzS6PbufOzjZgJq26aCLmC5YDomrpcrdvk0fvi6aEuBJEI3zcteh2fh/Q==',
|
||||
'selfie': {'file_id': 'DgADBAADEQQAAkopgFNr6oi-wISRtAI',
|
||||
'file_date': 1534074942},
|
||||
'reverse_side': {'file_id': 'DgADBAADNQQAAtoagFPf4wwmFZdmyQI',
|
||||
'file_date': 1534074942},
|
||||
'front_side': {'file_id': 'DgADBAADxwMAApnQgVPK2-ckL2eXVAI',
|
||||
'file_date': 1534074942}},
|
||||
{'type': 'address',
|
||||
'data': 'j9SksVkSj128DBtZA+3aNjSFNirzv+R97guZaMgae4Gi0oDVNAF7twPR7j9VSmPedfJrEwL3O889Ei+a5F1xyLLyEI/qEBljvL70GFIhYGitS0JmNabHPHSZrjOl8b4s/0Z0Px2GpLO5siusTLQonimdUvu4UPjKquYISmlKEKhtmGATy+h+JDjNCYuOkhakeNw0Rk0BHgj0C3fCb7WZNQSyVb+2GTu6caR6eXf/AFwFp0TV3sRz3h0WIVPW8bna'},
|
||||
{'type': 'utility_bill', 'files': [
|
||||
{'file_id': 'DgADBAADLAMAAhwfgVMyfGa5Nr0LvAI',
|
||||
'file_date': 1534074988},
|
||||
{'file_id': 'DgADBAADaQQAAsFxgVNVfLZuT-_3ZQI',
|
||||
'file_date': 1534074988}]},
|
||||
{'type': 'email', 'email': 'fb3e3i47zt@dispostable.com'}],
|
||||
'credentials': {
|
||||
'data': 'uI/g4fJLVO6132t+yuBvKExTpTubinscH8KLVc8YPuo1SiXaBg4A6AaVdv60CPViMw8n+ShVWOTL6oN5Ye0+CC2/URZ0eeTMJcKkvJYRI0Q6YJ3aeeEzslwORKho0mGk5xSWpPV5LHXhRIlgUMA32NkbNuzzoij7OhqxvuDE50/0pAUKtxy69h+heAzxFj8+jYjgnOwgwNa6FGUG59oUozgpB98XrEeWGW+JIGE9fux8dSGkFhF2SjkmdW6b2Gexuq94TVGDgFigSvqMOgZj9slZI4UEdZBIGldPHrc8/+EuqWv+WKWU8hdj1dxfY/pNvonb8MwrQLrUyNafdLq5QD4Kmg3XPnZTI9bsYUf6xO9oKU42JezDcRbaCqKkUn6UceCkV2hHMJP4aVVI9Bad1k/rXlaDh8PUV19n6tct5UH8JfkBbGlj2uASI5lPasIvnWg9s1vsZ4ynE2YAuU4iotMkgmJkj1+JCl8Ul9uqzfiK0IbYfu57V82gUEjn6c4br49pY+Cvo9od9Lx8fSJCiXq+DdmDTfIZxpeFqEYeJi6/v0CjJni4CtS6LJGo9JUR2MlqOAiyOLomadlrZyzC2eLm8X6ouIXTxtbUqzxcTiH/r23NQ44YwJpMdDiulNuPg0tEyio8TokHj9APORiW+QIw4zLZFyBEorT1DSALm4AV3A1lIg0svOncDkOqa3ZydQ0tdysoXOq5Zsu+Qu/DQZQz5IGEHb7N9QW6KZDGfBOP5Ok04OxlXO8UaTZr6mysmu8jDOlqtitLKSCGDy0LPfITzehTqfEu0KrtmxI91zJtiNyE4g+oBzQsLwQ7vSp1xl7YNViDi8ea/upZdRavh3NthVD5TxyNJedt4Xp8q5/H5kSV/EFhumONPwBwOuN4KrsCQEaNtHZfYB8SH1v0rWbiFw3/owxCrCPqgEwMGnx+JTqsAplurIZfxsNz+57O4Hq10VVt7yhroq9UpIAR8C8hW58dcZBflWyQwG8HalYAaPJ/teSLP9o6MyiqrUkADbNBOFsUhIerq6Q0BnQ941sWg10BkG8oQSU6JdnZ1Ygml2gpFabBRXeeF5ijD0Y9Bq8D3vDnHKx/GziAK0aKlwSqfTmJ+C1hm7AxBekjtDavkBeq5bIOtxYaXqrtunQFAZRCrcnQEg0DPY6dYw+jmOR0NuHRMU5KeZ0994Jn0TRGiUoJtLp1MHJ2D1MCWG3Fp9Ps7vB46a9XiGYHJUdJjHsavvQRQjhB1FvA/kxXNubCjAOPLUz1j+BEkUUgwi65l8+pViHUCIhBdLJn7S0J9HbMsc3jXOFusfvXfyvf2SZMqyhEscs/2HzYgbCWVSxQ//6eimZqvW4an1JIEfH1xUH3zS0HvS7NWChtX1Cj+jJ2vw+lyom6a84wJ2mjSRVcaV6JZa2mIf2IuXfX8EMZwKMDJagkQ7effV3MrnCNrXUXJYn8wVm6l+uP+R9mCn9qbGlvWToCID0YM8MTxJ0LgzC0n93m46OxxCI1p1hPzVrmDCcKt3OASe0zVat415/sz9TTU7Rm8oNSAVUVNo7FRg2XwEb9VupGMjlscu4cJKLCtUpImSKDKlVLH2KYy6s4NdPjOjqtjQLRoaCxbYHmNXXE+vVwPiNBK/bBVT3XJgdmbkXa/PDnMjhAmn0huuxBu8GsTOs+bBdyDCbr6mY6EzN9lCPspEoOPs7nmREpjrvGmEqEddRteyAebpVqZQhqklyT3RVl8AmfoF7QgTi0NYqFb50Lgou3hFrMg7isG5EKU+IKI5WfzyWONlHNSpvO',
|
||||
'hash': 'qyi5vQ2HCVjVMHb+l6HQ4krmvwwEkvm6Qmdf5GJcohM=',
|
||||
'secret': 'kgJE0VLB9enOq5fhhX8gOv0xoaMIcskmRPOG1eMbiC/Q8slr7kur12H/YIoOfd7/DQ0ggE7TAAe34PypFvtmwt5fDVtqtPl9YoCeAOCFWxHxLgTCLbzoJ0lTJXoJkdHjlvR2lKaP+rMtaU1w8WOpYOGiNXyblQoWwFRrWNTHmHnmwBfGBFCj/vp89+C1viEYHeWPPUkBhf1vT31L70BEoe8hxORJEDg+jY+80W2nFdIWNBF+o9GSmbMWFtd7UFiuLPp2JUBCy8XuHozk8xFk/PN6m6DgSu32rC4YBJv/sWGUo/MmH0nxR3gaiEkj+9rWIybCNAwgfdQpk/KH2RCF8g=='}}
|
||||
# Generated using the scope:
|
||||
# {
|
||||
# data: [
|
||||
# {
|
||||
# type: 'personal_details',
|
||||
# native_names: true
|
||||
# },
|
||||
# {
|
||||
# type: 'id_document',
|
||||
# selfie: true,
|
||||
# translation: true
|
||||
# },
|
||||
# {
|
||||
# type: 'address_document',
|
||||
# translation: true
|
||||
# },
|
||||
# 'address',
|
||||
# 'email'
|
||||
# ],
|
||||
# v: 1
|
||||
# }
|
||||
RAW_PASSPORT_DATA = {'credentials': {'hash': 'qB4hz2LMcXYhglwz6EvXMMyI3PURisWLXl/iCmCXcSk=',
|
||||
'secret': 'O6x3X2JrLO1lUIhw48os1gaenDuZLhesoZMKXehZwtM3vsxOdtxHKWQyLNwtbyy4snYpARXDwf8f1QHNmQ/M1PwBQvk1ozrZBXb4a6k/iYj+P4v8Xw2M++CRHqZv0LaxFtyHOXnNYZ6dXpNeF0ZvYYTmm0FsYvK+/3/F6VDB3Oe6xWlXFLwaCCP/jA9i2+dKp6iq8NLOo4VnxenPKWWYz20RZ50MdAbS3UR+NCx4AHM2P5DEGrHNW0tMXJ+FG3jpVrit5BuCbB/eRgKxNGRWNxEGV5hun5MChdxKCEHCimnUA97h7MZdoTgYxkrfvDSZ/V89BnFXLdr87t/NLvVE0Q==',
|
||||
'data': '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'},
|
||||
'data': [
|
||||
{
|
||||
'data': 'QRfzWcCN4WncvRO3lASG+d+c5gzqXtoCinQ1PgtYiZMKXCksx9eB9Ic1bOt8C/un9/XaX220PjJSO7Kuba+nXXC51qTsjqP9rnLKygnEIWjKrfiDdklzgcukpRzFSjiOAvhy86xFJZ1PfPSrFATy/Gp1RydLzbrBd2ZWxZqXrxcMoA0Q2UTTFXDoCYerEAiZoD69i79tB/6nkLBcUUvN5d52gKd/GowvxWqAAmdO6l1N7jlo6aWjdYQNBAK1KHbJdbRZMJLxC1MqMuZXAYrPoYBRKr5xAnxDTmPn/LEZKLc3gwwZyEgR5x7e9jp5heM6IEMmsv3O/6SUeEQs7P0iVuRSPLMJLfDdwns8Tl3fF2M4IxKVovjCaOVW+yHKsADDAYQPzzH2RcrWVD0TP5I64mzpK64BbTOq3qm3Hn51SV9uA/+LvdGbCp7VnzHx4EdUizHsVyilJULOBwvklsrDRvXMiWmh34ZSR6zilh051tMEcRf0I+Oe7pIxVJd/KKfYA2Z/eWVQTCn5gMuAInQNXFSqDIeIqBX+wca6kvOCUOXB7J2uRjTpLaC4DM9s/sNjSBvFixcGAngt+9oap6Y45rQc8ZJaNN/ALqEJAmkphW8=',
|
||||
'type': 'personal_details'
|
||||
}, {
|
||||
'reverse_side': {'file_date': 1534074942,
|
||||
'file_id': 'DgADBAADNQQAAtoagFPf4wwmFZdmyQI'},
|
||||
'translation': [{'file_size': 28640, 'file_date': 1535630933,
|
||||
'file_id': 'DgADBAADswMAAisqQVAmooP-kVgLgAI'},
|
||||
{'file_size': 28672, 'file_date': 1535630933,
|
||||
'file_id': 'DgADBAAD1QMAAnrpQFBMZsT3HysjwwI'}],
|
||||
'front_side': {'file_size': 28624, 'file_date': 1534074942,
|
||||
'file_id': 'DgADBAADxwMAApnQgVPK2-ckL2eXVAI'},
|
||||
'type': 'driver_license',
|
||||
'selfie': {'file_size': 28592, 'file_date': 1534074942,
|
||||
'file_id': 'DgADBAADEQQAAkopgFNr6oi-wISRtAI'},
|
||||
'data': 'eJUOFuY53QKmGqmBgVWlLBAQCUQJ79n405SX6M5aGFIIodOPQqnLYvMNqTwTrXGDlW+mVLZcbu+y8luLVO8WsJB/0SB7q5WaXn/IMt1G9lz5G/KMLIZG/x9zlnimsaQLg7u8srG6L4KZzv+xkbbHjZdETrxU8j0N/DoS4HvLMRSJAgeFUrY6v2YW9vSRg+fSxIqQy1jR2VKpzAT8OhOz7A=='
|
||||
}, {
|
||||
'translation': [{'file_size': 28480, 'file_date': 1535630939,
|
||||
'file_id': 'DgADBAADyQUAAqyqQVC_eoX_KwNjJwI'},
|
||||
{'file_size': 28528, 'file_date': 1535630939,
|
||||
'file_id': 'DgADBAADsQQAAubTQVDRO_FN3lOwWwI'}],
|
||||
'files': [{'file_size': 28640, 'file_date': 1534074988,
|
||||
'file_id': 'DgADBAADLAMAAhwfgVMyfGa5Nr0LvAI'},
|
||||
{'file_size': 28480, 'file_date': 1534074988,
|
||||
'file_id': 'DgADBAADaQQAAsFxgVNVfLZuT-_3ZQI'}],
|
||||
'type': 'utility_bill'
|
||||
}, {
|
||||
'data': 'j9SksVkSj128DBtZA+3aNjSFNirzv+R97guZaMgae4Gi0oDVNAF7twPR7j9VSmPedfJrEwL3O889Ei+a5F1xyLLyEI/qEBljvL70GFIhYGitS0JmNabHPHSZrjOl8b4s/0Z0Px2GpLO5siusTLQonimdUvu4UPjKquYISmlKEKhtmGATy+h+JDjNCYuOkhakeNw0Rk0BHgj0C3fCb7WZNQSyVb+2GTu6caR6eXf/AFwFp0TV3sRz3h0WIVPW8bna',
|
||||
'type': 'address'
|
||||
}, {
|
||||
'email': 'fb3e3i47zt@dispostable.com', 'type': 'email'
|
||||
}]}
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
|
@ -54,33 +88,42 @@ def all_passport_data():
|
|||
{'type': 'passport',
|
||||
'data': RAW_PASSPORT_DATA['data'][1]['data'],
|
||||
'front_side': RAW_PASSPORT_DATA['data'][1]['front_side'],
|
||||
'selfie': RAW_PASSPORT_DATA['data'][1]['selfie']},
|
||||
'selfie': RAW_PASSPORT_DATA['data'][1]['selfie'],
|
||||
'translation': RAW_PASSPORT_DATA['data'][1]['translation']},
|
||||
{'type': 'internal_passport',
|
||||
'data': RAW_PASSPORT_DATA['data'][1]['data'],
|
||||
'front_side': RAW_PASSPORT_DATA['data'][1]['front_side'],
|
||||
'selfie': RAW_PASSPORT_DATA['data'][1]['selfie']},
|
||||
'selfie': RAW_PASSPORT_DATA['data'][1]['selfie'],
|
||||
'translation': RAW_PASSPORT_DATA['data'][1]['translation']},
|
||||
{'type': 'driver_license',
|
||||
'data': RAW_PASSPORT_DATA['data'][1]['data'],
|
||||
'front_side': RAW_PASSPORT_DATA['data'][1]['front_side'],
|
||||
'reverse_side': RAW_PASSPORT_DATA['data'][1]['reverse_side'],
|
||||
'selfie': RAW_PASSPORT_DATA['data'][1]['selfie']},
|
||||
'selfie': RAW_PASSPORT_DATA['data'][1]['selfie'],
|
||||
'translation': RAW_PASSPORT_DATA['data'][1]['translation']},
|
||||
{'type': 'identity_card',
|
||||
'data': RAW_PASSPORT_DATA['data'][1]['data'],
|
||||
'front_side': RAW_PASSPORT_DATA['data'][1]['front_side'],
|
||||
'reverse_side': RAW_PASSPORT_DATA['data'][1]['reverse_side'],
|
||||
'selfie': RAW_PASSPORT_DATA['data'][1]['selfie']},
|
||||
{'type': 'address',
|
||||
'data': RAW_PASSPORT_DATA['data'][2]['data']},
|
||||
'selfie': RAW_PASSPORT_DATA['data'][1]['selfie'],
|
||||
'translation': RAW_PASSPORT_DATA['data'][1]['translation']},
|
||||
{'type': 'utility_bill',
|
||||
'files': RAW_PASSPORT_DATA['data'][3]['files']},
|
||||
'files': RAW_PASSPORT_DATA['data'][2]['files'],
|
||||
'translation': RAW_PASSPORT_DATA['data'][2]['translation']},
|
||||
{'type': 'bank_statement',
|
||||
'files': RAW_PASSPORT_DATA['data'][3]['files']},
|
||||
'files': RAW_PASSPORT_DATA['data'][2]['files'],
|
||||
'translation': RAW_PASSPORT_DATA['data'][2]['translation']},
|
||||
{'type': 'rental_agreement',
|
||||
'files': RAW_PASSPORT_DATA['data'][3]['files']},
|
||||
'files': RAW_PASSPORT_DATA['data'][2]['files'],
|
||||
'translation': RAW_PASSPORT_DATA['data'][2]['translation']},
|
||||
{'type': 'passport_registration',
|
||||
'files': RAW_PASSPORT_DATA['data'][3]['files']},
|
||||
'files': RAW_PASSPORT_DATA['data'][2]['files'],
|
||||
'translation': RAW_PASSPORT_DATA['data'][2]['translation']},
|
||||
{'type': 'temporary_registration',
|
||||
'files': RAW_PASSPORT_DATA['data'][3]['files']},
|
||||
'files': RAW_PASSPORT_DATA['data'][2]['files'],
|
||||
'translation': RAW_PASSPORT_DATA['data'][2]['translation']},
|
||||
{'type': 'address',
|
||||
'data': RAW_PASSPORT_DATA['data'][3]['data']},
|
||||
{'type': 'email',
|
||||
'email': 'fb3e3i47zt@dispostable.com'},
|
||||
{'type': 'phone_number',
|
||||
|
@ -96,8 +139,12 @@ class TestPassport(object):
|
|||
driver_license_selfie_file_id = 'DgADBAADEQQAAkopgFNr6oi-wISRtAI'
|
||||
driver_license_front_side_file_id = 'DgADBAADxwMAApnQgVPK2-ckL2eXVAI'
|
||||
driver_license_reverse_side_file_id = 'DgADBAADNQQAAtoagFPf4wwmFZdmyQI'
|
||||
driver_license_translation_1_file_id = 'DgADBAADswMAAisqQVAmooP-kVgLgAI'
|
||||
driver_license_translation_2_file_id = 'DgADBAAD1QMAAnrpQFBMZsT3HysjwwI'
|
||||
utility_bill_1_file_id = 'DgADBAADLAMAAhwfgVMyfGa5Nr0LvAI'
|
||||
utility_bill_2_file_id = 'DgADBAADaQQAAsFxgVNVfLZuT-_3ZQI'
|
||||
utility_bill_translation_1_file_id = 'DgADBAADyQUAAqyqQVC_eoX_KwNjJwI'
|
||||
utility_bill_translation_2_file_id = 'DgADBAADsQQAAubTQVDRO_FN3lOwWwI'
|
||||
driver_license_selfie_credentials_file_hash = 'Cila/qLXSBH7DpZFbb5bRZIRxeFW2uv/ulL0u0JNsYI='
|
||||
driver_license_selfie_credentials_secret = 'tivdId6RNYNsvXYPppdzrbxOBuBOr9wXRPDcCvnXU7E='
|
||||
|
||||
|
@ -105,7 +152,7 @@ class TestPassport(object):
|
|||
assert isinstance(passport_data, PassportData)
|
||||
|
||||
def test_expected_encrypted_values(self, passport_data):
|
||||
personal_details, driver_license, address, utility_bill, email = passport_data.data
|
||||
personal_details, driver_license, utility_bill, address, email = passport_data.data
|
||||
|
||||
assert personal_details.type == 'personal_details'
|
||||
assert personal_details.data == RAW_PASSPORT_DATA['data'][0]['data']
|
||||
|
@ -118,29 +165,41 @@ class TestPassport(object):
|
|||
assert driver_license.front_side.file_id == self.driver_license_front_side_file_id
|
||||
assert isinstance(driver_license.reverse_side, PassportFile)
|
||||
assert driver_license.reverse_side.file_id == self.driver_license_reverse_side_file_id
|
||||
|
||||
assert address.type == 'address'
|
||||
assert address.data == RAW_PASSPORT_DATA['data'][2]['data']
|
||||
assert isinstance(driver_license.translation[0], PassportFile)
|
||||
assert driver_license.translation[0].file_id == self.driver_license_translation_1_file_id
|
||||
assert isinstance(driver_license.translation[1], PassportFile)
|
||||
assert driver_license.translation[1].file_id == self.driver_license_translation_2_file_id
|
||||
|
||||
assert utility_bill.type == 'utility_bill'
|
||||
assert isinstance(utility_bill.files[0], PassportFile)
|
||||
assert utility_bill.files[0].file_id == self.utility_bill_1_file_id
|
||||
assert isinstance(utility_bill.files[1], PassportFile)
|
||||
assert utility_bill.files[1].file_id == self.utility_bill_2_file_id
|
||||
assert isinstance(utility_bill.translation[0], PassportFile)
|
||||
assert utility_bill.translation[0].file_id == self.utility_bill_translation_1_file_id
|
||||
assert isinstance(utility_bill.translation[1], PassportFile)
|
||||
assert utility_bill.translation[1].file_id == self.utility_bill_translation_2_file_id
|
||||
|
||||
assert address.type == 'address'
|
||||
assert address.data == RAW_PASSPORT_DATA['data'][3]['data']
|
||||
|
||||
assert email.type == 'email'
|
||||
assert email.email == 'fb3e3i47zt@dispostable.com'
|
||||
|
||||
def test_expected_decrypted_values(self, passport_data):
|
||||
(personal_details, driver_license, address,
|
||||
utility_bill, email) = passport_data.decrypted_data
|
||||
(personal_details, driver_license, utility_bill, address,
|
||||
email) = passport_data.decrypted_data
|
||||
|
||||
assert personal_details.type == 'personal_details'
|
||||
assert personal_details.data.to_dict() == {'gender': 'female',
|
||||
assert personal_details.data.to_dict() == {'first_name': 'FIRSTNAME',
|
||||
'middle_name': 'MIDDLENAME',
|
||||
'first_name_native': 'FIRSTNAMENATIVE',
|
||||
'residence_country_code': 'DK',
|
||||
'country_code': 'DK',
|
||||
'birth_date': '01.01.2001',
|
||||
'first_name': 'FIRSTNAME',
|
||||
'last_name_native': 'LASTNAMENATIVE',
|
||||
'gender': 'female',
|
||||
'middle_name_native': 'MIDDLENAMENATIVE',
|
||||
'country_code': 'DK',
|
||||
'last_name': 'LASTNAME'}
|
||||
|
||||
assert driver_license.type == 'driver_license'
|
||||
|
@ -210,7 +269,7 @@ class TestPassport(object):
|
|||
|
||||
def test_wrong_hash(self, bot):
|
||||
data = deepcopy(RAW_PASSPORT_DATA)
|
||||
data['credentials']['hash'] = b'notcorrecthash'
|
||||
data['credentials']['hash'] = 'bm90Y29ycmVjdGhhc2g=' # Not correct hash
|
||||
passport_data = PassportData.de_json(data, bot=bot)
|
||||
with pytest.raises(TelegramDecryptionError):
|
||||
assert passport_data.decrypted_data
|
||||
|
|
80
tests/test_passportelementerrortranslationfile.py
Normal file
80
tests/test_passportelementerrortranslationfile.py
Normal file
|
@ -0,0 +1,80 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2018
|
||||
# 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/].
|
||||
|
||||
import pytest
|
||||
|
||||
from telegram import PassportElementErrorTranslationFile, PassportElementErrorDataField
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def passport_element_error_translation_file():
|
||||
return PassportElementErrorTranslationFile(TestPassportElementErrorTranslationFile.type,
|
||||
TestPassportElementErrorTranslationFile.file_hash,
|
||||
TestPassportElementErrorTranslationFile.message)
|
||||
|
||||
|
||||
class TestPassportElementErrorTranslationFile(object):
|
||||
source = 'translation_file'
|
||||
type = 'test_type'
|
||||
file_hash = 'file_hash'
|
||||
message = 'Error message'
|
||||
|
||||
def test_expected_values(self, passport_element_error_translation_file):
|
||||
assert passport_element_error_translation_file.source == self.source
|
||||
assert passport_element_error_translation_file.type == self.type
|
||||
assert passport_element_error_translation_file.file_hash == self.file_hash
|
||||
assert passport_element_error_translation_file.message == self.message
|
||||
|
||||
def test_to_dict(self, passport_element_error_translation_file):
|
||||
passport_element_error_translation_file_dict = \
|
||||
passport_element_error_translation_file.to_dict()
|
||||
|
||||
assert isinstance(passport_element_error_translation_file_dict, dict)
|
||||
assert (passport_element_error_translation_file_dict['source'] ==
|
||||
passport_element_error_translation_file.source)
|
||||
assert (passport_element_error_translation_file_dict['type'] ==
|
||||
passport_element_error_translation_file.type)
|
||||
assert (passport_element_error_translation_file_dict['file_hash'] ==
|
||||
passport_element_error_translation_file.file_hash)
|
||||
assert (passport_element_error_translation_file_dict['message'] ==
|
||||
passport_element_error_translation_file.message)
|
||||
|
||||
def test_equality(self):
|
||||
a = PassportElementErrorTranslationFile(self.type, self.file_hash, self.message)
|
||||
b = PassportElementErrorTranslationFile(self.type, self.file_hash, self.message)
|
||||
c = PassportElementErrorTranslationFile(self.type, '', '')
|
||||
d = PassportElementErrorTranslationFile('', self.file_hash, '')
|
||||
e = PassportElementErrorTranslationFile('', '', self.message)
|
||||
f = PassportElementErrorDataField(self.type, '', '', self.message)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
assert a != f
|
||||
assert hash(a) != hash(f)
|
81
tests/test_passportelementerrortranslationfiles.py
Normal file
81
tests/test_passportelementerrortranslationfiles.py
Normal file
|
@ -0,0 +1,81 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2018
|
||||
# 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/].
|
||||
|
||||
import pytest
|
||||
|
||||
from telegram import PassportElementErrorTranslationFiles, PassportElementErrorSelfie
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def passport_element_error_translation_files():
|
||||
return PassportElementErrorTranslationFiles(TestPassportElementErrorTranslationFiles.type,
|
||||
TestPassportElementErrorTranslationFiles.file_hashes, # flake8: noqa
|
||||
TestPassportElementErrorTranslationFiles.message)
|
||||
|
||||
|
||||
class TestPassportElementErrorTranslationFiles(object):
|
||||
source = 'translation_files'
|
||||
type = 'test_type'
|
||||
file_hashes = ['hash1', 'hash2']
|
||||
message = 'Error message'
|
||||
|
||||
def test_expected_values(self, passport_element_error_translation_files):
|
||||
assert passport_element_error_translation_files.source == self.source
|
||||
assert passport_element_error_translation_files.type == self.type
|
||||
assert isinstance(passport_element_error_translation_files.file_hashes, list)
|
||||
assert passport_element_error_translation_files.file_hashes == self.file_hashes
|
||||
assert passport_element_error_translation_files.message == self.message
|
||||
|
||||
def test_to_dict(self, passport_element_error_translation_files):
|
||||
passport_element_error_translation_files_dict = \
|
||||
passport_element_error_translation_files.to_dict()
|
||||
|
||||
assert isinstance(passport_element_error_translation_files_dict, dict)
|
||||
assert (passport_element_error_translation_files_dict['source'] ==
|
||||
passport_element_error_translation_files.source)
|
||||
assert (passport_element_error_translation_files_dict['type'] ==
|
||||
passport_element_error_translation_files.type)
|
||||
assert (passport_element_error_translation_files_dict['file_hashes'] ==
|
||||
passport_element_error_translation_files.file_hashes)
|
||||
assert (passport_element_error_translation_files_dict['message'] ==
|
||||
passport_element_error_translation_files.message)
|
||||
|
||||
def test_equality(self):
|
||||
a = PassportElementErrorTranslationFiles(self.type, self.file_hashes, self.message)
|
||||
b = PassportElementErrorTranslationFiles(self.type, self.file_hashes, self.message)
|
||||
c = PassportElementErrorTranslationFiles(self.type, '', '')
|
||||
d = PassportElementErrorTranslationFiles('', self.file_hashes, '')
|
||||
e = PassportElementErrorTranslationFiles('', '', self.message)
|
||||
f = PassportElementErrorSelfie(self.type, '', self.message)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
assert a != f
|
||||
assert hash(a) != hash(f)
|
79
tests/test_passportelementerrorunspecified.py
Normal file
79
tests/test_passportelementerrorunspecified.py
Normal file
|
@ -0,0 +1,79 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# A library that provides a Python interface to the Telegram Bot API
|
||||
# Copyright (C) 2015-2018
|
||||
# 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/].
|
||||
|
||||
import pytest
|
||||
|
||||
from telegram import PassportElementErrorUnspecified, PassportElementErrorDataField
|
||||
|
||||
|
||||
@pytest.fixture(scope='class')
|
||||
def passport_element_error_unspecified():
|
||||
return PassportElementErrorUnspecified(TestPassportElementErrorUnspecified.type,
|
||||
TestPassportElementErrorUnspecified.element_hash,
|
||||
TestPassportElementErrorUnspecified.message)
|
||||
|
||||
|
||||
class TestPassportElementErrorUnspecified(object):
|
||||
source = 'unspecified'
|
||||
type = 'test_type'
|
||||
element_hash = 'element_hash'
|
||||
message = 'Error message'
|
||||
|
||||
def test_expected_values(self, passport_element_error_unspecified):
|
||||
assert passport_element_error_unspecified.source == self.source
|
||||
assert passport_element_error_unspecified.type == self.type
|
||||
assert passport_element_error_unspecified.element_hash == self.element_hash
|
||||
assert passport_element_error_unspecified.message == self.message
|
||||
|
||||
def test_to_dict(self, passport_element_error_unspecified):
|
||||
passport_element_error_unspecified_dict = passport_element_error_unspecified.to_dict()
|
||||
|
||||
assert isinstance(passport_element_error_unspecified_dict, dict)
|
||||
assert (passport_element_error_unspecified_dict['source'] ==
|
||||
passport_element_error_unspecified.source)
|
||||
assert (passport_element_error_unspecified_dict['type'] ==
|
||||
passport_element_error_unspecified.type)
|
||||
assert (passport_element_error_unspecified_dict['element_hash'] ==
|
||||
passport_element_error_unspecified.element_hash)
|
||||
assert (passport_element_error_unspecified_dict['message'] ==
|
||||
passport_element_error_unspecified.message)
|
||||
|
||||
def test_equality(self):
|
||||
a = PassportElementErrorUnspecified(self.type, self.element_hash, self.message)
|
||||
b = PassportElementErrorUnspecified(self.type, self.element_hash, self.message)
|
||||
c = PassportElementErrorUnspecified(self.type, '', '')
|
||||
d = PassportElementErrorUnspecified('', self.element_hash, '')
|
||||
e = PassportElementErrorUnspecified('', '', self.message)
|
||||
f = PassportElementErrorDataField(self.type, '', '', self.message)
|
||||
|
||||
assert a == b
|
||||
assert hash(a) == hash(b)
|
||||
assert a is not b
|
||||
|
||||
assert a != c
|
||||
assert hash(a) != hash(c)
|
||||
|
||||
assert a != d
|
||||
assert hash(a) != hash(d)
|
||||
|
||||
assert a != e
|
||||
assert hash(a) != hash(e)
|
||||
|
||||
assert a != f
|
||||
assert hash(a) != hash(f)
|
Loading…
Reference in a new issue