-
Notifications
You must be signed in to change notification settings - Fork 2
/
santander
executable file
·314 lines (278 loc) · 9.85 KB
/
santander
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
#! /usr/bin/env ruby
# encoding: utf-8
# create passwords file named passwords-santander.rb in the same directory with:
# {:dni=>"mydni", :numeric_password=>"4 digit pwd",
# :password=>"your password",
# :transfer_card=>["51", "25", "11", "60".......]}
# encrypt the file with gpg -c --cipher-algo BLOWFISH passwords-santander.rb
# delete the original file
require 'watir-webdriver'
require 'headless'
def login(b, dni, numeric_password, password)
b.goto 'https://www.personas.santanderrio.com.ar'
b.text_field(:name => "dni").set dni
b.text_field(:name => "clave").set numeric_password
b.text_field(:name => "usuario").set password
b.input(:type => "image").click
end
def login_company(b, cuit, numeric_password)
b.goto 'https://www.emp.santanderrio.com.ar/nb/'
b.text_field(:name => "cuit").set cuit
b.text_field(:name => "password").set numeric_password
b.input(:type => "button").click
end
def load_user_data(path)
puts "Ingrese la clave para desbloquear el archivo de secretos"
data = `gpg -d #{path} 2> /dev/null`
eval(data)
end
def find_menu(b, name)
b.frame(:name => "frame1").link(:text => name)
end
def find_company_menu(b, name)
b.frame(:name => "frameMenu").link(:text => name)
end
def find_company_submenu(b, name)
company_submenu_frame(b).link(:text => name)
end
def company_submenu_frame(b)
b.frame(:name => "frame2").frame(:name => "frameOperaciones")
end
def find_company_submenu_by_index(b, index)
company_submenu_frame(b).link(:index => index)
end
def within_company_main_frame(b, &block)
yield b.frame(:name => "frame2").frame(:name => "frameTrabajo")
end
def make_browser(download_directory, headless = false)
if headless && !@headless_instance
@headless_instance = Headless.new
@headless_instance.start
end
Dir.mkdir download_directory rescue nil
profile = Selenium::WebDriver::Firefox::Profile.new
profile['browser.download.folderList'] = 2 # custom location
profile['browser.download.dir'] = download_directory
profile['browser.helperApps.neverAsk.saveToDisk'] = "text/csv,application/pdf,application/vnd.ms-excel,application/msexcel,application/x-msexcel,application/x-ms-excel,application/vnd.ms-excel,application/x-excel,application/x-dos_ms_excel,application/xls"
Watir::Browser.new :firefox, :profile => profile
end
def main_frame(b)
b.frame(:name => 'frame2')
end
def submenu(b)
main_frame(b).frame(:name => "rowOperaciones")
end
def productos(b)
main_frame(b).frame(:name => "rowProductos")
end
def wait_and_click(b, link)
b.wait_until {|w| link.exists?}
link.click
end
def within_operation_area(b, &block)
yield(main_frame(b).frame(:name => 'rowWorkingArea'))
end
def show_message(title, msg)
system(%Q[zenity --info --title="#{title}" --text="#{msg}"])
end
def confirmation(title, msg)
system(%Q[zenity --question --title="#{title}" --text="#{msg}"])
$? == 0
end
def get_coord(c, coords_array)
col = c.downcase[0].ord - "a".ord
row = c[1].ord - "1".ord
coords_array[col + 9*row]
end
def transfer(b, to_account, user_data)
wait_and_click(b, find_menu(b, "PAGOS Y TRANSFERENCIAS"))
wait_and_click(b, submenu(b).link(:text => "Transferencias"))
within_operation_area(b) do |w|
if to_account
combo = w.select(:name => "selCtaDest")
accounts = combo.options.map(&:text)
reg = Regexp.new(".*#{to_account.downcase}.*")
if match = accounts.find {|acc| reg.match(acc.downcase)}
combo.select match
end
w.div(:class => "btnPanelCuentas").a.click
end
show_message "Transferencia", "Ingrese los datos de la transferencia en el browser y luego aprete OK aquí"
w.input(:value => "CONTINUAR").click
if w.th(:class => "aviso").exists? #show schedule warning?
w.input(:name => "Continuar").click
end
coords = w.form(:id => "fBotones").td(:align => "center").text
coords = coords.split
coords = coords.map {|c| get_coord(c, user_data[:coord_card])}
w.text_field(:name => "incoord1").set(coords[0])
w.text_field(:name => "incoord2").set(coords[1])
if confirmation("Transferencia", "Seguro que desea realizar esta transferencia?")
w.input(:value => "CONTINUAR").click
end
end
end
def operations(b, downloads_path)
wait_and_click(b, find_menu(b, "CUENTAS"))
wait_and_click(b, submenu(b).link(:text => "Últimos movimientos"))
within_operation_area(b) do |w|
w.select(:name => "cantDias").select("Últimos 60 días")
w.input(:value => "Generar archivo excel").click
end
puts "Movimientos de cuenta salvado en #{downloads_path}"
wait_and_click(b, find_menu(b, "TARJETAS"))
for prod in ["prod0", "prod1"]
wait_and_click(b, productos(b).span(:id => prod).link)
wait_and_click(b, submenu(b).link(:text => "Último Resumen"))
within_operation_area(b) do |w|
b.wait_until {|_| w.div(:id => "template_data_div").exists?}
File.open(File.join(downloads_path, "resumen-#{prod}.txt"), "w") do |f|
f.write w.div(:id => "template_data_div").text
puts "Resumen de #{prod} salvado en #{f.path}"
end
end
wait_and_click(b, submenu(b).link(:text => "Últimos Consumos"))
within_operation_area(b) do |w|
b.wait_until {|_| w.div(:id => "template_data_div").exists?}
File.open(File.join(downloads_path, "ultimos-movimientos-#{prod}.txt"), "w") do |f|
f.write w.div(:id => "template_data_div").text
puts "Últimos movimientos de #{prod} salvado en #{f.path}"
end
end
end
end
def balance(b)
b.wait_until {|_| main_frame(b).th(:text => "Cuenta").exists?}
accounts_table = main_frame(b).th(:text, "Cuenta").parent.parent.parent
accounts_table.tbody.strings.each do |row|
puts "#{row[0]}\t#{row[1]}"
end
end
def statements(b)
wait_and_click(b, find_menu(b, "CUENTAS"))
wait_and_click(b, submenu(b).link(:text => "Resumen de cuenta online"))
within_operation_area(b) do |w|
combo = w.select(:name => "resumenes")
dates = combo.options.map(&:text)
dates.shift #drop prompt
for res in dates
puts "Bajando resumen #{res}"
combo.select(res)
w.input(:value => "verresumen").click
end
end
end
def close_company_popups_and_keep_main(b)
puts "Intentando cerrar popups..."
# close initial window, main window is a popup
b.window(:index => 0).close rescue puts("No pude cerrar la ventana inicial")
# close 'Opere seguro' popup
begin
w = b.window(:title => "Opere seguro")
w.wait_until_present(10)
w.close
rescue
puts "No pude cerrar el popup 'Opere seguro'"
end
puts "Popups cerrados"
end
def company_operations_between_dates(b, from, to)
wait_and_click(b, find_company_menu(b, "Cuentas"))
wait_and_click(b, find_company_submenu(b, "Extracto y Movimientos del día"))
within_company_main_frame(b) do |f|
f.input(:value => "Búsqueda Avanzada").click
f.input(:name, "fechaDde").wait_until_present
format = "%d/%m/%Y"
f.text_field(:name, "fechaDde").set(from.strftime(format))
f.text_field(:name, "fechaHta").set(to.strftime(format))
f.input(:type => "radio", :name => "formato", :index => 1).click
f.input(:type => "button", :value => "Buscar").click
f.b(:text => "La descarga a archivo ha finalizado").wait_until_present
puts "El archivo ha sido descargado"
end
end
def company_operations_last_month(b)
today = Date.today
date_start = (today << 1) - today.day + 1
date_end = today - today.day
company_operations_between_dates(b, date_start, date_end)
end
def company_operations_this_month(b)
company_operations_between_dates(b, Date.today - Date.today.day + 1, Date.today - 1)
end
def company_balance(b)
wait_and_click(b, find_company_menu(b, "Cuentas"))
balance_detail_link = find_company_submenu_by_index(b, 1)
wait_and_click(b, balance_detail_link)
within_company_main_frame(b) do |f|
f.table(:id => "mainTablaResumen").strings.each do |row|
puts "#{row[0]}\t#{row[1]}"
end
end
end
def usage
puts "santander op [args]"
puts "op = login | transfer | operations | balance | statements | login_company | company_operations_last_month | company_operations_this_month | company_balance"
puts "args ="
puts " for transfer: account-name (optional)"
exit 1
end
COMPANY_SECRETS_PATH = File.join(File.dirname(__FILE__), "passwords-santander-company.rb.gpg")
SECRETS_PATH = File.join(File.dirname(__FILE__), "passwords-santander.rb.gpg")
DOWNLOADS_PATH = "/tmp/santander-downloads"
def start_browser_and_login(type, headless)
if type == :person
user_data = load_user_data(SECRETS_PATH)
b = make_browser DOWNLOADS_PATH, headless
login(b, user_data[:dni], user_data[:numeric_password], user_data[:password])
else
user_data = load_user_data(COMPANY_SECRETS_PATH)
b = make_browser DOWNLOADS_PATH, headless
login_company(b, user_data[:cuit], user_data[:numeric_password])
close_company_popups_and_keep_main b unless headless
end
b
end
def with_logged_in_browser(type = :person, close=true, headless = false)
b = start_browser_and_login type, headless
yield b
ensure
b.close rescue nil if close
@headless_instance.destroy rescue nil if @headless_instance
end
case ARGV[0]
when "login" then
with_logged_in_browser(:person, false) {|_|}
when "transfer" then
with_logged_in_browser do |b|
transfer b, ARGV[1], user_data
end
when "operations" then
with_logged_in_browser do |b|
operations b, DOWNLOADS_PATH
end
when "statements" then
with_logged_in_browser do |b|
statements b
end
when "balance" then
with_logged_in_browser do |b|
balance b
end
when "login_company" then
with_logged_in_browser(:company, false) {}
when "company_operations_last_month" then
with_logged_in_browser(:company, true, true) do |b|
company_operations_last_month b
end
when "company_operations_this_month" then
with_logged_in_browser(:company, true, true) do |b|
company_operations_this_month b
end
when "company_balance" then
with_logged_in_browser(:company, true, true) do |b|
company_balance b
end
else
usage
end