=begin
                  Arachni
  Copyright (c) 2010-2012 Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>

  This is free software; you can copy and distribute and modify
  this program under the term of the GPL v2.0 License
  (See LICENSE file for details)

=end

module Arachni
module Plugins

#
# Automated login plugin.
#
# It looks for the login form in the user provided URL,
# merges its input field with the user supplied parameters and sets the cookies
# of the response as framework-wide cookies to be used by the spider later on.
#
# @author: Tasos "Zapotek" Laskos
#                                      <tasos.laskos@gmail.com>
#                                      <zapotek@segfault.gr>
# @version: 0.1.1
#
class AutoLogin < Arachni::Plugin::Base

    attr_accessor :http

    MSG_SUCCESS     = 'Form submitted successfully.'
    MSG_FAILURE     = 'Could not find a form suiting the provided params at: '
    MSG_NO_RESPONSE = 'Form submitted but no response was returned.'

    def prepare
        @framework.pause!
        print_info( "System paused." )

        @params = parse_params

        # we need to declared this in order to pass ourselves
        # as the auditor to the form later in order to submit it.
        @http = @framework.http
    end

    def run

        # grab the page containing the login form
        res  = @http.get( @options['url'], :async => false ).response

        parser = Arachni::Parser.new( @framework.opts, res )
        # parse the response as a Page object
        page = parser.run

        # find the login form
        login_form = nil
        page.forms.each {
            |form|
            login_form = form if login_form?( form )
        }

        if !login_form
            register_results( { :code => 0, :msg => MSG_FAILURE + @options['url'] } )
            print_bad( MSG_FAILURE + @options['url'] )
            return
        end

        name = login_form.raw['attrs']['name'] ? login_form.raw['attrs']['name'] : '<n/a>'
        print_status( "Found log-in form with name: "  + name )

        # merge the input fields of the form with the user supplied parameters
        login_form.auditable.merge!( @params )

        # register us as the auditor
        login_form.auditor( self )
        res = login_form.submit( :async => false, :update_cookies => true ).response

        if !res
            register_results( { :code => -1, :msg => MSG_NO_RESPONSE } )
            print_bad( MSG_NO_RESPONSE )
            return
        else
            register_results( { :code => 1, :msg => MSG_SUCCESS, :cookies => @http.current_cookies.dup } )
            print_ok( MSG_SUCCESS )
            print_info( 'Cookies set to:' )
            @http.current_cookies.each_pair {
                |name, val|
                print_info( '    * ' + name + ' = ' + val )
            }
        end

    end

    def clean_up
        @framework.resume!
    end

    def login_form?( form )
        avail    = form.auditable.keys
        provided = @params.keys

        provided.each {
            |name|
            return false if !avail.include?( name )
        }

        return true
    end

    def parse_params
        params = {}
        @options['params'].split( '&' ).each {
            |param|
            k, v = param.split( '=', 2 )
            params[k] = v
        }
        return params
    end


    def self.info
        {
            :name           => 'AutoLogin',
            :description    => %q{It looks for the login form in the user provided URL,
                merges its input fields with the user supplied parameters and sets the cookies
                of the response and request as framework-wide cookies to be used by the spider later on.
            },
            :author         => 'Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>',
            :version        => '0.1.1',
            :options        => [
                Arachni::OptUrl.new( 'url', [ true, 'The URL that contains the login form.' ] ),
                Arachni::OptString.new( 'params', [ true, 'Form parameters to submit. ( username=user&password=pass )' ] )
            ]
        }
    end

end

end
end