#!/usr/bin/ruby
require 'optparse'
require 'csv'

def main
  input = parseInput
  queries = input[:queries]
  csv = input[:csv]
  dump = input[:dump]

  begin
    matches = findMatches csv, queries
  rescue
    bad_csv = File.read csv, encoding: 'windows-1251:utf-8'
    File.open(csv, 'w') do |f|
      f.write bad_csv.gsub('\\"', '""')
    end
    matches = findMatches csv, queries
  end

  if dump and not matches.empty?
    puts `svn cat svn://svn.exploit-db.com/exploitdb/#{matches.last['file']}`
  else
    matches.each do |m| puts m.to_s end
  end
end

def parseInput
  queries = {}
  csv = false
  dump = false

  OptionParser.new do |opts|
    opts.banner = 'Usage: exploitdb.rb [options]'
    opts.separator ''
    opts.separator 'Required, one or more queries:'
    opts.on '--file FILE',               'platforms/windows/remote/'  do |x| queries[:file] = x end
    opts.on '--description DESCRIPTION', 'wordpress, samba, apache..' do |x| queries[:description] = x end
    opts.on '--date DATE',               'YYYY-MM-DD'                 do |x| queries[:date] = x end
    opts.on '--author AUTHOR',           'kralor, romansoft..'        do |x| queries[:author] = x end
    opts.on '--platform PLATFORM',       'windows, linux, solaris..'  do |x| queries[:platform] = x end
    opts.on '--type TYPE',               'remote, local, dos..'       do |x| queries[:type] = x end
    opts.on '--port PORT',               '0, 80, 139..'               do |x| queries[:port] = x end
    opts.on '--id ID',                   '1, 2.. Useful with --dump'  do |x| queries[:id] = x end
    opts.separator 'Optional args:'
    opts.on '--dump', 'Dump code of last match. TIP: >> exploit_code' do |x| dump = x end
    opts.on '--csv CSV', 'Provide csv. WARNING: Will be auto-fixed'   do |x| csv = x end
  end.parse!

  if queries.empty? #Must give a query to filter search results
    puts 'Use --help to view help'
    Process.exit
  end

  #Check if valid file is given and default to downloading new one
  csv ||= '/tmp/exploitdb.csv'
  csv = '/tmp/exploitdb.csv' unless File.exists? csv
  unless File.exists? csv
    !`which svn`.empty? or raise 'apt-get install subversion #We need to pull in a fresh csv'
    `svn export svn://svn.exploit-db.com/exploitdb/files.csv /tmp/exploitdb.csv`
  end

  {queries: queries, csv: csv, dump: dump}
end

def findMatches(csv, queries)
  matches = []

  CSV.foreach csv, headers: true do |row|
    if queries[:id] #if id is specified ignore other queries
      if row['id'] == queries[:id]
        return [row]
      else
        next
      end
    end

    is_match = true
    queries.each do |option, value|
      next unless row[option.to_s] #skip empty properties, assume match
      is_match = false unless row[option.to_s].match /#{value}/i
    end

    matches.push row if is_match
  end

  matches
end

main
