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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8e5b9021cf033b5ec98a45bdd97701e6acb0d4e7f7ea12d2fe8247e91fb24dd7
4
- data.tar.gz: 9faacb99367c3fd68c1d93dc343a2dac43efd90f2c27291d6ab67cdb478fcc8a
3
+ metadata.gz: ee3ffd6c280bb2b48dba0c1b46d4c3a560f985a55b22793aa251ece82f69da28
4
+ data.tar.gz: a4a69ad6502fd3852fb91b21fc37ee2fe872f9432a575d8d72367125201d8ecd
5
5
  SHA512:
6
- metadata.gz: 7afd83c07054626508d65dc3b028a09aaf07f0625f81cf7f4b2f53b121fc34d43a89f269a6cedc9a3e064af09f29e5e68b3a2f79a5ecacb845d34bf1576d23d7
7
- data.tar.gz: c99a7db8b4c2fcb29a7331009dcd2cd2bc3c9a4256153e5fc7c188dac3689179607c52fafe8d234d66295158dce2a2c2989e17388b7a2ca4f609c85dca513ac0
6
+ metadata.gz: 232922b481796a104a241ee8a9c890082c93c4e23eb3de6635f06633539c0d87770cb0e85b86e1a72d94548004080a5277010cb529ab623299ac40364fa07ac9
7
+ data.tar.gz: 1e82254c8026f4f5cb4e9bd3d80971d31979aced7145fe15e44e9e7a7a9a4c0f6303e232f3468860b07b5ab5cf358b624f1da4f0e03669765494a4f07fd21cd2
@@ -2,10 +2,15 @@
2
2
  "cSpell.words": [
3
3
  "faraday",
4
4
  "nubank",
5
- "Nubank"
5
+ "Nubank",
6
+ "pkcs"
6
7
  ],
7
8
  "conventionalCommits.scopes": [
9
+ "api routes",
8
10
  "certificates",
9
- "version"
11
+ "auth",
12
+ "client",
13
+ "version",
14
+ "account"
10
15
  ]
11
16
  }
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- nubank_sdk (0.3.0)
4
+ nubank_sdk (0.4.1)
5
5
  faraday (~> 0.15.0)
6
6
  json (~> 2.1.0)
7
7
 
@@ -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 ||= Faraday.new(url: DISCOVERY_URI) do |faraday|
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
@@ -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
- class Client
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
@@ -1,3 +1,3 @@
1
1
  module NubankSdk
2
- VERSION = "0.3.0"
2
+ VERSION = "0.4.1"
3
3
  end
data/lib/nubank_sdk.rb CHANGED
@@ -1,5 +1,8 @@
1
+ require "nubank_sdk/account"
1
2
  require "nubank_sdk/api_routes"
3
+ require "nubank_sdk/auth"
2
4
  require "nubank_sdk/certificate"
5
+ require "nubank_sdk/client"
3
6
  require "nubank_sdk/version"
4
7
 
5
8
  module NubankSdk
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.3.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-22 00:00:00.000000000 Z
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: {}