=begin Copyright 2010-2014 Tasos Laskos This file is part of the Arachni Framework project and is subject to redistribution and commercial restrictions. Please see the Arachni Framework web site for more information on licensing and terms of use. =end module Arachni # The namespace under which all checks exist. module Checks end module Check # Manages and runs {Checks} against {Page}s. # # @author Tasos "Zapotek" Laskos class Manager < Arachni::Component::Manager # Namespace under which all checks reside. NAMESPACE = ::Arachni::Checks # {Manager} error namespace. # # All {Manager} errors inherit from and live under it. # # @author Tasos "Zapotek" Laskos class Error < Error # Raised when a loaded check targets invalid platforms. # @author Tasos "Zapotek" Laskos class InvalidPlatforms < Error end end # @param [Arachni::Framework] framework def initialize( framework ) self.class.reset @framework = framework super( @framework.options.paths.checks, NAMESPACE ) end # @param [Arachni::Page] page # Page to audit. def run( page ) schedule.each { |mod| exception_jail( false ){ run_one( mod, page ) } } end # @param [Symbol, String] name # Name of the check to retrieve. # # @return [Check::Base] # # @raise [Error::InvalidPlatforms] # On invalid check platforms. def []( name ) check = super( name ) if !Platform::Manager.valid?( check.platforms ) unload name fail Error::InvalidPlatforms, "Check #{name} contains invalid platforms: #{check.platforms.join(', ')}" end check end # @return [Array] # Checks in proper running order, taking account their declared # {Check::Base.prefer preferences}. def schedule schedule = Set.new preferred_over = Hash.new([]) preferred = self.reject do |name, klass| preferred_over[name] = klass.preferred if klass.preferred.any? end return self.values if preferred_over.empty? || preferred.empty? preferred_over.size.times do update = {} preferred.each do |name, klass| schedule << klass preferred_over.select { |_, v| v.include?( name.to_sym ) }.each do |k, v| schedule << (update[k] = self[k]) end end preferred.merge!( update ) end schedule |= preferred_over.keys.map { |n| self[n] } schedule.to_a end # @return [Hash] # Checks targeting specific platforms. def with_platforms select { |k, v| v.has_platforms? } end # @return [Hash] # Platform-agnostic checks. def without_platforms select { |k, v| !v.has_platforms? } end # Runs a single `check` against `page`. # # @param [Check::Base] check # Check to run as a class. # @param [Page] page # Page to audit. # # @return [Bool] # `true` if the check was ran (based on {Check::Auditor.check?}), # `false` otherwise. def run_one( check, page ) return false if !check.check?( page ) check_new = check.new( page, @framework ) check_new.prepare check_new.run check_new.clean_up true end def self.reset remove_constants( NAMESPACE ) end def reset self.class.reset end end end end