1717# You should have received a copy of the GNU Lesser Public License
1818# along with this program. If not, see [http://www.gnu.org/licenses/].
1919from copy import deepcopy
20- from threading import Event
2120
2221import pytest
2322
24- from telegram import (PassportData , PassportFile , Bot , Update , File , PassportElementErrorSelfie ,
25- PassportElementErrorDataField )
23+ from telegram import (PassportData , PassportFile , Bot , File , PassportElementErrorSelfie ,
24+ PassportElementErrorDataField , Credentials , TelegramDecryptionError )
2625
2726RAW_PASSPORT_DATA = {'data' : [{'type' : 'personal_details' ,
2827 'data' : 'tj3pNwOpN+ZHsyb6F3aJcNmEyPxrOtGTbu3waBlCQDNaQ9oJlkbXpw+HI3y9faq/+TCeB/WsS/2TxRXTKZw4zXvGP2UsfdRkJ2SQq6x+Ffe/oTF9/q8sWp2BwU3hHUOz7ec1/QrdPBhPJjbwSykEBNggPweiBVDZ0x/DWJ0guCkGT9smYGqog1vqlqbIWG7AWcxVy2fpUy9w/zDXjxj5WQ3lRpHJmi46s9xIHobNGGBvWw6/bGBCInMoovgqRCEu1sgz2QXF3wNiUzGFycEzLz7o+1htLys5n8Pdi9MG4RY=' },
3534 'front_side' : {'file_id' : 'DgADBAADxwMAApnQgVPK2-ckL2eXVAI' ,
3635 'file_date' : 1534074942 }},
3736 {'type' : 'address' ,
38- 'data' : 'j9SksVkSj128DBtZA+3aNjSFNirzv+R97guZaMgae4Gi0oDVNAF7twPR7j9VSmPedfJrEwL3O889Ei+a5F1xyLLyEI/qEBljvL70GFIhYGitS0JmNabHPHSZrjOl8b4s/0Z0Px2GpLO5siusTLQonimdUvu4UPjKquYISmlKEKhtmGATy+h+JDjNCYuOkhakeNw0Rk0BHgj0C3fCb7WZNQSyVb+2GTu6caR6eXf/AFwFp0TV3sRz3h0WIVPW8bna' }, # noqa: E501
37+ 'data' : 'j9SksVkSj128DBtZA+3aNjSFNirzv+R97guZaMgae4Gi0oDVNAF7twPR7j9VSmPedfJrEwL3O889Ei+a5F1xyLLyEI/qEBljvL70GFIhYGitS0JmNabHPHSZrjOl8b4s/0Z0Px2GpLO5siusTLQonimdUvu4UPjKquYISmlKEKhtmGATy+h+JDjNCYuOkhakeNw0Rk0BHgj0C3fCb7WZNQSyVb+2GTu6caR6eXf/AFwFp0TV3sRz3h0WIVPW8bna' },
3938 {'type' : 'utility_bill' , 'files' : [
4039 {'file_id' : 'DgADBAADLAMAAhwfgVMyfGa5Nr0LvAI' ,
4140 'file_date' : 1534074988 },
5049
5150@pytest .fixture (scope = 'function' )
5251def all_passport_data ():
53- raw_passport_data = deepcopy (RAW_PASSPORT_DATA )
5452 return [{'type' : 'personal_details' ,
55- 'data' : raw_passport_data ['data' ][0 ]['data' ]},
53+ 'data' : RAW_PASSPORT_DATA ['data' ][0 ]['data' ]},
5654 {'type' : 'passport' ,
57- 'data' : raw_passport_data ['data' ][1 ]['data' ],
58- 'front_side' : raw_passport_data ['data' ][1 ]['front_side' ],
59- 'selfie' : raw_passport_data ['data' ][1 ]['selfie' ]},
55+ 'data' : RAW_PASSPORT_DATA ['data' ][1 ]['data' ],
56+ 'front_side' : RAW_PASSPORT_DATA ['data' ][1 ]['front_side' ],
57+ 'selfie' : RAW_PASSPORT_DATA ['data' ][1 ]['selfie' ]},
6058 {'type' : 'internal_passport' ,
61- 'data' : raw_passport_data ['data' ][1 ]['data' ],
62- 'front_side' : raw_passport_data ['data' ][1 ]['front_side' ],
63- 'selfie' : raw_passport_data ['data' ][1 ]['selfie' ]},
59+ 'data' : RAW_PASSPORT_DATA ['data' ][1 ]['data' ],
60+ 'front_side' : RAW_PASSPORT_DATA ['data' ][1 ]['front_side' ],
61+ 'selfie' : RAW_PASSPORT_DATA ['data' ][1 ]['selfie' ]},
6462 {'type' : 'driver_license' ,
65- 'data' : raw_passport_data ['data' ][1 ]['data' ],
66- 'front_side' : raw_passport_data ['data' ][1 ]['front_side' ],
67- 'reverse_side' : raw_passport_data ['data' ][1 ]['reverse_side' ],
68- 'selfie' : raw_passport_data ['data' ][1 ]['selfie' ]},
63+ 'data' : RAW_PASSPORT_DATA ['data' ][1 ]['data' ],
64+ 'front_side' : RAW_PASSPORT_DATA ['data' ][1 ]['front_side' ],
65+ 'reverse_side' : RAW_PASSPORT_DATA ['data' ][1 ]['reverse_side' ],
66+ 'selfie' : RAW_PASSPORT_DATA ['data' ][1 ]['selfie' ]},
6967 {'type' : 'identity_card' ,
70- 'data' : raw_passport_data ['data' ][1 ]['data' ],
71- 'front_side' : raw_passport_data ['data' ][1 ]['front_side' ],
72- 'reverse_side' : raw_passport_data ['data' ][1 ]['reverse_side' ],
73- 'selfie' : raw_passport_data ['data' ][1 ]['selfie' ]},
68+ 'data' : RAW_PASSPORT_DATA ['data' ][1 ]['data' ],
69+ 'front_side' : RAW_PASSPORT_DATA ['data' ][1 ]['front_side' ],
70+ 'reverse_side' : RAW_PASSPORT_DATA ['data' ][1 ]['reverse_side' ],
71+ 'selfie' : RAW_PASSPORT_DATA ['data' ][1 ]['selfie' ]},
7472 {'type' : 'address' ,
75- 'data' : raw_passport_data ['data' ][2 ]['data' ]},
73+ 'data' : RAW_PASSPORT_DATA ['data' ][2 ]['data' ]},
7674 {'type' : 'utility_bill' ,
77- 'files' : raw_passport_data ['data' ][3 ]['files' ]},
75+ 'files' : RAW_PASSPORT_DATA ['data' ][3 ]['files' ]},
7876 {'type' : 'bank_statement' ,
79- 'files' : raw_passport_data ['data' ][3 ]['files' ]},
77+ 'files' : RAW_PASSPORT_DATA ['data' ][3 ]['files' ]},
8078 {'type' : 'rental_agreement' ,
81- 'files' : raw_passport_data ['data' ][3 ]['files' ]},
79+ 'files' : RAW_PASSPORT_DATA ['data' ][3 ]['files' ]},
8280 {'type' : 'passport_registration' ,
83- 'files' : raw_passport_data ['data' ][3 ]['files' ]},
81+ 'files' : RAW_PASSPORT_DATA ['data' ][3 ]['files' ]},
8482 {'type' : 'temporary_registration' ,
85- 'files' : raw_passport_data ['data' ][3 ]['files' ]},
83+ 'files' : RAW_PASSPORT_DATA ['data' ][3 ]['files' ]},
8684 {'type' : 'email' ,
8785 'email' : 'fb3e3i47zt@dispostable.com' },
8886 {'type' : 'phone_number' ,
@@ -91,7 +89,7 @@ def all_passport_data():
9189
9290@pytest .fixture (scope = 'function' )
9391def passport_data (bot ):
94- return PassportData .de_json (deepcopy ( RAW_PASSPORT_DATA ) , bot = bot )
92+ return PassportData .de_json (RAW_PASSPORT_DATA , bot = bot )
9593
9694
9795class TestPassport (object ):
@@ -106,9 +104,37 @@ class TestPassport(object):
106104 def test_creation (self , passport_data ):
107105 assert isinstance (passport_data , PassportData )
108106
109- def test_expected_values (self , passport_data ):
107+ def test_expected_encrypted_values (self , passport_data ):
110108 personal_details , driver_license , address , utility_bill , email = passport_data .data
111109
110+ assert personal_details .type == 'personal_details'
111+ assert personal_details .data == RAW_PASSPORT_DATA ['data' ][0 ]['data' ]
112+
113+ assert driver_license .type == 'driver_license'
114+ assert driver_license .data == RAW_PASSPORT_DATA ['data' ][1 ]['data' ]
115+ assert isinstance (driver_license .selfie , PassportFile )
116+ assert driver_license .selfie .file_id == self .driver_license_selfie_file_id
117+ assert isinstance (driver_license .front_side , PassportFile )
118+ assert driver_license .front_side .file_id == self .driver_license_front_side_file_id
119+ assert isinstance (driver_license .reverse_side , PassportFile )
120+ assert driver_license .reverse_side .file_id == self .driver_license_reverse_side_file_id
121+
122+ assert address .type == 'address'
123+ assert address .data == RAW_PASSPORT_DATA ['data' ][2 ]['data' ]
124+
125+ assert utility_bill .type == 'utility_bill'
126+ assert isinstance (utility_bill .files [0 ], PassportFile )
127+ assert utility_bill .files [0 ].file_id == self .utility_bill_1_file_id
128+ assert isinstance (utility_bill .files [1 ], PassportFile )
129+ assert utility_bill .files [1 ].file_id == self .utility_bill_2_file_id
130+
131+ assert email .type == 'email'
132+ assert email .email == 'fb3e3i47zt@dispostable.com'
133+
134+ def test_expected_decrypted_values (self , passport_data ):
135+ (personal_details , driver_license , address ,
136+ utility_bill , email ) = passport_data .decrypted_data
137+
112138 assert personal_details .type == 'personal_details'
113139 assert personal_details .data .to_dict () == {'gender' : 'female' ,
114140 'residence_country_code' : 'DK' ,
@@ -142,11 +168,11 @@ def test_expected_values(self, passport_data):
142168 assert email .email == 'fb3e3i47zt@dispostable.com'
143169
144170 def test_all_types (self , passport_data , bot , all_passport_data ):
145- credentials = passport_data .credentials .to_dict ()
171+ credentials = passport_data .decrypted_credentials .to_dict ()
146172
147173 # Copy credentials from other types to all types so we can decrypt everything
148- sd = credentials ['data' ][ ' secure_data' ]
149- credentials ['data' ][ ' secure_data' ] = {
174+ sd = credentials ['secure_data' ]
175+ credentials ['secure_data' ] = {
150176 'personal_details' : sd ['personal_details' ].copy (),
151177 'passport' : sd ['driver_license' ].copy (),
152178 'internal_passport' : sd ['driver_license' ].copy (),
@@ -160,10 +186,16 @@ def test_all_types(self, passport_data, bot, all_passport_data):
160186 'temporary_registration' : sd ['utility_bill' ].copy (),
161187 }
162188
163- assert isinstance ( PassportData .de_json ({
189+ new = PassportData .de_json ({
164190 'data' : all_passport_data ,
165- 'credentials' : credentials
166- }, bot = bot ), PassportData )
191+ # Replaced below
192+ 'credentials' : {'data' : 'data' , 'hash' : 'hash' , 'secret' : 'secret' }
193+ }, bot = bot )
194+
195+ new .credentials ._decrypted_data = Credentials .de_json (credentials , bot )
196+
197+ assert isinstance (new , PassportData )
198+ assert new .decrypted_data
167199
168200 def test_bot_init_invalid_key (self , bot ):
169201 with pytest .raises (TypeError ):
@@ -172,61 +204,36 @@ def test_bot_init_invalid_key(self, bot):
172204 with pytest .raises (ValueError ):
173205 Bot (bot .token , private_key = b'Invalid key!' )
174206
175- def test_passport_data_update_on_non_crypto_bot (self , bot ):
207+ def test_passport_data_okay_with_non_crypto_bot (self , bot ):
176208 b = Bot (bot .token )
177- with pytest .warns (UserWarning ):
178- PassportData .de_json (deepcopy (RAW_PASSPORT_DATA ), bot = b )
209+ assert PassportData .de_json (RAW_PASSPORT_DATA , bot = b )
179210
180211 def test_wrong_hash (self , bot ):
181212 data = deepcopy (RAW_PASSPORT_DATA )
182213 data ['credentials' ]['hash' ] = b'notcorrecthash'
183- with pytest .warns (UserWarning , match = 'Telegram passport decryption error: '
184- 'Hashes are not equal!' ):
185- PassportData .de_json (data , bot = bot )
186-
187- def test_wrong_hash_in_updater (self , updater , dp , monkeypatch ):
188- # Make sure first call doesn't halt the updater by requiring two calls
189- event = Event ()
190- event2 = Event ()
191-
192- def test (* args , ** kwargs ):
193- if event .is_set ():
194- event2 .set ()
195- else :
196- event .set ()
197- data = deepcopy (RAW_PASSPORT_DATA )
198- data ['credentials' ]['hash' ] = b'notcorrecthash'
199- return [Update (1 , passport_data = PassportData .de_json (data ,
200- bot = dp .bot ))]
201-
202- monkeypatch .setattr ('telegram.Bot.get_updates' , test )
203- monkeypatch .setattr ('telegram.Bot.set_webhook' , lambda * args , ** kwargs : True )
204- with pytest .warns (UserWarning , match = 'Telegram passport decryption error: '
205- 'Hashes are not equal!' ):
206- updater .start_polling (0.01 )
207- event2 .wait ()
214+ passport_data = PassportData .de_json (data , bot = bot )
215+ with pytest .raises (TelegramDecryptionError ):
216+ assert passport_data .decrypted_data
208217
209218 def test_wrong_key (self , bot ):
210219 short_key = b"-----BEGIN RSA PRIVATE KEY-----\r \n MIIBOQIBAAJBAKU+OZ2jJm7sCA/ec4gngNZhXYPu+DZ/TAwSMl0W7vAPXAsLplBk\r \n O8l6IBHx8N0ZC4Bc65mO3b2G8YAzqndyqH8CAwEAAQJAWOx3jQFzeVXDsOaBPdAk\r \n YTncXVeIc6tlfUl9mOLyinSbRNCy1XicOiOZFgH1rRKOGIC1235QmqxFvdecySoY\r \n wQIhAOFeGgeX9CrEPuSsd9+kqUcA2avCwqdQgSdy2qggRFyJAiEAu7QHT8JQSkHU\r \n DELfzrzc24AhjyG0z1DpGZArM8COascCIDK42SboXj3Z2UXiQ0CEcMzYNiVgOisq\r \n BUd5pBi+2mPxAiAM5Z7G/Sv1HjbKrOGh29o0/sXPhtpckEuj5QMC6E0gywIgFY6S\r \n NjwrAA+cMmsgY0O2fAzEKkDc5YiFsiXaGaSS4eA=\r \n -----END RSA PRIVATE KEY-----"
211220 b = Bot (bot .token , private_key = short_key )
212- data = deepcopy (RAW_PASSPORT_DATA )
213- with pytest .warns (UserWarning , match = 'Telegram passport decryption error: Ciphertext '
214- 'length must be equal to key size' ):
215- PassportData .de_json (data , bot = b )
221+ passport_data = PassportData .de_json (RAW_PASSPORT_DATA , bot = b )
222+ with pytest .raises (TelegramDecryptionError ):
223+ assert passport_data .decrypted_data
216224
217225 wrong_key = b"-----BEGIN RSA PRIVATE KEY-----\r \n MIIEogIBAAKCAQB4qCFltuvHakZze86TUweU7E/SB3VLGEHAe7GJlBmrou9SSWsL\r \n H7E++157X6UqWFl54LOE9MeHZnoW7rZ+DxLKhk6NwAHTxXPnvw4CZlvUPC3OFxg3\r \n hEmNen6ojSM4sl4kYUIa7F+Q5uMEYaboxoBen9mbj4zzMGsG4aY/xBOb2ewrXQyL\r \n Rh//tk1Px4ago+lUPisAvQVecz7/6KU4Xj4Lpv2z20f3cHlZX6bb7HlE1vixCMOf\r \n xvfC5SkWEGZMR/ZoWQUsoDkrDSITF/S3GtLfg083TgtCKaOF3mCT27sJ1og77npP\r \n 0cH/qdlbdoFtdrRj3PvBpaj/TtXRhmdGcJBxAgMBAAECggEAYSq1Sp6XHo8dkV8B\r \n K2/QSURNu8y5zvIH8aUrgqo8Shb7OH9bryekrB3vJtgNwR5JYHdu2wHttcL3S4SO\r \n ftJQxbyHgmxAjHUVNGqOM6yPA0o7cR70J7FnMoKVgdO3q68pVY7ll50IET9/T0X9\r \n DrTdKFb+/eILFsXFS1NpeSzExdsKq3zM0sP/vlJHHYVTmZDGaGEvny/eLAS+KAfG\r \n rKP96DeO4C/peXEJzALZ/mG1ReBB05Qp9Dx1xEC20yreRk5MnnBA5oiHVG5ZLOl9\r \n EEHINidqN+TMNSkxv67xMfQ6utNu5IpbklKv/4wqQOJOO50HZ+qBtSurTN573dky\r \n zslbCQKBgQDHDUBYyKN/v69VLmvNVcxTgrOcrdbqAfefJXb9C3dVXhS8/oRkCRU/\r \n dzxYWNT7hmQyWUKor/izh68rZ/M+bsTnlaa7IdAgyChzTfcZL/2pxG9pq05GF1Q4\r \n BSJ896ZEe3jEhbpJXRlWYvz7455svlxR0H8FooCTddTmkU3nsQSx0wKBgQCbLSa4\r \n yZs2QVstQQerNjxAtLi0IvV8cJkuvFoNC2Q21oqQc7BYU7NJL7uwriprZr5nwkCQ\r \n OFQXi4N3uqimNxuSng31ETfjFZPp+pjb8jf7Sce7cqU66xxR+anUzVZqBG1CJShx\r \n VxN7cWN33UZvIH34gA2Ax6AXNnJG42B5Gn1GKwKBgQCZ/oh/p4nGNXfiAK3qB6yy\r \n FvX6CwuvsqHt/8AUeKBz7PtCU+38roI/vXF0MBVmGky+HwxREQLpcdl1TVCERpIT\r \n UFXThI9OLUwOGI1IcTZf9tby+1LtKvM++8n4wGdjp9qAv6ylQV9u09pAzZItMwCd\r \n Ux5SL6wlaQ2y60tIKk0lfQKBgBJS+56YmA6JGzY11qz+I5FUhfcnpauDNGOTdGLT\r \n 9IqRPR2fu7RCdgpva4+KkZHLOTLReoRNUojRPb4WubGfEk93AJju5pWXR7c6k3Bt\r \n ovS2mrJk8GQLvXVksQxjDxBH44sLDkKMEM3j7uYJqDaZNKbyoCWT7TCwikAau5qx\r \n aRevAoGAAKZV705dvrpJuyoHFZ66luANlrAwG/vNf6Q4mBEXB7guqMkokCsSkjqR\r \n hsD79E6q06zA0QzkLCavbCn5kMmDS/AbA80+B7El92iIN6d3jRdiNZiewkhlWhEG\r \n m4N0gQRfIu+rUjsS/4xk8UuQUT/Ossjn/hExi7ejpKdCc7N++bc=\r \n -----END RSA PRIVATE KEY-----"
218226 b = Bot (bot .token , private_key = wrong_key )
219- data = deepcopy (RAW_PASSPORT_DATA )
220- with pytest .warns (UserWarning , match = 'Telegram passport decryption error: '
221- 'Decryption failed.' ):
222- PassportData .de_json (data , bot = b )
227+ passport_data = PassportData .de_json (RAW_PASSPORT_DATA , bot = b )
228+ with pytest .raises (TelegramDecryptionError ):
229+ assert passport_data .decrypted_data
223230
224231 def test_mocked_download_passport_file (self , passport_data , monkeypatch ):
225232 # The files are not coming from our test bot, therefore the file id is invalid/wrong
226233 # when coming from this bot, so we monkeypatch the call, to make sure that Bot.get_file
227234 # at least gets called
228235 # TODO: Actually download a passport file in a test
229- selfie = passport_data .data [1 ].selfie
236+ selfie = passport_data .decrypted_data [1 ].selfie
230237
231238 def get_file (* args , ** kwargs ):
232239 return File (args [1 ])
@@ -240,25 +247,34 @@ def get_file(*args, **kwargs):
240247 def test_mocked_set_passport_data_errors (self , monkeypatch , bot , chat_id , passport_data ):
241248 def test (_ , url , data , ** kwargs ):
242249 return (data ['user_id' ] == chat_id and
243- data ['errors' ][0 ]['file_hash' ] == (passport_data .credentials .data .secure_data
244- .driver_license .selfie .file_hash ) and
245- data ['errors' ][1 ]['data_hash' ] == (passport_data .credentials .data .secure_data
246- .driver_license .data .data_hash ))
250+ data ['errors' ][0 ]['file_hash' ] == (passport_data .decrypted_credentials
251+ .secure_data .driver_license
252+ .selfie .file_hash ) and
253+ data ['errors' ][1 ]['data_hash' ] == (passport_data .decrypted_credentials
254+ .secure_data .driver_license
255+ .data .data_hash ))
247256
248257 monkeypatch .setattr ('telegram.utils.request.Request.post' , test )
249258 message = bot .set_passport_data_errors (chat_id , [
250259 PassportElementErrorSelfie ('driver_license' ,
251- (passport_data .credentials . data
260+ (passport_data .decrypted_credentials
252261 .secure_data .driver_license .selfie .file_hash ),
253262 'You\' re not handsome enough to use this app!' ),
254263 PassportElementErrorDataField ('driver_license' ,
255264 'expiry_date' ,
256- (passport_data .credentials . data
265+ (passport_data .decrypted_credentials
257266 .secure_data .driver_license .data .data_hash ),
258267 'Your driver license is expired!' )
259268 ])
260269 assert message
261270
271+ def test_de_json_and_to_dict (self , bot ):
272+ passport_data = PassportData .de_json (RAW_PASSPORT_DATA , bot )
273+ assert passport_data .to_dict () == RAW_PASSPORT_DATA
274+
275+ assert passport_data .decrypted_data
276+ assert passport_data .to_dict () == RAW_PASSPORT_DATA
277+
262278 def test_equality (self , passport_data ):
263279 a = PassportData (passport_data .data , passport_data .credentials )
264280 b = PassportData (passport_data .data , passport_data .credentials )
0 commit comments