bank_scrap 0.0.6 → 0.0.7

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
  SHA1:
3
- metadata.gz: 8aa6ea0f009804787942dd42adff98aef36dd601
4
- data.tar.gz: a137f771dfd1eee094edbd9f71d74cbc02cce20f
3
+ metadata.gz: 4680376ad7f26ae34f9cf4262fa04b98b5b466ea
4
+ data.tar.gz: 4be7fda00b5c1a410ffb602979d20894d3511f6b
5
5
  SHA512:
6
- metadata.gz: e0b08d23ebcd36680a143636d1f7eb5452b28049bee9f17b2e5b42548fa016f1627f3358216f5dcfe51c1ea7afdfa0b53129c83e76d5be4a035f8c0c0604819a
7
- data.tar.gz: 558ce9735baad049a50360b48b66b13755a28365347cde5577c0625492f283522b59193a45d390af25cb6b4bd55c90f7d80b3c673ae9293a7dbaebfc52284627
6
+ metadata.gz: 9debe3eadab0fa8a98e3d52640cf2d2a49348f92f6a5b0d2bb5b2a9555ca19d4e61559ea3b990f28bbdcef9ceda1bf36e259d540ffe4c1e23ef25ec7ce53c250
7
+ data.tar.gz: d314b783e5a962669d2717f1fa2d15568284e7c4e03195e8d32073296138f7325758d2d218aa492cbfff6fe1b0b47105b951a94d05f995ba2f7fc34bcb128e70
data/.gitignore CHANGED
@@ -13,5 +13,7 @@
13
13
  *.a
14
14
  mkmf.log
15
15
 
16
+ *.gem
17
+
16
18
  # MAC OS X files
17
19
  .DS_Store
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Bankscrap
1
+ # BankScrap
2
2
 
3
3
  Ruby gem to extract balance and transactions from banks. You can use it either as command line tool or as a library.
4
4
 
@@ -23,7 +23,7 @@ There are two approaches to solve this problem:
23
23
  - Web scraping on the bank's site.
24
24
  - Reverse engineering the bank's mobile app to use the same API the app uses.
25
25
 
26
- Bankscrap uses both methods depending on the bank.
26
+ BankScrap uses both methods depending on the bank.
27
27
 
28
28
  ## Requirements
29
29
 
@@ -52,10 +52,22 @@ Or, if you're using Bundler, just add the following to your Gemfile:
52
52
  ### From terminal
53
53
  Retrieve balance account
54
54
 
55
- $ bank_scrap balance BANK_NAME --user YOUR_BANK_USER --password YOUR_BANK_PASSWORD
55
+ ##### Bankinter
56
56
 
57
- BANK_NAME should be in underscore case (`bankinter`, `bbva`).
57
+ $ bank_scrap balance bankinter --user YOUR_BANKINTER_USER --password YOUR_BANKINTER_PASSWORD
58
58
 
59
+ ##### BBVA
60
+
61
+ $ bank_scrap balance bbva --user YOUR_BBVA_USER --password YOUR_BBVA_PASSWORD
62
+
63
+ ##### ING Direct
64
+ ING needs one more argument: your bithday.
65
+
66
+ $ bank_scrap balance ing --user YOUR_DNI --password YOUR_PASSWORD --extra=birthday:01/01/1980
67
+
68
+ Replace 01/01/1980 with your actual birthday.
69
+
70
+ ---
59
71
  If you don't want to pass your user and password everytime you can define them in your .bash_profile by adding:
60
72
 
61
73
  export BANK_SCRAP_USER=YOUR_BANK_USER
@@ -63,7 +75,7 @@ If you don't want to pass your user and password everytime you can define them i
63
75
 
64
76
  ### From Ruby code
65
77
 
66
- You can also use this gem from your own app as library. To do so first you must initialize a Bankscrapper::Bank object
78
+ You can also use this gem from your own app as library. To do so first you must initialize a BankScrap::Bank object
67
79
 
68
80
  ```ruby
69
81
  require 'bank_scrap'
data/bank_scrap.gemspec CHANGED
@@ -22,12 +22,12 @@ Gem::Specification.new do |spec|
22
22
 
23
23
  spec.add_development_dependency 'bundler', '~> 1.7'
24
24
  spec.add_development_dependency 'rake', '~> 10.0'
25
- spec.add_development_dependency 'byebug', '~> 3.5.1'
25
+ spec.add_development_dependency 'byebug', '~> 3.5', '>= 3.5.1'
26
26
 
27
27
  spec.add_dependency 'thor', "~> 0.19"
28
28
  spec.add_dependency 'nokogiri', "~> 1.6"
29
29
  spec.add_dependency 'execjs', "~> 2.2"
30
- spec.add_dependency 'curb', "~> 0.8"
30
+ spec.add_dependency 'mechanize', "~> 2.7.3"
31
31
  spec.add_dependency 'activesupport', "~> 4.1"
32
- spec.add_dependency 'rmagick', "~> 2.2.2"
32
+ spec.add_dependency 'rmagick', '~> 2.2', '>= 2.2.2'
33
33
  end
@@ -1,66 +1,58 @@
1
- require 'curb'
1
+ require 'mechanize'
2
+ require 'logger'
2
3
 
3
4
  module BankScrap
4
5
  class Bank
5
6
 
6
7
  WEB_USER_AGENT = 'Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 4 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19'
8
+ attr_accessor :headers
7
9
 
8
10
  private
9
11
 
10
12
  def get(url)
11
- @curl.url = url
12
- @curl.get
13
-
14
- @curl.body_str
13
+ @http.get(url).body
15
14
  end
16
15
 
17
16
  def post(url, fields)
18
- @curl.url = url
19
-
20
- # If hash, transform to Curl::PostField objects
21
- if fields.is_a? Hash
22
- fields = fields.collect {|key, value| Curl::PostField.content(key, value)}
23
- end
24
-
25
- @curl.post(fields)
26
- @curl.body_str
17
+ @http.post(url, fields, @headers).body
27
18
  end
28
19
 
29
20
  def put(url, fields)
30
- @curl.url = url
31
-
32
- @curl.put(fields)
33
- @curl.body_str
21
+ @http.put(url, fields, @headers).body
34
22
  end
35
23
 
36
- def set_header(name, value)
37
- @curl.headers[name] = value
24
+ # Sets temporary HTTP headers, execute a code block
25
+ # and resets the headers
26
+ def with_headers(tmp_headers)
27
+ current_headers = @headers
28
+ set_headers(tmp_headers)
29
+ yield
30
+ ensure
31
+ set_headers(current_headers)
38
32
  end
39
33
 
34
+
40
35
  def set_headers(headers)
41
- headers.each { |key, value| set_header(key, value) }
36
+ @headers.merge! headers
37
+ @http.request_headers = @headers
42
38
  end
43
39
 
44
- def get_headers
45
- @curl.header_str
46
- end
47
40
 
48
41
  def initialize_cookie(url)
49
42
  log 'Initialize cookie'
50
43
 
51
- @curl.url = url
52
- @curl.get
53
-
54
- @curl.body_str
44
+ @http.url = url
45
+ @http.get(url).body
55
46
  end
56
47
 
57
48
  def initialize_connection
58
- @curl = Curl::Easy.new
59
- @curl.follow_location = true
60
- @curl.ssl_verify_peer = false
61
- @curl.verbose = true if @debug
62
- @curl.enable_cookies = true
63
- @curl.headers["User-Agent"] = WEB_USER_AGENT
49
+ @http = Mechanize.new do |mechanize|
50
+ mechanize.user_agent = WEB_USER_AGENT
51
+ mechanize.agent.http.verify_mode = OpenSSL::SSL::VERIFY_NONE
52
+ mechanize.log = Logger.new(STDOUT) if @debug
53
+ end
54
+
55
+ @headers = {}
64
56
  end
65
57
 
66
58
  def log(msg)
@@ -5,7 +5,8 @@ module BankScrap
5
5
  BASE_ENDPOINT = 'https://bancamovil.grupobbva.com'
6
6
  LOGIN_ENDPOINT = '/DFAUTH/slod/DFServletXML'
7
7
  BALANCE_ENDPOINT = '/ENPP/enpp_mult_web_mobility_02/products/v1'
8
- USER_AGENT = 'Android;LGE;Nexus 5;1080x1776;Android;4.4.4;BMES;4.0.4'
8
+ # BBVA expects an identifier before the actual User Agent, but 12345 works fine
9
+ USER_AGENT = '12345;Android;LGE;Nexus 5;1080x1776;Android;4.4.4;BMES;4.0.4'
9
10
 
10
11
  def initialize(user, password, log: false, debug: false, extra_args: nil)
11
12
  @user = format_user(user.dup)
@@ -24,6 +25,7 @@ module BankScrap
24
25
  'Accept-Charset' => 'UTF-8',
25
26
  'Connection' => 'Keep-Alive',
26
27
  'Host' => 'bancamovil.grupobbva.com',
28
+ 'Cookie2' => '$Version=1'
27
29
  })
28
30
 
29
31
  login
@@ -31,7 +33,13 @@ module BankScrap
31
33
 
32
34
  def get_balance
33
35
  log 'get_balance'
34
- response = post(BASE_ENDPOINT + BALANCE_ENDPOINT, nil)
36
+
37
+ # Even if the required method is an HTTP POST
38
+ # the API requires a funny header that says is a GET
39
+ # otherwise the request doesn't work.
40
+ response = with_headers({'BBVA-Method' => 'GET'}) do
41
+ post(BASE_ENDPOINT + BALANCE_ENDPOINT, {})
42
+ end
35
43
 
36
44
  json = JSON.parse(response)
37
45
  json["balances"]["personalAccounts"]
@@ -37,6 +37,10 @@ module BankScrap
37
37
  balance
38
38
  end
39
39
 
40
+ def raw_product_data
41
+ @data
42
+ end
43
+
40
44
  private
41
45
 
42
46
  def bundled_login
@@ -120,7 +124,7 @@ module BankScrap
120
124
  0.upto(9) do |j|
121
125
  pinpad_pixels_sample = single_number.get_pixels(0,0, SAMPLE_WIDTH, SAMPLE_HEIGHT)
122
126
 
123
- img = Magick::ImageList.new("lib/bank_scrap/banks/ing/numbers/pinpad#{j}.png").first
127
+ img = Magick::ImageList.new(File.join(File.dirname(__FILE__), "/ing/numbers/pinpad#{j}.png")).first
124
128
  number_pixels_sample = img.get_pixels(0, 0, SAMPLE_WIDTH, SAMPLE_HEIGHT)
125
129
  diff = 0
126
130
  pinpad_pixels_sample.each_with_index do |pixel, index|
@@ -0,0 +1,237 @@
1
+ require 'execjs'
2
+ require 'pp'
3
+ require 'json'
4
+ require 'base64'
5
+ require 'RMagick'
6
+ require 'active_support'
7
+ require 'byebug'
8
+ require 'open-uri'
9
+
10
+ module BankScrap
11
+ class Ing < Bank
12
+
13
+ DESKTOP_USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.111 Safari/537.36'
14
+
15
+ BASE_ENDPOINT = 'https://ing.ingdirect.es/'
16
+ FALSE_LOGIN_ENDPOINT = BASE_ENDPOINT + 'login/'
17
+ CACHE_ENDPOINT = BASE_ENDPOINT + 'login/cache.manifest'
18
+ DELETE_SESSION_ENDPOINT = BASE_ENDPOINT + 'genoma_api/rest/session'
19
+ LOGIN_ENDPOINT = BASE_ENDPOINT + 'genoma_login/rest/session'
20
+ POST_AUTH_ENDPOINT = BASE_ENDPOINT + 'genoma_api/login/auth/response'
21
+ CLIENT_ENDPOINT = BASE_ENDPOINT + 'genoma_api/rest/client'
22
+ PRODUCTS_ENDPOINT = BASE_ENDPOINT + 'genoma_api/rest/products'
23
+
24
+ SAMPLE_WIDTH = 30
25
+ SAMPLE_HEIGHT = 30
26
+
27
+ def initialize(dni, birthday, password, log: false, debug: false)
28
+ @dni = dni
29
+ @birthday = birthday
30
+ @password = password.to_s
31
+ @log = log
32
+ @debug = debug
33
+
34
+ initialize_connection
35
+
36
+ @curl.proxy_port = 8888
37
+ @curl.proxy_url = '192.168.1.21'
38
+
39
+ false_login
40
+ cache
41
+ delete_session
42
+ selected_positions = login
43
+
44
+ ticket = pass_pinpad(selected_positions)
45
+
46
+ post_auth(ticket)
47
+ call_client
48
+
49
+ get_products
50
+ end
51
+
52
+ private
53
+
54
+ def false_login
55
+ @curl.url = FALSE_LOGIN_ENDPOINT
56
+ @curl.headers['Host'] = 'ing.ingdirect.es'
57
+ @curl.headers['Connection'] = 'keep-alive'
58
+ @curl.headers['Accept'] = 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8'
59
+ @curl.headers['Accept-Encoding'] = 'gzip,deflate,sdch'
60
+ @curl.headers['Accept-Language'] = 'en,es;q=0.8'
61
+
62
+ response = @curl.get
63
+ end
64
+
65
+ def cache
66
+ @curl.url = CACHE_ENDPOINT
67
+ @curl.headers['Host'] = 'ing.ingdirect.es'
68
+ @curl.headers['Connection'] = 'keep-alive'
69
+ @curl.headers['Accept-Encoding'] = 'gzip,deflate,sdch'
70
+ @curl.headers['Accept-Language'] = 'en,es;q=0.8'
71
+ end
72
+
73
+ def delete_session
74
+ @curl.headers['Host'] = 'ing.ingdirect.es'
75
+ @curl.headers['Connection'] = 'keep-alive'
76
+ @curl.headers['Pragma'] = 'no-cache'
77
+ @curl.headers['Accept'] = 'application/json, text/javascript, */*; q=0.01'
78
+ @curl.headers['Origin'] = 'https://ing.ingdirect.es'
79
+ @curl.headers['X-Requested-With'] = 'XMLHttpRequest'
80
+ @curl.headers['Content-Type'] = 'application/json; charset=utf-8'
81
+ @curl.headers['Referer'] = 'https://ing.ingdirect.es/login/'
82
+ @curl.headers['Accept-Encoding'] = 'zip,deflate,sdch'
83
+ @curl.headers['Accept-Language'] = 'n,es;q=0.8'
84
+ @curl.headers['Cookie'] = 's_cc=true; s_mca=Direct; s_gts=1; s_nr=1414955726141; s_sq=%5B%5BB%5D%5D'
85
+
86
+ response = @curl.delete
87
+ pp response
88
+ end
89
+
90
+ def login
91
+ param = '{"loginDocument":{"documentType":0,"document":"' + @dni.to_s +
92
+ '"},"birthday":"' + @birthday.to_s + '","companyDocument":null,"device":"desktop"}'
93
+ puts param
94
+ @curl.url = LOGIN_ENDPOINT
95
+ @curl.headers['Host'] = 'ing.ingdirect.es'
96
+ @curl.headers['Connection'] = 'keep-alive'
97
+ @curl.headers['Pragma'] = 'no-cache'
98
+
99
+ @curl.headers['Accept'] = 'application/json, text/javascript, */*; q=0.01'
100
+ @curl.headers['Origin'] = 'https://ing.ingdirect.es'
101
+ @curl.headers['X-Requested-With'] = 'XMLHttpRequest'
102
+ @curl.headers['Content-Type'] = 'application/json; charset=utf-8'
103
+ @curl.headers['Referer'] = 'https://ing.ingdirect.es/login/'
104
+ @curl.headers['Accept-Encoding'] = 'zip,deflate,sdch'
105
+ @curl.headers['Accept-Language'] = 'n,es;q=0.8'
106
+ @curl.headers['Cookie'] = 's_cc=true; s_mca=Direct; s_gts=1; s_nr=1414955726141; s_sq=%5B%5BB%5D%5D'
107
+
108
+ response = post(LOGIN_ENDPOINT, param)
109
+ # response = @curl.body_str
110
+ response = JSON.parse(response)
111
+ positions = response['pinPositions']
112
+ pinpad = response['pinpad']
113
+
114
+ save_pinpad_numbers(pinpad)
115
+ pinpad_numbers = recognize_pinpad_numbers
116
+
117
+ get_correct_positions(pinpad_numbers, positions)
118
+ end
119
+
120
+ def pass_pinpad(positions)
121
+ param = "{\"pinPositions\": #{positions}}"
122
+ @curl.url = LOGIN_ENDPOINT
123
+ @curl.headers['Host'] = 'ing.ingdirect.es'
124
+ @curl.headers['Connection'] = 'keep-alive'
125
+ @curl.headers['Accept'] = 'application/json, text/javascript, */*; q=0.01'
126
+ @curl.headers['Origin'] = 'https://ing.ingdirect.es'
127
+ @curl.headers['X-Requested-With'] = 'XMLHttpRequest'
128
+ @curl.headers['Content-Type'] = 'application/json; charset=utf-8'
129
+ @curl.headers['Referer'] = 'https://ing.ingdirect.es/login/?clientId=281afde24c938607e5edeac6239e8a38&continue=%2Fpfm%2F'
130
+ @curl.headers['Accept-Encoding'] = 'gzip,deflate,sdch'
131
+
132
+ response = put(LOGIN_ENDPOINT, param)
133
+ response = ActiveSupport::Gzip.decompress(response)
134
+ response = JSON.parse(response)
135
+
136
+ response['ticket']
137
+ end
138
+
139
+ def post_auth(ticket)
140
+ @curl.headers['Host'] = 'ing.ingdirect.es'
141
+ @curl.headers['Connection'] = 'keep-alive'
142
+ @curl.headers['Accept'] = 'application/json, text/javascript, */*; q=0.01'
143
+ @curl.headers['Origin'] = 'https://ing.ingdirect.es'
144
+ @curl.headers['X-Requested-With'] = 'XMLHttpRequest'
145
+ @curl.headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'
146
+ @curl.headers['Referer'] = 'https://ing.ingdirect.es/login'
147
+ @curl.headers['Accept-Encoding'] = 'gzip,deflate'
148
+
149
+ @curl.url = POST_AUTH_ENDPOINT
150
+ param = "ticket=#{ticket}&device=desktop"
151
+ @curl.post(param)
152
+ response = @curl.body_str
153
+ end
154
+
155
+ def call_client
156
+ @curl.headers['Host'] = 'ing.ingdirect.es'
157
+ @curl.headers['Connection'] = 'keep-alive'
158
+ @curl.headers['Accept'] = 'application/json, text/javascript, */*; q=0.01'
159
+ @curl.headers['X-Requested-With'] = 'XMLHttpRequest'
160
+ @curl.headers['Content-Type'] = 'application/json; charset=utf-8'
161
+ @curl.headers['Referer'] = 'https://ing.ingdirect.es/pfm'
162
+ @curl.headers['Accept-Encoding'] = 'gzip,deflate,sdch'
163
+
164
+ response = get(CLIENT_ENDPOINT)
165
+
166
+ response = ActiveSupport::Gzip.decompress(response)
167
+ response = JSON.parse(response)
168
+ end
169
+
170
+ def get_products
171
+ @curl.headers['Host'] = 'ing.ingdirect.es'
172
+ @curl.headers['Connection'] = 'keep-alive'
173
+ @curl.headers['Accept'] = '*/*'
174
+ @curl.headers['X-Requested-With'] = 'XMLHttpRequest'
175
+ @curl.headers['Content-Type'] = 'application/json; charset=utf-8'
176
+ @curl.headers['Referer'] = 'https://ing.ingdirect.es/pfm'
177
+ @curl.headers['Accept-Encoding'] = 'gzip,deflate,sdch'
178
+
179
+ response = get(PRODUCTS_ENDPOINT)
180
+
181
+ File.open('response_raw.txt', 'w') { |file| file.write(response) }
182
+ response = ActiveSupport::Gzip.decompress(response)
183
+ File.open('response_decompressed.txt', 'w') { |file| file.write(response) }
184
+ File.open('response_parsed.txt', 'w') { |file| file.write(JSON.parse(response)) }
185
+ end
186
+
187
+ def save_pinpad_numbers(pinpad)
188
+ pinpad.each_with_index do |p,index|
189
+ File.open(build_tmp_path(index), 'wb'){ |f| f.write(Base64.decode64(p)) }
190
+ end
191
+ end
192
+
193
+ def build_tmp_path(number)
194
+ "tmp/original_pinpad_#{number}.png"
195
+ end
196
+
197
+ def recognize_pinpad_numbers
198
+ pinpad_numbers = []
199
+ 0.upto(9) do |i|
200
+ pinpad = Magick::ImageList.new(build_tmp_path(i)).first
201
+
202
+ differences = []
203
+ 0.upto(9) do |j|
204
+ pinpad_pixels_sample = pinpad.get_pixels(0,0, SAMPLE_WIDTH, SAMPLE_HEIGHT)
205
+
206
+ img = Magick::ImageList.new("numbers/pinpad#{j}.png").first
207
+ number_pixels_sample = img.get_pixels(0, 0, SAMPLE_WIDTH, SAMPLE_HEIGHT)
208
+ diff = 0
209
+ pinpad_pixels_sample.each_with_index do |pixel, index|
210
+ sample_pixel = number_pixels_sample[index]
211
+ diff += (pixel.red - sample_pixel.red).abs +
212
+ (pixel.green - sample_pixel.green).abs +
213
+ (pixel.blue - sample_pixel.blue).abs
214
+ end
215
+ differences << diff
216
+ end
217
+
218
+ real_number = differences.each_with_index.min.last
219
+ pinpad_numbers << real_number
220
+ end
221
+
222
+ pinpad_numbers
223
+ end
224
+
225
+ def get_correct_positions(pinpad_numbers, positions)
226
+ first_digit = @password[positions[0] - 1]
227
+ second_digit = @password[positions[1] - 1]
228
+ third_digit = @password[positions[2] - 1]
229
+
230
+ [
231
+ pinpad_numbers.index(first_digit.to_i),
232
+ pinpad_numbers.index(second_digit.to_i),
233
+ pinpad_numbers.index(third_digit.to_i)
234
+ ]
235
+ end
236
+ end
237
+ end
@@ -1,3 +1,3 @@
1
1
  module BankScrap
2
- VERSION = "0.0.6"
2
+ VERSION = "0.0.7"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bank_scrap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ismael Sánchez
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2014-11-10 00:00:00.000000000 Z
14
+ date: 2015-01-25 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: bundler
@@ -46,6 +46,9 @@ dependencies:
46
46
  requirement: !ruby/object:Gem::Requirement
47
47
  requirements:
48
48
  - - "~>"
49
+ - !ruby/object:Gem::Version
50
+ version: '3.5'
51
+ - - ">="
49
52
  - !ruby/object:Gem::Version
50
53
  version: 3.5.1
51
54
  type: :development
@@ -53,6 +56,9 @@ dependencies:
53
56
  version_requirements: !ruby/object:Gem::Requirement
54
57
  requirements:
55
58
  - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '3.5'
61
+ - - ">="
56
62
  - !ruby/object:Gem::Version
57
63
  version: 3.5.1
58
64
  - !ruby/object:Gem::Dependency
@@ -98,19 +104,19 @@ dependencies:
98
104
  - !ruby/object:Gem::Version
99
105
  version: '2.2'
100
106
  - !ruby/object:Gem::Dependency
101
- name: curb
107
+ name: mechanize
102
108
  requirement: !ruby/object:Gem::Requirement
103
109
  requirements:
104
110
  - - "~>"
105
111
  - !ruby/object:Gem::Version
106
- version: '0.8'
112
+ version: 2.7.3
107
113
  type: :runtime
108
114
  prerelease: false
109
115
  version_requirements: !ruby/object:Gem::Requirement
110
116
  requirements:
111
117
  - - "~>"
112
118
  - !ruby/object:Gem::Version
113
- version: '0.8'
119
+ version: 2.7.3
114
120
  - !ruby/object:Gem::Dependency
115
121
  name: activesupport
116
122
  requirement: !ruby/object:Gem::Requirement
@@ -130,6 +136,9 @@ dependencies:
130
136
  requirement: !ruby/object:Gem::Requirement
131
137
  requirements:
132
138
  - - "~>"
139
+ - !ruby/object:Gem::Version
140
+ version: '2.2'
141
+ - - ">="
133
142
  - !ruby/object:Gem::Version
134
143
  version: 2.2.2
135
144
  type: :runtime
@@ -137,6 +146,9 @@ dependencies:
137
146
  version_requirements: !ruby/object:Gem::Requirement
138
147
  requirements:
139
148
  - - "~>"
149
+ - !ruby/object:Gem::Version
150
+ version: '2.2'
151
+ - - ">="
140
152
  - !ruby/object:Gem::Version
141
153
  version: 2.2.2
142
154
  description: Command line tools to get bank account details from some banks.
@@ -169,6 +181,7 @@ files:
169
181
  - lib/bank_scrap/banks/ing/numbers/pinpad7.png
170
182
  - lib/bank_scrap/banks/ing/numbers/pinpad8.png
171
183
  - lib/bank_scrap/banks/ing/numbers/pinpad9.png
184
+ - lib/bank_scrap/banks/ing_backup.rb
172
185
  - lib/bank_scrap/cli.rb
173
186
  - lib/bank_scrap/version.rb
174
187
  homepage: https://github.com/ismaGNU/bank_scrap
@@ -196,4 +209,3 @@ signing_key:
196
209
  specification_version: 4
197
210
  summary: Get your bank account details.
198
211
  test_files: []
199
- has_rdoc: