stealth_browser_automation 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bcd01c1ba08e79360a113829c62e85d65ae8f414
4
+ data.tar.gz: 4701e9a79e13ab2111d83f8c48a722eab6245f37
5
+ SHA512:
6
+ metadata.gz: 63de89c480ebcd7aa799f6a6fd32b7a8759d29454929f8941a74601bdac2b6be35356240ecd48fb1edf712e0a8281921ad9e1339794cf2628bfdca7ee9b82c9c
7
+ data.tar.gz: 27d27a9e215ae62df3eacfa9175ad756f73ed1c77e33ca8b236caf7cd458c7549df14fb96823d7914b17bd737b4c5c2e13b090f1a3b85647fba06404f767f76e
data/lib/baseproxy.rb ADDED
@@ -0,0 +1,33 @@
1
+ module BlackStack
2
+
3
+ module BaseProxy
4
+
5
+ #
6
+ def chrome_switches
7
+ return ["--proxy-server=#{self.ip}:#{self.port}","--proxy-user-and-password=#{self.user}:#{self.password}"]
8
+ end
9
+
10
+ # Warning: Out to Date
11
+ def firefox_profile_parameter(agent_name = nil, profile_name = nil)
12
+ if (profile_name == nil)
13
+ profile = Selenium::WebDriver::Firefox::Profile.new
14
+ else
15
+ profile = Selenium::WebDriver::Firefox::Profile.from_name profile_name
16
+ end
17
+
18
+ if (agent_name!=nil)
19
+ profile['general.useragent.override'] = agent_name
20
+ end
21
+
22
+ proxy = Selenium::WebDriver::Proxy.new(:http => self.ip.to_s+":"+self.port.to_s, :ssl => self.ip.to_s+":"+self.port.to_s)
23
+ profile.proxy = proxy
24
+ return profile
25
+ end
26
+
27
+ # Warning: Out to Date
28
+ def phantomjs_switches
29
+ return ['--proxy='+self.ip.to_s+':'+self.port.to_s, '--proxy-auth='+self.user.to_s+':'+self.password.to_s, '--ignore-ssl-errors=yes', '--ssl-protocol=any', '--load-images=false']
30
+ end
31
+ end
32
+
33
+ end # module BlackStack
@@ -0,0 +1,498 @@
1
+ require 'watir-webdriver'
2
+ require "pathname"
3
+
4
+ module BlackStack
5
+
6
+ class PampaBrowser < Watir::Browser
7
+
8
+ attr_accessor :proxy, :lnuser, :agent_name, :profile_name
9
+
10
+ def notify(method)
11
+ url = "#{BlackStack::Pampa::api_protocol}://#{PROCESS.ws_url}:#{PROCESS.ws_port}/api1.3/pampa/browser/notify.json"
12
+ res = BlackStack::Netting::call_post(url, {
13
+ :api_key => BlackStack::Pampa::api_key,
14
+ :filename => $0,
15
+ :method => method,
16
+ :worker_name => PROCESS.fullWorkerName,
17
+ :id_proxy => self.proxy.nil? ? nil : self.proxy.id,
18
+ :id_lnuser => self.lnuser.nil? ? nil : self.lnuser.id,
19
+ :worker_assigned_process => PROCESS.worker.assigned_process,
20
+ :profile_name => self.profile_name,
21
+ :agent_name => self.agent_name,
22
+ })
23
+ parsed = JSON.parse(res.body)
24
+ if parsed['status'] != "success"
25
+ raise "Error Tracing BrowserActivity: #{parsed['status']}"
26
+ end
27
+ end
28
+
29
+ def push_screenshot(filename=nil)
30
+ filename = "#{PROCESS.fullWorkerName}.png" if filename.nil?
31
+ BrowserFactory::screenshot(filename)
32
+
33
+ image = MiniMagick::Image.open(filename)
34
+ w = (image[:width].to_f * 0.25).to_i
35
+ h = (image[:height].to_f * 0.25).to_i
36
+ image.resize "#{w.to_s}x#{h.to_s}"
37
+ image.format "png"
38
+ image.write filename
39
+
40
+ url = "#{BlackStack::Pampa::api_protocol}://#{PROCESS.ws_url}:#{PROCESS.ws_port}/api1.3/pampa/browser/screenshot.json"
41
+ res = RestClient::Request.execute(
42
+ :api_key => BlackStack::Pampa::api_key,
43
+ :verify_ssl => false,
44
+ :url => url,
45
+ :method => :post,
46
+ :headers => {
47
+ :accept => 'application/json',
48
+ :params => {
49
+ :api_key => BlackStack::Pampa.api_key,
50
+ :filename => filename,
51
+ },
52
+ },
53
+ :payload => {
54
+ :file => File.new(filename, "r"),
55
+ :multipart => false,
56
+ }
57
+ )
58
+ parsed = JSON.parse(res.body)
59
+ if parsed['status'] != "success"
60
+ raise "Error Uploading Screenshot: #{parsed['status']}"
61
+ end
62
+ end
63
+
64
+ def back
65
+ self.notify("back")
66
+ super
67
+ self.push_screenshot
68
+ end
69
+
70
+ def forward
71
+ self.notify("forward")
72
+ super
73
+ self.push_screenshot
74
+ end
75
+
76
+ def execute_script(script, *args)
77
+ self.notify("execute_script")
78
+ super
79
+ self.push_screenshot
80
+ end
81
+
82
+ def goto(url)
83
+ self.notify("goto")
84
+ super
85
+ self.push_screenshot
86
+ end
87
+
88
+ def screenshot
89
+ self.notify("screenshot")
90
+ super
91
+ end
92
+
93
+ def reset!
94
+ self.notify("reset!")
95
+ super
96
+ end
97
+
98
+ def refresh
99
+ self.notify("refresh")
100
+ super
101
+ self.push_screenshot
102
+ end
103
+
104
+ def inspect
105
+ self.notify("inspect")
106
+ super
107
+ end
108
+
109
+ =begin # se da de baja, porque incremente el # de llamadas a la API de 800/hora a 5000/hora, y eso requiere mas infraestructura
110
+ def send_keys(*args)
111
+ self.notify("send_keys")
112
+ super
113
+ end
114
+ =end
115
+
116
+ def text
117
+ self.notify("text")
118
+ super
119
+ end
120
+
121
+ def title
122
+ self.notify("title")
123
+ super
124
+ end
125
+
126
+ def url
127
+ self.notify("url")
128
+ super
129
+ end
130
+
131
+ def wait(timeout = 5)
132
+ self.notify("wait")
133
+ super
134
+ end
135
+ end # class PampaBrowser
136
+
137
+
138
+ class BrowserFactory
139
+ LOCKING_FILENAME = BlackStack::MyProcess.macaddress # manejo de concurrencia en la creación de browsers
140
+ PROFILE_PID_LIST_FILENAME = "./browserfactory.%PRFILE_NAME%.list" # manejo de concurrencia en la creación de browsers
141
+ PROFILE_PID_LOCK_FILENAME = "./browserfactory.%PRFILE_NAME%.lock" # manejo de concurrencia en la creación de browsers
142
+ CHROME_EXTENSION_DIRECTORY = File.absolute_path('./chrome_extension')
143
+ DEFAULT_LOAD_TIMEOUT = 360
144
+ DEFAULT_CHROMEDRIVER_PATH = 'chromedriver.exe'
145
+
146
+ def self.addPidToProfileList(profile_name, pid)
147
+ fname = PROFILE_PID_LIST_FILENAME.gsub('%PRFILE_NAME%', profile_name)
148
+ f = File.open(fname, 'a')
149
+ f.write("#{pid},")
150
+ f.close
151
+ end
152
+
153
+ def self.removePidToProfileList(profile_name, pid)
154
+ fname = PROFILE_PID_LIST_FILENAME.gsub('%PRFILE_NAME%', profile_name)
155
+ s = File.read(fname)
156
+ s = s.gsub("#{pid},", "")
157
+ f = File.open(fname, 'w')
158
+ f.write(s)
159
+ f.close
160
+ end
161
+
162
+ def self.readPidToProfileList(profile_name)
163
+ if (profile_name != nil)
164
+ fname = PROFILE_PID_LIST_FILENAME.gsub('%PRFILE_NAME%', profile_name)
165
+ s = File.read(fname)
166
+ return s.split(",")
167
+ else
168
+ return []
169
+ end
170
+ end
171
+
172
+ def self.updateProfileList()
173
+ addPidToProfileList(@@profile_name, @@pid)
174
+ PROCESS.list().select { |p| p[:ppid] == @@pid && p[:executablepath] =~ /chrome\.exe/ }.each { |p2|
175
+ addPidToProfileList(@@profile_name, p2[:pid])
176
+ }
177
+ end
178
+
179
+ TYPE_PHANTOMJS = 0 # discontinued!
180
+ TYPE_FIREFOX = 1
181
+ TYPE_CHROME = 2
182
+
183
+ @@fd = File.open(LOCKING_FILENAME,"w")
184
+ @@fd_profile = nil
185
+ @@driver = nil
186
+ @@browser = nil
187
+ @@pid = nil
188
+ @@profile_name = nil
189
+
190
+
191
+ def self.lockProfileList()
192
+ # @@fd_profile.flock(File::LOCK_EX)
193
+ end
194
+
195
+ def self.releaseProfileList()
196
+ # @@fd_profile.flock(File::LOCK_UN)
197
+ =begin
198
+ begin
199
+ @@fd_profile.close
200
+ rescue
201
+ end
202
+ @@fd_profile = nil
203
+ =end
204
+ end
205
+
206
+
207
+ # NOTA: esta lista debe estar permitida por LinkedIn. De caso contrario, aparecera el mensaje "Upgrad your browser"
208
+ # Se puede obtener una lista actualizada de este sitio: https://techblog.willshouse.com/2012/01/03/most-common-user-agents/
209
+ @@arAgents = [
210
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36",
211
+ "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36",
212
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0",
213
+ "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36",
214
+ "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:56.0) Gecko/20100101 Firefox/56.0",
215
+ "Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko",
216
+ "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063",
217
+ ]
218
+
219
+ # toma una captura del area visible de la pagina
220
+ # mas informacion: https://stackoverflow.com/questions/25543651/screenshot-of-entire-webpage-using-selenium-webdriver-rc-rails
221
+ def self.screenshot(filename)
222
+ @@driver.save_screenshot(filename)
223
+ end
224
+
225
+ def self.agents()
226
+ return @@arAgents
227
+ end
228
+
229
+ def self.getPid()
230
+ return @@pid
231
+ end
232
+
233
+ def self.isCreated()
234
+ if (self.readPidToProfileList(@@profile_name).size>0)
235
+ return true
236
+ end
237
+ if (@@browser != nil)
238
+ return true
239
+ end
240
+
241
+ return false
242
+ end
243
+
244
+ def self.isCreated?
245
+ self.isCreated()
246
+ end
247
+
248
+ def self.reservation_id()
249
+ q = "SELECT TOP 1 reservation_id FROM browserfactory WHERE host_name='#{Socket.gethostname}'"
250
+ row = DB[q].first
251
+ if (row == nil)
252
+ DB.execute("INSERT INTO browserfactory (reservation_id, reservation_time, host_name) VALUES (NULL, NULL, '#{Socket.gethostname}')")
253
+ end
254
+ row = DB[q].first
255
+ return row[:reservation_id]
256
+ end
257
+
258
+ def self.lock()
259
+ @@fd.flock(File::LOCK_EX)
260
+ end
261
+
262
+ def self.release()
263
+ @@fd.flock(File::LOCK_UN)
264
+ end
265
+
266
+ def self.destroy()
267
+ self.lockProfileList()
268
+ self.readPidToProfileList(@@profile_name).each { |pid|
269
+ MyProcess.kill(pid)
270
+ self.removePidToProfileList(@@profile_name, pid)
271
+ }
272
+ self.releaseProfileList()
273
+ begin
274
+ if (@@browser != nil)
275
+ @@browser.close
276
+ else
277
+ end
278
+ rescue => e
279
+ #
280
+ end
281
+ # reseteo las variables
282
+ @@browser = nil
283
+ @@pid = nil
284
+ @@profile_name = nil
285
+ @@driver = nil
286
+ @@type = nil
287
+ end
288
+
289
+ #
290
+ def self.chrome_version
291
+ res = `reg query \"HKEY_CURRENT_USER\\Software\\Google\\Chrome\\BLBeacon\" /v version`.scan(/REG_SZ (.*)$/).first
292
+ return nil if res.nil?
293
+ return res[0] if res.size > 0
294
+ return nil
295
+ end
296
+
297
+ #
298
+ def self.chromedriver_version(filename=nil)
299
+ res = `chromedriver -v`.scan(/ChromeDriver\s(.*)\s\(/).first if filename.nil?
300
+ res = `#{filename} -v`.scan(/ChromeDriver\s(.*)\s\(/).first if !filename.nil?
301
+ return nil if res.nil?
302
+ return res[0] if res.size > 0
303
+ return nil
304
+ end
305
+
306
+ #
307
+ def self.chrome(h)
308
+ # TODO: check if h is a hash
309
+ # TODO: check the variable type of each param
310
+ # TODO: check mandatory params
311
+ self.launch_chrome(
312
+ h[:proxy],
313
+ h[:load_timeout].nil? ? DEFAULT_LOAD_TIMEOUT : h[:load_timeout],
314
+ h[:user_agent],
315
+ h[:profile_name],
316
+ h[:chromedriver_path],
317
+ h[:chromedriver_signature]
318
+ )
319
+ end
320
+
321
+ def self.mimic(mimic_profile_id)
322
+ begin
323
+ # Levantar el flag de reserva a mi favor
324
+ self.lock()
325
+
326
+ @@profile_name = mimic_profile_id
327
+ url_2 = nil
328
+ i = 0
329
+ max = 2
330
+ while (i<max && url_2.nil?)
331
+ i += 1
332
+ url = "http://127.0.0.1:#{BlackStack::StealthBrowserAutomation::Multilogin::mla_local_port}/api/v1/profile/start?automation=true&profileId=#{@@profile_name}"
333
+ uri = URI.parse(url)
334
+ req = Net::HTTP::Get.new(url)
335
+ res = Net::HTTP.start(uri.host, uri.port, :use_ssl => true, :verify_mode => OpenSSL::SSL::VERIFY_NONE) {|http|
336
+ http.request(req)
337
+ }
338
+ res = JSON.parse(res.body)
339
+ if !res.has_key?('status')
340
+ if i<max
341
+ self.release() # libero el flag de reserva de turno para crar un browser
342
+ raise "Error removing Multilogin profile: #{res.to_s}"
343
+ end
344
+ elsif res['status'] != 'OK'
345
+ if i<max
346
+ self.release() # libero el flag de reserva de turno para crar un browser
347
+ raise "Error removing Multilogin profile: #{res['status'].to_s}"
348
+ end
349
+ else
350
+ url_2 = res['value']
351
+ end
352
+ end
353
+
354
+ if !url_2.nil?
355
+ #uri_2 = URI.parse(url_2)
356
+ #req_2 = Net::HTTP::Get.new(url_2)
357
+ #res_2 = Net::HTTP.start(uri_2.host, uri_2.port, :use_ssl => true, :verify_mode => OpenSSL::SSL::VERIFY_NONE) {|http|
358
+ # http.request(req_2)
359
+ #}
360
+ @@driver = Selenium::WebDriver.for(:remote, :url => url_2, :desired_capabilities => nil)
361
+ bridge = @@driver.instance_variable_get(:@bridge)
362
+ service = bridge.instance_variable_get(:@service)
363
+ process = service.instance_variable_get(:@process)
364
+ @@pid = process.pid.to_s # es el PID del chromedriver
365
+ @@driver.manage.window().maximize()
366
+ @@browser = Watir::Browser.new(@@driver)
367
+ self.updateProfileList
368
+ end
369
+
370
+ rescue => e
371
+ p1 = PROCESS.list().select { |p| p[:ppid] == PROCESS.pid && p[:executablepath] =~ /chromedriver(.*)\.exe/ }.first
372
+ if (p1 != nil)
373
+ @@pid = p1[:pid]
374
+ self.updateProfileList
375
+ end
376
+ self.releaseProfileList()
377
+ raise e
378
+ end
379
+
380
+ #
381
+ self.releaseProfileList()
382
+
383
+ # libero el flag de reserva de turno para crar un browser
384
+ self.release()
385
+ end
386
+
387
+ #
388
+ def self.launch_chrome(proxy=nil, load_timeout=DEFAULT_LOAD_TIMEOUT, user_agent=nil, profile_name=nil, chromedriver_path=nil, chromedriver_signature=nil)
389
+ #
390
+ @@browser = nil
391
+ @@driver = nil
392
+ @@profile_name = profile_name
393
+
394
+ #
395
+ fname = PROFILE_PID_LOCK_FILENAME.gsub('%PRFILE_NAME%', @@profile_name)
396
+ @@fd_profile = File.open(fname,"w")
397
+
398
+ #
399
+ agent = @@arAgents[0] if user_agent.nil?
400
+ agent = user_agent if !user_agent.nil?
401
+
402
+ # #959 - valido que el parametro agents sea un array - porque si se pasa un string se lo procesa como array y se toma un UA name de un char.
403
+ #raise "Array expected in parameter agents in BrowserFactory.create." if !(agent.is_a? String)
404
+
405
+ #
406
+ while (@@browser == nil)
407
+
408
+ # Levantar el flag de reserva a mi favor
409
+ self.lock()
410
+
411
+ begin
412
+ client = Selenium::WebDriver::Remote::Http::Default.new
413
+ begin
414
+ client.read_timeout = load_timeout # for newest selenium webdriver version
415
+ rescue => e
416
+ client.timeout = load_timeout # deprecated in newest selenium webdriver version
417
+ end
418
+
419
+ # se agregan extensiones por el issue #1171
420
+ #
421
+ # UPDATE: Las extensiones en JavaScript para eliminar rastros, dejan rastros en si mismas.
422
+ #
423
+ switches = ["lang=en", "--log-level=3", "--user-agent=#{agent}", "disable-infobars", "load-extension=#{File.absolute_path('../chrome_extension')}"]
424
+
425
+ #
426
+ if (profile_name!=nil)
427
+
428
+ # issue #964
429
+ filename = "#{profile_name}/#{profile_name}/Default/Preferences"
430
+ if ( File.file?(filename) == true )
431
+ File.delete(filename)
432
+ end
433
+
434
+ # issue #964
435
+ filename = "#{profile_name}/#{profile_name}/Local State"
436
+ if ( File.file?(filename) == true )
437
+ File.delete(filename)
438
+ end
439
+
440
+ # configuro el browser para que use este perfil
441
+ switches += ["--user-data-dir=#{profile_name}/#{profile_name}"]
442
+
443
+ end
444
+
445
+ if (proxy!=nil)
446
+ switches += proxy.chrome_switches
447
+ end
448
+
449
+ self.lockProfileList()
450
+
451
+ begin
452
+
453
+ Selenium::WebDriver::Chrome.driver_path = chromedriver_path if !chromedriver_path.nil?
454
+ Selenium::WebDriver::Chrome.driver_path = DEFAULT_CHROMEDRIVER_PATH if chromedriver_path.nil?
455
+
456
+ @@driver = Selenium::WebDriver.for :chrome, :switches => switches
457
+ bridge = @@driver.instance_variable_get(:@bridge)
458
+ service = bridge.instance_variable_get(:@service)
459
+ process = service.instance_variable_get(:@process)
460
+ @@pid = process.pid.to_s # es el PID del chromedriver
461
+ @@driver.manage.window().maximize()
462
+ @@browser = PampaBrowser.new(@@driver)
463
+ @@browser.proxy = proxy.clone if !proxy.nil?
464
+ @@browser.agent_name = agent
465
+ @@browser.profile_name = profile_name
466
+ self.updateProfileList
467
+ rescue => e
468
+ p1 = PROCESS.list().select { |p| p[:ppid] == PROCESS.pid && p[:executablepath] =~ /chromedriver(.*)\.exe/ }.first
469
+ if (p1 != nil)
470
+ @@pid = p1[:pid]
471
+ self.updateProfileList
472
+ end
473
+ self.releaseProfileList()
474
+ raise e
475
+ end
476
+ self.releaseProfileList()
477
+
478
+ # Liberar el flag de reserva de creacion del browser
479
+ self.release()
480
+
481
+ #
482
+ rescue => e # TODO: Se atrapa una expecion porque sigue ocurreiendo el error reportado en el issue #134 y #129
483
+ # Liberar el flag de reserva de creacion del browser
484
+ self.release()
485
+
486
+ # disparar la exepcion
487
+ raise e
488
+ end
489
+ end # while
490
+
491
+ #
492
+ @@browser
493
+ end # create
494
+
495
+
496
+ end # class
497
+
498
+ end # module BlackStack
data/lib/proxy.rb ADDED
@@ -0,0 +1,80 @@
1
+ require_relative './baseproxy'
2
+
3
+ module BlackStack
4
+
5
+ # proxy almacenado en la base de datos
6
+ class Proxy < Sequel::Model(:proxy)
7
+ include BaseProxy
8
+
9
+ Proxy.dataset = Proxy.dataset.disable_insert_output
10
+
11
+ def self.availablesWithStealth(
12
+ process,
13
+ discretion_seconds_to_wait_if_proxy_has_been_reserved_but_didnt_finish,
14
+ discretion_seconds_to_wait_if_proxy_has_finished_successfully,
15
+ discretion_seconds_to_wait_if_proxy_has_been_blocked,
16
+ discretion_seconds_to_wait_for_long_sleep,
17
+ discretion_stop_from,
18
+ discretion_stop_until
19
+ )
20
+
21
+ q =
22
+ "SELECT COUNT(*) c FROM dbo.fnProxyDiscretion(" +
23
+ "'#{process}', " +
24
+ "#{discretion_seconds_to_wait_if_proxy_has_been_reserved_but_didnt_finish.to_s}, " +
25
+ "#{discretion_seconds_to_wait_if_proxy_has_finished_successfully.to_s}, " +
26
+ "#{discretion_seconds_to_wait_if_proxy_has_been_blocked.to_s}, " +
27
+ "#{discretion_seconds_to_wait_for_long_sleep.to_s}, " +
28
+ "'#{discretion_stop_from.to_s}', " +
29
+ "'#{discretion_stop_until.to_s}')"
30
+
31
+ return DB[q].first[:c].to_i
32
+ end
33
+
34
+ def self.getWithStealth(
35
+ process,
36
+ discretion_seconds_to_wait_if_proxy_has_been_reserved_but_didnt_finish,
37
+ discretion_seconds_to_wait_if_proxy_has_finished_successfully,
38
+ discretion_seconds_to_wait_if_proxy_has_been_blocked,
39
+ discretion_seconds_to_wait_for_long_sleep,
40
+ discretion_stop_from,
41
+ discretion_stop_until
42
+ )
43
+ rid = guid()
44
+ DB.execute(
45
+ "EXEC dbo.reserveProxyWithDiscretion " +
46
+ "'#{rid}', " +
47
+ "'#{process}', " +
48
+ "#{discretion_seconds_to_wait_if_proxy_has_been_reserved_but_didnt_finish.to_s}, " +
49
+ "#{discretion_seconds_to_wait_if_proxy_has_finished_successfully.to_s}, " +
50
+ "#{discretion_seconds_to_wait_if_proxy_has_been_blocked.to_s}, " +
51
+ "#{discretion_seconds_to_wait_for_long_sleep.to_s}, " +
52
+ "'#{discretion_stop_from.to_s}', " +
53
+ "'#{discretion_stop_until.to_s}'"
54
+ )
55
+ BlackStack::Proxy.where(:reservation_id=>rid).first
56
+ end
57
+
58
+ def startJob()
59
+ DB.execute("UPDATE proxy SET reservation_start_time=GETDATE() WHERE [id]='#{self.id}'")
60
+ end
61
+
62
+ # TODO: Reemplazar el parametro records_before_long_sleep por un registro en la tabla PARAMS
63
+ def endJob(id_object, result, description, records_before_long_sleep)
64
+ # => #464
65
+ =begin
66
+ DB.execute("UPDATE proxy SET reservation_end_time=GETDATE(), reservation_result='#{result.to_s}', reservation_description='#{description.to_s}' WHERE [id]='#{self.id}'")
67
+
68
+ DB.execute(
69
+ "EXEC dbo.endProxyJob " +
70
+ "'#{self.id}', " +
71
+ "'#{id_object}', " +
72
+ "#{result.to_s}, " +
73
+ "'#{description.to_s}', " +
74
+ "#{records_before_long_sleep.to_s} "
75
+ )
76
+ =end
77
+ end
78
+ end
79
+
80
+ end # module BlackStack
@@ -0,0 +1,8 @@
1
+
2
+ module BlackStack
3
+
4
+ class ProxyProvider < Sequel::Model(:proxyprovider)
5
+ ProxyProvider.dataset = ProxyProvider.dataset.disable_insert_output
6
+ end
7
+
8
+ end # module BlackStack
@@ -0,0 +1,9 @@
1
+
2
+ module BlackStack
3
+
4
+ class RemoteProxy
5
+ attr_accessor :id, :ip, :port, :user, :password
6
+ include BaseProxy
7
+ end
8
+
9
+ end # module BlackStack
@@ -0,0 +1,73 @@
1
+ require 'mini_magick'
2
+ require 'rest_client'
3
+ require 'pampa_workers'
4
+
5
+ require_relative './baseproxy'
6
+ require_relative './remoteproxy'
7
+ require_relative './browserfactory'
8
+
9
+ module BlackStack
10
+
11
+ module StealthBrowserAutomation
12
+
13
+ module Multilogin
14
+ #
15
+ @@auth_token = nil
16
+ @@mla_version = nil
17
+ @@mla_local_port = nil
18
+
19
+ def self.auth_token()
20
+ @@auth_token
21
+ end
22
+
23
+ def self.mla_version()
24
+ @@mla_version
25
+ end
26
+
27
+ def self.mla_local_port()
28
+ @@mla_local_port
29
+ end
30
+
31
+ def self.set(h)
32
+ @@auth_token = h[:auth_token]
33
+ @@mla_version = h[:mla_version]
34
+ @@mla_local_port = h[:mla_local_port]
35
+ end
36
+
37
+ # returns the profileId of the new Mimic profile
38
+ def self.create_profile(data)
39
+ url = "https://api.multiloginapp.com/v2/profile?token=#{BlackStack::StealthBrowserAutomation::Multilogin::auth_token.to_s}&mlaVersion=#{BlackStack::StealthBrowserAutomation::Multilogin::mla_version.to_s}"
40
+ uri = URI(url)
41
+ Net::HTTP.start(uri.host, uri.port, :use_ssl => true, :verify_mode => OpenSSL::SSL::VERIFY_NONE) do |http|
42
+ req = Net::HTTP::Post.new(uri)
43
+ req['Content-Type'] = 'application/json'
44
+ req.body = data.to_json
45
+ res = JSON.parse(http.request(req).body)
46
+ raise "Error creating Multilogin profile: #{res.to_s}" if !res.has_key?('uuid')
47
+ return res['uuid']
48
+ end
49
+ end
50
+
51
+ # returns the profileId of the new Mimic profile
52
+ def self.remove_profile(profile_id)
53
+ url = "https://api.multiloginapp.com/v1/profile/remove?token=#{BlackStack::StealthBrowserAutomation::Multilogin::auth_token.to_s}&profileId=#{profile_id}"
54
+ uri = URI.parse(url)
55
+ req = Net::HTTP::Get.new(url)
56
+ res = Net::HTTP.start(uri.host, uri.port, :use_ssl => true, :verify_mode => OpenSSL::SSL::VERIFY_NONE) {|http|
57
+ http.request(req)
58
+ }
59
+ res = JSON.parse(res.body)
60
+ raise "Error removing Multilogin profile: #{res.to_s}" if !res.has_key?('status')
61
+ raise "Error removing Multilogin profile: #{res['status'].to_s}" if res['status'] != 'OK'
62
+ end # def self.delete_profile
63
+ end # module MultiLogin
64
+
65
+ #
66
+ def self.require_db_classes()
67
+ # You have to load all the Sinatra classes after connect the database.
68
+ require_relative '../lib/proxy.rb'
69
+ end
70
+
71
+ end # module StealthBrowserAutomation
72
+
73
+ end # module BlackStack
metadata ADDED
@@ -0,0 +1,250 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: stealth_browser_automation
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.7
5
+ platform: ruby
6
+ authors:
7
+ - Leandro Daniel Sardi
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2019-12-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: mini_magick
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 4.9.3
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 4.9.3
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: 4.9.3
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 4.9.3
33
+ - !ruby/object:Gem::Dependency
34
+ name: rest-client
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: 2.0.2
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 2.0.2
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: 2.0.2
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 2.0.2
53
+ - !ruby/object:Gem::Dependency
54
+ name: websocket
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: 1.2.8
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 1.2.8
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: 1.2.8
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 1.2.8
73
+ - !ruby/object:Gem::Dependency
74
+ name: json
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: 1.8.1
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 1.8.1
83
+ type: :runtime
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 1.8.1
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 1.8.1
93
+ - !ruby/object:Gem::Dependency
94
+ name: tiny_tds
95
+ requirement: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - "~>"
98
+ - !ruby/object:Gem::Version
99
+ version: 1.0.5
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: 1.0.5
103
+ type: :runtime
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: 1.0.5
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: 1.0.5
113
+ - !ruby/object:Gem::Dependency
114
+ name: sequel
115
+ requirement: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - "~>"
118
+ - !ruby/object:Gem::Version
119
+ version: 4.28.0
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: 4.28.0
123
+ type: :runtime
124
+ prerelease: false
125
+ version_requirements: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - "~>"
128
+ - !ruby/object:Gem::Version
129
+ version: 4.28.0
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: 4.28.0
133
+ - !ruby/object:Gem::Dependency
134
+ name: blackstack_commons
135
+ requirement: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - "~>"
138
+ - !ruby/object:Gem::Version
139
+ version: 0.0.20
140
+ - - ">="
141
+ - !ruby/object:Gem::Version
142
+ version: 0.0.20
143
+ type: :runtime
144
+ prerelease: false
145
+ version_requirements: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - "~>"
148
+ - !ruby/object:Gem::Version
149
+ version: 0.0.20
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: 0.0.20
153
+ - !ruby/object:Gem::Dependency
154
+ name: simple_cloud_logging
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: 1.1.16
160
+ - - ">="
161
+ - !ruby/object:Gem::Version
162
+ version: 1.1.16
163
+ type: :runtime
164
+ prerelease: false
165
+ version_requirements: !ruby/object:Gem::Requirement
166
+ requirements:
167
+ - - "~>"
168
+ - !ruby/object:Gem::Version
169
+ version: 1.1.16
170
+ - - ">="
171
+ - !ruby/object:Gem::Version
172
+ version: 1.1.16
173
+ - !ruby/object:Gem::Dependency
174
+ name: simple_command_line_parser
175
+ requirement: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - "~>"
178
+ - !ruby/object:Gem::Version
179
+ version: 1.1.1
180
+ - - ">="
181
+ - !ruby/object:Gem::Version
182
+ version: 1.1.1
183
+ type: :runtime
184
+ prerelease: false
185
+ version_requirements: !ruby/object:Gem::Requirement
186
+ requirements:
187
+ - - "~>"
188
+ - !ruby/object:Gem::Version
189
+ version: 1.1.1
190
+ - - ">="
191
+ - !ruby/object:Gem::Version
192
+ version: 1.1.1
193
+ - !ruby/object:Gem::Dependency
194
+ name: pampa_workers
195
+ requirement: !ruby/object:Gem::Requirement
196
+ requirements:
197
+ - - "~>"
198
+ - !ruby/object:Gem::Version
199
+ version: 0.0.39
200
+ - - ">="
201
+ - !ruby/object:Gem::Version
202
+ version: 0.0.39
203
+ type: :runtime
204
+ prerelease: false
205
+ version_requirements: !ruby/object:Gem::Requirement
206
+ requirements:
207
+ - - "~>"
208
+ - !ruby/object:Gem::Version
209
+ version: 0.0.39
210
+ - - ">="
211
+ - !ruby/object:Gem::Version
212
+ version: 0.0.39
213
+ description: 'THIS GEM IS STILL IN DEVELOPMENT STAGE. Find documentation here: https://github.com/leandrosardi/stealth_browser_automation.'
214
+ email: leandro.sardi@expandedventure.com
215
+ executables: []
216
+ extensions: []
217
+ extra_rdoc_files: []
218
+ files:
219
+ - lib/baseproxy.rb
220
+ - lib/browserfactory.rb
221
+ - lib/proxy.rb
222
+ - lib/proxyprovider.rb
223
+ - lib/remoteproxy.rb
224
+ - lib/stealth_browser_automation.rb
225
+ homepage: https://rubygems.org/gems/stealth_browser_automation
226
+ licenses:
227
+ - MIT
228
+ metadata: {}
229
+ post_install_message:
230
+ rdoc_options: []
231
+ require_paths:
232
+ - lib
233
+ required_ruby_version: !ruby/object:Gem::Requirement
234
+ requirements:
235
+ - - ">="
236
+ - !ruby/object:Gem::Version
237
+ version: '0'
238
+ required_rubygems_version: !ruby/object:Gem::Requirement
239
+ requirements:
240
+ - - ">="
241
+ - !ruby/object:Gem::Version
242
+ version: '0'
243
+ requirements: []
244
+ rubyforge_project:
245
+ rubygems_version: 2.4.5.1
246
+ signing_key:
247
+ specification_version: 4
248
+ summary: THIS GEM IS STILL IN DEVELOPMENT STAGE. Scrape the web and automate social
249
+ accounts with not footprints. Track the browser acivity. Manage proxies stealthly.
250
+ test_files: []