ferrumwizard 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/lib/ferrumwizard.rb +148 -30
- metadata +2 -2
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eb46fd03834d035f319b5654848eb8db05c4d8d870b59f261657fedc42b60222
|
4
|
+
data.tar.gz: a0e9d66110acbf0439494087795620675b10743eb767891e28cd9d0db55b4475
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f7f3129f81ae7a79646f3ce13299a174265f7d42c1be53ef88dffe9461fddc42793c28b97ba55703d5ccfe62ef5aa5a9dd3a80665d3b3a897550de0d83325946
|
7
|
+
data.tar.gz: c7c5bac0cde40acc8d91a07e55890043bc16ae08d8533b4f0cf24719419cf62d5ee012b059dfd5d15befcd619140632cd4194dbb3294e09c1038f022ebccd524
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/lib/ferrumwizard.rb
CHANGED
@@ -8,96 +8,214 @@ require 'ferrum'
|
|
8
8
|
|
9
9
|
class FerrumWizard
|
10
10
|
|
11
|
-
attr_reader :browser, :links
|
11
|
+
attr_reader :browser, :links, :radio, :buttons, :js_methods
|
12
12
|
|
13
13
|
def initialize(url, headless: true, debug: false)
|
14
14
|
|
15
15
|
@url, @debug = url, debug
|
16
16
|
@browser = Ferrum::Browser.new headless: headless
|
17
|
-
|
17
|
+
sleep 2
|
18
|
+
end
|
19
|
+
|
20
|
+
def inspect()
|
21
|
+
"#<FerrumWizard>"
|
18
22
|
end
|
19
23
|
|
20
|
-
def login(username, password)
|
24
|
+
def login(usernamex=nil, passwordx=nil, username: usernamex, password: passwordx)
|
25
|
+
|
26
|
+
puts 'username: ' + username.inspect if @debug
|
21
27
|
|
22
28
|
b = @browser
|
23
29
|
b.goto(@url)
|
24
|
-
|
30
|
+
@browser.network.wait_for_idle
|
31
|
+
sleep 3
|
25
32
|
|
26
33
|
# search for the username input box
|
27
34
|
e_username = b.at_xpath('//input[@type="email"]')
|
28
|
-
|
35
|
+
puts 'e_username: ' + e_username.inspect if @debug
|
36
|
+
sleep 1
|
29
37
|
# search for the password input box
|
30
38
|
e_password = b.at_xpath('//input[@type="password"]')
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
39
|
+
sleep 1
|
40
|
+
|
41
|
+
if username and e_username then
|
42
|
+
puts 'entering the username' if @debug
|
43
|
+
e_username.focus.type(username)
|
44
|
+
sleep 1
|
37
45
|
end
|
38
46
|
|
47
|
+
e_password.focus.type(password, :Enter) if e_password
|
48
|
+
@browser.network.wait_for_idle
|
49
|
+
|
39
50
|
sleep 4
|
40
|
-
|
41
|
-
|
51
|
+
|
52
|
+
scan_page()
|
42
53
|
|
43
|
-
end
|
54
|
+
end
|
44
55
|
|
45
56
|
def quit
|
46
57
|
@browser.quit
|
47
58
|
end
|
59
|
+
|
60
|
+
def scan_page()
|
61
|
+
|
62
|
+
@doc = Rexle.new @browser.body
|
63
|
+
fetch_links()
|
64
|
+
scan_form_elements()
|
65
|
+
scan_js_links()
|
66
|
+
self
|
67
|
+
end
|
48
68
|
|
49
69
|
def to_rb()
|
50
70
|
end
|
51
71
|
|
52
72
|
private
|
53
73
|
|
74
|
+
def fetch_buttons()
|
75
|
+
|
76
|
+
a2 = @browser.xpath('//input[@type="button"]')
|
77
|
+
@buttons = a2.flat_map do |x|
|
78
|
+
|
79
|
+
a = x.value.split(/\W+/).map {|label| [label, x]}
|
80
|
+
a << [x.value, x]
|
81
|
+
a + a.map {|x, obj| [x.downcase, obj]}
|
82
|
+
|
83
|
+
end.to_h
|
84
|
+
|
85
|
+
names = @buttons.keys.map(&:downcase).uniq.select {|x| x =~ /^\w+$/}
|
86
|
+
buttons = @buttons
|
87
|
+
|
88
|
+
names.each do |name|
|
89
|
+
|
90
|
+
define_singleton_method name.to_sym do
|
91
|
+
buttons[name].click
|
92
|
+
@browser.network.wait_for_idle
|
93
|
+
sleep = 1
|
94
|
+
self
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
54
101
|
def fetch_links()
|
102
|
+
|
103
|
+
all_links = @doc.root.xpath('//a')
|
55
104
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
105
|
+
all_links.each do |x|
|
106
|
+
|
107
|
+
if x.plaintext.empty? then
|
108
|
+
x.text = x.attributes[:href].sub(/\.\w+$/,'')[/([^\/]+)$/].split(/[_]|(?=[A-Z])/).join(' ')
|
109
|
+
else
|
110
|
+
x.text = x.plaintext.gsub('&','&')
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
60
115
|
valid_links = all_links.reject do |x|
|
61
116
|
|
62
117
|
puts 'x: ' + x.inspect if @debug
|
63
|
-
|
64
|
-
r = (x.attributes[:target] == '_blank') | s.empty?
|
118
|
+
r = (x.attributes[:target] == '_blank')
|
65
119
|
|
66
120
|
puts 'r: ' + r.inspect if @debug
|
67
121
|
r
|
68
122
|
|
69
|
-
end
|
123
|
+
end
|
124
|
+
indices = valid_links.map {|x| all_links.index x}
|
70
125
|
|
71
|
-
active_links =
|
72
|
-
valid_active_links =
|
126
|
+
active_links = @browser.xpath('//a')
|
127
|
+
valid_active_links = indices.map {|n| active_links[n]}
|
73
128
|
|
74
129
|
|
75
|
-
@links = valid_active_links.flat_map do |x|
|
76
|
-
|
130
|
+
@links = valid_active_links.flat_map.with_index do |x, i|
|
131
|
+
|
132
|
+
a = valid_links[i].text.split(/\W+/).map {|label| [label, x]}
|
133
|
+
a << [valid_links[i].text, x]
|
134
|
+
|
135
|
+
puts 'a: ' + a.inspect if @debug
|
77
136
|
a + a.map {|x, obj| [x.downcase, obj]}
|
78
137
|
end.to_h
|
79
138
|
|
80
|
-
names = @links.keys.map(&:downcase).uniq.select {|x| x =~
|
139
|
+
names = @links.keys.map(&:downcase).uniq.select {|x| x =~ /^[\w ]+$/}
|
81
140
|
links = @links
|
82
141
|
|
83
142
|
names.each do |name|
|
84
143
|
|
85
|
-
define_singleton_method name.to_sym do
|
144
|
+
define_singleton_method name.gsub(/ +/,'_').to_sym do
|
86
145
|
links[name].click
|
87
|
-
sleep
|
146
|
+
sleep 1
|
147
|
+
scan_page()
|
88
148
|
self
|
89
149
|
end
|
90
150
|
|
91
151
|
end
|
92
152
|
|
93
|
-
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def scan_form_elements()
|
156
|
+
|
157
|
+
# find radio buttons
|
158
|
+
|
159
|
+
#a = doc.root.xpath('//input[@type="radio"]')
|
160
|
+
a = @browser.xpath('//input[@type="radio"]')
|
161
|
+
#h = a.group_by {|x| x.attributes[:name]}
|
162
|
+
h = a.group_by {|x| x.attribute('name')}
|
163
|
+
@radio = h.values
|
164
|
+
define_singleton_method(:on) { @radio[0][0].click; self }
|
165
|
+
define_singleton_method(:off) { @radio[0][1].click; self }
|
166
|
+
|
167
|
+
fetch_buttons()
|
168
|
+
|
169
|
+
end
|
170
|
+
|
171
|
+
def scan_js_links()
|
172
|
+
|
173
|
+
@js_methods = {}
|
174
|
+
b = @browser
|
175
|
+
|
176
|
+
b.xpath('//a').select {|x| x.attribute('href') =~ /^javascript/}.each do |e|
|
177
|
+
|
178
|
+
|
179
|
+
s = e.attribute('href')[/(?<=^javascript:)[^\(]+/]
|
180
|
+
puts 's: ' + s.inspect
|
181
|
+
a = s.split(/\W+|(?=[A-Z])/).map {|label| [label, s]}
|
182
|
+
a << [s, s]
|
183
|
+
a << [s.split(/\W+|(?=[A-Z])/).join('_'), s]
|
184
|
+
a << [s.split(/\W+|(?=[A-Z])/).join('_').downcase, s]
|
185
|
+
#@js_methods[s] = a
|
186
|
+
|
187
|
+
a.concat a.map {|x, name| [x.downcase, name] }
|
188
|
+
|
189
|
+
puts 'a: ' + a.inspect
|
190
|
+
|
191
|
+
a.uniq.select {|x, _| x =~ /^[a-z0-9_]+$/}.each do |x, name|
|
192
|
+
|
193
|
+
if @debug then
|
194
|
+
puts 'x: ' + x.inspect
|
195
|
+
puts 'name: ' + name.inspect
|
196
|
+
end
|
197
|
+
|
198
|
+
define_singleton_method(x.to_sym) do |*args|
|
199
|
+
#args = raw_args.map {|x| x[/^[0-9]+$/] ? x.to_i : x}
|
200
|
+
js_method = "%s(%s)" % [name, args.map(&:inspect).join(', ')]
|
201
|
+
puts 'js_method: ' + js_method.inspect if @debug
|
202
|
+
@browser.evaluate(js_method)
|
203
|
+
@browser.network.wait_for_idle
|
204
|
+
sleep 4
|
205
|
+
self.scan_page()
|
206
|
+
end
|
207
|
+
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|
211
|
+
end
|
94
212
|
|
95
213
|
def method_missing(method_name, *args)
|
96
214
|
|
215
|
+
puts 'method_missing: ' + method_name.inspect if @debug
|
97
216
|
node = @browser.at_css '.' + method_name.to_s
|
98
217
|
node.text if node
|
99
218
|
|
100
219
|
end
|
101
220
|
|
102
221
|
end
|
103
|
-
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ferrumwizard
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Robertson
|
@@ -35,7 +35,7 @@ cert_chain:
|
|
35
35
|
7e24hNRMt3t/JE9ogEO4JzFUH2vq2zzR5X9JQqEclWfwHi4cf8bZFJ7spjZQPjSZ
|
36
36
|
Ok3rs0A+kW4ixAj1rDYuoyG/
|
37
37
|
-----END CERTIFICATE-----
|
38
|
-
date: 2020-
|
38
|
+
date: 2020-08-01 00:00:00.000000000 Z
|
39
39
|
dependencies:
|
40
40
|
- !ruby/object:Gem::Dependency
|
41
41
|
name: rexle
|
metadata.gz.sig
CHANGED
Binary file
|