# XML Output # # Does anyone use XML output? # We'd love to hear any suggestions you may have! # Does it bother you that some types of output are joined by commas # but other types aren't? class LoggingXML < Logging def initialize(f = STDOUT) super @substitutions = { '&' => '&', '"' => '"', '<' => '<', '>' => '>' } # only output ' end @f.puts '' end def close @f.puts '' @f.close end def escape(t) text = t.to_s.dup # use sort_by so that & is before ", etc. @substitutions.sort_by { |a, _| a == '&' ? 0 : 1 }.map { |from, to| text.gsub!(from, to) } # Encode all special characters # More info: http://www.asciitable.com/ r = /[^\x20-\x5A\x5E-\x7E]/ # based on code for CGI.escape text.gsub!(r) { |x| "%#{x.unpack('H2' * x.size).join('%').upcase}" } text end def out(target, status, results) $semaphore.synchronize do @f.puts '' @f.puts "\t#{escape(target)}" @f.puts "\t#{escape(status)}" @f.puts "\t" @f.puts "\t\t" if $USE_PROXY @f.puts "\t\t\t#{escape($PROXY_HOST)}:#{escape($PROXY_PORT)}" if $PROXY_HOST && $PROXY_PORT @f.puts "\t\t\t#{escape($PROXY_USER)}" if $PROXY_USER @f.puts "\t\t" if $USE_PROXY $CUSTOM_HEADERS.each do |header_name, header_value| @f.puts "\t\t
" @f.puts "\t\t\t#{escape(header_name)}" @f.puts "\t\t\t#{escape(header_value)}" @f.puts "\t\t
" end @f.puts "\t
" results.each do |plugin_name, plugin_results| @f.puts "\t" @f.puts "\t\t#{escape(plugin_name)}" unless plugin_results.empty? # important info in brief mode is version, type and ? # what's the highest probability for the match? certainty = plugin_results.map do |x| x[:certainty] unless x[:certainty].class == Regexp end.flatten.compact.sort.uniq.last version = plugin_results.map do |x| x[:version] unless x[:version].class == Regexp end.flatten.compact.sort.uniq os = plugin_results.map do |x| x[:os] unless x[:os].class == Regexp end.flatten.compact.sort.uniq string = plugin_results.map do |x| x[:string] unless x[:string].class == Regexp end.flatten.compact.sort.uniq model = plugin_results.map do |x| x[:model] unless x[:model].class == Regexp end.flatten.compact.sort.uniq firmware = plugin_results.map do |x| x[:firmware] unless x[:firmware].class == Regexp end.flatten.compact.sort.uniq filepath = plugin_results.map do |x| x[:filepath] unless x[:filepath].class == Regexp end.flatten.compact.sort.uniq account = plugin_results.map do |x| x[:account] unless x[:account].class == Regexp end.flatten.compact.sort.uniq modules = plugin_results.map do |x| x[:module] unless x[:module].class == Regexp end.flatten.compact.sort.uniq # Output results @f.puts "\t\t#{escape(certainty)}" if certainty && certainty < 100 version.map { |x| @f.puts "\t\t#{escape(x)}" } os.map { |x| @f.puts "\t\t#{escape(x)}" } string.map { |x| @f.puts "\t\t#{escape(x)}" } model.map { |x| @f.puts "\t\t#{escape(x)}" } firmware.map { |x| @f.puts "\t\t#{escape(x)}" } filepath.map { |x| @f.puts "\t\t#{escape(x)}" } account.map { |x| @f.puts "\t\t#{escape(x)}" } modules.map { |x| @f.puts "\t\t#{escape(x)}" } end @f.puts "\t" end @f.puts '
' end end end