stratagem 0.1.7 → 0.1.8
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/Manifest +16 -4
- data/Rakefile +2 -2
- data/lib/bootstrap.rb +1 -0
- data/lib/stratagem/auto_mock/aquifer.rb +15 -7
- data/lib/stratagem/auto_mock/factory.rb +12 -2
- data/lib/stratagem/auto_mock/value_generator.rb +1 -1
- data/lib/stratagem/commands.rb +0 -1
- data/lib/stratagem/crawler/authentication.rb +116 -54
- data/lib/stratagem/crawler/form.rb +12 -0
- data/lib/stratagem/crawler/html_utils.rb +19 -7
- data/lib/stratagem/crawler/session.rb +156 -68
- data/lib/stratagem/crawler/site_model.rb +21 -7
- data/lib/stratagem/crawler/trace_utils.rb +3 -1
- data/lib/stratagem/extensions/trace_compression.rb +52 -0
- data/lib/stratagem/extensions.rb +1 -0
- data/lib/stratagem/framework_extensions/models/adapters/active_model/metadata.rb +3 -8
- data/lib/stratagem/framework_extensions/models/adapters/active_model/tracing.rb +21 -2
- data/lib/stratagem/framework_extensions/models/adapters/common/detect.rb +7 -0
- data/lib/stratagem/framework_extensions/models/adapters/common/extensions.rb +0 -0
- data/lib/stratagem/framework_extensions/models/adapters/common/metadata.rb +36 -0
- data/lib/stratagem/framework_extensions/models/adapters/common/tracing.rb +4 -0
- data/lib/stratagem/framework_extensions/models/adapters/{common → util}/authentication_metadata.rb +0 -0
- data/lib/stratagem/framework_extensions/models/annotations.rb +23 -1
- data/lib/stratagem/framework_extensions/models/metadata.rb +3 -3
- data/lib/stratagem/framework_extensions/models/tracing.rb +32 -10
- data/lib/stratagem/framework_extensions/models.rb +2 -2
- data/lib/stratagem/model/application.rb +8 -4
- data/lib/stratagem/model/components/base.rb +3 -0
- data/lib/stratagem/model/components/controller.rb +22 -23
- data/lib/stratagem/model/components/model.rb +3 -2
- data/lib/stratagem/model/components/reference.rb +24 -13
- data/lib/stratagem/model/components/route.rb +0 -3
- data/lib/stratagem/model/components/view.rb +1 -0
- data/lib/stratagem/model_builder.rb +9 -11
- data/lib/stratagem/site_crawler.rb +14 -19
- data/lib/stratagem.rb +1 -1
- data/spec/model/component_spec.rb +43 -0
- data/spec/model/components/view_spec.rb +43 -0
- data/spec/model/test_spec.rb +10 -0
- data/spec/samples/404.html.erb +30 -0
- data/spec/samples/_form.html.erb +8 -0
- data/spec/samples/index.html.erb +77 -0
- data/spec/samples/sample_model.rb +5 -0
- data/spec/samples/signup.html.erb +14 -0
- data/spec/scan/checks/email_address_spec.rb +24 -0
- data/spec/scan/checks/error_pages_spec.rb +22 -0
- data/stratagem.gemspec +7 -4
- metadata +50 -21
- data/lib/stratagem/commands/devel_crawl.rb +0 -27
- data/lib/stratagem/scan/checks/ssl/secure_login_page.rb +0 -19
- data/lib/stratagem/scan/checks/ssl/secure_login_submit.rb +0 -18
data/Manifest
CHANGED
@@ -15,7 +15,6 @@ lib/stratagem/command.rb
|
|
15
15
|
lib/stratagem/commands.rb
|
16
16
|
lib/stratagem/commands/analyze.rb
|
17
17
|
lib/stratagem/commands/base.rb
|
18
|
-
lib/stratagem/commands/devel_crawl.rb
|
19
18
|
lib/stratagem/commands/devel_mock.rb
|
20
19
|
lib/stratagem/crawler.rb
|
21
20
|
lib/stratagem/crawler/authentication.rb
|
@@ -31,6 +30,7 @@ lib/stratagem/extensions/module.rb
|
|
31
30
|
lib/stratagem/extensions/object.rb
|
32
31
|
lib/stratagem/extensions/red_parse.rb
|
33
32
|
lib/stratagem/extensions/string.rb
|
33
|
+
lib/stratagem/extensions/trace_compression.rb
|
34
34
|
lib/stratagem/framework_extensions.rb
|
35
35
|
lib/stratagem/framework_extensions/controllers.rb
|
36
36
|
lib/stratagem/framework_extensions/controllers/action_controller.rb
|
@@ -44,11 +44,15 @@ lib/stratagem/framework_extensions/models/adapters/authlogic/detect.rb
|
|
44
44
|
lib/stratagem/framework_extensions/models/adapters/authlogic/extensions.rb
|
45
45
|
lib/stratagem/framework_extensions/models/adapters/authlogic/metadata.rb
|
46
46
|
lib/stratagem/framework_extensions/models/adapters/authlogic/tracing.rb
|
47
|
-
lib/stratagem/framework_extensions/models/adapters/common/
|
47
|
+
lib/stratagem/framework_extensions/models/adapters/common/detect.rb
|
48
|
+
lib/stratagem/framework_extensions/models/adapters/common/extensions.rb
|
49
|
+
lib/stratagem/framework_extensions/models/adapters/common/metadata.rb
|
50
|
+
lib/stratagem/framework_extensions/models/adapters/common/tracing.rb
|
48
51
|
lib/stratagem/framework_extensions/models/adapters/restful_authentication/detect.rb
|
49
52
|
lib/stratagem/framework_extensions/models/adapters/restful_authentication/extensions.rb
|
50
53
|
lib/stratagem/framework_extensions/models/adapters/restful_authentication/metadata.rb
|
51
54
|
lib/stratagem/framework_extensions/models/adapters/restful_authentication/tracing.rb
|
55
|
+
lib/stratagem/framework_extensions/models/adapters/util/authentication_metadata.rb
|
52
56
|
lib/stratagem/framework_extensions/models/annotations.rb
|
53
57
|
lib/stratagem/framework_extensions/models/detect.rb
|
54
58
|
lib/stratagem/framework_extensions/models/metadata.rb
|
@@ -90,10 +94,18 @@ lib/stratagem/scan/checks/filter_parameter_logging.rb
|
|
90
94
|
lib/stratagem/scan/checks/mongo_mapper/base.rb
|
91
95
|
lib/stratagem/scan/checks/mongo_mapper/foreign_keys_exposed.rb
|
92
96
|
lib/stratagem/scan/checks/routes.rb
|
93
|
-
lib/stratagem/scan/checks/ssl/secure_login_page.rb
|
94
|
-
lib/stratagem/scan/checks/ssl/secure_login_submit.rb
|
95
97
|
lib/stratagem/scan/result.rb
|
96
98
|
lib/stratagem/scanner.rb
|
97
99
|
lib/stratagem/site_crawler.rb
|
98
100
|
lib/stratagem/snapshot.rb
|
99
101
|
lib/tasks/_old_stratagem.rake
|
102
|
+
spec/model/component_spec.rb
|
103
|
+
spec/model/components/view_spec.rb
|
104
|
+
spec/model/test_spec.rb
|
105
|
+
spec/samples/404.html.erb
|
106
|
+
spec/samples/_form.html.erb
|
107
|
+
spec/samples/index.html.erb
|
108
|
+
spec/samples/sample_model.rb
|
109
|
+
spec/samples/signup.html.erb
|
110
|
+
spec/scan/checks/email_address_spec.rb
|
111
|
+
spec/scan/checks/error_pages_spec.rb
|
data/Rakefile
CHANGED
@@ -2,14 +2,14 @@ require 'rubygems'
|
|
2
2
|
require 'rake'
|
3
3
|
require 'echoe'
|
4
4
|
|
5
|
-
Echoe.new('stratagem', '0.1.
|
5
|
+
Echoe.new('stratagem', '0.1.8') do |p|
|
6
6
|
p.description = "Intuitive security analysis of your Rails applications"
|
7
7
|
p.url = "http://github.com/stratagem/stratagem"
|
8
8
|
p.author = "Charles Grimes"
|
9
9
|
p.email = "cj@stratagemapp.com"
|
10
10
|
p.executable_pattern = ['bin/*']
|
11
11
|
p.ignore_pattern = ["tmp/*", "script/*", "spec/*", "webapp/*"]
|
12
|
-
p.runtime_dependencies = ["launchy >=0.3.5", "redparse >=0.8.4", "haml >=3.0.0"]
|
12
|
+
p.runtime_dependencies = ["launchy >=0.3.5", "redparse >=0.8.4", "haml >=3.0.0", "nokogiri >=1.4.3"]
|
13
13
|
p.development_dependencies = ["launchy >=0.3.5", "redparse >=0.8.4", "sinatra =1.0", "haml >=3.0.0", "webrat >=0.4.3"]
|
14
14
|
# p.requirements ["Install the stratagem-ui gem for the web browser interface."]
|
15
15
|
end
|
data/lib/bootstrap.rb
CHANGED
@@ -35,31 +35,39 @@ module Stratagem::AutoMock
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def instances_of(model_klass)
|
38
|
-
repo[model_klass].clone
|
38
|
+
objects = (repo[model_klass.name] || []).clone
|
39
|
+
puts "found #{objects.size} instances in well"
|
40
|
+
objects
|
39
41
|
end
|
40
42
|
|
41
43
|
def random_instance(model_klass)
|
42
|
-
objects = repo[model_klass]
|
44
|
+
objects = repo[model_klass.name]
|
43
45
|
puts "found #{objects.size} instances in well"
|
44
46
|
instance = objects[rand objects.size]
|
45
47
|
instance
|
46
48
|
end
|
47
49
|
|
48
|
-
def fill
|
50
|
+
def fill(model_count=nil)
|
49
51
|
Stratagem.logger.phase "mocking_models"
|
50
52
|
application.models.each do |meta_model|
|
51
|
-
models = mock_model(meta_model.klass) if (meta_model.stratagem?)
|
53
|
+
models = mock_model(meta_model.klass, model_count) if (meta_model.stratagem?)
|
52
54
|
end
|
53
55
|
puts "aquifer full"
|
56
|
+
print
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
60
|
+
def print
|
54
61
|
application.models.each do |meta_model|
|
55
62
|
puts "#{meta_model.klass.name}"
|
56
|
-
(repo[meta_model.klass] || []).each do |instance|
|
57
|
-
puts "\t#{instance.
|
63
|
+
(repo[meta_model.klass.name] || []).each do |instance|
|
64
|
+
puts "\t#{instance.class} - #{instance}"
|
58
65
|
end
|
59
66
|
end
|
60
67
|
end
|
61
68
|
|
62
|
-
def mock_model(klass, count=
|
69
|
+
def mock_model(klass, count=nil)
|
70
|
+
count ||= 6
|
63
71
|
count.times do |i|
|
64
72
|
instance,valid = mock(klass)
|
65
73
|
end
|
@@ -11,6 +11,13 @@ module Stratagem::AutoMock
|
|
11
11
|
module Factory
|
12
12
|
include ValueGenerator
|
13
13
|
|
14
|
+
def mock_attributes(model)
|
15
|
+
object = model.new
|
16
|
+
populate_attributes(object, [])
|
17
|
+
correct_invalid_columns(object, [])
|
18
|
+
object.stratagem.mock_attributes
|
19
|
+
end
|
20
|
+
|
14
21
|
def mock(model,mock_chain=[], belongs_to=nil)
|
15
22
|
return if mock_chain.select {|m| m == model }.size > 1
|
16
23
|
mock_chain << model
|
@@ -47,13 +54,13 @@ module Stratagem::AutoMock
|
|
47
54
|
protected
|
48
55
|
|
49
56
|
def add_mocked(instance)
|
50
|
-
(mocked
|
57
|
+
(mocked(instance.class)) << instance
|
51
58
|
end
|
52
59
|
|
53
60
|
def mocked(model=nil)
|
54
61
|
@mocked ||= {}
|
55
62
|
if (model)
|
56
|
-
@mocked[model] ||= []
|
63
|
+
@mocked[model.name] ||= []
|
57
64
|
else
|
58
65
|
@mocked
|
59
66
|
end
|
@@ -174,6 +181,9 @@ module Stratagem::AutoMock
|
|
174
181
|
end
|
175
182
|
puts $!.backtrace unless valid
|
176
183
|
end
|
184
|
+
|
185
|
+
puts "\t#{object.stratagem.mock_attributes.inspect}" if (valid)
|
186
|
+
|
177
187
|
valid
|
178
188
|
end
|
179
189
|
|
@@ -51,7 +51,7 @@ module Stratagem::AutoMock
|
|
51
51
|
else
|
52
52
|
raise Stratagem::AutoMock::UnsupportedColumnTypeError.new("Attribute #{attribute_name} of type #{attribute_type} is not supported")
|
53
53
|
end
|
54
|
-
value = nil if (rand(20) == 1) && !NUMERIC_TYPES.include?(attribute_type)
|
54
|
+
value = nil if (rand(20) == 1) && (!NUMERIC_TYPES.include?(attribute_type)) && (attribute_name.to_s !~ /password/)
|
55
55
|
value
|
56
56
|
end
|
57
57
|
|
data/lib/stratagem/commands.rb
CHANGED
@@ -7,73 +7,104 @@ module Stratagem::Crawler
|
|
7
7
|
module Authentication
|
8
8
|
include Stratagem::Crawler::TraceUtils
|
9
9
|
|
10
|
+
def users
|
11
|
+
page = find_login_form
|
12
|
+
users = []
|
13
|
+
if (page)
|
14
|
+
form = page.login_form
|
15
|
+
attr_names = form.inputs.map {|input| input.guess_attribute.to_sym }
|
16
|
+
model = guess_login_model(attr_names)
|
17
|
+
if (model)
|
18
|
+
users = aquifer.instances_of(model.klass)
|
19
|
+
else
|
20
|
+
log "ERROR: Unable to determine user model"
|
21
|
+
end
|
22
|
+
else
|
23
|
+
log "ERROR: Could not find login form"
|
24
|
+
end
|
25
|
+
users
|
26
|
+
end
|
27
|
+
|
28
|
+
def reset_authentication
|
29
|
+
@authentication_data = nil
|
30
|
+
end
|
31
|
+
|
10
32
|
def authentication
|
11
|
-
@authentication_data
|
33
|
+
unless @authentication_data
|
34
|
+
@authentication_data = AuthenticationData.new()
|
35
|
+
site_model.authentication = @authentication_data
|
36
|
+
end
|
37
|
+
@authentication_data
|
12
38
|
end
|
13
39
|
|
14
|
-
def authenticate
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
begin
|
40
|
+
def authenticate(user, recursion_count=0)
|
41
|
+
reset_authentication
|
42
|
+
|
43
|
+
login(user)
|
44
|
+
route = application_model.routes.recognize(response.request.path, :post)
|
45
|
+
|
46
|
+
redirected_to = nil
|
47
|
+
page = site_model.add(route, response) {|redirect_url| redirected_to = redirect_url }
|
48
|
+
authentication.response_page = page
|
49
|
+
|
50
|
+
begin
|
51
|
+
if (response.request.url == (redirected_to || '')) || (![200,302].include?(response.code.to_i))
|
52
|
+
authentication.success = false
|
53
|
+
else
|
29
54
|
authentication.success = authentication.response_page.login_form.nil?
|
30
|
-
rescue
|
31
|
-
puts $!.message
|
32
|
-
puts $!.backtrace
|
33
55
|
end
|
34
|
-
|
35
|
-
|
36
|
-
puts
|
56
|
+
rescue
|
57
|
+
puts $!.message
|
58
|
+
puts $!.backtrace
|
37
59
|
end
|
38
60
|
|
39
|
-
|
61
|
+
puts "authenticated? #{authentication.success}"
|
62
|
+
if (response && authentication.success)
|
40
63
|
authentication.ssl = response.request.ssl?
|
41
|
-
|
64
|
+
yield
|
65
|
+
logout
|
42
66
|
else
|
43
67
|
false
|
44
68
|
end
|
45
69
|
end
|
46
70
|
|
47
71
|
def find_login_form
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
72
|
+
puts "finding login form"
|
73
|
+
if authentication.login_page.nil?
|
74
|
+
puts "locating login page"
|
75
|
+
puts "testing #{site_models.first.pages.size} pages"
|
76
|
+
site_models.first.pages.sort {|a,b| b.inbound_edges(:redirect).size <=> a.inbound_edges(:redirect).size }.each do |page|
|
77
|
+
puts "Testing page #{page.url} for sign in form"
|
78
|
+
# page.reload {|url| get url; response }
|
79
|
+
# form = page.login_form
|
80
|
+
if (page.login_form)
|
81
|
+
puts "FOUND! - #{page.login_form}"
|
82
|
+
authentication.login_page = page
|
83
|
+
return page
|
84
|
+
end
|
85
|
+
end
|
86
|
+
else
|
87
|
+
return authentication.login_page
|
53
88
|
end
|
54
|
-
|
89
|
+
nil
|
55
90
|
end
|
56
91
|
|
57
|
-
def
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
record = Stratagem::AutoMock::Aquifer.instance.random_instance(model.klass)
|
92
|
+
def logout
|
93
|
+
get "/signout"
|
94
|
+
get "/logout"
|
95
|
+
delete "/user_sessions/1"
|
96
|
+
end
|
63
97
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
end
|
70
|
-
else
|
71
|
-
raise "Unable to infer model from inputs"
|
72
|
-
end
|
98
|
+
def login(user)
|
99
|
+
populate_login_form(user).submit {|action,params|
|
100
|
+
post(action, params)
|
101
|
+
puts response.body
|
102
|
+
}
|
73
103
|
end
|
74
104
|
|
75
105
|
def guess_login_model(attr_names)
|
76
106
|
selections = application_model.models.select {|model|
|
107
|
+
puts "#{model.klass.name} - #{model.model_attributes.keys.inspect}"
|
77
108
|
intersect = (model.model_attributes.keys & attr_names)
|
78
109
|
intersect.size > 0
|
79
110
|
}.sort {|a,b|
|
@@ -81,28 +112,59 @@ module Stratagem::Crawler
|
|
81
112
|
b_intersect = (b.model_attributes.keys & attr_names)
|
82
113
|
b_intersect.size <=> a_intersect.size
|
83
114
|
}
|
84
|
-
|
115
|
+
|
116
|
+
explicit_model = application_model.models.find {|model| model.klass.name == 'User' }
|
117
|
+
selections.unshift explicit_model if explicit_model
|
118
|
+
|
119
|
+
puts "selecting model #{selections.first.klass.name} for authentication" if (selections.size > 0)
|
85
120
|
selections.first
|
86
121
|
end
|
87
122
|
|
88
123
|
|
89
|
-
def populate_login_form(
|
124
|
+
def populate_login_form(user)
|
125
|
+
# set up the form
|
126
|
+
page = find_login_form
|
127
|
+
page.reload {|url| get url; response }
|
128
|
+
form = page.login_form
|
129
|
+
|
130
|
+
# map the input values
|
90
131
|
form.inputs.each do |input|
|
132
|
+
# try the expected
|
91
133
|
attribute_name = input.guess_attribute.to_sym
|
92
|
-
attribute_value =
|
134
|
+
attribute_value = user.stratagem.read_mock_attribute(attribute_name) || input.value
|
93
135
|
|
94
|
-
|
136
|
+
# try again
|
137
|
+
if (attribute_value.nil? || attribute_value == '')
|
138
|
+
attribute_name = input.guess_alternate_attribute.to_sym
|
139
|
+
attribute_value = user.stratagem.read_mock_attribute(attribute_name) || input.value
|
140
|
+
end
|
141
|
+
|
142
|
+
# if it still failed is it a confirmation value? if so, try the original
|
143
|
+
if (attribute_value.nil? || attribute_value == '')
|
144
|
+
if (attribute_name.to_s =~ /confirm/)
|
145
|
+
possible_match = attribute_name.to_s.split('_').select {|a| a !~ /confirm/ }.join('_')
|
146
|
+
if user.stratagem.mock_attributes.keys.include?(possible_match)
|
147
|
+
attribute_value = user.stratagem.read_mock_attribute(possible_match) || input.value
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
95
152
|
|
96
153
|
if (input.kind_of? Stratagem::Crawler::Toggle)
|
97
154
|
input.check
|
98
|
-
elsif (
|
99
|
-
input.value =
|
155
|
+
elsif (user.stratagem.mock_attributes.keys.include?(attribute_name))
|
156
|
+
input.value = user.stratagem.read_mock_attribute(attribute_name) unless input.hidden?
|
157
|
+
elsif (attribute_name.to_s == 'authenticity_token')
|
158
|
+
puts input.value
|
100
159
|
else
|
101
|
-
puts
|
102
|
-
puts "ERROR: Cannot find attribute #{attribute_name} in model #{
|
160
|
+
puts user.stratagem.mock_attributes.inspect
|
161
|
+
puts "ERROR: Cannot find attribute #{attribute_name} in model #{user.class.name}"
|
103
162
|
end
|
163
|
+
|
164
|
+
puts "3 authentication field: #{input.name} -> #{input.value}"
|
165
|
+
|
104
166
|
end
|
105
|
-
form
|
167
|
+
form
|
106
168
|
end
|
107
169
|
|
108
170
|
end
|
@@ -58,6 +58,14 @@ module Stratagem::Crawler
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
+
def guess_alternate_attribute
|
62
|
+
if (name =~ /(.*)\[(.*)\]/)
|
63
|
+
$1.to_sym
|
64
|
+
else
|
65
|
+
name.to_sym
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
61
69
|
def guess_model
|
62
70
|
return $1.camelize if (name =~ /(.*)?\[/)
|
63
71
|
return nil
|
@@ -96,6 +104,10 @@ module Stratagem::Crawler
|
|
96
104
|
|
97
105
|
def <<(value)
|
98
106
|
@options << value
|
107
|
+
self.value = value if self.value.nil?
|
99
108
|
end
|
100
109
|
end
|
110
|
+
|
111
|
+
class Radio < Select
|
112
|
+
end
|
101
113
|
end
|
@@ -6,6 +6,7 @@ module Stratagem::Crawler
|
|
6
6
|
INPUT_TEXT = ['text', 'password', 'hidden']
|
7
7
|
INPUT_BUTTON = ['button', 'submit', 'reset', 'image', 'src']
|
8
8
|
INPUT_TOGGLE = ['checkbox']
|
9
|
+
INPUT_RADIO = ['radio']
|
9
10
|
|
10
11
|
def find_login_form(document)
|
11
12
|
possibilities = parse_forms(document).select {|form|
|
@@ -65,16 +66,27 @@ module Stratagem::Crawler
|
|
65
66
|
input = Button.new()
|
66
67
|
elsif (INPUT_TOGGLE.include?(type))
|
67
68
|
input = Toggle.new()
|
69
|
+
elsif (INPUT_RADIO.include?(type))
|
70
|
+
name = form_load_attribute(input_tag, 'name', false)
|
71
|
+
input = form.inputs.find {|i| i.name == name } || Radio.new()
|
68
72
|
else
|
69
|
-
raise FormParseError.new("Unsupported <input> type: '#{type}'", :html => input_tag.to_html)
|
73
|
+
#raise FormParseError.new("Unsupported <input> type: '#{type}'", :html => input_tag.to_html)
|
74
|
+
puts "ERROR: Unsupported input type: #{type}"
|
70
75
|
end
|
71
76
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
77
|
+
if (input)
|
78
|
+
input.id = form_load_attribute(input_tag, 'id', false)
|
79
|
+
input.type = form_load_attribute(input_tag, 'type', false) || 'text'
|
80
|
+
input.name = form_load_attribute(input_tag, 'name', false)
|
81
|
+
if (input.class.ancestors.include?(Select))
|
82
|
+
input << form_load_attribute(input_tag, 'value', false)
|
83
|
+
else
|
84
|
+
input.value = form_load_attribute(input_tag, 'value', false)
|
85
|
+
end
|
76
86
|
|
77
|
-
|
87
|
+
form << input
|
88
|
+
end
|
89
|
+
form
|
78
90
|
end
|
79
91
|
|
80
92
|
def form_load_attribute(node, attribute_name, raise_error = true)
|
@@ -82,7 +94,7 @@ module Stratagem::Crawler
|
|
82
94
|
attr = node.attributes[attribute_name]
|
83
95
|
value = nil
|
84
96
|
if (attr)
|
85
|
-
value = attr.value.strip
|
97
|
+
value = attr.value.strip
|
86
98
|
elsif (raise_error)
|
87
99
|
raise FormParseError.new("#{attribute_name} attribute not found in tag - #{node.to_html}")
|
88
100
|
end
|