nubank_sdk 0.3.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.vscode/settings.json +7 -2
- data/Gemfile.lock +1 -1
- data/lib/nubank_sdk/account.rb +43 -0
- data/lib/nubank_sdk/api_routes.rb +1 -4
- data/lib/nubank_sdk/auth.rb +137 -0
- data/lib/nubank_sdk/client.rb +48 -1
- data/lib/nubank_sdk/version.rb +1 -1
- data/lib/nubank_sdk.rb +3 -0
- data/usage_example.rb +19 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ee3ffd6c280bb2b48dba0c1b46d4c3a560f985a55b22793aa251ece82f69da28
|
4
|
+
data.tar.gz: a4a69ad6502fd3852fb91b21fc37ee2fe872f9432a575d8d72367125201d8ecd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 232922b481796a104a241ee8a9c890082c93c4e23eb3de6635f06633539c0d87770cb0e85b86e1a72d94548004080a5277010cb529ab623299ac40364fa07ac9
|
7
|
+
data.tar.gz: 1e82254c8026f4f5cb4e9bd3d80971d31979aced7145fe15e44e9e7a7a9a4c0f6303e232f3468860b07b5ab5cf358b624f1da4f0e03669765494a4f07fd21cd2
|
data/.vscode/settings.json
CHANGED
data/Gemfile.lock
CHANGED
@@ -0,0 +1,43 @@
|
|
1
|
+
module NubankSdk
|
2
|
+
class Account
|
3
|
+
attr_reader :cpf, :device_id
|
4
|
+
|
5
|
+
def initialize(cpf:, key:, device_id: nil, adapter: nil)
|
6
|
+
@cpf = cpf
|
7
|
+
@device_id = device_id || generate_device_id
|
8
|
+
|
9
|
+
@api_routes = NubankSdk::ApiRoutes.new(connection_adapter: adapter)
|
10
|
+
@adapter = adapter
|
11
|
+
@key = key
|
12
|
+
end
|
13
|
+
|
14
|
+
def auth
|
15
|
+
@auth ||= NubankSdk::Auth.new(
|
16
|
+
cpf: @cpf,
|
17
|
+
key: @key,
|
18
|
+
device_id: @device_id,
|
19
|
+
api_routes: @api_routes,
|
20
|
+
adapter: @adapter
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
def account_balance
|
25
|
+
query_url = auth.api_routes.entrypoint(path: :ssl, entrypoint: :query)
|
26
|
+
connection = Client::HTTPS.new(auth.certificate.encoded, @adapter)
|
27
|
+
|
28
|
+
response = connection.post(query_url, {
|
29
|
+
'variables': {},
|
30
|
+
'query': '{viewer {savingsAccount {currentSavingsBalance {netAmount}}}}'
|
31
|
+
}, { Authorization: "Bearer #{auth.access_token}" })
|
32
|
+
|
33
|
+
data = JSON.parse(response.body, symbolize_names: true)
|
34
|
+
data[:data][:viewer][:savingsAccount][:currentSavingsBalance][:netAmount]
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def generate_device_id
|
40
|
+
SecureRandom.uuid.split('-').last
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -51,10 +51,7 @@ module NubankSdk
|
|
51
51
|
end
|
52
52
|
|
53
53
|
def connection
|
54
|
-
@connection ||=
|
55
|
-
faraday.adapter(*@connection_adapter) if @connection_adapter
|
56
|
-
faraday.adapter Faraday.default_adapter unless @connection_adapter
|
57
|
-
end
|
54
|
+
@connection ||= Client::HTTP.new(DISCOVERY_URI, @connection_adapter)
|
58
55
|
end
|
59
56
|
end
|
60
57
|
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module NubankSdk
|
4
|
+
class Auth
|
5
|
+
attr_reader :refresh_token, :refresh_before, :access_token
|
6
|
+
|
7
|
+
def initialize(cpf:, device_id:, key: nil, api_routes: nil, adapter: nil)
|
8
|
+
@cpf = cpf
|
9
|
+
@device_id = device_id
|
10
|
+
@key = key || generate_key
|
11
|
+
@api_routes = api_routes || NubankSdk::ApiRoutes.new
|
12
|
+
|
13
|
+
@adapter = adapter
|
14
|
+
end
|
15
|
+
|
16
|
+
def api_routes
|
17
|
+
@api_routes
|
18
|
+
end
|
19
|
+
|
20
|
+
def certificate
|
21
|
+
@certificate ||= NubankSdk::Certificate.new(@cpf, @key)
|
22
|
+
end
|
23
|
+
|
24
|
+
def authenticate_with_certificate(password)
|
25
|
+
token_url = @api_routes.entrypoint(path: :app, entrypoint: :token)
|
26
|
+
response = ssl_connection.post(token_url, token_payload(password))
|
27
|
+
|
28
|
+
response_hash = Client.get_body(response)
|
29
|
+
|
30
|
+
@refresh_token = response_hash[:refresh_token]
|
31
|
+
@refresh_before = response_hash[:refresh_before]
|
32
|
+
@access_token = response_hash[:access_token]
|
33
|
+
|
34
|
+
update_api_routes(response_hash[:_links])
|
35
|
+
end
|
36
|
+
|
37
|
+
def request_email_code(password)
|
38
|
+
response = default_connection.post(@gen_certificate_path, payload(password))
|
39
|
+
|
40
|
+
response_parsed = parse_authenticate_headers(response.headers['WWW-Authenticate'])
|
41
|
+
@encrypted_code = response_parsed[:device_authorization_encrypted_code]
|
42
|
+
|
43
|
+
response_parsed[:sent_to]
|
44
|
+
end
|
45
|
+
|
46
|
+
def exchange_certs(email_code, password)
|
47
|
+
response = default_connection.post(@gen_certificate_path, payload(password).merge({
|
48
|
+
code: email_code,
|
49
|
+
'encrypted-code': @encrypted_code
|
50
|
+
})
|
51
|
+
)
|
52
|
+
|
53
|
+
response_data = Client.get_body(response)
|
54
|
+
certificate.process_decoded response_data[:certificate]
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def parse_authenticate_headers(header_content)
|
60
|
+
chunks = header_content.split(',')
|
61
|
+
parsed = {}
|
62
|
+
|
63
|
+
chunks.each do |chunk|
|
64
|
+
key, value = chunk.split('=')
|
65
|
+
key = key.strip().gsub(' ', '_').gsub('-', '_').to_sym
|
66
|
+
value = value.gsub('"', '')
|
67
|
+
parsed[key] = value
|
68
|
+
end
|
69
|
+
|
70
|
+
parsed
|
71
|
+
end
|
72
|
+
|
73
|
+
def payload(password)
|
74
|
+
{
|
75
|
+
login: @cpf,
|
76
|
+
password: password,
|
77
|
+
public_key: @key.public_key.to_pem,
|
78
|
+
device_id: @device_id,
|
79
|
+
model: "NubankSdk Client (#@device_id)",
|
80
|
+
}
|
81
|
+
end
|
82
|
+
|
83
|
+
def token_payload(password)
|
84
|
+
{
|
85
|
+
'grant_type': 'password',
|
86
|
+
'client_id': 'legacy_client_id',
|
87
|
+
'client_secret': 'legacy_client_secret',
|
88
|
+
'login': @cpf,
|
89
|
+
'password': password
|
90
|
+
}
|
91
|
+
end
|
92
|
+
|
93
|
+
def generate_key
|
94
|
+
OpenSSL::PKey::RSA.new 2048
|
95
|
+
end
|
96
|
+
|
97
|
+
def update_api_routes(links)
|
98
|
+
feed_url_keys = ['events', 'magnitude']
|
99
|
+
bills_url_keys = ['bills_summary']
|
100
|
+
customer_url_keys = ['customer']
|
101
|
+
account_url_keys = ['account']
|
102
|
+
@api_routes.add_entrypoint(path: :ssl, entrypoint: :revoke_token, url: links[:revoke_token][:href])
|
103
|
+
@api_routes.add_entrypoint(path: :ssl, entrypoint: :query, url: links[:ghostflame][:href])
|
104
|
+
@api_routes.add_entrypoint(path: :ssl, entrypoint: :feed, url: find_url(feed_url_keys, links))
|
105
|
+
@api_routes.add_entrypoint(path: :ssl, entrypoint: :bills, url: find_url(bills_url_keys, links))
|
106
|
+
@api_routes.add_entrypoint(path: :ssl, entrypoint: :customer, url: find_url(customer_url_keys, links))
|
107
|
+
@api_routes.add_entrypoint(path: :ssl, entrypoint: :account, url: find_url(account_url_keys, links))
|
108
|
+
end
|
109
|
+
|
110
|
+
def find_url(keys, list)
|
111
|
+
links_keys = list.keys
|
112
|
+
|
113
|
+
keys.each do |key|
|
114
|
+
return list[key]['href'] if links_keys.include?(key)
|
115
|
+
end
|
116
|
+
''
|
117
|
+
end
|
118
|
+
|
119
|
+
def prepare_connections
|
120
|
+
uri, @gen_certificate_path = @api_routes.entrypoint(
|
121
|
+
path: :app,
|
122
|
+
entrypoint: :gen_certificate,
|
123
|
+
type: :splitted
|
124
|
+
)
|
125
|
+
|
126
|
+
Client::HTTP.new(uri, @adapter)
|
127
|
+
end
|
128
|
+
|
129
|
+
def default_connection
|
130
|
+
@default_connection ||= prepare_connections
|
131
|
+
end
|
132
|
+
|
133
|
+
def ssl_connection
|
134
|
+
@ssl_connection ||= Client::HTTPS.new(certificate.encoded, @adapter)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
data/lib/nubank_sdk/client.rb
CHANGED
@@ -1,11 +1,58 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'faraday'
|
3
4
|
require 'json'
|
4
5
|
|
5
6
|
module NubankSdk
|
6
|
-
|
7
|
+
module Client
|
7
8
|
def self.get_body(response)
|
8
9
|
JSON.parse(response.body, symbolize_names: true)
|
9
10
|
end
|
11
|
+
|
12
|
+
class HTTP
|
13
|
+
def initialize(base_url, adapter = nil)
|
14
|
+
@connection = Faraday.new(url: base_url) do |faraday|
|
15
|
+
faraday.adapter *adapter if adapter
|
16
|
+
faraday.adapter Faraday.default_adapter unless adapter
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def post(path, body)
|
21
|
+
@connection.post(path) do |req|
|
22
|
+
req.headers['Content-Type'] = 'application/json'
|
23
|
+
req.body = body.to_json
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def get(path)
|
28
|
+
@connection.get(path)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class HTTPS
|
33
|
+
def initialize(certificate, adapter = nil)
|
34
|
+
client_cert = OpenSSL::X509::Certificate.new(certificate.certificate)
|
35
|
+
client_key = OpenSSL::PKey::RSA.new(certificate.key)
|
36
|
+
|
37
|
+
@connection = Faraday.new(ssl: { client_cert: client_cert, client_key: client_key}) do |faraday|
|
38
|
+
faraday.adapter *adapter if adapter
|
39
|
+
faraday.adapter Faraday.default_adapter unless adapter
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def post(url, body, headers = {})
|
44
|
+
@connection.post(url) do |req|
|
45
|
+
req.headers['Content-Type'] = 'application/json'
|
46
|
+
req.headers['X-Correlation-Id'] = '772428d8-f0ee-43d6-8093-a13de3c9ce96'
|
47
|
+
req.headers['User-Agent'] = "NubankSdk Client (#{NubankSdk::VERSION})"
|
48
|
+
|
49
|
+
headers.each do |key, value|
|
50
|
+
req.headers[key] = value
|
51
|
+
end
|
52
|
+
|
53
|
+
req.body = body.to_json
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
10
57
|
end
|
11
58
|
end
|
data/lib/nubank_sdk/version.rb
CHANGED
data/lib/nubank_sdk.rb
CHANGED
data/usage_example.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'nubank_sdk'
|
2
|
+
|
3
|
+
# instance a nubank account object
|
4
|
+
account = NubankSdk::Account.new(cpf: '12345678909')
|
5
|
+
password = 'dracarys'
|
6
|
+
# authenticate the account
|
7
|
+
|
8
|
+
# request an email code
|
9
|
+
account_email = account.auth.request_email_code(password)
|
10
|
+
|
11
|
+
# get the email code from the user
|
12
|
+
puts "Enter the code sent to #{account_email}: "
|
13
|
+
email_code = gets.chomp
|
14
|
+
account.auth.exchange_certs(email_code, password)
|
15
|
+
|
16
|
+
account.auth.authenticate_with_certificate(password)
|
17
|
+
|
18
|
+
# get the account balance
|
19
|
+
account.account_balance
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nubank_sdk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Viserion77
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-10-
|
11
|
+
date: 2022-10-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -100,11 +100,14 @@ files:
|
|
100
100
|
- bin/setup
|
101
101
|
- certificates/.gitkeep
|
102
102
|
- lib/nubank_sdk.rb
|
103
|
+
- lib/nubank_sdk/account.rb
|
103
104
|
- lib/nubank_sdk/api_routes.rb
|
105
|
+
- lib/nubank_sdk/auth.rb
|
104
106
|
- lib/nubank_sdk/certificate.rb
|
105
107
|
- lib/nubank_sdk/client.rb
|
106
108
|
- lib/nubank_sdk/version.rb
|
107
109
|
- nubank_sdk.gemspec
|
110
|
+
- usage_example.rb
|
108
111
|
homepage: https://github.com/Viserion77/nubank_sdk
|
109
112
|
licenses: []
|
110
113
|
metadata: {}
|