banker 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,112 @@
1
+ module Banker
2
+ # This class allows the retrieval of credit score data
3
+ # for Credit Expert UK
4
+ #
5
+ # == Examples
6
+ #
7
+ # Get Score from Credit Expert UK
8
+ #
9
+ # site = Banker::CreditExpertUK.new(:username => "joe",
10
+ # :password => '123456',
11
+ # :memorable_word => 'superduper')
12
+ #
13
+ # site.score #=> 800
14
+ #
15
+ class CreditExpertUK
16
+ attr_accessor :username, :password, :memorable_word, :agent, :score
17
+
18
+ LOGIN_ENDPOINT = "https://www.creditexpert.co.uk/MCCLogin.aspx"
19
+
20
+ FIELDS = {
21
+ username: 'loginUser:txtUsername:ECDTextBox',
22
+ password: 'loginUser:txtPassword:ECDTextBox',
23
+ questions: [
24
+ 'label span#loginUserMemorableWord_SecurityQuestionLetter1',
25
+ 'label span#loginUserMemorableWord_SecurityQuestionLetter2'
26
+ ],
27
+ answers: [
28
+ 'loginUserMemorableWord:SecurityQuestionUK1_SecurityAnswer1_ECDTextBox',
29
+ 'loginUserMemorableWord:SecurityQuestionUK1_SecurityAnswer2_ECDTextBox'
30
+ ],
31
+ score: 'span#MCC_ScoreIntelligence_ScoreIntelligence_Dial1_MyScoreV31_pnlMyScore1_lblMyScore'
32
+ }
33
+
34
+ def initialize(args)
35
+ @username = args[:username]
36
+ @password = args[:password]
37
+ @memorable_word = args[:memorable_word]
38
+
39
+ @agent = Mechanize.new
40
+ @agent.log = Logger.new 'mech.log'
41
+ @agent.user_agent = 'Mozilla/5.0 (Banker)'
42
+
43
+ authenticate
44
+ end
45
+
46
+ private
47
+
48
+ def authenticate
49
+ @score = data
50
+ =begin
51
+ page = @agent.get(LOGIN_ENDPOINT)
52
+
53
+ form = page.form_with(:action => 'MCCLogin.aspx')
54
+
55
+ form[FIELDS[:username]] = @username
56
+ form[FIELDS[:password]] = @password
57
+
58
+
59
+ page = @agent.submit(form, form.buttons.first)
60
+
61
+ form = page.form_with(:name => 'MasterPage')
62
+
63
+ first_letter = page.at(FIELDS[:questions][0]).content.scan(/\d+/).first.to_i
64
+ second_letter = page.at(FIELDS[:questions][1]).content.scan(/\d+/).first.to_i
65
+
66
+ form[FIELDS[:answers][0]] = get_letter(first_letter)
67
+
68
+ form[FIELDS[:answers][1]] = get_letter(second_letter)
69
+
70
+ page = @agent.submit(form, form.buttons.first)
71
+
72
+ @score = page.at(FIELDS[:score]).content.to_i
73
+ =end
74
+ end
75
+
76
+ def start
77
+ page = @agent.get(LOGIN_ENDPOINT)
78
+
79
+ form = page.form_with(:action => 'MCCLogin.aspx')
80
+
81
+ form[FIELDS[:username]] = @username
82
+ form[FIELDS[:password]] = @password
83
+
84
+ @agent.submit(form, form.buttons.first)
85
+ end
86
+
87
+ def step1
88
+ page = start
89
+ form = page.form_with(name: 'MasterPage')
90
+
91
+ first_letter = extract_digit(page.at(FIELDS[:questions][0]).content)
92
+ second_letter = extract_digit(page.at(FIELDS[:questions][1]).content)
93
+
94
+ form[FIELDS[:answers][0]] = get_letter(first_letter)
95
+ form[FIELDS[:answers][1]] = get_letter(second_letter)
96
+
97
+ @agent.submit(form, form.buttons.first)
98
+ end
99
+
100
+ def data
101
+ step1.at(FIELDS[:score]).content.to_i
102
+ end
103
+
104
+ def extract_digit(content)
105
+ content.scan(/\d+/).first.to_i
106
+ end
107
+
108
+ def get_letter(index)
109
+ @memorable_word[index-1]
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,5 @@
1
+ module Banker
2
+ module Error
3
+ class InvalidParams < ArgumentError;end
4
+ end
5
+ end
@@ -0,0 +1,130 @@
1
+ module Banker
2
+ # This class allows the data retrieval of accounts for Lloyds TSB UK
3
+ #
4
+ # == Examples
5
+ #
6
+ # Retrieve Account Balance
7
+ #
8
+ # user_params = { username: 'Joe', password: 'password', memorable_word: 'superduper' }
9
+ # lloyds = Banker::LloydsTSBUK.new(user_params)
10
+ # lloyds.balance
11
+ # # => [ {:current_account => { :balance => 160940,
12
+ # :details => { :sort_code => "928277",
13
+ # :account_number => "92837592" }}},
14
+ #
15
+ # {:savings_account => { :balance => 0.0,
16
+ # :details => { :sort_code => "918260",
17
+ # :account_number=>"91850261" }}},
18
+ #
19
+ # {:lloyds_tsb_platinum_mastercard => { :balance => 0.0,
20
+ # :details => { :card_number => "9284710274618391" }}}
21
+ # ]
22
+ #
23
+ class LloydsTSBUK
24
+ attr_accessor :username, :password, :memorable_word, :balance, :agent
25
+
26
+ LOGIN_ENDPOINT = "https://online.lloydstsb.co.uk/personal/logon/login.jsp"
27
+
28
+ def initialize(args)
29
+ @username = args[:username]
30
+ @password = args[:password]
31
+ @memorable_word = args[:memorable_word]
32
+
33
+ @agent = Mechanize.new
34
+ @agent.log = Logger.new 'mech.log'
35
+ @agent.user_agent = 'Mozilla/5.0 (Banker)'
36
+ @agent.force_default_encoding = 'utf8'
37
+
38
+ @balance = authenticate
39
+ end
40
+
41
+ def get_memorable_word_letter(letter)
42
+ @memorable_word.to_s[letter.to_i - 1]
43
+ end
44
+
45
+ def cleaner(str)
46
+ str.gsub(/[^\d+]/, '')
47
+ end
48
+
49
+ private
50
+
51
+ def authenticate
52
+ page = @agent.get(LOGIN_ENDPOINT)
53
+
54
+ # Login Page
55
+ page = page.form('frmLogin') do |f|
56
+ f.fields[0].value = @username
57
+ f.fields[1].value = @password
58
+ end.click_button
59
+
60
+ # Memorable Word
61
+ form = page.form('frmentermemorableinformation1')
62
+ memorable_set(page, form)
63
+ page = @agent.submit(form, form.buttons.first)
64
+
65
+ # Accounts Page
66
+ return account_return(page)
67
+ end
68
+
69
+ def memorable_letters(page)
70
+ {
71
+ first: memorable_required(page)[0],
72
+ second: memorable_required(page)[1],
73
+ third: memorable_required(page)[2]
74
+ }
75
+ end
76
+
77
+ def memorable_set(page, form)
78
+ letters = memorable_letters(page)
79
+
80
+ form.fields[2].value = '&nbsp;' + get_memorable_word_letter(letters.fetch(:first))
81
+ form.fields[3].value = '&nbsp;' + get_memorable_word_letter(letters.fetch(:second))
82
+ form.fields[4].value = '&nbsp;' + get_memorable_word_letter(letters.fetch(:third))
83
+ end
84
+
85
+ def memorable_required(page)
86
+ page.labels.collect { |char| cleaner(char.to_s) }
87
+ end
88
+
89
+ def account_name(page)
90
+ page.search('div.accountDetails h2').collect {|a| a.content.downcase.gsub(/\s/, '_').to_sym }
91
+ end
92
+
93
+ def account_detail(page)
94
+ page.search('div.accountDetails p.numbers').collect {|n| n.content }
95
+ end
96
+
97
+ def account_balance(page)
98
+ page.search('div.balanceActionsWrapper p.balance').collect {|b| b.content }
99
+ end
100
+
101
+ def formatted_detail(page)
102
+ resp = account_detail(page).map { |detail| detail.split(',').map { |d| cleaner(d) } }
103
+ resp.map! do |r|
104
+ if r.length == 2
105
+ { sort_code: r[0], account_number: r[1] }
106
+ elsif r.length == 1
107
+ { card_number: r[0] }
108
+ else
109
+ STDERR.puts "[Error] It seems we got account details that we did not expect! - #{r.inspect}"
110
+ end
111
+ end
112
+ end
113
+
114
+ def formatted_balance(page)
115
+ account_balance(page).map do |b|
116
+ resp = cleaner(b)
117
+ resp.empty? ? 0.00 : resp.to_i
118
+ end
119
+ end
120
+
121
+ def account_return(page)
122
+ resp = []
123
+ account_name(page).zip(formatted_balance(page), formatted_detail(page)).each_with_index do |acc, index|
124
+ resp << { acc[0] => { balance: acc[1], details: acc[2] } }
125
+ end
126
+ resp
127
+ end
128
+
129
+ end
130
+ end
@@ -0,0 +1,3 @@
1
+ module Banker
2
+ VERSION = "0.0.3"
3
+ end
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe Banker::Account do
4
+ let(:attr){{
5
+ name:'',
6
+ uid:'',
7
+ amount:'',
8
+ limit:''
9
+ }}
10
+ subject {Banker::Account}
11
+
12
+ it {subject.new(attr).should respond_to(:name)}
13
+ it {subject.new(attr).should respond_to(:uid)}
14
+ it {subject.new(attr).should respond_to(:amount)}
15
+ it {subject.new(attr).should respond_to(:limit)}
16
+
17
+ it "validates presence of name" do
18
+ expect{
19
+ subject.new
20
+ }.to raise_error(ArgumentError, "missing attribute `name`")
21
+ end
22
+ it "validates presence of uid" do
23
+ expect{
24
+ subject.new(name:'')
25
+ }.to raise_error(ArgumentError, "missing attribute `uid`")
26
+ end
27
+ it "validates presence of amount" do
28
+ expect{
29
+ subject.new(name:'',uid:'')
30
+ }.to raise_error(ArgumentError, "missing attribute `amount`")
31
+ end
32
+ end
@@ -0,0 +1,167 @@
1
+ require 'spec_helper'
2
+
3
+ describe Banker::BarclaycardUK do
4
+ let(:support_files) {File.expand_path('../../support/barclaycard_uk/',__FILE__)}
5
+
6
+ LOGIN_ENDPOINT = 'https://bcol.barclaycard.co.uk/ecom/as2/initialLogon.do'
7
+ EXPORT_ENDPOINT = 'https://bcol.barclaycard.co.uk/ecom/as2/export.do?doAction=processRecentExportTransaction&type=OFX_2_0_2&statementDate=&sortBy=transactionDate&sortType=Dsc'
8
+
9
+ let(:mechanize) {mock('mechanize').as_null_object}
10
+ let(:node) {mock('node').as_null_object}
11
+ let(:form) {mock('form').as_null_object}
12
+ let(:button) {mock('button').as_null_object}
13
+ let(:ofx) {
14
+ f = File.open(File.expand_path('data.ofx',support_files), 'r:iso-8859-1')
15
+ f.read
16
+ }
17
+
18
+ subject { Banker::BarclaycardUK }
19
+
20
+ before do
21
+ subject.any_instance.stub(:params)
22
+ subject.any_instance.stub(:authenticate!)
23
+ subject.any_instance.stub(:get_data)
24
+ end
25
+
26
+ it {subject.new.should respond_to(:accounts)}
27
+
28
+ context "Parameters" do
29
+ before do
30
+ subject.any_instance.unstub(:params)
31
+ end
32
+
33
+ it "raises InvalidParams when username is missing" do
34
+ expect{
35
+ subject.new
36
+ }.to raise_error(Banker::Error::InvalidParams,
37
+ "missing parameters `username` `password` `memorable_word` ")
38
+ end
39
+
40
+ it "raises InvalidParams when password is missing" do
41
+ expect{
42
+ subject.new(username: "joe")
43
+ }.to raise_error(Banker::Error::InvalidParams,
44
+ "missing parameters `password` `memorable_word` ")
45
+ end
46
+
47
+ it "raises InvalidParams when memorable_word is missing" do
48
+ expect{
49
+ subject.new(username: "joe", password: "123456")
50
+ }.to raise_error(Banker::Error::InvalidParams,
51
+ "missing parameters `memorable_word` ")
52
+
53
+ end
54
+
55
+ it "accepts username, password and memorable_word" do
56
+ expect{
57
+
58
+ subject.new(username: "joe", password: "123456",
59
+ memorable_word: "superduper")
60
+ }.to_not raise_error
61
+ end
62
+ end
63
+
64
+ context "calls" do
65
+ it "calls params" do
66
+ subject.any_instance.should_receive(:params)
67
+ subject.new
68
+ end
69
+ it "calls authenticate!" do
70
+ subject.any_instance.should_receive(:authenticate!)
71
+ subject.new
72
+ end
73
+ it "calls get_data" do
74
+ subject.any_instance.should_receive(:get_data)
75
+ subject.new
76
+ end
77
+ end
78
+
79
+ context "private" do
80
+ before do
81
+ Mechanize.stub(:new).and_return(mechanize)
82
+ mechanize.stub(:get).and_return(mechanize)
83
+ mechanize.stub(:form_with).and_return(form)
84
+ mechanize.stub(:at).and_return(node)
85
+ mechanize.stub(:submit).and_return(mechanize)
86
+ end
87
+
88
+ describe "#authenticate!" do
89
+ before do
90
+ subject.any_instance.unstub(:authenticate!)
91
+ subject.any_instance.stub(:get_letter).and_return("A")
92
+ end
93
+ it "gets #{LOGIN_ENDPOINT}" do
94
+ mechanize.should_receive(:get).
95
+ with("https://bcol.barclaycard.co.uk/ecom/as2/initialLogon.do").
96
+ and_return(mechanize)
97
+ subject.new
98
+ end
99
+ it "finds by form action" do
100
+ mechanize.should_receive(:form_with).
101
+ with(action: "/ecom/as2/initialLogon.do").
102
+ and_return(form)
103
+ subject.new
104
+ end
105
+ it "fills in form inputs" do
106
+ mechanize.should_receive(:at).
107
+ with("label[for='lettera']").
108
+ and_return(node)
109
+
110
+ mechanize.should_receive(:at).
111
+ with("label[for='letterb']").
112
+ and_return(node)
113
+
114
+
115
+ node.should_receive(:content).
116
+ at_least(:twice).
117
+ and_return("1")
118
+
119
+ subject.any_instance.unstub(:get_letter)
120
+
121
+ form.should_receive(:[]=).with("username", "joe")
122
+ form.should_receive(:[]=).with("password", "123456")
123
+ form.should_receive(:[]=).with("firstAnswer", "S")
124
+ form.should_receive(:[]=).with("secondAnswer", "S")
125
+
126
+
127
+ subject.new(username: "joe", password: "123456",
128
+ memorable_word: "superduper")
129
+ end
130
+
131
+ it "submits form" do
132
+ form.should_receive(:buttons).
133
+ twice.
134
+ and_return([button])
135
+ mechanize.should_receive(:submit).
136
+ with(form,button)
137
+ subject.new
138
+ end
139
+
140
+ it "parses html for account limit" do
141
+ mechanize.should_receive(:at).
142
+ with(".panelSummary .limit .figure").
143
+ and_return(node)
144
+ subject.new
145
+ end
146
+
147
+ end
148
+
149
+ describe "#get_data" do
150
+ before do
151
+ subject.any_instance.unstub(:get_data)
152
+ mechanize.stub(get: stub(body: ofx))
153
+ end
154
+
155
+ it "gets #{EXPORT_ENDPOINT}" do
156
+ mechanize.should_receive(:get).
157
+ with(EXPORT_ENDPOINT).
158
+ and_return(stub(body: ofx))
159
+ subject.new
160
+ end
161
+ it "finds account balance" do
162
+
163
+ end
164
+ it "finds account limit"
165
+ end
166
+ end
167
+ end