bank_scrap 0.0.6 → 0.0.7
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 +4 -4
- data/.gitignore +2 -0
- data/README.md +17 -5
- data/bank_scrap.gemspec +3 -3
- data/lib/bank_scrap/bank.rb +26 -34
- data/lib/bank_scrap/banks/bbva.rb +10 -2
- data/lib/bank_scrap/banks/ing.rb +5 -1
- data/lib/bank_scrap/banks/ing_backup.rb +237 -0
- data/lib/bank_scrap/version.rb +1 -1
- metadata +18 -6
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA1:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 4680376ad7f26ae34f9cf4262fa04b98b5b466ea
         | 
| 4 | 
            +
              data.tar.gz: 4be7fda00b5c1a410ffb602979d20894d3511f6b
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 9debe3eadab0fa8a98e3d52640cf2d2a49348f92f6a5b0d2bb5b2a9555ca19d4e61559ea3b990f28bbdcef9ceda1bf36e259d540ffe4c1e23ef25ec7ce53c250
         | 
| 7 | 
            +
              data.tar.gz: d314b783e5a962669d2717f1fa2d15568284e7c4e03195e8d32073296138f7325758d2d218aa492cbfff6fe1b0b47105b951a94d05f995ba2f7fc34bcb128e70
         | 
    
        data/.gitignore
    CHANGED
    
    
    
        data/README.md
    CHANGED
    
    | @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            #  | 
| 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 | 
            -
             | 
| 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 | 
            -
             | 
| 55 | 
            +
            ##### Bankinter
         | 
| 56 56 |  | 
| 57 | 
            -
             | 
| 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  | 
| 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 ' | 
| 30 | 
            +
              spec.add_dependency 'mechanize', "~> 2.7.3"
         | 
| 31 31 | 
             
              spec.add_dependency 'activesupport', "~> 4.1"
         | 
| 32 | 
            -
              spec.add_dependency 'rmagick',  | 
| 32 | 
            +
              spec.add_dependency 'rmagick', '~> 2.2', '>= 2.2.2'
         | 
| 33 33 | 
             
            end
         | 
    
        data/lib/bank_scrap/bank.rb
    CHANGED
    
    | @@ -1,66 +1,58 @@ | |
| 1 | 
            -
            require ' | 
| 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 | 
            -
                  @ | 
| 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 | 
            -
                  @ | 
| 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 | 
            -
                  @ | 
| 31 | 
            -
             | 
| 32 | 
            -
                  @curl.put(fields)
         | 
| 33 | 
            -
                  @curl.body_str
         | 
| 21 | 
            +
                  @http.put(url, fields, @headers).body
         | 
| 34 22 | 
             
                end
         | 
| 35 23 |  | 
| 36 | 
            -
                 | 
| 37 | 
            -
             | 
| 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. | 
| 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 | 
            -
                  @ | 
| 52 | 
            -
                  @ | 
| 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 | 
            -
                  @ | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 62 | 
            -
                   | 
| 63 | 
            -
             | 
| 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 | 
            -
                 | 
| 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 | 
            -
                   | 
| 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"]
         | 
    
        data/lib/bank_scrap/banks/ing.rb
    CHANGED
    
    | @@ -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(" | 
| 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
         | 
    
        data/lib/bank_scrap/version.rb
    CHANGED
    
    
    
        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. | 
| 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:  | 
| 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:  | 
| 107 | 
            +
              name: mechanize
         | 
| 102 108 | 
             
              requirement: !ruby/object:Gem::Requirement
         | 
| 103 109 | 
             
                requirements:
         | 
| 104 110 | 
             
                - - "~>"
         | 
| 105 111 | 
             
                  - !ruby/object:Gem::Version
         | 
| 106 | 
            -
                    version:  | 
| 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:  | 
| 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: 
         |