=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 Report # # Provides some common options for the reports # # # @author: Tasos "Zapotek" Laskos # <tasos.laskos@gmail.com> # <zapotek@segfault.gr> # @version: 0.1 # module Options # # Returns a string option named 'outfile'. # # Default value is: # year-month-day hour.minute.second +timezone.extension # # @param [String] ext extension for the outfile # @param [String] desc description of the option # # @return [Arachni::OptString] # def outfile( ext = '', desc = 'Where to save the report.' ) Arachni::OptString.new( 'outfile', [ false, desc, Time.now.to_s.gsub( ':', '.' ) + ext ] ) end extend self end class FormatterManager < ComponentManager def paths cpaths = paths = Dir.glob( File.join( "#{@lib}", "*.rb" ) ) return paths.reject { |path| helper?( path ) } end end # # Arachni::Report::Base class # # An abstract class for the reports.<br/> # All reports must extend this. # # @author: Tasos "Zapotek" Laskos # <tasos.laskos@gmail.com> # <zapotek@segfault.gr> # @version: 0.1.1 # @abstract # class Base # get the output interface include Arachni::UI::Output include Arachni::Module::Utilities # where to report false positives <br/> # info about this should be included in all templates REPORT_FP = 'http://github.com/Zapotek/arachni/issues' module PluginFormatters end # # @param [AuditStore] audit_store # @param [Hash] options options passed to the report # def initialize( audit_store, options ) @audit_store = audit_store @options = options end # # REQUIRED # def run end # # Runs plugin formatters for the running report and returns a hash # with the prepared/formatted results. # # @param [AuditStore#plugins] plugins plugin data/results # def format_plugin_results( plugins ) formatted = {} return formatted if !plugins # get the object that extends this class (i.e. the running report) ancestor = self.class.ancestors[0] # add the PluginFormatters module to the report eval( "class " + ancestor.to_s + "\n module PluginFormatters end \n end" ) # get the path to the report file # this is a very bad way to do it... report_path = ::Kernel.caller[0].match( /^(.+?):(\d+)(?::in `(.*)')?/ )[1] # prepare the directory of the formatters for the running report lib = File.dirname( report_path ) + '/plugin_formatters/' + File.basename( report_path, '.rb' ) + '/' @@formatters ||= {} # initialize a new component manager to handle the plugin formatters @@formatters[ancestor] ||= FormatterManager.new( lib, ancestor.const_get( 'PluginFormatters' ) ) # load all the formatters @@formatters[ancestor].load( ['*'] ) if @@formatters[ancestor].empty? # run the formatters and gather the formatted data they return @@formatters[ancestor].each_pair { |name, formatter| plugin_results = plugins[name] next if !plugin_results || plugin_results[:results].empty? exception_jail( false ) { formatted[name] = formatter.new( plugin_results.deep_clone ).run } } return formatted end # # REQUIRED # # Do not ommit any of the info. # def self.info { :name => 'Report abstract class.', :options => [ # option name required? description default # Arachni::OptBool.new( 'html', [ false, 'Include the HTML responses in the report?', true ] ), # Arachni::OptBool.new( 'headers', [ false, 'Include the headers in the report?', true ] ), ], :description => %q{This class should be extended by all reports.}, :author => 'zapotek', :version => '0.1.1', } end end end end