nubank_sdk 0.2.0 → 0.4.0

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: 4f097d1d4da02660155bd767854ef6202e5622821e0eda6b9804b5d1cbf33d07
4
- data.tar.gz: 4b3844c8054f98f3cc10e6eb881021146ac0b59efd998bbd47282455f035cb62
3
+ metadata.gz: b37684fbfd690e5b972c3626514ef706766af1279c9c1f4049310f94f31e90b9
4
+ data.tar.gz: 6052b2f3a8cc2d879960414d415898b9c5bbc6eb66a7aafad7003788d38696f7
5
5
  SHA512:
6
- metadata.gz: 5baf7e493f3e48bff114f053c918309f86d57d5af72288322cc88a698f886e36151487c80ad986b3727acde28e0a9c66f8116bdeaed639f5f2ec16a6c2d6abbe
7
- data.tar.gz: 3f58b9e0caa25fa36e14687c0ef50a7dee002930d73f729a73efb2d85a2c839d8aea51ab525ca2ae2cbe6ac577685fd711cc5dbc05b3a39f261876e59014bcea
6
+ metadata.gz: e659147f1a8eb81e4442a4268c915e3391e337e44a81a59c7faecbcf4e9eaaf0de4e1abc2650de1e91aa5226d680b58b5b19b277e13b2bbc0fd3999076dcdaab
7
+ data.tar.gz: e362fd35b8ab55e31ec48740369570b964b56990bfe51940a61ea03d5f22518bd08b8cb7fa919b6265a1dbc184271a09557352f3844b44b719ee2f12501d4b31
data/.gitignore CHANGED
@@ -6,6 +6,7 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ /certificates/*.p12
9
10
 
10
11
  # rspec failure tracking
11
12
  .rspec_status
@@ -2,9 +2,14 @@
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",
10
+ "certificates",
11
+ "auth",
12
+ "client",
8
13
  "version"
9
14
  ]
10
15
  }
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- nubank_sdk (0.2.0)
4
+ nubank_sdk (0.4.0)
5
5
  faraday (~> 0.15.0)
6
6
  json (~> 2.1.0)
7
7
 
File without changes
@@ -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,135 @@
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 certificate
17
+ @certificate ||= NubankSdk::Certificate.new(@cpf, @key)
18
+ end
19
+
20
+ def authenticate_with_certificate(password)
21
+ token_url = @api_routes.entrypoint(path: :app, entrypoint: :token)
22
+ response = ssl_connection.post(token_url, token_payload(password))
23
+
24
+ response_hash = Client.get_body(response)
25
+
26
+ @refresh_token = response_hash[:refresh_token]
27
+ @refresh_before = response_hash[:refresh_before]
28
+ @access_token = response_hash[:access_token]
29
+
30
+ update_api_routes(response_hash[:_links])
31
+ end
32
+
33
+ def request_email_code(password)
34
+ response = default_connection.post(@gen_certificate_path, payload(password))
35
+
36
+ response_parsed = parse_authenticate_headers(response.headers['WWW-Authenticate'])
37
+ @encrypted_code = response_parsed[:device_authorization_encrypted_code]
38
+
39
+ response_parsed[:sent_to]
40
+ end
41
+
42
+ def exchange_certs(email_code, password)
43
+ response = default_connection.post(@gen_certificate_path, payload(password).merge({
44
+ code: email_code,
45
+ 'encrypted-code': @encrypted_code
46
+ })
47
+ )
48
+
49
+ response_data = Client.get_body(response)
50
+ certificate.process_decoded response_data[:certificate]
51
+ end
52
+
53
+ private
54
+
55
+ def parse_authenticate_headers(header_content)
56
+ chunks = header_content.split(',')
57
+ parsed = {}
58
+
59
+ chunks.each do |chunk|
60
+ key, value = chunk.split('=')
61
+ key = key.strip().gsub(' ', '_').gsub('-', '_').to_sym
62
+ value = value.gsub('"', '')
63
+ parsed[key] = value
64
+ end
65
+
66
+ parsed
67
+ end
68
+
69
+ def payload(password)
70
+ {
71
+ login: @cpf,
72
+ password: password,
73
+ public_key: @key.public_key.to_pem,
74
+ device_id: @device_id,
75
+ model: "NubankSdk Client (#@device_id)",
76
+ }
77
+ end
78
+
79
+ def token_payload(password)
80
+ {
81
+ 'grant_type': 'password',
82
+ 'client_id': 'legacy_client_id',
83
+ 'client_secret': 'legacy_client_secret',
84
+ 'login': @cpf,
85
+ 'password': password
86
+ }
87
+ end
88
+
89
+ def generate_key
90
+ OpenSSL::PKey::RSA.new 2048
91
+ end
92
+
93
+ def update_api_routes(links)
94
+ feed_url_keys = ['events', 'magnitude']
95
+ bills_url_keys = ['bills_summary']
96
+ customer_url_keys = ['customer']
97
+ account_url_keys = ['account']
98
+
99
+ @api_routes.add_entrypoint(:ssl, :revoke_token, links[:revoke_token][:href])
100
+ @api_routes.add_entrypoint(:ssl, :query, links[:ghostflame][:href])
101
+ @api_routes.add_entrypoint(:ssl, :feed, find_url(feed_url_keys, links))
102
+ @api_routes.add_entrypoint(:ssl, :bills, find_url(bills_url_keys, links))
103
+ @api_routes.add_entrypoint(:ssl, :customer, find_url(customer_url_keys, links))
104
+ @api_routes.add_entrypoint(:ssl, :account, find_url(account_url_keys, links))
105
+ @api_routes
106
+ end
107
+
108
+ def find_url(keys, list)
109
+ links_keys = list.keys
110
+
111
+ keys.each do |key|
112
+ return list[key]['href'] if links_keys.include?(key)
113
+ end
114
+ ''
115
+ end
116
+
117
+ def prepare_connections
118
+ uri, @gen_certificate_path = @api_routes.entrypoint(
119
+ path: :app,
120
+ entrypoint: :gen_certificate,
121
+ type: :splitted
122
+ )
123
+
124
+ Client::HTTP.new(uri, @adapter)
125
+ end
126
+
127
+ def default_connection
128
+ @default_connection ||= prepare_connections
129
+ end
130
+
131
+ def ssl_connection
132
+ @ssl_connection ||= Client::HTTPS.new(certificate.encoded, @adapter)
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'openssl'
4
+
5
+ module NubankSdk
6
+ class Certificate
7
+ FILES_PATH = './certificates/'
8
+
9
+ def initialize(cpf, key)
10
+ @cpf = cpf
11
+ @key = key
12
+ end
13
+
14
+ def process_decoded(certificate)
15
+ encoded = encode certificate
16
+
17
+ p12 = create_pkcs12_from encoded
18
+ save p12
19
+ end
20
+
21
+ def encoded
22
+ @encoded ||= OpenSSL::PKCS12.new(file.read, 'password')
23
+ end
24
+
25
+ private
26
+
27
+ def file
28
+ File.open("#{FILES_PATH}#{@cpf}.p12", 'rb')
29
+ end
30
+
31
+ def save(p12)
32
+ File.open("#{FILES_PATH}#{@cpf}.p12", 'wb') do |file|
33
+ file.write p12.to_der
34
+ end
35
+ end
36
+
37
+ def create_pkcs12_from(certificate)
38
+ OpenSSL::PKCS12.create("password", "key", @key, certificate)
39
+ end
40
+
41
+ def encode(certificate)
42
+ OpenSSL::X509::Certificate.new certificate
43
+ end
44
+ end
45
+ end
@@ -1,11 +1,51 @@
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)
44
+ @connection.post(url) do |req|
45
+ req.headers['Content-Type'] = 'application/json'
46
+ req.body = body.to_json
47
+ end
48
+ end
49
+ end
10
50
  end
11
51
  end
@@ -1,3 +1,3 @@
1
1
  module NubankSdk
2
- VERSION = "0.2.0"
2
+ VERSION = "0.4.0"
3
3
  end
data/lib/nubank_sdk.rb CHANGED
@@ -1,4 +1,7 @@
1
1
  require "nubank_sdk/api_routes"
2
+ require "nubank_sdk/auth"
3
+ require "nubank_sdk/certificate"
4
+ require "nubank_sdk/client"
2
5
  require "nubank_sdk/version"
3
6
 
4
7
  module NubankSdk
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.2.0
4
+ version: 0.4.0
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-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -98,8 +98,11 @@ files:
98
98
  - Rakefile
99
99
  - bin/console
100
100
  - bin/setup
101
+ - certificates/.gitkeep
101
102
  - lib/nubank_sdk.rb
102
103
  - lib/nubank_sdk/api_routes.rb
104
+ - lib/nubank_sdk/auth.rb
105
+ - lib/nubank_sdk/certificate.rb
103
106
  - lib/nubank_sdk/client.rb
104
107
  - lib/nubank_sdk/version.rb
105
108
  - nubank_sdk.gemspec