@@ -43,7 +43,7 @@ class Session:
43
43
>>> import proton
44
44
>>> s = proton.Session("https://url-to-api.ch")
45
45
>>> s.enable_alternative_routing = True
46
- >>> s.api_request(' /api/endpoint' )
46
+ >>> s.api_request(" /api/endpoint" )
47
47
<Response [200]>
48
48
"""
49
49
_base_headers = {
@@ -73,10 +73,10 @@ def load(
73
73
Returns:
74
74
proton.Session
75
75
"""
76
- api_url = dump [' api_url' ]
77
- appversion = dump [' appversion' ]
78
- user_agent = dump [' User-Agent' ]
79
- cookies = dump .get (' cookies' , {})
76
+ api_url = dump [" api_url" ]
77
+ appversion = dump [" appversion" ]
78
+ user_agent = dump [" User-Agent" ]
79
+ cookies = dump .get (" cookies" , {})
80
80
s = Session (
81
81
api_url = api_url ,
82
82
log_dir_path = log_dir_path ,
@@ -88,10 +88,10 @@ def load(
88
88
proxies = proxies
89
89
)
90
90
requests .utils .add_dict_to_cookiejar (s .s .cookies , cookies )
91
- s ._session_data = dump [' session_data' ]
91
+ s ._session_data = dump [" session_data" ]
92
92
if s .UID is not None :
93
- s .s .headers [' x-pm-uid' ] = s .UID
94
- s .s .headers [' Authorization' ] = ' Bearer ' + s .AccessToken
93
+ s .s .headers [" x-pm-uid" ] = s .UID
94
+ s .s .headers [" Authorization" ] = " Bearer " + s .AccessToken
95
95
return s
96
96
97
97
def dump (self ):
@@ -104,11 +104,11 @@ def dump(self):
104
104
dict
105
105
"""
106
106
return {
107
- ' api_url' : self .__api_url ,
108
- ' appversion' : self .__appversion ,
109
- ' User-Agent' : self .__user_agent ,
110
- ' cookies' : self .s .cookies .get_dict (),
111
- ' session_data' : self ._session_data
107
+ " api_url" : self .__api_url ,
108
+ " appversion" : self .__appversion ,
109
+ " User-Agent" : self .__user_agent ,
110
+ " cookies" : self .s .cookies .get_dict (),
111
+ " session_data" : self ._session_data
112
112
}
113
113
114
114
def __init__ (
@@ -165,8 +165,8 @@ def __init__(
165
165
if self .__tls_pinning_enabled :
166
166
self .s .mount (self .__api_url , TLSPinningAdapter ())
167
167
168
- self .s .headers [' x-pm-appversion' ] = appversion
169
- self .s .headers [' User-Agent' ] = user_agent
168
+ self .s .headers [" x-pm-appversion" ] = appversion
169
+ self .s .headers [" User-Agent" ] = user_agent
170
170
171
171
def api_request (
172
172
self , endpoint ,
@@ -205,11 +205,11 @@ def api_request(
205
205
fct = self .s .post
206
206
else :
207
207
fct = {
208
- ' get' : self .s .get ,
209
- ' post' : self .s .post ,
210
- ' put' : self .s .put ,
211
- ' delete' : self .s .delete ,
212
- ' patch' : self .s .patch
208
+ " get" : self .s .get ,
209
+ " post" : self .s .post ,
210
+ " put" : self .s .put ,
211
+ " delete" : self .s .delete ,
212
+ " patch" : self .s .patch
213
213
}.get (method .lower ())
214
214
215
215
if fct is None :
@@ -273,8 +273,8 @@ def api_request(
273
273
}
274
274
)
275
275
276
- if response [' Code' ] not in [1000 , 1001 ]:
277
- if response [' Code' ] == 9001 :
276
+ if response [" Code" ] not in [1000 , 1001 ]:
277
+ if response [" Code" ] == 9001 :
278
278
self .__captcha_token = response ["Details" ]["HumanVerificationToken" ]
279
279
280
280
raise ProtonAPIError (response )
@@ -344,7 +344,7 @@ def verify_modulus(self, armored_modulus):
344
344
verified = self .__gnupg .decrypt (armored_modulus )
345
345
346
346
if not (verified .valid and verified .fingerprint .lower () == SRP_MODULUS_KEY_FINGERPRINT ):
347
- raise ValueError (' Invalid modulus' )
347
+ raise ValueError (" Invalid modulus" )
348
348
349
349
return base64 .b64decode (verified .data .strip ())
350
350
@@ -365,7 +365,7 @@ def authenticate(self, username, password, human_verification=None):
365
365
366
366
payload = {"Username" : username }
367
367
if self .__clientsecret :
368
- payload [' ClientSecret' ] = self .__clientsecret
368
+ payload [" ClientSecret" ] = self .__clientsecret
369
369
370
370
additional_headers = {}
371
371
@@ -381,7 +381,7 @@ def authenticate(self, username, password, human_verification=None):
381
381
additional_headers = additional_headers
382
382
)
383
383
384
- modulus = self .verify_modulus (info_response [' Modulus' ])
384
+ modulus = self .verify_modulus (info_response [" Modulus" ])
385
385
server_challenge = base64 .b64decode (info_response ["ServerEphemeral" ])
386
386
salt = base64 .b64decode (info_response ["Salt" ])
387
387
version = info_response ["Version" ]
@@ -391,38 +391,39 @@ def authenticate(self, username, password, human_verification=None):
391
391
client_proof = usr .process_challenge (salt , server_challenge , version )
392
392
393
393
if client_proof is None :
394
- raise ValueError (' Invalid challenge' )
394
+ raise ValueError (" Invalid challenge" )
395
395
396
396
# Send response
397
397
payload = {
398
398
"Username" : username ,
399
399
"ClientEphemeral" : base64 .b64encode (client_challenge ).decode (
400
- ' utf8'
400
+ " utf8"
401
401
),
402
- "ClientProof" : base64 .b64encode (client_proof ).decode (' utf8' ),
402
+ "ClientProof" : base64 .b64encode (client_proof ).decode (" utf8" ),
403
403
"SRPSession" : info_response ["SRPSession" ],
404
404
}
405
405
if self .__clientsecret :
406
- payload [' ClientSecret' ] = self .__clientsecret
406
+ payload [" ClientSecret" ] = self .__clientsecret
407
407
auth_response = self .api_request ("/auth" , payload )
408
408
409
409
if "ServerProof" not in auth_response :
410
410
raise ValueError ("Invalid password" )
411
411
412
412
usr .verify_session (base64 .b64decode (auth_response ["ServerProof" ]))
413
413
if not usr .authenticated ():
414
- raise ValueError (' Invalid server proof' )
414
+ raise ValueError (" Invalid server proof" )
415
415
416
416
self ._session_data = {
417
- 'UID' : auth_response ["UID" ],
418
- 'AccessToken' : auth_response ["AccessToken" ],
419
- 'RefreshToken' : auth_response ["RefreshToken" ],
420
- 'Scope' : auth_response ["Scope" ].split (),
417
+ "UID" : auth_response ["UID" ],
418
+ "AccessToken" : auth_response ["AccessToken" ],
419
+ "RefreshToken" : auth_response ["RefreshToken" ],
420
+ "PasswordMode" : auth_response ["PasswordMode" ],
421
+ "Scope" : auth_response ["Scope" ].split (),
421
422
}
422
423
423
424
if self .UID is not None :
424
- self .s .headers [' x-pm-uid' ] = self .UID
425
- self .s .headers [' Authorization' ] = ' Bearer ' + self .AccessToken
425
+ self .s .headers [" x-pm-uid" ] = self .UID
426
+ self .s .headers [" Authorization" ] = " Bearer " + self .AccessToken
426
427
427
428
return self .Scope
428
429
@@ -438,17 +439,17 @@ def provide_2fa(self, code):
438
439
The returning dict contains the Scope of the account. This allows
439
440
to identify if the account is locked, has unpaid invoices, etc.
440
441
"""
441
- ret = self .api_request (' /auth/2fa' , {"TwoFactorCode" : code })
442
- self ._session_data [' Scope' ] = ret [' Scope' ]
442
+ ret = self .api_request (" /auth/2fa" , {"TwoFactorCode" : code })
443
+ self ._session_data [" Scope" ] = ret [" Scope" ]
443
444
444
445
return self .Scope
445
446
446
447
def logout (self ):
447
448
"""Logout from API."""
448
449
if self ._session_data :
449
- self .api_request (' /auth' , method = ' DELETE' )
450
- del self .s .headers [' Authorization' ]
451
- del self .s .headers [' x-pm-uid' ]
450
+ self .api_request (" /auth" , method = " DELETE" )
451
+ del self .s .headers [" Authorization" ]
452
+ del self .s .headers [" x-pm-uid" ]
452
453
self ._session_data = {}
453
454
454
455
def refresh (self ):
@@ -459,17 +460,17 @@ def refresh(self):
459
460
re-authenticate.
460
461
"""
461
462
refresh_response = self .api_request (
462
- ' /auth/refresh' ,
463
+ " /auth/refresh" ,
463
464
{
464
465
"ResponseType" : "token" ,
465
466
"GrantType" : "refresh_token" ,
466
467
"RefreshToken" : self .RefreshToken ,
467
468
"RedirectURI" : "http://protonmail.ch"
468
469
}
469
470
)
470
- self ._session_data [' AccessToken' ] = refresh_response ["AccessToken" ]
471
- self ._session_data [' RefreshToken' ] = refresh_response ["RefreshToken" ]
472
- self .s .headers [' Authorization' ] = ' Bearer ' + self .AccessToken
471
+ self ._session_data [" AccessToken" ] = refresh_response ["AccessToken" ]
472
+ self ._session_data [" RefreshToken" ] = refresh_response ["RefreshToken" ]
473
+ self .s .headers [" Authorization" ] = " Bearer " + self .AccessToken
473
474
474
475
def get_alternative_routes_from_dns (self , callback = None ):
475
476
"""Get alternative routes to circumvent firewalls and API restrictions.
@@ -642,16 +643,20 @@ def force_skip_alternative_routing(self, newvalue):
642
643
643
644
@property
644
645
def UID (self ):
645
- return self ._session_data .get (' UID' , None )
646
+ return self ._session_data .get (" UID" , None )
646
647
647
648
@property
648
649
def AccessToken (self ):
649
- return self ._session_data .get (' AccessToken' , None )
650
+ return self ._session_data .get (" AccessToken" , None )
650
651
651
652
@property
652
653
def RefreshToken (self ):
653
- return self ._session_data .get ('RefreshToken' , None )
654
+ return self ._session_data .get ("RefreshToken" , None )
655
+
656
+ @property
657
+ def PasswordMode (self ):
658
+ return self ._session_data .get ("PasswordMode" , None )
654
659
655
660
@property
656
661
def Scope (self ):
657
- return self ._session_data .get (' Scope' , [])
662
+ return self ._session_data .get (" Scope" , [])
0 commit comments