require 'spec_helper'
describe Arachni::Element::LinkTemplate do
html = "stuff"
it_should_behave_like 'element'
it_should_behave_like 'with_node', html
it_should_behave_like 'with_dom', html
it_should_behave_like 'auditable'
before :each do
Arachni::Options.audit.link_templates = /param\/(?\w+)/
end
def auditable_extract_parameters( resource )
YAML.load( resource.body )
end
def run
http.run
end
after :each do
reset_options
end
subject do
described_class.new(
url: url_with_inputs,
template: template
)
end
let(:inputtable) do
described_class.new(
url: "#{url}input1/value1/input2/value2",
template: /input1\/(?\w+)\/input2\/(?\w+)/
)
end
let(:mutable){ inputtable }
let(:url_with_inputs) { "#{url}param/val" }
let(:template) { /param\/(?\w+)/ }
let(:inputs) { { 'param' => 'val' } }
let(:url) { utilities.normalize_url( web_server_url_for( :link_template ) ) }
let(:http) { Arachni::HTTP::Client }
let(:utilities) { Arachni::Utilities }
describe '#initialize' do
describe :options do
describe :template do
it 'sets the #template' do
described_class.new(
url: url_with_inputs,
template: template
).template.should == template
end
end
describe :inputs do
it 'sets the #inputs' do
described_class.new(
url: url_with_inputs,
inputs: inputs,
template: template
).inputs.should == inputs
end
end
context 'when no :inputs are provided' do
it 'uses the given :template to extract them' do
described_class.new(
url: url_with_inputs,
template: template
).inputs.should == inputs
end
context 'when no :template is provided' do
it "tries to match one of #{Arachni::OptionGroups::Audit}#link_templates" do
Arachni::Options.audit.link_templates = template
l = described_class.new( url: url_with_inputs )
l.inputs.should == inputs
l.template.should == template
end
end
end
end
end
describe '#simple' do
it 'returns a simple hash representation' do
subject.simple.should == {
subject.action => subject.inputs
}
end
end
describe '#valid_input_name?' do
context 'when the name can be found in the #template named captures' do
it 'returns true' do
subject.template.names.should be_any
subject.template.names.each do |name|
subject.valid_input_name?( name ).should be_true
end
end
end
context 'when the name cannot be found in the #template named captures' do
it 'returns false' do
subject.valid_input_name?( 'stuff' ).should be_false
end
end
end
describe '#valid_input_data?' do
it 'returns true' do
subject.valid_input_data?( 'stuff' ).should be_true
end
described_class::INVALID_INPUT_DATA.each do |invalid_data|
context "when the value contains #{invalid_data.inspect}" do
it 'returns false' do
subject.valid_input_data?( "stuff #{invalid_data}" ).should be_false
end
end
end
end
describe '#dom' do
context 'when there are no DOM#inputs' do
it 'returns nil' do
subject.html = 'Bla'
subject.dom.should be_nil
end
end
context 'when there is no #node' do
it 'returns nil' do
subject.html = nil
subject.dom.should be_nil
end
end
end
describe '#to_s' do
it 'returns the updated link' do
inputtable.to_s.should == inputtable.action
inputtable.inputs = {
'input1' => 'new value 1',
'input2' => 'new value 2'
}
inputtable.to_s.should == "#{url}input1/new%20value%201/input2/new%20value%202"
end
end
describe '#coverage_id' do
it "takes into account #{described_class::DOM}#template names" do
e = subject.dup
e.html = "stuff"
c = subject.dup
c.html = "stuff"
c.coverage_id.should == e.coverage_id
e = subject.dup
e.html = "stuff"
Arachni::Options.audit.link_templates << /param2\/(?\w+)/
c = subject.dup
c.html = "stuff"
c.coverage_id.should_not == e.coverage_id
end
end
describe '#id' do
it "takes into account #{described_class::DOM}#inputs" do
e = subject.dup
e.html = "stuff"
c = subject.dup
c.html = "stuff"
c.id.should == e.id
e = subject.dup
e.html = "stuff"
c = subject.dup
c.html = "stuff"
c.id.should_not == e.id
e = subject.dup
e.html = "stuff"
c = subject.dup
c.html = "stuff"
c.id.should_not == e.id
end
end
describe '#to_rpc_data' do
it "does not include 'dom_data'" do
subject.html = html
subject.dom.should be_true
subject.to_rpc_data.should_not include 'dom_data'
end
end
describe '.encode' do
it "double encodes ';'" do
described_class.encode( 'test;' ).should == 'test%253B'
end
it "double encodes '/'" do
described_class.encode( 'test/' ).should == 'test%2F'
end
end
describe '.decode' do
it 'URL-decodes the passed string' do
v = '%25+value%5C+%2B%3D%26%3B'
described_class.decode( v ).should == URI.decode( v )
end
end
describe '#decode' do
it 'URL-decodes the passed string' do
v = '%25+value%5C+%2B%3D%26%3B'
subject.decode( v ).should == described_class.decode( v )
end
end
describe '.extract_inputs' do
it 'returns a hash of inputs and the matching template' do
url = "#{url}input1/value1/input2/value2"
templates = [/input1\/(?\w+)\/input2\/(?\w+)/]
template, inputs = described_class.extract_inputs( url, templates )
templates.should == [template]
inputs.should == {
'input1' => 'value1',
'input2' => 'value2'
}
end
it 'decodes the input values' do
url = "#{url}input1/val%20ue1/input2/val%20ue2"
templates = [/input1\/(?.+)\/input2\/(?.+)/]
_, inputs = described_class.extract_inputs( url, templates )
inputs.should == {
'input1' => 'val ue1',
'input2' => 'val ue2'
}
end
context 'when no URL is given' do
it 'returns an empty array' do
described_class.extract_inputs( nil ).should == []
end
end
context 'when no templates are given' do
it "defaults to #{Arachni::OptionGroups::Audit}#link_templates" do
url = "#{url}input1/value1/input2/value2"
templates = [/input1\/(?\w+)\/input2\/(?\w+)/]
Arachni::Options.audit.link_templates = templates
template, inputs = described_class.extract_inputs( url )
inputs.should == {
'input1' => 'value1',
'input2' => 'value2'
}
[templates].should == [Arachni::Options.audit.link_templates]
end
end
context 'when no matches are found' do
it 'returns an empty array' do
url = "#{url}input3/value1/input4/value2"
templates = [/input1\/(?\w+)\/input2\/(?\w+)/]
described_class.extract_inputs( url, templates ).should == []
end
end
end
describe '.type' do
it 'returns :link_template' do
described_class.type.should == :link_template
end
end
describe '.from_response' do
it 'returns an array of link template from the response' do
response = Arachni::HTTP::Response.new(
url: url,
body: '
'
)
link = described_class.from_response( response ).first
link.action.should == url + 'test2/param/myvalue'
link.url.should == url
link.inputs.should == {
'param' => 'myvalue'
}
end
context 'when the URL matches a link template' do
it 'includes it' do
response = Arachni::HTTP::Response.new(
url: url + '/test2/param/myvalue'
)
link = described_class.from_response( response ).first
link.action.should == url + 'test2/param/myvalue'
link.url.should == link.action
link.inputs.should == {
'param' => 'myvalue'
}
end
end
end
describe '.from_document' do
context 'when the response does not contain any link templates' do
it 'returns an empty array' do
described_class.from_document( '', '' ).should be_empty
end
end
context 'when links have actions that are out of scope' do
it 'ignores them' do
html = '
'
Arachni::Options.scope.exclude_path_patterns = [/exclude/]
links = described_class.from_document( url, html )
links.size.should == 1
links.first.action.should == url + 'test2/param/myvalue'
end
end
context 'when the response contains link templates' do
it 'returns an array of link templates' do
html = '
'
link = described_class.from_document( url, html ).first
link.action.should == url + 'test2/param/myvalue'
link.url.should == url
link.inputs.should == {
'param' => 'myvalue'
}
end
context 'and includes a base attribute' do
it 'should return an array of link templates with adjusted URIs' do
base_url = "#{url}this_is_the_base/"
html = '
'
link = described_class.from_document( url, html ).first
link.action.should == base_url + 'test/param/myvalue'
link.url.should == url
link.inputs.should == {
'param' => 'myvalue'
}
end
end
end
end
end