miketracy-wwmd 0.2.11
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.
- data/History.txt +3 -0
- data/README +62 -0
- data/README.txt +62 -0
- data/Rakefile +34 -0
- data/examples/config_example.yaml +24 -0
- data/examples/wwmd_example.rb +73 -0
- data/lib/wwmd.rb +78 -0
- data/lib/wwmd/encoding.rb +40 -0
- data/lib/wwmd/form.rb +110 -0
- data/lib/wwmd/form_array.rb +273 -0
- data/lib/wwmd/guid.rb +155 -0
- data/lib/wwmd/hpricot_html2text.rb +76 -0
- data/lib/wwmd/mixins.rb +318 -0
- data/lib/wwmd/mixins_extends.rb +188 -0
- data/lib/wwmd/mixins_external.rb +18 -0
- data/lib/wwmd/nokogiri_html2text.rb +41 -0
- data/lib/wwmd/page.rb +414 -0
- data/lib/wwmd/page/auth.rb +183 -0
- data/lib/wwmd/page/config.rb +44 -0
- data/lib/wwmd/page/constants.rb +60 -0
- data/lib/wwmd/page/headers.rb +107 -0
- data/lib/wwmd/page/inputs.rb +47 -0
- data/lib/wwmd/page/irb_helpers.rb +90 -0
- data/lib/wwmd/page/scrape.rb +202 -0
- data/lib/wwmd/page/spider.rb +127 -0
- data/lib/wwmd/page/urlparse.rb +79 -0
- data/lib/wwmd/page/utils.rb +30 -0
- data/lib/wwmd/viewstate.rb +118 -0
- data/lib/wwmd/viewstate/viewstate_class_helpers.rb +35 -0
- data/lib/wwmd/viewstate/viewstate_deserializer_methods.rb +213 -0
- data/lib/wwmd/viewstate/viewstate_from_xml.rb +126 -0
- data/lib/wwmd/viewstate/viewstate_types.rb +51 -0
- data/lib/wwmd/viewstate/viewstate_utils.rb +157 -0
- data/lib/wwmd/viewstate/viewstate_yaml.rb +25 -0
- data/lib/wwmd/viewstate/vs_array.rb +36 -0
- data/lib/wwmd/viewstate/vs_binary_serialized.rb +28 -0
- data/lib/wwmd/viewstate/vs_hashtable.rb +40 -0
- data/lib/wwmd/viewstate/vs_hybrid_dict.rb +40 -0
- data/lib/wwmd/viewstate/vs_indexed_string.rb +6 -0
- data/lib/wwmd/viewstate/vs_indexed_string_ref.rb +22 -0
- data/lib/wwmd/viewstate/vs_int_enum.rb +25 -0
- data/lib/wwmd/viewstate/vs_list.rb +32 -0
- data/lib/wwmd/viewstate/vs_pair.rb +27 -0
- data/lib/wwmd/viewstate/vs_read_types.rb +11 -0
- data/lib/wwmd/viewstate/vs_read_value.rb +33 -0
- data/lib/wwmd/viewstate/vs_sparse_array.rb +56 -0
- data/lib/wwmd/viewstate/vs_string.rb +29 -0
- data/lib/wwmd/viewstate/vs_string_array.rb +37 -0
- data/lib/wwmd/viewstate/vs_string_formatted.rb +30 -0
- data/lib/wwmd/viewstate/vs_triplet.rb +29 -0
- data/lib/wwmd/viewstate/vs_type.rb +21 -0
- data/lib/wwmd/viewstate/vs_unit.rb +28 -0
- data/lib/wwmd/viewstate/vs_value.rb +33 -0
- data/spec/README +3 -0
- data/spec/form_array.spec +49 -0
- data/spec/spider_csrf_test.spec +28 -0
- data/spec/urlparse_test.spec +89 -0
- data/tasks/ann.rake +80 -0
- data/tasks/bones.rake +20 -0
- data/tasks/gem.rake +201 -0
- data/tasks/git.rake +40 -0
- data/tasks/notes.rake +27 -0
- data/tasks/post_load.rake +34 -0
- data/tasks/rdoc.rake +51 -0
- data/tasks/rubyforge.rake +55 -0
- data/tasks/setup.rb +292 -0
- data/tasks/spec.rake +54 -0
- data/tasks/test.rake +40 -0
- data/tasks/zentest.rake +36 -0
- metadata +164 -0
@@ -0,0 +1,183 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
This is where we do all the undocumented auth stuff. NTLM is here and
|
3
|
+
hooked in.
|
4
|
+
|
5
|
+
WWMDNTLM is an incredibly naive NTLM implementation (used to get
|
6
|
+
around NTLM for one project ahwile back
|
7
|
+
=end
|
8
|
+
|
9
|
+
module WWMD
|
10
|
+
class Page
|
11
|
+
|
12
|
+
#:stopdoc:
|
13
|
+
|
14
|
+
#:section: Authentication helpers
|
15
|
+
|
16
|
+
# check if this request requires NTLM
|
17
|
+
def ntlm?
|
18
|
+
return false if self.code != 401
|
19
|
+
count = 0
|
20
|
+
self.header_data.each do |i|
|
21
|
+
if i[0] =~ /www-authenticate/i
|
22
|
+
count += 1 if (i[1] == "Negotiate" || i[1] == "NTLM")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
return (count > 0)
|
26
|
+
end
|
27
|
+
|
28
|
+
# does this request have an authenticate header?
|
29
|
+
def auth?
|
30
|
+
return false if self.code != 401
|
31
|
+
count = 0
|
32
|
+
self.header_data.each do |i|
|
33
|
+
if i[0] =~ /www-authenticate/i
|
34
|
+
count += 1
|
35
|
+
end
|
36
|
+
end
|
37
|
+
return (count > 0)
|
38
|
+
end
|
39
|
+
|
40
|
+
# not sure why this is here
|
41
|
+
def ntlm_perform(exp=nil)#:nodoc:
|
42
|
+
self.perform
|
43
|
+
return (self.code == exp)
|
44
|
+
end
|
45
|
+
|
46
|
+
# perform a get usig NTLM
|
47
|
+
def ntlm_get(url=nil?,debug=false)
|
48
|
+
self.clear_header('Authorization')
|
49
|
+
nobj = WWMDNTLM.new(self.opts)
|
50
|
+
self.url = @urlparse.parse(self.opts[:base_url],url) if not url.nil?
|
51
|
+
self.perform
|
52
|
+
return "This request does not appear to require NTLM" if not self.ntlm?
|
53
|
+
self.headers['Authorization'] = nobj.type_1_msg
|
54
|
+
self.perform
|
55
|
+
type2 = self.header_data.get_value('WWW-Authenticate')
|
56
|
+
nonce = nobj.get_nonce(type2)
|
57
|
+
type3 = nobj.type_3_msg(nonce)
|
58
|
+
self.headers['Authorization'] = type3
|
59
|
+
self.perform
|
60
|
+
self.clear_header('Authorization')
|
61
|
+
return self.code
|
62
|
+
end
|
63
|
+
|
64
|
+
#:startdoc:
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
class WWMDNTLM#:nodoc:
|
69
|
+
attr_accessor :hostname
|
70
|
+
attr_accessor :domain
|
71
|
+
attr_accessor :username
|
72
|
+
attr_accessor :password
|
73
|
+
attr_accessor :opts
|
74
|
+
attr_accessor :negotiate_flags
|
75
|
+
attr_accessor :debug
|
76
|
+
|
77
|
+
def initialize(opts,debug=false)
|
78
|
+
@opts = opts
|
79
|
+
@hostname = self.opts[:hostname]
|
80
|
+
@domain = self.opts[:domain]
|
81
|
+
@username = self.opts[:username]
|
82
|
+
@password = self.opts[:password]
|
83
|
+
@hostname = "LOCALHOST" if self.hostname.nil?
|
84
|
+
@negotiate_flags = 0x00002201.to_l32
|
85
|
+
@debug = debug
|
86
|
+
end
|
87
|
+
|
88
|
+
def type_1_msg
|
89
|
+
# do not add domain for now here as it doesn't seem to be needed
|
90
|
+
# it does need to be set for type3 messages
|
91
|
+
host_len = self.hostname.size
|
92
|
+
host_off = 0x20
|
93
|
+
# if self.domain.nil?
|
94
|
+
if true
|
95
|
+
dom_off = 0
|
96
|
+
dom_len = 0
|
97
|
+
else
|
98
|
+
dom_off = (host_off + hostname.size)
|
99
|
+
dom_len = self.domain.size
|
100
|
+
end
|
101
|
+
msg = ""
|
102
|
+
msg << "NTLMSSP\x00" # signature[8]
|
103
|
+
msg << 0x01.to_l32 # type[4]
|
104
|
+
msg << self.negotiate_flags # NegotiateFlags[4]
|
105
|
+
msg << dom_len.to_l16 # domain string length[2]
|
106
|
+
msg << dom_len.to_l16 # domain string length[2]
|
107
|
+
msg << dom_off.to_l32 # domain string offset[4]
|
108
|
+
msg << host_len.to_l16 # host string length[2]
|
109
|
+
msg << host_len.to_l16 # host string length[2]
|
110
|
+
msg << host_off.to_l32 # host string offset[4]
|
111
|
+
# msg << self.domain if not self.domain.nil? # domain[var]
|
112
|
+
msg << self.hostname # host name[var]
|
113
|
+
return "NTLM " + msg.b64e
|
114
|
+
end
|
115
|
+
|
116
|
+
def get_nonce(t2msg)
|
117
|
+
# Signature[8]
|
118
|
+
# MessageType[4]
|
119
|
+
# TargetNameFields[8]
|
120
|
+
# NegotiateFlags[4]
|
121
|
+
# ServerChallenge[8]
|
122
|
+
# Reserved[8] ! 0x00
|
123
|
+
# TargetInfoFields[8]
|
124
|
+
# Version[8]
|
125
|
+
# Payload[var]
|
126
|
+
msg = t2msg.split[1].b64d
|
127
|
+
return msg[24..31]
|
128
|
+
end
|
129
|
+
|
130
|
+
def type_3_msg(nonce)
|
131
|
+
hlen = 0x40
|
132
|
+
poff = hlen
|
133
|
+
domain = self.domain.to_utf16
|
134
|
+
username = self.username.to_utf16
|
135
|
+
hostname = self.hostname.to_utf16
|
136
|
+
lmresp = NTLM.lm_response(self.opts[:password],nonce,:lmhash)
|
137
|
+
ntresp = NTLM.lm_response(self.opts[:password],nonce,:nthash)
|
138
|
+
msg = ""
|
139
|
+
msg << "NTLMSSP\x00" # Signature[8]
|
140
|
+
msg << 0x03.to_l32 # MessageType[4]
|
141
|
+
# LmChallengeResonseFields[8]
|
142
|
+
msg << lmresp.size.to_l16 # LmChallengeResponseLen[2]
|
143
|
+
msg << lmresp.size.to_l16 # LmChallengeResponseMaxLen[2]
|
144
|
+
msg << poff.to_l32 # LmChallengeResponseBufferOffset[4]
|
145
|
+
poff += lmresp.size
|
146
|
+
# msg << 0x40.to_l32 # LmChallengeResponseBufferOffset[4]
|
147
|
+
# NtChallengeResponseFields[8]
|
148
|
+
msg << ntresp.size.to_l16 # NtChallengeResponseLen[2]
|
149
|
+
msg << ntresp.size.to_l16 # NtChallengeResponseMaxLen[2]
|
150
|
+
# msg << 0x58.to_l32 # NtChallengeResponseBufferOffset[4]
|
151
|
+
msg << poff.to_l32 # NtChallengeResponseBufferOffset[4]
|
152
|
+
poff += ntresp.size
|
153
|
+
# DomainNameFields[8]
|
154
|
+
msg << domain.size.to_l16 # DomainNameLen[2]
|
155
|
+
msg << domain.size.to_l16 # DomainNameMaxLen[2]
|
156
|
+
msg << poff.to_l32 # DomainNameBufferOffset[4]
|
157
|
+
poff += domain.size
|
158
|
+
# UserNameFields[8]
|
159
|
+
msg << username.size.to_l16 # UserNameLen[2]
|
160
|
+
msg << username.size.to_l16 # UserNameMaxLen[2]
|
161
|
+
msg << poff.to_l32 # UserNameBufferOffset[4]
|
162
|
+
poff += username.size
|
163
|
+
# WorkstationFields[8]
|
164
|
+
msg << hostname.size.to_l16 # WorkstationLen[2]
|
165
|
+
msg << hostname.size.to_l16 # WorkstationMaxLen[2]
|
166
|
+
msg << poff.to_l32 # WorkstationBufferOffset[4]
|
167
|
+
poff += hostname.size
|
168
|
+
# EncryptedRandomSessionKeyFields[8]
|
169
|
+
msg << 0x00.to_l16 # EncryptedRandomSessionKeyLen[2]
|
170
|
+
msg << 0x00.to_l16 # EncryptedRandomSessionKeyMaxLen[2]
|
171
|
+
msg << 0x00.to_l32 # EncryptedRandomSessionKeyBufferOffset[4]
|
172
|
+
msg << self.negotiate_flags # NegotiateFlags[4]
|
173
|
+
# Version[8] (optional do not add)
|
174
|
+
# Payload[var]
|
175
|
+
msg << lmresp # LmChallenge[var]
|
176
|
+
msg << ntresp # NtChallenge[var]
|
177
|
+
msg << domain # DomainName[var]
|
178
|
+
msg << username # UserName[var]
|
179
|
+
msg << hostname # Workstation[var]
|
180
|
+
return "NTLM " + msg.b64e
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module WWMD
|
2
|
+
class WWMDConfig
|
3
|
+
|
4
|
+
def self.load_config(file)
|
5
|
+
begin
|
6
|
+
config = YAML.load_file(file)
|
7
|
+
rescue => e
|
8
|
+
putw "config file not found #{file}"
|
9
|
+
putw e.inspect
|
10
|
+
exit
|
11
|
+
end
|
12
|
+
return config
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.parse_opts(args)
|
16
|
+
inopts = Hash.new
|
17
|
+
opts = OptionParser.new do |opts|
|
18
|
+
# set defaults
|
19
|
+
opts.on("-p", "--password PASSWORD", "Password") { |v| inopts[:password] = v }
|
20
|
+
opts.on("-u", "--username USERNAME", "Username") { |v| inopts[:username] = v }
|
21
|
+
opts.on("--header_file HEADER_FILE","Header file") { |v| inopts[:header_file] = v }
|
22
|
+
opts.on("--base_url BASE_URL","Base url") { |v| inopts[:base_url] = v }
|
23
|
+
opts.on("--use_proxy PROXY_URL", "Use proxy at url") do |v|
|
24
|
+
ENV['HTTP_PROXY'] = "http://" + v.to_s
|
25
|
+
inopts[:use_proxy] = true
|
26
|
+
inopts[:proxy_url] = v
|
27
|
+
end
|
28
|
+
opts.on("--no_proxy","do not use proxy") do |v|
|
29
|
+
inopts[:use_proxy] = false
|
30
|
+
inopts[:proxy_url] = nil
|
31
|
+
end
|
32
|
+
opts.on("--use_auth","login before getting url") { |v| inopts[:use_auth] = true }
|
33
|
+
opts.on("--no_auth","no login before getting url") { |v| inopts[:use_auth] = false }
|
34
|
+
opts.on("--debug","debugging really doesn't work") { |v| inopts[:debug] = true }
|
35
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
36
|
+
putx opts
|
37
|
+
exit
|
38
|
+
end
|
39
|
+
end
|
40
|
+
opts.parse!(args)
|
41
|
+
return inopts
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module WWMD
|
2
|
+
XSSFISH = "<;'\"}()[]>{"
|
3
|
+
|
4
|
+
DEFAULTS = {
|
5
|
+
:base_url => "",
|
6
|
+
:use_auth => true,
|
7
|
+
:enable_cookies => true,
|
8
|
+
:cookiejar => "./__cookiejar",
|
9
|
+
:follow_location => true,
|
10
|
+
:max_redirects => 20,
|
11
|
+
:use_proxy => false,
|
12
|
+
:debug => false,
|
13
|
+
:scrape_warn => true,
|
14
|
+
:parse => true,
|
15
|
+
:timeout => 20,
|
16
|
+
}
|
17
|
+
|
18
|
+
ESCAPE = {
|
19
|
+
:url => /[^a-zA-Z0-9\-_%]/,
|
20
|
+
:nalnum => /[^a-zA-Z0-9]/,
|
21
|
+
:xss => /[^a-zA-Z0-9=?&()']/,
|
22
|
+
:ltgt => /[<>]/,
|
23
|
+
:all => /.*/,
|
24
|
+
:b64 => /[=+\/]/,
|
25
|
+
:none => :none,
|
26
|
+
:default => :default,
|
27
|
+
}
|
28
|
+
|
29
|
+
UA = {
|
30
|
+
:mozilla => "Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.16) Gecko/20080702 Firefox/2.0.0.16",
|
31
|
+
:moz3 => "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.0.1) Gecko/2008070206 Firefox/3.0.1",
|
32
|
+
:ie6 => "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)",
|
33
|
+
:ie7 => "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)",
|
34
|
+
:ie8 => "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0)",
|
35
|
+
:opera => "Opera/9.20 (Windows NT 6.0; U; en)",
|
36
|
+
:safari => "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_4_11; en) AppleWebKit/525.18 (KHTML, like Gecko) Version/3.1.2 Safari/525.22"
|
37
|
+
}
|
38
|
+
|
39
|
+
DEFAULT_HEADERS = {
|
40
|
+
"User-Agent" => UA[:moz3],
|
41
|
+
"Accept" => "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
42
|
+
"Accept-Language" => "en-US,en;q=0.8,en-au;q=0.6,en-us;q=0.4,en;q=0.2",
|
43
|
+
"Accept-Encoding" => "gzip,deflate",
|
44
|
+
"Accept-Charset" => "SO-8859-1,utf-8;q=0.7,*;q=0.7",
|
45
|
+
"Keep-Alive" => "300",
|
46
|
+
"Connection" => "keep-alive",
|
47
|
+
}
|
48
|
+
|
49
|
+
HEADERS = {
|
50
|
+
:default => nil,
|
51
|
+
:utf7 => {
|
52
|
+
"Content-Type" => "application/x-www-form-urlencoded;charset=UTF-7",
|
53
|
+
"Content-Transfer-Encoding" => "7bit",
|
54
|
+
},
|
55
|
+
:ajax => {
|
56
|
+
"X-Requested-With" => "XMLHttpRequest",
|
57
|
+
"X-Prototype-Version" => "1.5.0",
|
58
|
+
},
|
59
|
+
}
|
60
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module WWMD
|
2
|
+
class Page
|
3
|
+
|
4
|
+
#:section: Header helper methods
|
5
|
+
|
6
|
+
# clear header at <key>
|
7
|
+
def clear_header(key)
|
8
|
+
self.headers.delete_if { |k,v| k.upcase == key.upcase }
|
9
|
+
return nil
|
10
|
+
end
|
11
|
+
|
12
|
+
alias_method :delete_header, :clear_header#:nodoc:
|
13
|
+
|
14
|
+
# clear all headers
|
15
|
+
def clear_headers
|
16
|
+
self.headers.delete_if { |k,v| true }
|
17
|
+
"headers cleared"
|
18
|
+
end
|
19
|
+
|
20
|
+
# set headers from passed argument
|
21
|
+
# Nil: set headers from WWMD::DEFAULT_HEADERS
|
22
|
+
# Symbol: entry in WWMD::HEADERS to set from
|
23
|
+
# Hash: hash to set headers from
|
24
|
+
# String: filename (NOT IMPLEMENTED)
|
25
|
+
#
|
26
|
+
# if clear == true then headers will be cleared before setting
|
27
|
+
def set_headers(arg=nil,clear=false)
|
28
|
+
self.clear_headers if clear
|
29
|
+
if arg.nil?
|
30
|
+
begin
|
31
|
+
self.clear_headers
|
32
|
+
WWMD::DEFAULT_HEADERS.each { |k,v| self.headers[k] = v }
|
33
|
+
return "headers set from default"
|
34
|
+
rescue => e
|
35
|
+
puts e
|
36
|
+
return "error setting headers"
|
37
|
+
end
|
38
|
+
elsif arg.class == Symbol
|
39
|
+
self.set_headers(WWMD::HEADERS[arg])
|
40
|
+
return "headers set from #{arg}"
|
41
|
+
elsif arg.class == Hash
|
42
|
+
arg.each { |k,v| self.headers[k] = v }
|
43
|
+
return "headers set from hash"
|
44
|
+
end
|
45
|
+
"error setting headers"
|
46
|
+
end
|
47
|
+
|
48
|
+
# set headers back to default headers
|
49
|
+
def default_headers(arg=nil)
|
50
|
+
self.set_headers
|
51
|
+
end
|
52
|
+
|
53
|
+
alias_method :set_default, :default_headers
|
54
|
+
|
55
|
+
# set headers from text
|
56
|
+
def headers_from_array(arr)
|
57
|
+
self.clear_headers
|
58
|
+
arr.each do |line|
|
59
|
+
h = line.split(":",2)
|
60
|
+
next if h[1].class != String
|
61
|
+
self.headers[h[0]] = h[1].strip
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# set headers from file
|
66
|
+
def headers_from_file(fn)
|
67
|
+
self.clear_headers
|
68
|
+
File.read(fn).each do |line|
|
69
|
+
h = line.split(":",2)
|
70
|
+
next if h[1].class != String
|
71
|
+
self.headers[h[0]] = h[1].strip
|
72
|
+
end
|
73
|
+
return nil
|
74
|
+
end
|
75
|
+
|
76
|
+
# set headers to utf7 encoding post
|
77
|
+
def set_utf7_headers
|
78
|
+
self.headers["Content-Type"] = "application/x-www-form-urlencoded;charset=UTF-7"
|
79
|
+
"headers set to utf7"
|
80
|
+
end
|
81
|
+
|
82
|
+
# set headers to ajax
|
83
|
+
def set_ajax_headers
|
84
|
+
self.headers["X-Requested-With"] = "XMLHttpRequest"
|
85
|
+
self.headers["X-Prototype-Version"] = "1.5.0"
|
86
|
+
return "headers set to ajax"
|
87
|
+
end
|
88
|
+
|
89
|
+
# set headers to SOAP request headers
|
90
|
+
def set_soap_headers
|
91
|
+
self.headers['Content-Type'] = "text/xml;charset=utf-8"
|
92
|
+
self.headers['SOAPAction'] = "\"\""
|
93
|
+
return "headers set to soap"
|
94
|
+
end
|
95
|
+
|
96
|
+
# get the current Cookie header
|
97
|
+
def get_cookie
|
98
|
+
self.headers["Cookie"]
|
99
|
+
end
|
100
|
+
|
101
|
+
# set the Cookie header
|
102
|
+
def set_cookie(cookie=nil)
|
103
|
+
self.headers["Cookie"] = cookie
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module WWMD
|
2
|
+
class Inputs
|
3
|
+
attr_accessor :elems
|
4
|
+
|
5
|
+
@cobj = '' # wwmd object
|
6
|
+
@elems = '' # array of elems parse out by self.new()
|
7
|
+
|
8
|
+
def initialize(*args)
|
9
|
+
@cobj = args.shift
|
10
|
+
end
|
11
|
+
|
12
|
+
def show
|
13
|
+
puts @elems
|
14
|
+
end
|
15
|
+
|
16
|
+
# call me from Page.set_data
|
17
|
+
def set
|
18
|
+
@elems = [@cobj.search("//input").map,@cobj.search("//select").map].flatten
|
19
|
+
end
|
20
|
+
|
21
|
+
def get(attr=nil)
|
22
|
+
@elems.map { |x| x[attr] }.reject { |y| y.nil? }
|
23
|
+
end
|
24
|
+
|
25
|
+
#
|
26
|
+
# return: FormArray containing all page inputs
|
27
|
+
def form
|
28
|
+
ret = {}
|
29
|
+
@elems.map do |x|
|
30
|
+
name = x['name']
|
31
|
+
id = x['id']
|
32
|
+
next if (name.nil? && id.nil?)
|
33
|
+
value = x['value']
|
34
|
+
type = x['type']
|
35
|
+
ret[name] = value
|
36
|
+
ret[id] = value if ((id || name) != name)
|
37
|
+
end
|
38
|
+
return FormArray.new(ret)
|
39
|
+
end
|
40
|
+
|
41
|
+
#
|
42
|
+
# return: FormArray containing get params
|
43
|
+
def params
|
44
|
+
return FormArray.new(@cobj.cur.clop.to_form)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
=begin rdoc
|
2
|
+
this file contains methods to help operations in irb (display methods etc.).
|
3
|
+
=end
|
4
|
+
module WWMD
|
5
|
+
class Page
|
6
|
+
|
7
|
+
#:section: IRB helper methods
|
8
|
+
|
9
|
+
def head(i=1)
|
10
|
+
if i.kind_of?(Range)
|
11
|
+
puts self.body_data.split("\n")[i].join("\n")
|
12
|
+
return nil
|
13
|
+
end
|
14
|
+
puts self.body_data.head(i)
|
15
|
+
end
|
16
|
+
|
17
|
+
# IRB: text report what has been parsed from this page
|
18
|
+
def report(short=nil)
|
19
|
+
putx "-------------------------------------------------"
|
20
|
+
self.summary
|
21
|
+
putx "---- links found [#{self.has_links?.to_s} | #{self.links.size}]"
|
22
|
+
self.links.each_index { |i| putx "#{i.to_s} :: #{@links[i]}" } if short.nil?
|
23
|
+
putx "---- javascript found [#{self.has_jlinks?.to_s} | #{self.jlinks.size}]"
|
24
|
+
self.jlinks.each { |url| putx url } if short.nil?
|
25
|
+
putx "---- forms found [#{self.has_form?.to_s} | #{self.forms.size}]"
|
26
|
+
putx "---- comments found [#{self.has_comments?.to_s}]"
|
27
|
+
return nil
|
28
|
+
end
|
29
|
+
|
30
|
+
alias_method :show, :report#:nodoc:
|
31
|
+
|
32
|
+
# IRB: display summary of what has been parsed from this page
|
33
|
+
def summary
|
34
|
+
status = self.page_status
|
35
|
+
putx "XXXX[#{self.report_flags}] | #{self.response_code.to_s} | #{status} | #{self.url} | #{self.size}"
|
36
|
+
return nil
|
37
|
+
end
|
38
|
+
|
39
|
+
# IRB: display current headers
|
40
|
+
def request_headers
|
41
|
+
self.headers.each_pair { |k,v| putx "#{k}: #{v}" }
|
42
|
+
return nil
|
43
|
+
end
|
44
|
+
|
45
|
+
alias_method :show_headers, :request_headers#:nodoc:
|
46
|
+
alias_method :req_headers, :request_headers#:nodoc:
|
47
|
+
|
48
|
+
# IRB: display response headers
|
49
|
+
def response_headers
|
50
|
+
self.header_data.each { |x| putx "#{x[0]} :: #{x[1]}" }
|
51
|
+
return nil
|
52
|
+
end
|
53
|
+
|
54
|
+
alias_method :resp_headers, :response_headers#:nodoc:
|
55
|
+
|
56
|
+
# display self.body_data
|
57
|
+
def dump_body
|
58
|
+
putx self.body_data
|
59
|
+
end
|
60
|
+
|
61
|
+
alias_method :dump, :dump_body#:nodoc:
|
62
|
+
|
63
|
+
# IRB: puts the page filtered through html2text
|
64
|
+
def to_text; putx self.html2text; end
|
65
|
+
def text; self.html2text; end
|
66
|
+
|
67
|
+
# IRB: display a human readable report of all forms contained in page.body_data
|
68
|
+
def all_forms
|
69
|
+
self.forms.each_index { |x| putx "[#{x.to_s}]-------"; self.forms[x].report }
|
70
|
+
nil
|
71
|
+
end
|
72
|
+
|
73
|
+
def onclicks
|
74
|
+
self.search("//*[@onclick]").each { |x| puts x[:onclick] }
|
75
|
+
nil
|
76
|
+
end
|
77
|
+
|
78
|
+
# hexdump self.body_data
|
79
|
+
def hexdump
|
80
|
+
puts self.body_data.hexdump
|
81
|
+
end
|
82
|
+
|
83
|
+
# this only works on a mac so get a mac
|
84
|
+
def open #:nodoc:
|
85
|
+
fn = "wwmdtmp_#{Guid.new}.html"
|
86
|
+
self.write(fn)
|
87
|
+
%x[open #{fn}]
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|