require 'spec_helper' describe Arachni::Element::Link do html = 'Bla' it_should_behave_like 'element' it_should_behave_like 'with_node' it_should_behave_like 'with_dom', html it_should_behave_like 'refreshable' it_should_behave_like 'with_source' it_should_behave_like 'with_auditor' it_should_behave_like 'submittable' it_should_behave_like 'inputtable' it_should_behave_like 'mutable' it_should_behave_like 'auditable' before :each do @framework ||= Arachni::Framework.new @auditor = Auditor.new( Arachni::Page.from_url( url ), @framework ) end after :each do @framework.reset reset_options end let(:auditor) { @auditor } def auditable_extract_parameters( resource ) YAML.load( resource.body ) end def run http.run end before :each do reset_options end subject { described_class.new( url: "#{url}submit", inputs: inputs, source: html ) } let(:inputs) { { 'name1' => 'value1', 'name2' => 'value2' } } let(:url) { utilities.normalize_url( web_server_url_for( :link ) ) } let(:http) { Arachni::HTTP::Client } let(:utilities) { Arachni::Utilities } let(:rewrite_rules) do { /articles\/[\w-]+\/(\d+)/ => 'articles.php?id=\1' } end it 'is assigned to Arachni::Link for easy access' do expect(Arachni::Link).to eq(described_class) end describe '#initialize' do describe :action do it 'sets #action' do action = "#{url}stuff" expect(described_class.new( url: url, action: action ).action).to eq(action) end context 'when nil' do it 'defaults to :url' do expect(described_class.new( url: url ).action).to eq(url) end end end end describe '#action=' do let(:action) { action = "#{url}?stuff=here&and=here2" } let(:query_inputs) do { 'stuff' => 'here', 'and' => 'here2' } end let(:option_inputs) do { 'more-stuff' => 'here3', 'yet-more-stuff' => 'here4' } end subject do described_class.new( url: url, action: action, inputs: option_inputs ) end it 'removes the URL query' do expect(subject.action).to eq(url) end it 'merges the URL query parameters with the given :inputs' do expect(subject.inputs).to eq(query_inputs.merge( option_inputs )) end context 'when URL query parameters and :inputs have the same name' do let(:option_inputs) do { 'stuff' => 'here3', 'yet-more-stuff' => 'here4' } end it 'it gives precedence to the :inputs' do expect(subject.inputs).to eq(query_inputs.merge( option_inputs )) end end context "when there are #{Arachni::OptionGroups::Scope}#url_rewrites" do it 'rewrites the #action' do Arachni::Options.scope.url_rewrites = rewrite_rules link = described_class.new( url: url, action: "#{url}/articles/some-stuff/23" ) expect(link.action).to eq(url + 'articles.php') expect(link.url).to eq(url) expect(link.inputs).to eq({ 'id' => '23' }) end end end describe '#dom' do context 'when there are no DOM#inputs' do it 'returns nil' do subject.source = 'Bla' expect(subject.dom).to be_nil end end context 'when there is no #node' do it 'returns nil' do subject.source = nil expect(subject.dom).to be_nil end end end describe '#simple' do it 'should return a simplified version as a hash' do expect(subject.simple).to eq({ subject.action => subject.inputs }) end end describe '#to_s' do it 'returns a URL' do expect(subject.to_s).to eq("#{subject.action}?name1=value1&name2=value2") end end describe '#type' do it 'should be "link"' do expect(subject.type).to eq(:link) end end describe '#coverage_id' do it "takes into account #{described_class::DOM}#inputs.keys" do e = subject.dup e.source = 'Bla' c = subject.dup c.source = 'Bla' expect(c.coverage_id).to eq(e.coverage_id) e = subject.dup e.source = 'Bla' c = subject.dup c.source = 'Bla' expect(c.coverage_id).not_to eq(e.coverage_id) end end describe '#id' do it "takes into account #{described_class::DOM}#inputs" do e = subject.dup e.source = 'Bla' c = subject.dup c.source = 'Bla' expect(c.id).to eq(e.id) e = subject.dup e.source = 'Bla' c = subject.dup c.source = 'Bla' expect(c.id).not_to eq(e.id) end end describe '#to_rpc_data' do it "does not include 'dom_data'" do subject.source = html expect(subject.dom).to be_truthy expect(subject.to_rpc_data).not_to include 'dom_data' end end describe '.from_document' do context 'when the response does not contain any links' do it 'should return an empty array' do expect(described_class.from_document( '', '' )).to 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 ) expect(links.size).to eq(1) expect(links.first.action).to eq(url + 'stuff') end end context 'when the response contains links' do it 'should return an array of links' do html = ' ' link = described_class.from_document( url, html ).first expect(link.action).to eq(url + 'test2') expect(link.url).to eq(url) expect(link.inputs).to eq({ 'param_one' => 'value_one', 'param_two' => 'value_two' }) end context 'and includes a base attribute' do it 'should return an array of links with adjusted URIs' do base_url = "#{url}this_is_the_base/" html = '