1
- import json
2
1
import os
3
2
import uuid
4
3
from typing import Tuple
5
4
6
- import requests
7
5
from qrcode import QRCode
8
- from requests import Response
6
+
7
+ from pynubank .utils .discovery import Discovery
8
+ from pynubank .utils .http import HttpClient
9
9
10
10
PAYMENT_EVENT_TYPES = (
11
11
'TransferOutEvent' ,
17
17
)
18
18
19
19
20
- class NuException (Exception ):
21
- def __init__ (self , status_code , response , url ):
22
- super ().__init__ (f'The request made failed with HTTP status code { status_code } ' )
23
- self .url = url
24
- self .status_code = status_code
25
- self .response = response
26
-
27
-
28
20
class Nubank :
29
- DISCOVERY_URL = 'https://prod-s0-webapp-proxy.nubank.com.br/api/discovery'
30
- DISCOVERY_APP_URL = 'https://prod-s0-webapp-proxy.nubank.com.br/api/app/discovery'
31
- auth_url = None
32
21
feed_url = None
33
- proxy_list_url = None
34
- proxy_list_app_url = None
35
22
query_url = None
36
23
bills_url = None
37
24
38
25
def __init__ (self ):
39
- self .headers = {
40
- 'Content-Type' : 'application/json' ,
41
- 'X-Correlation-Id' : 'WEB-APP.pewW9' ,
42
- 'User-Agent' : 'pynubank Client - https://github.com/andreroggeri/pynubank' ,
43
- }
44
- self ._update_proxy_urls ()
45
- self .auth_url = self .proxy_list_url ['login' ]
26
+ self .client = HttpClient ()
27
+ self .discovery = Discovery (self .client )
46
28
47
29
@staticmethod
48
30
def _get_query (query_name ):
@@ -52,19 +34,11 @@ def _get_query(query_name):
52
34
with open (path ) as gql :
53
35
return gql .read ()
54
36
55
- def _update_proxy_urls (self ):
56
- request = requests .get (self .DISCOVERY_URL , headers = self .headers )
57
- self .proxy_list_url = json .loads (request .content .decode ('utf-8' ))
58
- request = requests .get (self .DISCOVERY_APP_URL , headers = self .headers )
59
- self .proxy_list_app_url = json .loads (request .content .decode ('utf-8' ))
60
-
61
37
def _make_graphql_request (self , graphql_object ):
62
38
body = {
63
39
'query' : self ._get_query (graphql_object )
64
40
}
65
- response = requests .post (self .query_url , json = body , headers = self .headers )
66
-
67
- return self ._handle_response (response )
41
+ return self .client .post (self .query_url , json = body )
68
42
69
43
def _password_auth (self , cpf : str , password : str ):
70
44
payload = {
@@ -74,15 +48,13 @@ def _password_auth(self, cpf: str, password: str):
74
48
"client_id" : "other.conta" ,
75
49
"client_secret" : "yQPeLzoHuJzlMMSAjC-LgNUJdUecx8XO"
76
50
}
77
- response = requests .post (self .auth_url , json = payload , headers = self .headers )
78
- data = self ._handle_response (response )
79
- return data
80
-
81
- def _handle_response (self , response : Response ) -> dict :
82
- if response .status_code != 200 :
83
- raise NuException (response .status_code , response .json (), response .url )
51
+ return self .client .post (self .discovery .get_url ('login' ), json = payload )
84
52
85
- return response .json ()
53
+ def _save_auth_data (self , auth_data : dict ) -> None :
54
+ self .client .set_header ('Authorization' , f'Bearer { auth_data ["access_token" ]} ' )
55
+ self .feed_url = auth_data ['_links' ]['events' ]['href' ]
56
+ self .query_url = auth_data ['_links' ]['ghostflame' ]['href' ]
57
+ self .bills_url = auth_data ['_links' ]['bills_summary' ]['href' ]
86
58
87
59
def get_qr_code (self ) -> Tuple [str , QRCode ]:
88
60
content = str (uuid .uuid4 ())
@@ -92,36 +64,62 @@ def get_qr_code(self) -> Tuple[str, QRCode]:
92
64
93
65
def authenticate_with_qr_code (self , cpf : str , password , uuid : str ):
94
66
auth_data = self ._password_auth (cpf , password )
95
- self .headers [ 'Authorization' ] = f'Bearer { auth_data ["access_token" ]} '
67
+ self .client . set_header ( 'Authorization' , f'Bearer { auth_data ["access_token" ]} ' )
96
68
97
69
payload = {
98
70
'qr_code_id' : uuid ,
99
71
'type' : 'login-webapp'
100
72
}
101
73
102
- response = requests . post (self .proxy_list_app_url [ 'lift' ] , json = payload , headers = self . headers )
74
+ response = self . client . post (self .discovery . get_app_url ( 'lift' ) , json = payload )
103
75
104
- auth_data = self ._handle_response (response )
105
- self .headers ['Authorization' ] = f'Bearer { auth_data ["access_token" ]} '
106
- self .feed_url = auth_data ['_links' ]['events' ]['href' ]
107
- self .query_url = auth_data ['_links' ]['ghostflame' ]['href' ]
108
- self .bills_url = auth_data ['_links' ]['bills_summary' ]['href' ]
76
+ self ._save_auth_data (response )
77
+
78
+ def authenticate_with_cert (self , cpf : str , password : str , cert_path : str ):
79
+ self .client .set_cert (cert_path )
80
+ url = self .discovery .get_app_url ('token' )
81
+ payload = {
82
+ 'grant_type' : 'password' ,
83
+ 'client_id' : 'legacy_client_id' ,
84
+ 'client_secret' : 'legacy_client_secret' ,
85
+ 'login' : cpf ,
86
+ 'password' : password
87
+ }
88
+
89
+ response = self .client .post (url , json = payload )
90
+
91
+ self ._save_auth_data (response )
92
+
93
+ return response .get ('refresh_token' )
94
+
95
+ def authenticate_with_refresh_token (self , refresh_token : str , cert_path : str ):
96
+ self .client .set_cert (cert_path )
97
+
98
+ url = self .discovery .get_app_url ('token' )
99
+ payload = {
100
+ 'grant_type' : 'refresh_token' ,
101
+ 'client_id' : 'legacy_client_id' ,
102
+ 'client_secret' : 'legacy_client_secret' ,
103
+ 'refresh_token' : refresh_token ,
104
+ }
105
+
106
+ response = self .client .post (url , json = payload )
107
+
108
+ self ._save_auth_data (response )
109
109
110
110
def get_card_feed (self ):
111
- request = requests .get (self .feed_url , headers = self .headers )
112
- return json .loads (request .content .decode ('utf-8' ))
111
+ return self .client .get (self .feed_url )
113
112
114
113
def get_card_statements (self ):
115
114
feed = self .get_card_feed ()
116
115
return list (filter (lambda x : x ['category' ] == 'transaction' , feed ['events' ]))
117
116
118
117
def get_bills (self ):
119
- request = requests . get (self .bills_url , headers = self . headers )
120
- return json . loads ( request . content . decode ( 'utf-8' )) ['bills' ]
118
+ request = self . client . get (self .bills_url )
119
+ return request ['bills' ]
121
120
122
121
def get_bill_details (self , bill ):
123
- request = requests .get (bill ['_links' ]['self' ]['href' ], headers = self .headers )
124
- return json .loads (request .content .decode ('utf-8' ))
122
+ return self .client .get (bill ['_links' ]['self' ]['href' ])
125
123
126
124
def get_account_feed (self ):
127
125
data = self ._make_graphql_request ('account_feed' )
0 commit comments