nubank_sdk 0.3.0 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
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: {}