Skip to content

Commit

Permalink
--browser-cluster-session-storage: Sets the browsers' session storage
Browse files Browse the repository at this point in the history
  • Loading branch information
Zapotek committed Jul 14, 2017
1 parent 5676fa4 commit 5ee35d4
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
- Options
- New
- `--scope-dom-event-inheritance-limit` -- Limits the amount of inherited events.
- `--browser-cluster-session-storage` -- Sets the browsers' session storage.
- `Element`
- Added `NestedCookie`: Handles key-value pairs inside individual cookies.
- `Browser`
Expand Down
29 changes: 23 additions & 6 deletions lib/arachni/browser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1442,16 +1442,17 @@ def load_cookies( url, cookies = {} )
end

return if set_cookies.empty? &&
Arachni::Options.browser_cluster.local_storage.empty?
Options.browser_cluster.local_storage.empty? &&
Options.browser_cluster.session_storage.empty?

set_cookie = set_cookies.values.map(&:to_set_cookie)
print_debug_level_2 "Setting cookies: #{set_cookie}"

body = ''
if Arachni::Options.browser_cluster.local_storage.any?
body = <<EOJS
if Options.browser_cluster.local_storage.any?
body << <<EOJS
<script>
var data = #{Arachni::Options.browser_cluster.local_storage.to_json};
var data = #{Options.browser_cluster.local_storage.to_json};
for( prop in data ) {
localStorage.setItem( prop, data[prop] );
Expand All @@ -1460,6 +1461,18 @@ def load_cookies( url, cookies = {} )
EOJS
end

if Options.browser_cluster.session_storage.any?
body << <<EOJS
<script>
var data = #{Options.browser_cluster.session_storage.to_json};
for( prop in data ) {
sessionStorage.setItem( prop, data[prop] );
}
</script>
EOJS
end

@selenium.navigate.to preload( HTTP::Response.new(
code: 200,
url: "#{url}/set-cookies-#{request_token}",
Expand Down Expand Up @@ -1559,7 +1572,7 @@ def request_handler( request, response )
#
# Still, it's a nice feature to have when requesting assets or anything
# else.
if request.url == @last_url
if !@last_url || request.url == @last_url
request.headers.delete 'If-None-Match'
request.headers.delete 'If-Modified-Since'
end
Expand Down Expand Up @@ -1614,7 +1627,11 @@ def response_handler( request, response )

# Prevent PhantomJS from caching the root page, we need to have an
# associated response.
if @last_url == response.url
#
# Also don't cache when we don't have a @last_url because this could
# be driven directly from Selenium/Watir via a plugin and caching it
# can ruin the scan.
if !@last_url || @last_url == response.url
response.headers.delete 'Cache-control'
response.headers.delete 'Etag'
response.headers.delete 'Date'
Expand Down
15 changes: 15 additions & 0 deletions lib/arachni/option_groups/browser_cluster.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ class BrowserCluster < Arachni::OptionGroup
# Data to be set in the browser's `localStorage`.
attr_accessor :local_storage

# @return [Hash]
# Data to be set in the browser's `sessionStorage`.
attr_accessor :session_storage

# @return [Hash<Regexp,String>]
# When the page URL matched the key `Regexp`, wait until the `String` CSS
# selector in the value matches an element.
Expand Down Expand Up @@ -48,6 +52,7 @@ class BrowserCluster < Arachni::OptionGroup

set_defaults(
local_storage: {},
session_storage: {},
wait_for_elements: {},
pool_size: 6,
# Not actually a timeout for the job anymore, sets a timeout for Selenium
Expand All @@ -71,6 +76,16 @@ def local_storage=( data )
@local_storage = data
end

def session_storage=( data )
data ||= {}

if !data.is_a?( Hash )
fail ArgumentError, "Expected data to be Hash, got #{data.class} instead."
end

@session_storage = data
end

def css_to_wait_for( url )
wait_for_elements.map do |pattern, css|
next if !(url =~ pattern)
Expand Down
59 changes: 59 additions & 0 deletions spec/arachni/browser_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2348,6 +2348,52 @@ def element
expect(subject.response.headers).not_to include 'Content-Security-Policy'
end

context 'when there is no page URL' do
it 'does not receive a Date header' do
subject.watir.goto "#{@url}/Date"
expect(subject.response.code).to eq(200)
expect(subject.response.headers).not_to include 'Date'
end

it 'does not receive an Etag header' do
subject.watir.goto "#{@url}/Etag"
expect(subject.response.code).to eq(200)
expect(subject.response.headers).not_to include 'Etag'
end

it 'does not receive a Cache-Control header' do
subject.watir.goto "#{@url}/Cache-Control"
expect(subject.response.code).to eq(200)
expect(subject.response.headers).not_to include 'Cache-Control'
end

it 'does not receive a Last-Modified header' do
subject.watir.goto "#{@url}/Last-Modified"
expect(subject.response.code).to eq(200)
expect(subject.response.headers).not_to include 'Last-Modified'
end

it 'does not send If-None-Match request headers' do
subject.watir.goto "#{@url}/If-None-Match"
expect(subject.response.code).to eq(200)
expect(subject.response.request.headers).not_to include 'If-None-Match'

subject.watir.goto "#{@url}/If-None-Match"
expect(subject.response.code).to eq(200)
expect(subject.response.request.headers).not_to include 'If-None-Match'
end

it 'does not send If-Modified-Since request headers' do
subject.watir.goto "#{@url}/If-Modified-Since"
expect(subject.response.code).to eq(200)
expect(subject.response.request.headers).not_to include 'If-Modified-Since'

subject.watir.goto "#{@url}/If-Modified-Since"
expect(subject.response.code).to eq(200)
expect(subject.response.request.headers).not_to include 'If-Modified-Since'
end
end

context 'when requesting the page URL' do
it 'does not receive a Date header' do
subject.goto "#{@url}/Date"
Expand Down Expand Up @@ -2573,6 +2619,19 @@ def element
end
end

context "with #{Arachni::OptionGroups::BrowserCluster}#session_storage" do
before do
Arachni::Options.browser_cluster.session_storage = {
'name' => 'value'
}
end

it 'sets the data as session storage' do
subject.load @url
expect( subject.javascript.run( 'return sessionStorage.getItem( "name" )' ) ).to eq 'value'
end
end

context "with #{Arachni::OptionGroups::BrowserCluster}#wait_for_elements" do
before do
Arachni::Options.browser_cluster.wait_for_elements = {
Expand Down
17 changes: 17 additions & 0 deletions spec/arachni/option_groups/browser_cluster_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,21 @@
end
end
end

describe '#session_storage' do
context 'when passed a Hash' do
it 'sets it' do
subject.session_storage = { 1 => 2 }
expect(subject.session_storage).to eq({ 1 => 2 })
end
end

context 'when passed anything other than Hash' do
it 'raises ArgumentError' do
expect do
subject.session_storage = 1
end.to raise_error ArgumentError
end
end
end
end
6 changes: 6 additions & 0 deletions ui/cli/framework/option_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -584,6 +584,12 @@ def browser_cluster
options.browser_cluster.local_storage = ::JSON.load( IO.read( file ) )
end

on( '--browser-cluster-session-storage FILE',
"Sets the browsers' session storage using the JSON data in FILE."
) do |file|
options.browser_cluster.session_storage = ::JSON.load( IO.read( file ) )
end

on( '--browser-cluster-wait-for-element PATTERN:CSS',
'Wait for element matching CSS to appear when visiting a page whose' <<
' URL matches the PATTERN.'
Expand Down

0 comments on commit 5ee35d4

Please sign in to comment.