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,202 @@
|
|
1
|
+
module WWMD
|
2
|
+
LINKS_REGEXP = [
|
3
|
+
/window\.open\s*\(([^\)]+)/i,
|
4
|
+
/open_window\s*\(([^\)]+)/i,
|
5
|
+
/window\.location\s*=\s*(['"][^'"]+['"])/i,
|
6
|
+
/.*location.href\s*=\s*(['"][^'"]+['"])/i,
|
7
|
+
/document.forms.*action\s*=\s*(['"][^'"]+['"])/i,
|
8
|
+
/Ajax\.Request\s*\((['"][^'"]+['"])/i,
|
9
|
+
]
|
10
|
+
|
11
|
+
AJAX_REGEXP = [
|
12
|
+
/Ajax\.Request\s*\((['"][^'"]+['"])/i,
|
13
|
+
]
|
14
|
+
|
15
|
+
SRC_REGEXP = [
|
16
|
+
/src=\s*(['"][^'"]+['"])/i
|
17
|
+
]
|
18
|
+
|
19
|
+
# NOT_URL_CHAR = "[^0-9a-zA-Z\:\/\+\\-\%\#]"
|
20
|
+
|
21
|
+
class Scrape
|
22
|
+
|
23
|
+
attr_accessor :debug
|
24
|
+
attr_accessor :warn
|
25
|
+
attr_accessor :links # links found on page
|
26
|
+
attr_accessor :jlinks # links to javascript includes
|
27
|
+
|
28
|
+
attr_reader :hdoc
|
29
|
+
|
30
|
+
@debug = false
|
31
|
+
@warn = true
|
32
|
+
|
33
|
+
# create a new scrape object using passed HTML
|
34
|
+
def initialize(page='<>')
|
35
|
+
@page = page
|
36
|
+
@hdoc = HDOC.parse(@page)
|
37
|
+
@links = Array.new
|
38
|
+
@debug = false
|
39
|
+
@warn = true
|
40
|
+
end
|
41
|
+
|
42
|
+
# reset this scrape object (called by WWMD::Page)
|
43
|
+
def reset(page)
|
44
|
+
@page = page
|
45
|
+
@hdoc = HDOC.parse(@page)
|
46
|
+
@links = Array.new
|
47
|
+
end
|
48
|
+
|
49
|
+
# scan the passed string for the configured regular expressions
|
50
|
+
# and return them as an array
|
51
|
+
def urls_from_regexp(content,re,split=0)
|
52
|
+
ret = []
|
53
|
+
scrape = content.scan(re)
|
54
|
+
scrape.each do |url|
|
55
|
+
# cheat and take split string(,)[split]
|
56
|
+
add = url.to_s.split(',')[split].gsub(/['"]/, '')
|
57
|
+
next if (add == '' || add.nil?)
|
58
|
+
ret << add
|
59
|
+
end
|
60
|
+
return ret
|
61
|
+
end
|
62
|
+
|
63
|
+
# xpath search for tags and return the passed attribute
|
64
|
+
# urls_from_xpath("//a","href")
|
65
|
+
def urls_from_xpath(xpath,attr)
|
66
|
+
ret = []
|
67
|
+
@hdoc.search(xpath).each do |elem|
|
68
|
+
url = elem[attr]
|
69
|
+
next if url.empty?
|
70
|
+
ret << url.strip
|
71
|
+
end
|
72
|
+
return ret
|
73
|
+
end
|
74
|
+
|
75
|
+
# <b>NEED</b> to move this to external configuration
|
76
|
+
#
|
77
|
+
# list of urls we don't care to store in our links list
|
78
|
+
def reject_links
|
79
|
+
putw "WARN: override reject_links in helper script" if @warn
|
80
|
+
default_reject_links
|
81
|
+
end
|
82
|
+
|
83
|
+
# default reject links (override using reject_links in helper script)
|
84
|
+
def default_reject_links
|
85
|
+
@links.reject! do |url|
|
86
|
+
url.nil? ||
|
87
|
+
url.extname == ".css" ||
|
88
|
+
url.extname == ".pdf" ||
|
89
|
+
url =~ /javascript:/i ||
|
90
|
+
url =~ /mailto:/i ||
|
91
|
+
url =~ /[\[\]]/ ||
|
92
|
+
url =~ /^#/
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# define an urls_from_helper method in your task specific script
|
97
|
+
def urls_from_helper
|
98
|
+
putw "WARN: Please set an urls_from_helper override in your helper script" if @warn
|
99
|
+
return nil
|
100
|
+
end
|
101
|
+
|
102
|
+
# use xpath searches to get
|
103
|
+
# * //a href
|
104
|
+
# * //area href
|
105
|
+
# * //frame src
|
106
|
+
# * //iframe src
|
107
|
+
# * //form action
|
108
|
+
# * //meta refresh content urls
|
109
|
+
# then get //script tags and regexp out links in javascript function calls
|
110
|
+
# from elem.inner_html
|
111
|
+
def for_links(reject=true)
|
112
|
+
self.urls_from_xpath("//a","href").each { |url| @links << url }; # get <a href=""> elements
|
113
|
+
self.urls_from_xpath("//area","href").each { |url| @links << url }; # get <area href=""> elements
|
114
|
+
self.urls_from_xpath("//frame","src").each { |url| @links << url }; # get <frame src=""> elements
|
115
|
+
self.urls_from_xpath("//iframe","src").each { |url| @links << url }; # get <iframe src=""> elements
|
116
|
+
self.urls_from_xpath("//form","action").each { |url| @links << url }; # get <form action=""> elements
|
117
|
+
|
118
|
+
# <meta> refresh
|
119
|
+
@hdoc.search("//meta").each do |meta|
|
120
|
+
next if meta['http-equiv'] != "refresh"
|
121
|
+
next if not (content = meta['content'].split(/=/)[1])
|
122
|
+
@links << content.strip
|
123
|
+
end
|
124
|
+
|
125
|
+
# add urls from onclick handlers
|
126
|
+
@hdoc.search("*[@onclick]").each do |onclick|
|
127
|
+
LINKS_REGEXP.each do |re|
|
128
|
+
self.urls_from_regexp(onclick['onclick'],re).each do |url|
|
129
|
+
@links << url
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# add urls_from_regexp (limit to <script> tags (elem.inner_html))
|
135
|
+
@hdoc.search("//script").each do |scr|
|
136
|
+
LINKS_REGEXP.each do |re|
|
137
|
+
self.urls_from_regexp(scr.inner_html,re).each { |url| @links << url }
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# re-define urls_from_helper in what you mix in
|
142
|
+
begin
|
143
|
+
self.urls_from_helper
|
144
|
+
end
|
145
|
+
|
146
|
+
self.reject_links; # reject links we don't care about
|
147
|
+
return @links
|
148
|
+
end
|
149
|
+
|
150
|
+
# scrape the page for <script src=""> tags
|
151
|
+
def for_javascript_links
|
152
|
+
urls = []
|
153
|
+
@hdoc.search("//script[@src]").each { |tag| urls << tag['src'] }
|
154
|
+
urls.reject! { |url| File.extname(url).clip != ".js" }
|
155
|
+
return urls
|
156
|
+
end
|
157
|
+
|
158
|
+
# scan page for comment fields
|
159
|
+
def for_comments
|
160
|
+
@page.scan(/\<!\s*--(.*?)--\s*\>/m).map { |x| x.to_s }
|
161
|
+
end
|
162
|
+
|
163
|
+
# scrape the page for a meta refresh tag and return the url from the contents attribute or nil
|
164
|
+
def for_meta_refresh
|
165
|
+
has_mr = @hdoc.search("//meta").map { |x| x['http-equiv'] }.include?('Refresh')
|
166
|
+
if has_mr
|
167
|
+
urls = @hdoc.search("//meta[@content]").map { |x| x['content'].split(";",2)[1] }
|
168
|
+
if urls.size > 1
|
169
|
+
STDERR.puts "PARSE ERROR: more than one meta refresh tag"
|
170
|
+
return "ERR"
|
171
|
+
end
|
172
|
+
k,v = urls.first.split("=",2)
|
173
|
+
if k.upcase.strip != "URL"
|
174
|
+
STDERR.puts "PARSE ERROR: content attribute of meta refresh does not contain url"
|
175
|
+
return "ERR"
|
176
|
+
end
|
177
|
+
return v.strip
|
178
|
+
else
|
179
|
+
return nil
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
# scrape the page for a script tag that contains a bare location.href tag (to redirect the page)
|
184
|
+
def for_javascript_redirect
|
185
|
+
redirs = []
|
186
|
+
@hdoc.search("//script").each do |scr|
|
187
|
+
scr.inner_html.scan(/.*location.href\s*=\s*['"]([^'"]+)['"]/i).each { |x| redirs += x }
|
188
|
+
end
|
189
|
+
if redirs.size > 1
|
190
|
+
STDERR.puts "PARSE ERROR: more than one javascript redirect"
|
191
|
+
return "ERR"
|
192
|
+
end
|
193
|
+
return redirs.first if not redirs.empty?
|
194
|
+
return nil
|
195
|
+
end
|
196
|
+
|
197
|
+
# renamed class variable (for backward compat)
|
198
|
+
def warnings#:nodoc:
|
199
|
+
return @warn
|
200
|
+
end
|
201
|
+
end
|
202
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module WWMD
|
2
|
+
# when a WWMD::Page object is created, it created its own WWMD::Spider object
|
3
|
+
# which can be accessed using <tt>page.spider.method</tt>. The <tt>page.set_data</tt>
|
4
|
+
# method calls <tt>page.spider.add</tt> with the current url and a list of scraped
|
5
|
+
# links from the page. This class doesn't do any real heavy lifting.
|
6
|
+
#
|
7
|
+
# a simple spider can be written just by recursing through page.spider.next until
|
8
|
+
# it's empty.
|
9
|
+
class Spider
|
10
|
+
|
11
|
+
attr_accessor :queued
|
12
|
+
attr_accessor :visited
|
13
|
+
attr_accessor :bypass
|
14
|
+
attr_accessor :local_only
|
15
|
+
attr_reader :opts
|
16
|
+
attr_accessor :ignore
|
17
|
+
attr_accessor :csrf_token
|
18
|
+
|
19
|
+
DEFAULT_IGNORE = [
|
20
|
+
/logoff/i,
|
21
|
+
/logout/i,
|
22
|
+
]
|
23
|
+
|
24
|
+
# pass me opts and an array of regexps to ignore
|
25
|
+
# we have a set of sane(ish) defaults here
|
26
|
+
def initialize(opts={},ignore=nil)
|
27
|
+
@opts = opts
|
28
|
+
@visited = []
|
29
|
+
@queued = []
|
30
|
+
@bypass = []
|
31
|
+
@local_only = true
|
32
|
+
@csrf_token = nil
|
33
|
+
if !opts[:spider_local_only].nil?
|
34
|
+
@local_only = opts[:spider_local_only]
|
35
|
+
end
|
36
|
+
@ignore = ignore || DEFAULT_IGNORE
|
37
|
+
end
|
38
|
+
|
39
|
+
# push an url onto the queue
|
40
|
+
def push_url(url)
|
41
|
+
return false if _check_ignore(url)
|
42
|
+
url = _de_csrf(url)
|
43
|
+
if @local_only
|
44
|
+
return false if !(url =~ /#{@opts[:base_url]}/)
|
45
|
+
end
|
46
|
+
@bypass.each { |b| return true if (url =~ b) }
|
47
|
+
@queued.push(url) if (@visited.find { |v| v == url }.nil? and @queued.find { |q| q == url }.nil?)
|
48
|
+
return true
|
49
|
+
end
|
50
|
+
|
51
|
+
# skip items in the queue
|
52
|
+
def skip(tim=1)
|
53
|
+
tim.times { |i| @queued.shift }
|
54
|
+
return true
|
55
|
+
end
|
56
|
+
|
57
|
+
# get the next url in the queue
|
58
|
+
def get_next
|
59
|
+
return queued.shift
|
60
|
+
end
|
61
|
+
|
62
|
+
alias_method :next, :get_next
|
63
|
+
|
64
|
+
# more elements in the queue?
|
65
|
+
def next?
|
66
|
+
return !queued.empty?
|
67
|
+
end
|
68
|
+
|
69
|
+
# get the last ul we visited? this doesn't look right
|
70
|
+
def get_last(url)
|
71
|
+
tmp = @visited.reject { |v| v =~ /#{url}/ }
|
72
|
+
return tmp[-1]
|
73
|
+
end
|
74
|
+
|
75
|
+
# show the visited list (or the entry in the list at [id])
|
76
|
+
def show_visited(id=nil)
|
77
|
+
if id.nil?
|
78
|
+
@visited.each_index { |i| putx i.to_s + " :: " + @visited[i].to_s }
|
79
|
+
return nil
|
80
|
+
else
|
81
|
+
return @visited[id]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
alias_method :v, :show_visited
|
86
|
+
|
87
|
+
# return the current queue (or the entry in the queue at [id]
|
88
|
+
def show_queue(id=nil)
|
89
|
+
if id.nil?
|
90
|
+
@queued.each_index { |i| putx i.to_s + " :: " + @queued[i].to_s }
|
91
|
+
return nil
|
92
|
+
else
|
93
|
+
return @queued[id]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
alias_method :q, :show_queue
|
98
|
+
|
99
|
+
# add url to queue
|
100
|
+
def add(url='',links=[])
|
101
|
+
@visited.push(_de_csrf(url))
|
102
|
+
links.each { |l| self.push_url l }
|
103
|
+
return nil
|
104
|
+
end
|
105
|
+
|
106
|
+
# set up the ignore list
|
107
|
+
# ignore list is an array of regexp objects
|
108
|
+
# remember to set this up before calling any Page methods
|
109
|
+
def set_ignore(arr)
|
110
|
+
@ignore = arr
|
111
|
+
end
|
112
|
+
|
113
|
+
def _de_csrf(url)
|
114
|
+
return url if @csrf_token.nil?
|
115
|
+
act,params = url.clopa
|
116
|
+
form = params.to_form
|
117
|
+
return url if !form.has_key?(@csrf_token)
|
118
|
+
form[@csrf_token] = ''
|
119
|
+
url = act + form.to_get
|
120
|
+
end
|
121
|
+
|
122
|
+
def _check_ignore(url)
|
123
|
+
@ignore.each { |x| return true if (url =~ x) }
|
124
|
+
return false
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module WWMD
|
2
|
+
# yay for experiments in re-inventing the wheel
|
3
|
+
class URLParse
|
4
|
+
HANDLERS = [:https,:http,:ftp,:file]
|
5
|
+
attr_reader :proto,:location,:path,:script,:rpath,:params,:base_url,:fqpath
|
6
|
+
|
7
|
+
def initialize()
|
8
|
+
# nothing to see here, move along
|
9
|
+
end
|
10
|
+
|
11
|
+
def parse(*args)
|
12
|
+
if args.size == 1
|
13
|
+
base = ""
|
14
|
+
actual = args.shift
|
15
|
+
else
|
16
|
+
base = args.shift
|
17
|
+
actual = args.shift
|
18
|
+
end
|
19
|
+
@proto = @location = @path = @script = @rpath = nil
|
20
|
+
@base = base.to_s
|
21
|
+
@actual = actual
|
22
|
+
if self.has_proto?
|
23
|
+
@base = @actual
|
24
|
+
@actual = ""
|
25
|
+
end
|
26
|
+
# does this work for http://location/? probably not
|
27
|
+
@base += "/" if (!@base.has_ext? || @base.split("/").size == 3)
|
28
|
+
@rpath = make_me_path.join("/")
|
29
|
+
@params = @rpath.clop
|
30
|
+
@path = "/" + @rpath
|
31
|
+
if @rpath.has_ext?
|
32
|
+
@path = "/" + @rpath.dirname
|
33
|
+
@script = @rpath.basename.clip
|
34
|
+
end
|
35
|
+
@script = "" if @script.nil?
|
36
|
+
@base_url = @proto + "://" + @location
|
37
|
+
@fqpath = @path + @script
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
def make_me_path
|
42
|
+
@proto,tpath = @base.split(":",2)
|
43
|
+
tpath ||= ""
|
44
|
+
if @actual.empty?
|
45
|
+
a_path = tpath.split("/").reject { |x| x.empty? }
|
46
|
+
else
|
47
|
+
a_path = tpath.dirname.split("/").reject { |x| x.empty? }
|
48
|
+
end
|
49
|
+
@location = a_path.shift
|
50
|
+
a_path = [] if (@actual =~ (/^\//))
|
51
|
+
b_path = @actual.split("/").reject { |x| x.empty? }
|
52
|
+
a_path.pop if (a_path[-1] =~ /^\?/).kind_of?(Fixnum) && !b_path.empty?
|
53
|
+
c_path = (a_path + @actual.split("/").reject { |x| x.empty? }).flatten
|
54
|
+
d_path = []
|
55
|
+
c_path.each do |x|
|
56
|
+
(d_path.pop;next) if x == ".."
|
57
|
+
next if x == "."
|
58
|
+
d_path << x
|
59
|
+
end
|
60
|
+
return d_path
|
61
|
+
end
|
62
|
+
|
63
|
+
def has_proto?
|
64
|
+
return true if HANDLERS.include?(@actual.split(":").first.downcase.to_sym)
|
65
|
+
return false
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_s
|
69
|
+
return "#{@proto}://#{@location}/#{rpath}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class String
|
75
|
+
def has_ext? #:nodoc:
|
76
|
+
return false if self.basename.split(".",2)[1].empty?
|
77
|
+
return true
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module WWMD
|
2
|
+
class WWMDUtils
|
3
|
+
|
4
|
+
def self.header_array_from_file(filename)
|
5
|
+
ret = Hash.new
|
6
|
+
File.readlines(filename).each do |line|
|
7
|
+
a = line.chomp.split(/\t/,2)
|
8
|
+
ret[a[0]] = a[1]
|
9
|
+
end
|
10
|
+
return ret
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.ranstr(len=8,digits=false)
|
14
|
+
chars = ("a".."z").to_a
|
15
|
+
chars += ("0".."9").to_a if digits
|
16
|
+
ret = ""
|
17
|
+
1.upto(len) { |i| ret << chars[rand(chars.size-1)] }
|
18
|
+
return ret
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.rannum(len=8,hex=false)
|
22
|
+
chars = ("0".."9").to_a
|
23
|
+
chars += ("A".."F").to_a if hex
|
24
|
+
ret = ""
|
25
|
+
1.upto(len) { |i| ret << chars[rand(chars.size-1)] }
|
26
|
+
return ret
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'wwmd/viewstate/viewstate_utils'
|
2
|
+
module WWMD
|
3
|
+
class ViewState < ViewStateUtils
|
4
|
+
end
|
5
|
+
end
|
6
|
+
require 'rubygems'
|
7
|
+
require 'nokogiri'
|
8
|
+
require 'htmlentities'
|
9
|
+
require 'rexml/document'
|
10
|
+
require 'wwmd/mixins'
|
11
|
+
require 'wwmd/mixins_extends'
|
12
|
+
require 'wwmd/viewstate/viewstate_types'
|
13
|
+
require 'wwmd/viewstate/viewstate_class_helpers'
|
14
|
+
require 'wwmd/viewstate/viewstate_yaml'
|
15
|
+
require 'wwmd/viewstate/viewstate_deserializer_methods'
|
16
|
+
require 'wwmd/viewstate/viewstate_from_xml'
|
17
|
+
require 'wwmd/viewstate/vs_read_value'
|
18
|
+
require 'wwmd/viewstate/vs_read_types'
|
19
|
+
require 'wwmd/viewstate/vs_value'
|
20
|
+
require 'wwmd/viewstate/vs_array'
|
21
|
+
require 'wwmd/viewstate/vs_binary_serialized'
|
22
|
+
require 'wwmd/viewstate/vs_int_enum'
|
23
|
+
require 'wwmd/viewstate/vs_hashtable'
|
24
|
+
require 'wwmd/viewstate/vs_hybrid_dict'
|
25
|
+
require 'wwmd/viewstate/vs_list'
|
26
|
+
require 'wwmd/viewstate/vs_pair'
|
27
|
+
require 'wwmd/viewstate/vs_sparse_array'
|
28
|
+
require 'wwmd/viewstate/vs_string'
|
29
|
+
require 'wwmd/viewstate/vs_string_array'
|
30
|
+
require 'wwmd/viewstate/vs_string_formatted'
|
31
|
+
require 'wwmd/viewstate/vs_triplet'
|
32
|
+
require 'wwmd/viewstate/vs_type'
|
33
|
+
require 'wwmd/viewstate/vs_unit'
|
34
|
+
require 'wwmd/viewstate/vs_indexed_string'
|
35
|
+
require 'wwmd/viewstate/vs_indexed_string_ref'
|
36
|
+
module WWMD
|
37
|
+
class ViewState
|
38
|
+
attr_accessor :b64
|
39
|
+
attr_accessor :obj_queue
|
40
|
+
attr_accessor :mac
|
41
|
+
attr_accessor :debug
|
42
|
+
attr_reader :raw
|
43
|
+
attr_reader :stack
|
44
|
+
attr_reader :bufarr
|
45
|
+
attr_reader :magic
|
46
|
+
attr_reader :size
|
47
|
+
attr_reader :indexed_strings
|
48
|
+
attr_reader :last_offset
|
49
|
+
attr_reader :xml
|
50
|
+
|
51
|
+
def initialize(b64=nil)
|
52
|
+
@b64 = b64
|
53
|
+
@raw = ""
|
54
|
+
@stack = ""
|
55
|
+
@obj_queue = []
|
56
|
+
@bufarr = []
|
57
|
+
@size = 0
|
58
|
+
@indexed_strings = []
|
59
|
+
@mac = nil
|
60
|
+
@debug = false
|
61
|
+
end
|
62
|
+
|
63
|
+
# mac_enabled?
|
64
|
+
def mac_enabled?
|
65
|
+
return !@mac.nil?
|
66
|
+
end
|
67
|
+
|
68
|
+
# deserialize
|
69
|
+
def deserialize(b64=nil)
|
70
|
+
@obj_queue = []
|
71
|
+
@b64 = b64 if b64
|
72
|
+
@raw = @b64.b64d
|
73
|
+
@bufarr = @raw.scan(/./m)
|
74
|
+
@size = @bufarr.size
|
75
|
+
raise "Invalid ViewState" if not self.magic?
|
76
|
+
@obj_queue << self.deserialize_value
|
77
|
+
if @bufarr.size == 20 then
|
78
|
+
@mac = bufarr.slice!(0..19).join("")
|
79
|
+
dlog(0x00,"MAC = #{@mac.hexify}")
|
80
|
+
end
|
81
|
+
raise "Error Parsing Viewstate (left: #{@buffarr.size})" if not @bufarr.size == 0
|
82
|
+
return !self.raw.nil?
|
83
|
+
end
|
84
|
+
|
85
|
+
def serialize(objs=nil,version=2)
|
86
|
+
@obj_queue = objs if objs
|
87
|
+
@stack << "\xFF\x01"
|
88
|
+
@stack << @obj_queue.first.serialize
|
89
|
+
@stack << @mac if @mac
|
90
|
+
return !self.stack.nil?
|
91
|
+
end
|
92
|
+
|
93
|
+
def to_xml
|
94
|
+
@xml = REXML::Document.new()
|
95
|
+
header = REXML::Element.new("ViewState")
|
96
|
+
header.add_attribute("version", @magic.b64e)
|
97
|
+
header.add_attribute("version_string", @magic.hexify)
|
98
|
+
header.add_element(@obj_queue.first.to_xml)
|
99
|
+
if self.mac_enabled?
|
100
|
+
max = REXML::Element.new("Mac")
|
101
|
+
max.add_attribute("encoding","hexify")
|
102
|
+
max.add_text(@mac.hexify)
|
103
|
+
header.add_element(max)
|
104
|
+
end
|
105
|
+
@xml.add_element(header)
|
106
|
+
@xml
|
107
|
+
end
|
108
|
+
|
109
|
+
def from_yaml(yaml)
|
110
|
+
@obj_queue = YAML.load(yaml)
|
111
|
+
end
|
112
|
+
|
113
|
+
def to_yaml
|
114
|
+
@obj_queue.to_yaml
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
end
|