@@ -288,6 +288,8 @@ def api_request(
288
288
if response ["Code" ] not in [1000 , 1001 ]:
289
289
if response ["Code" ] == 9001 :
290
290
self .__captcha_token = response ["Details" ]["HumanVerificationToken" ]
291
+ elif response ["Code" ] == 12087 :
292
+ del self .human_verification_token
291
293
292
294
raise ProtonAPIError (response )
293
295
except TypeError as e :
@@ -363,7 +365,7 @@ def verify_modulus(self, armored_modulus):
363
365
364
366
return base64 .b64decode (verified .data .strip ())
365
367
366
- def authenticate (self , username , password , human_verification = None ):
368
+ def authenticate (self , username , password ):
367
369
"""Authenticate user against API.
368
370
369
371
Args:
@@ -382,19 +384,7 @@ def authenticate(self, username, password, human_verification=None):
382
384
if self .__clientsecret :
383
385
payload ["ClientSecret" ] = self .__clientsecret
384
386
385
- additional_headers = {}
386
-
387
- if human_verification :
388
- human_verification_header = {
389
- "X-PM-Human-Verification-Token-Type" : human_verification [0 ],
390
- "X-PM-Human-Verification-Token" : human_verification [1 ]
391
- }
392
- additional_headers .update (human_verification_header )
393
-
394
- info_response = self .api_request (
395
- "/auth/info" , payload ,
396
- additional_headers = additional_headers
397
- )
387
+ info_response = self .api_request ("/auth/info" , payload )
398
388
399
389
modulus = self .verify_modulus (info_response ["Modulus" ])
400
390
server_challenge = base64 .b64decode (info_response ["ServerEphemeral" ])
@@ -419,6 +409,7 @@ def authenticate(self, username, password, human_verification=None):
419
409
}
420
410
if self .__clientsecret :
421
411
payload ["ClientSecret" ] = self .__clientsecret
412
+
422
413
auth_response = self .api_request ("/auth" , payload )
423
414
424
415
if "ServerProof" not in auth_response :
@@ -663,6 +654,39 @@ def force_skip_alternative_routing(self, newvalue):
663
654
"""
664
655
self .__force_skip_alternative_routing = bool (newvalue )
665
656
657
+ @property
658
+ def human_verification_token (self ):
659
+ return (
660
+ self .s .headers .get ("X-PM-Human-Verification-Token-Type" , None ),
661
+ self .s .headers .get ("X-PM-Human-Verification-Token" , None )
662
+ )
663
+
664
+ @human_verification_token .setter
665
+ def human_verification_token (self , newtuplevalue ):
666
+ """Set human verification token:
667
+
668
+ Args:
669
+ newtuplevalue (tuple): (token_type, token_value)
670
+ """
671
+ self .s .headers ["X-PM-Human-Verification-Token-Type" ] = newtuplevalue [0 ]
672
+ self .s .headers ["X-PM-Human-Verification-Token" ] = newtuplevalue [1 ]
673
+
674
+ @human_verification_token .deleter
675
+ def human_verification_token (self ):
676
+ # Safest to use .pop() as it will onyl attempt to remove the key by name
677
+ # while del can also remove the whole dict (in case of code/programming error)
678
+ # Thus to prevent this, pop() is used.
679
+
680
+ try :
681
+ self .s .headers .pop ("X-PM-Human-Verification-Token-Type" )
682
+ except (KeyError , IndexError ):
683
+ pass
684
+
685
+ try :
686
+ self .s .headers .pop ("X-PM-Human-Verification-Token" )
687
+ except (KeyError , IndexError ):
688
+ pass
689
+
666
690
@property
667
691
def UID (self ):
668
692
return self ._session_data .get ("UID" , None )
0 commit comments