bankscrap-bbva 1.0.0 → 2.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +5 -0
- data/README.md +2 -2
- data/Rakefile +1 -2
- data/bankscrap-bbva.gemspec +9 -9
- data/lib/bankscrap-bbva.rb +1 -0
- data/lib/bankscrap/bbva/bank.rb +48 -37
- data/lib/bankscrap/bbva/version.rb +1 -1
- data/lib/monkey_patch/mechanize.rb +55 -0
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 34df67e80fb703b3062b1ddb00ec2be8ad25b285
|
4
|
+
data.tar.gz: bd806c0c5b61626262b542f0f2dd0e91f5c2562d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ccb5d6536cb19ca254d51708175c2a88f87dadcccb8a80f5dc156c309f48a3038b8d2812958f5b5d3e3f30a187bc015ce0863a37059fd864a1ddcf4496b40c00
|
7
|
+
data.tar.gz: 35c34f71df5a9cee1dfa2f261ba657e9b72c78de72a848b8a1972cb2c630a4a5274eeb1bc63c393337e115b3486e1b15742c53675d0348e58bf107818f2d4ed0
|
data/.rubocop.yml
ADDED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Bankscrap::BBVA
|
2
2
|
|
3
|
-
Bankscrap adapter for the API behind BBVA's [mobile app](https://play.google.com/store/apps/
|
3
|
+
Bankscrap adapter for the API behind BBVA's [mobile app](https://play.google.com/store/apps/details?id=com.bbva.bbvacontigo&hl=en).
|
4
4
|
This adapter is only valid for personal accounts (the ones that work with that mobile APP), not for company accounts.
|
5
5
|
|
6
6
|
## Installation
|
@@ -26,7 +26,7 @@ For usage instructions please read [Bankscrap readme](https://github.com/bankscr
|
|
26
26
|
|
27
27
|
## Contributing
|
28
28
|
|
29
|
-
1. Fork it ( https://github.com/
|
29
|
+
1. Fork it ( https://github.com/bankscrap/bankscrap-bbva/fork )
|
30
30
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
31
31
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
32
32
|
4. Push to the branch (`git push origin my-new-feature`)
|
data/Rakefile
CHANGED
@@ -1,2 +1 @@
|
|
1
|
-
require
|
2
|
-
|
1
|
+
require 'bundler/gem_tasks'
|
data/bankscrap-bbva.gemspec
CHANGED
@@ -4,20 +4,20 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'bankscrap/bbva/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
7
|
+
spec.name = 'bankscrap-bbva'
|
8
8
|
spec.version = Bankscrap::BBVA::VERSION
|
9
9
|
spec.authors = ['Javier Cuevas']
|
10
|
-
spec.email = [
|
11
|
-
spec.summary =
|
12
|
-
spec.homepage =
|
13
|
-
spec.license =
|
10
|
+
spec.email = ['javier@diacode.com']
|
11
|
+
spec.summary = 'BBVA adapter for Bankscrap'
|
12
|
+
spec.homepage = ''
|
13
|
+
spec.license = 'MIT'
|
14
14
|
|
15
15
|
spec.files = `git ls-files -z`.split("\x0")
|
16
16
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
-
spec.require_paths = [
|
18
|
+
spec.require_paths = ['lib']
|
19
19
|
|
20
|
-
spec.add_runtime_dependency
|
21
|
-
spec.add_development_dependency
|
22
|
-
spec.add_development_dependency
|
20
|
+
spec.add_runtime_dependency 'bankscrap', '~> 2.0.3'
|
21
|
+
spec.add_development_dependency 'bundler', '~> 1.7'
|
22
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
23
23
|
end
|
data/lib/bankscrap-bbva.rb
CHANGED
data/lib/bankscrap/bbva/bank.rb
CHANGED
@@ -3,35 +3,35 @@ require 'bankscrap'
|
|
3
3
|
module Bankscrap
|
4
4
|
module BBVA
|
5
5
|
class Bank < ::Bankscrap::Bank
|
6
|
-
BASE_ENDPOINT = 'https://servicios.bbva.es'
|
7
|
-
LOGIN_ENDPOINT = '/DFAUTH/slod/DFServletXML'
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
USER_AGENT = '12345;Android;LGE;Nexus 5;1080x1776;Android;5.1.1;BMES;4.4;xxhd'
|
12
|
-
|
13
|
-
def initialize(user, password, log: false, debug: false, extra_args: nil)
|
14
|
-
@user = format_user(user.dup)
|
15
|
-
@password = password
|
16
|
-
@log = log
|
17
|
-
@debug = debug
|
18
|
-
|
19
|
-
initialize_connection
|
20
|
-
|
21
|
-
add_headers(
|
22
|
-
'User-Agent' => USER_AGENT,
|
23
|
-
'BBVA-User-Agent' => USER_AGENT,
|
24
|
-
'Accept-Language' => 'spa',
|
25
|
-
'Content-Language' => 'spa',
|
26
|
-
'Accept' => 'application/json',
|
27
|
-
'Accept-Charset' => 'UTF-8',
|
28
|
-
'Connection' => 'Keep-Alive',
|
29
|
-
'Host' => 'bancamovil.grupobbva.com',
|
30
|
-
'Cookie2' => '$Version=1'
|
31
|
-
)
|
6
|
+
BASE_ENDPOINT = 'https://servicios.bbva.es'.freeze
|
7
|
+
LOGIN_ENDPOINT = '/DFAUTH/slod/DFServletXML'.freeze
|
8
|
+
SESSIONS_ENDPOINT = '/ENPP/enpp_mult_web_mobility_02/sessions/v1'.freeze
|
9
|
+
PRODUCTS_ENDPOINT = '/ENPP/enpp_mult_web_mobility_02/products/v2'.freeze
|
10
|
+
ACCOUNT_ENDPOINT = '/ENPP/enpp_mult_web_mobility_02/accounts/'.freeze
|
32
11
|
|
33
|
-
|
34
|
-
|
12
|
+
# BBVA expects an identifier before the actual User Agent, but 12345 works fine
|
13
|
+
USER_AGENT = SecureRandom.hex(64).upcase + ';iPhone;Apple;iPhone5,2;640x1136;iOS;9.3.2;WOODY;5.1.2;xhdpi'.freeze
|
14
|
+
REQUIRED_CREDENTIALS = [:user, :password].freeze
|
15
|
+
|
16
|
+
# This is probably some sort of identifier of Android vs iOS consumer app
|
17
|
+
CONSUMER_ID = '00000013'.freeze
|
18
|
+
|
19
|
+
def initialize(credentials = {})
|
20
|
+
super do
|
21
|
+
@user = format_user(@user.dup)
|
22
|
+
|
23
|
+
add_headers(
|
24
|
+
'User-Agent' => USER_AGENT,
|
25
|
+
'BBVA-User-Agent' => USER_AGENT,
|
26
|
+
'Accept-Language' => 'spa',
|
27
|
+
'Content-Language' => 'spa',
|
28
|
+
'Accept' => 'application/json',
|
29
|
+
'Accept-Charset' => 'UTF-8',
|
30
|
+
'Connection' => 'Keep-Alive',
|
31
|
+
'Host' => 'servicios.bbva.es',
|
32
|
+
'ConsumerID' => CONSUMER_ID
|
33
|
+
)
|
34
|
+
end
|
35
35
|
end
|
36
36
|
|
37
37
|
# Fetch all the accounts for the given user
|
@@ -65,11 +65,11 @@ module Bankscrap
|
|
65
65
|
'BBVA-Method' => 'GET'
|
66
66
|
}
|
67
67
|
|
68
|
-
#
|
68
|
+
# The API accepts a toDate param that we could pass the end_date argument,
|
69
69
|
# however when we pass the toDate param, the API stops returning the account balance.
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
70
|
+
# Therefore we need to take a workaround: only filter with fromDate and loop
|
71
|
+
# over all the available pages, filtering out the movements that doesn't match
|
72
|
+
# the end_date argument.
|
73
73
|
url = BASE_ENDPOINT +
|
74
74
|
ACCOUNT_ENDPOINT +
|
75
75
|
account.id +
|
@@ -113,7 +113,7 @@ module Bankscrap
|
|
113
113
|
def format_user(user)
|
114
114
|
user.upcase!
|
115
115
|
|
116
|
-
if user
|
116
|
+
if user =~ /^[0-9]{8}[A-Z]$/
|
117
117
|
# It's a DNI
|
118
118
|
"0019-0#{user}"
|
119
119
|
else
|
@@ -130,6 +130,19 @@ module Bankscrap
|
|
130
130
|
'eai_password' => @password
|
131
131
|
}
|
132
132
|
post(BASE_ENDPOINT + LOGIN_ENDPOINT, fields: params)
|
133
|
+
|
134
|
+
# We also need to initialize a session
|
135
|
+
with_headers('Content-Type' => 'application/json') do
|
136
|
+
post(SESSIONS_ENDPOINT, fields: {
|
137
|
+
consumerID: CONSUMER_ID
|
138
|
+
}.to_json)
|
139
|
+
end
|
140
|
+
|
141
|
+
# We need to extract the "tsec" header from the last response.
|
142
|
+
# As the Bankscrap core library doesn't expose the headers of each response
|
143
|
+
# we have to use Mechanize's HTTP client "current_page" method.
|
144
|
+
tsec = @http.current_page.response['tsec']
|
145
|
+
add_headers('tsec' => tsec)
|
133
146
|
end
|
134
147
|
|
135
148
|
# Build an Account object from API data
|
@@ -138,9 +151,8 @@ module Bankscrap
|
|
138
151
|
bank: self,
|
139
152
|
id: data['id'],
|
140
153
|
name: data['name'],
|
141
|
-
available_balance: data['availableBalance'],
|
142
|
-
balance: data['
|
143
|
-
currency: data['currency'],
|
154
|
+
available_balance: Money.new(data['availableBalance'].to_f * 100, data['currency']),
|
155
|
+
balance: Money.new(data['actualBalance'].to_f * 100, data['currency']),
|
144
156
|
iban: data['iban'],
|
145
157
|
description: "#{data['typeDescription']} #{data['familyCode']}"
|
146
158
|
)
|
@@ -154,7 +166,6 @@ module Bankscrap
|
|
154
166
|
amount: transaction_amount(data),
|
155
167
|
description: data['conceptDescription'] || data['description'],
|
156
168
|
effective_date: Date.strptime(data['operationDate'], '%Y-%m-%d'),
|
157
|
-
currency: data['currency'],
|
158
169
|
balance: transaction_balance(data)
|
159
170
|
)
|
160
171
|
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
# Extracted from http://scottwb.com/blog/2013/11/09/defeating-the-infamous-mechanize-too-many-connection-resets-bug/
|
2
|
+
|
3
|
+
class Mechanize::HTTP::Agent
|
4
|
+
MAX_RESET_RETRIES = 10
|
5
|
+
|
6
|
+
# We need to replace the core Mechanize HTTP method:
|
7
|
+
#
|
8
|
+
# Mechanize::HTTP::Agent#fetch
|
9
|
+
#
|
10
|
+
# with a wrapper that handles the infamous "too many connection resets"
|
11
|
+
# Mechanize bug that is described here:
|
12
|
+
#
|
13
|
+
# https://github.com/sparklemotion/mechanize/issues/123
|
14
|
+
#
|
15
|
+
# The wrapper shuts down the persistent HTTP connection when it fails with
|
16
|
+
# this error, and simply tries again. In practice, this only ever needs to
|
17
|
+
# be retried once, but I am going to let it retry a few times
|
18
|
+
# (MAX_RESET_RETRIES), just in case.
|
19
|
+
#
|
20
|
+
def fetch_with_retry(
|
21
|
+
uri,
|
22
|
+
method = :get,
|
23
|
+
headers = {},
|
24
|
+
params = [],
|
25
|
+
referer = current_page,
|
26
|
+
redirects = 0
|
27
|
+
)
|
28
|
+
action = "#{method.to_s.upcase} #{uri.to_s}"
|
29
|
+
retry_count = 0
|
30
|
+
|
31
|
+
begin
|
32
|
+
fetch_without_retry(uri, method, headers, params, referer, redirects)
|
33
|
+
rescue Net::HTTP::Persistent::Error => e
|
34
|
+
# Pass on any other type of error.
|
35
|
+
raise unless e.message =~ /too many connection resets/
|
36
|
+
|
37
|
+
# Pass on the error if we've tried too many times.
|
38
|
+
if retry_count >= MAX_RESET_RETRIES
|
39
|
+
puts "**** WARN: Mechanize retried connection reset #{MAX_RESET_RETRIES} times and never succeeded: #{action}" if Bankscrap.debug
|
40
|
+
raise
|
41
|
+
end
|
42
|
+
|
43
|
+
# Otherwise, shutdown the persistent HTTP connection and try again.
|
44
|
+
puts "**** WARN: Mechanize retrying connection reset error: #{action}" if Bankscrap.debug
|
45
|
+
retry_count += 1
|
46
|
+
self.http.shutdown
|
47
|
+
retry
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Alias so #fetch actually uses our new #fetch_with_retry to wrap the
|
52
|
+
# old one aliased as #fetch_without_retry.
|
53
|
+
alias_method :fetch_without_retry, :fetch
|
54
|
+
alias_method :fetch, :fetch_with_retry
|
55
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bankscrap-bbva
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Javier Cuevas
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-03-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bankscrap
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 2.0.3
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 2.0.3
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -60,6 +60,7 @@ extensions: []
|
|
60
60
|
extra_rdoc_files: []
|
61
61
|
files:
|
62
62
|
- ".gitignore"
|
63
|
+
- ".rubocop.yml"
|
63
64
|
- Gemfile
|
64
65
|
- LICENSE.txt
|
65
66
|
- README.md
|
@@ -68,6 +69,7 @@ files:
|
|
68
69
|
- lib/bankscrap-bbva.rb
|
69
70
|
- lib/bankscrap/bbva/bank.rb
|
70
71
|
- lib/bankscrap/bbva/version.rb
|
72
|
+
- lib/monkey_patch/mechanize.rb
|
71
73
|
homepage: ''
|
72
74
|
licenses:
|
73
75
|
- MIT
|
@@ -88,7 +90,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
88
90
|
version: '0'
|
89
91
|
requirements: []
|
90
92
|
rubyforge_project:
|
91
|
-
rubygems_version: 2.
|
93
|
+
rubygems_version: 2.4.8
|
92
94
|
signing_key:
|
93
95
|
specification_version: 4
|
94
96
|
summary: BBVA adapter for Bankscrap
|