class Arachni::Platform::Manager
Represents a collection of platform {List lists}.
It also holds a DB
of all fingerprints per URI
as a class variable and provides helper method for accessing and manipulating it.
@author Tasos “Zapotek” Laskos <tasos.laskos@arachni-scanner.com>
Constants
- DB
- FRAMEWORKS
WebApp frameworks.
- LANGUAGES
- OS
- PLATFORM_CACHE_SIZE
- PLATFORM_NAMES
- SERVERS
- TYPES
Public Class Methods
@param [String, URI] uri
@return [Manager]
Platform for the given `uri`
# File lib/arachni/platform/manager.rb, line 284 def self.[]( uri ) # If fingerprinting is disabled there's no point in filling the cache # with the same object over and over, create an identical one for all # URLs and return that always. if !Options.fingerprint? return @default ||= new_from_options end return new_from_options if !(key = make_key( uri )) synchronize { @platforms.fetch(key) { new_from_options } } end
Sets platform manager for the given ‘uri`.
@param [String, URI] uri @param [Enumerable] platforms
@return [Manager]
@raise [Error::Invalid]
On {#invalid?} platforms.
# File lib/arachni/platform/manager.rb, line 305 def self.[]=( uri, platforms ) # For some reason we failed to make a key, try to salvage the situation. if !(key = make_key( uri )) return new_from_options( platforms ) end synchronize do @platforms[key] = platforms.is_a?( self ) ? platforms : new_from_options( platforms ) end end
@return [Boolean]
`true` if there are platforms fingerprints, `false` otherwise.
# File lib/arachni/platform/manager.rb, line 352 def self.any? !empty? end
Clears global platforms DB
.
# File lib/arachni/platform/manager.rb, line 220 def self.clear @platforms.clear end
@return [Boolean]
`true` if there are no platforms fingerprints, `false` otherwise.
# File lib/arachni/platform/manager.rb, line 346 def self.empty? @platforms.empty? end
# File lib/arachni/platform/manager.rb, line 184 def self.find_type( platform ) @find_type ||= {} if @find_type.empty? TYPES.keys.each do |type| platforms = const_get( type.to_s.upcase.to_sym ) platforms = platforms.find_symbol_keys_recursively if platforms.is_a?( Hash ) platforms.each do |p| @find_type[p] = type end end end @find_type[platform] end
Runs all fingerprinters against the given ‘page`.
@param [Page] page
Page to fingerprint.
@return [Manager]
Updated `self`.
# File lib/arachni/platform/manager.rb, line 259 def self.fingerprint( page ) synchronize do return page if !fingerprint? page fingerprinters.available.each do |name| exception_jail( false ) do fingerprinters[name].new( page ).run end end # We do this to flag the resource as checked even if no platforms # were identified. We don't want to keep checking a resource that # yields nothing over and over. update( page.url, [] ) end # Fingerprinting will have resulted in element parsing, clear the element # caches to keep RAM consumption down. page.clear_cache end
@param [HTTP::Response, Page] resource
@return [Bool]
`true` if the resource should be fingerprinted, `false` otherwise.
# File lib/arachni/platform/manager.rb, line 247 def self.fingerprint?( resource ) !(!Options.fingerprint? || resource.code != 200 || !resource.text? || include?( resource.url ) || resource.scope.out?) end
# File lib/arachni/platform/manager.rb, line 236 def self.fingerprinters @manager ||= Component::Manager.new( Options.paths.fingerprinters, Platform::Fingerprinters ) end
@param [String, URI] uri
# File lib/arachni/platform/manager.rb, line 324 def self.include?( uri ) @platforms.include?( make_key( uri ) ) end
# File lib/arachni/platform/manager.rb, line 356 def self.make_key( uri ) return if !(parsed = Arachni::URI( uri )) parsed.without_query end
@param [Array<String, Symbol>] platforms
Platforms with which to initialize the lists.
# File lib/arachni/platform/manager.rb, line 367 def initialize( platforms = [] ) @platforms = {} TYPES.keys.each do |type| @platforms[type] = List.new( self.class.const_get( type.to_s.upcase.to_sym ) ) end update platforms end
# File lib/arachni/platform/manager.rb, line 361 def self.new_from_options( platforms = [] ) new( platforms | Options.platforms ) end
Empties the global platform fingerprints.
# File lib/arachni/platform/manager.rb, line 225 def self.reset set Hash.new @manager.clear if @manager @manager = nil @mutex = Monitor.new self end
Sets global platforms fingerprints @private
# File lib/arachni/platform/manager.rb, line 213 def self.set( platforms ) @platforms = Support::Cache::LeastRecentlyPushed.new( PLATFORM_CACHE_SIZE ) platforms.each { |k, v| @platforms[k] = v } @platforms end
# File lib/arachni/platform/manager.rb, line 319 def self.size @platforms.size end
# File lib/arachni/platform/manager.rb, line 180 def self.synchronize( &block ) @mutex.synchronize( &block ) end
Updates the ‘platforms` for the given `uri`.
@param [String, URI] uri @param [Manager] platforms
@return [Manager]
Updated manager.
@raise [Error::Invalid]
On {#invalid?} platforms.
# File lib/arachni/platform/manager.rb, line 338 def self.update( uri, platforms ) synchronize do self[uri].update platforms end end
# File lib/arachni/platform/manager.rb, line 202 def self.valid @valid ||= Set.new( PLATFORM_NAMES.keys ) end
# File lib/arachni/platform/manager.rb, line 206 def self.valid?( platforms ) platforms = [platforms].flatten.compact (valid & platforms).to_a == platforms end
Public Instance Methods
@param [Symbol, String] platform
Platform to add to the appropriate list.
@return [Manager]
`self`
@raise [Error::Invalid]
On {#invalid?} platforms.
# File lib/arachni/platform/manager.rb, line 550 def <<( platform ) find_list( platform ) << platform self end
@return [Boolean]
`true` if there are applicable platforms, `false` otherwise.
# File lib/arachni/platform/manager.rb, line 521 def any? !empty? end
# File lib/arachni/platform/manager.rb, line 525 def clear @platforms.clear end
@param [Block] block
Block to be passed each platform.
@return [Enumerator, Manager]
`Enumerator` if no `block` is given, `self` otherwise.
# File lib/arachni/platform/manager.rb, line 495 def each( &block ) return enum_for( __method__ ) if !block_given? @platforms.map { |_, p| p.to_a }.flatten.each( &block ) self end
@return [Boolean]
`true` if there are no applicable platforms, `false` otherwise.
# File lib/arachni/platform/manager.rb, line 515 def empty? !@platforms.map { |_, p| p.empty? }.include?( false ) end
@param [String, Symbol] platform
Platform whose list to find.
@return [List]
Platform list.
# File lib/arachni/platform/manager.rb, line 568 def find_list( platform ) @platforms[find_type( normalize( platform ) )] end
@param [String, Symbol] platform
Platform whose type to find
@return [Symbol] Platform
type.
# File lib/arachni/platform/manager.rb, line 559 def find_type( platform ) self.class.find_type( platform ) end
Converts a platform shortname to a full name.
@param [String, Symbol] platform
Platform shortname.
@return [String]
Full name.
@raise [Error::Invalid]
On {#invalid?} platforms.
# File lib/arachni/platform/manager.rb, line 423 def fullname( platform ) PLATFORM_NAMES[normalize( platform )] end
@param [Symbol, String] platform
Platform to check.
@return [Boolean]
`true` if one of the lists contains the `platform`, `false` otherwise.
@raise [Error::Invalid]
On {#invalid?} `platforms`.
# File lib/arachni/platform/manager.rb, line 509 def include?( platform ) find_list( platform ).include?( platform ) end
@param [Symbol, String] platform
Platform to check.
@return [Boolean]
`true` if platform is invalid (i.e. not in {#valid}), `false` otherwise.
@see invalid?
# File lib/arachni/platform/manager.rb, line 486 def invalid?( platform ) !valid?( platform ) end
Selects appropriate data, depending on the applicable platforms, from ‘data_per_platform`.
@param [Hash{<Symbol, String> => Object}] data_per_platform
Hash with platform names as keys and arbitrary data as values.
@return [Hash]
`data_per_platform` with non-applicable entries (for non-empty platform lists) removed. Data for platforms whose list is empty will not be removed.
@raise [Error::Invalid]
On {#invalid?} platforms.
# File lib/arachni/platform/manager.rb, line 439 def pick( data_per_platform ) data_per_list = {} data_per_platform.each do |platform, value| list = find_list( platform ) data_per_list[list] ||= {} data_per_list[list][platform] = value end picked = {} data_per_list.each do |list, data| # If a platform list is empty pass the given data without picking... if list.empty? picked.merge! data next end # ...otherwise enforce its platform restrictions. picked.merge! list.pick( data ) end picked end
@param [Enumerable] enum
Enumerable object containing platforms.
@return [Manager]
Updated `self`.
@raise [Error::Invalid]
On {#invalid?} platforms.
# File lib/arachni/platform/manager.rb, line 537 def update( enum ) enum.each { |p| self << p } self end
@return [Set<Symbol>]
List of valid platforms.
# File lib/arachni/platform/manager.rb, line 464 def valid self.class.valid end
@param [Symbol, String] platform
Platform to check.
@return [Boolean]
`true` if platform is valid (i.e. in {#valid}), `false` otherwise.
@see invalid?
# File lib/arachni/platform/manager.rb, line 475 def valid?( platform ) valid.include? platform end
Private Instance Methods
# File lib/arachni/platform/manager.rb, line 574 def normalize( platform ) platform = List.normalize( platform ) fail Error::Invalid, "Invalid platform: #{platform}" if invalid?( platform ) platform end