Land #3269 (Pro) fix report import issue
commit
e556997bf7
|
@ -2172,35 +2172,63 @@ class DBManager
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
#
|
# TODO This method does not attempt to find. It just creates
|
||||||
# Find or create a task matching this type/data
|
# a report based on the passed params.
|
||||||
#
|
|
||||||
def find_or_create_report(opts)
|
def find_or_create_report(opts)
|
||||||
report_report(opts)
|
report_report(opts)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Creates a Report based on passed parameters. Does not handle
|
||||||
|
# child artifacts.
|
||||||
|
# @param opts [Hash]
|
||||||
|
# @return [Integer] ID of created report
|
||||||
def report_report(opts)
|
def report_report(opts)
|
||||||
return if not active
|
return if not active
|
||||||
::ActiveRecord::Base.connection_pool.with_connection {
|
::ActiveRecord::Base.connection_pool.with_connection {
|
||||||
wspace = opts.delete(:workspace) || workspace
|
|
||||||
path = opts.delete(:path) || (raise RuntimeError, "A report :path is required")
|
|
||||||
|
|
||||||
ret = {}
|
report = Report.new(opts)
|
||||||
user = opts.delete(:user)
|
unless report.valid?
|
||||||
options = opts.delete(:options)
|
errors = report.errors.full_messages.join('; ')
|
||||||
rtype = opts.delete(:rtype)
|
raise RuntimeError "Report to be imported is not valid: #{errors}"
|
||||||
report = wspace.reports.new
|
end
|
||||||
report.created_by = user
|
report.state = :complete # Presume complete since it was exported
|
||||||
report.options = options
|
report.save
|
||||||
report.rtype = rtype
|
|
||||||
report.path = path
|
|
||||||
msf_import_timestamps(opts,report)
|
|
||||||
report.save!
|
|
||||||
|
|
||||||
ret[:task] = report
|
report.id
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Creates a ReportArtifact based on passed parameters.
|
||||||
|
# @param opts [Hash] of ReportArtifact attributes
|
||||||
|
def report_artifact(opts)
|
||||||
|
artifacts_dir = Report::ARTIFACT_DIR
|
||||||
|
tmp_path = opts[:file_path]
|
||||||
|
artifact_name = File.basename tmp_path
|
||||||
|
new_path = File.join(artifacts_dir, artifact_name)
|
||||||
|
|
||||||
|
unless File.exists? tmp_path
|
||||||
|
raise DBImportError 'Report artifact file to be imported does not exist.'
|
||||||
|
end
|
||||||
|
|
||||||
|
unless (File.directory?(artifacts_dir) && File.writable?(artifacts_dir))
|
||||||
|
raise DBImportError "Could not move report artifact file to #{artifacts_dir}."
|
||||||
|
end
|
||||||
|
|
||||||
|
if File.exists? new_path
|
||||||
|
unique_basename = "#{(Time.now.to_f*1000).to_i}_#{artifact_name}"
|
||||||
|
new_path = File.join(artifacts_dir, unique_basename)
|
||||||
|
end
|
||||||
|
|
||||||
|
FileUtils.copy(tmp_path, new_path)
|
||||||
|
opts[:file_path] = new_path
|
||||||
|
artifact = ReportArtifact.new(opts)
|
||||||
|
unless artifact.valid?
|
||||||
|
errors = artifact.errors.full_messages.join('; ')
|
||||||
|
raise RuntimeError "Artifact to be imported is not valid: #{errors}"
|
||||||
|
end
|
||||||
|
artifact.save
|
||||||
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
# This methods returns a list of all reports in the database
|
# This methods returns a list of all reports in the database
|
||||||
#
|
#
|
||||||
|
@ -3793,43 +3821,55 @@ class DBManager
|
||||||
|
|
||||||
# Import Reports
|
# Import Reports
|
||||||
doc.elements.each("/#{btag}/reports/report") do |report|
|
doc.elements.each("/#{btag}/reports/report") do |report|
|
||||||
tmp = args[:ifd][:zip_tmp]
|
import_report(report, args, basedir)
|
||||||
report_info = {}
|
|
||||||
report_info[:workspace] = args[:wspace]
|
|
||||||
# Should user be imported (original) or declared (the importing user)?
|
|
||||||
report_info[:user] = nils_for_nulls(report.elements["created-by"].text.to_s.strip)
|
|
||||||
report_info[:options] = nils_for_nulls(report.elements["options"].text.to_s.strip)
|
|
||||||
report_info[:rtype] = nils_for_nulls(report.elements["rtype"].text.to_s.strip)
|
|
||||||
report_info[:created_at] = nils_for_nulls(report.elements["created-at"].text.to_s.strip)
|
|
||||||
report_info[:updated_at] = nils_for_nulls(report.elements["updated-at"].text.to_s.strip)
|
|
||||||
report_info[:orig_path] = nils_for_nulls(report.elements["path"].text.to_s.strip)
|
|
||||||
report_info[:task] = args[:task]
|
|
||||||
report_info[:orig_path].gsub!(/^\./, tmp) if report_info[:orig_path]
|
|
||||||
|
|
||||||
# Only report a report if we actually have it.
|
|
||||||
# TODO: Copypasta. Seperate this out.
|
|
||||||
if ::File.exists? report_info[:orig_path]
|
|
||||||
reports_dir = ::File.join(basedir,"reports")
|
|
||||||
report_file = ::File.split(report_info[:orig_path]).last
|
|
||||||
if ::File.exists? reports_dir
|
|
||||||
unless (::File.directory?(reports_dir) && ::File.writable?(reports_dir))
|
|
||||||
raise DBImportError.new("Could not move files to #{reports_dir}")
|
|
||||||
end
|
|
||||||
else
|
|
||||||
::FileUtils.mkdir_p(reports_dir)
|
|
||||||
end
|
|
||||||
new_report = ::File.join(reports_dir,report_file)
|
|
||||||
report_info[:path] = new_report
|
|
||||||
if ::File.exists?(new_report)
|
|
||||||
::File.unlink new_report
|
|
||||||
else
|
|
||||||
report_report(report_info)
|
|
||||||
end
|
|
||||||
::FileUtils.copy(report_info[:orig_path], new_report)
|
|
||||||
yield(:msf_report, new_report) if block
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# @param report [REXML::Element] to be imported
|
||||||
|
# @param args [Hash]
|
||||||
|
# @param base_dir [String]
|
||||||
|
def import_report(report, args, base_dir)
|
||||||
|
tmp = args[:ifd][:zip_tmp]
|
||||||
|
report_info = {}
|
||||||
|
|
||||||
|
report.elements.each do |e|
|
||||||
|
node_name = e.name
|
||||||
|
node_value = e.text
|
||||||
|
|
||||||
|
# These need to be converted back to arrays:
|
||||||
|
array_attrs = %w|addresses file-formats options sections|
|
||||||
|
if array_attrs.member? node_name
|
||||||
|
node_value = JSON.parse(node_value)
|
||||||
|
end
|
||||||
|
# Don't restore these values:
|
||||||
|
skip_nodes = %w|id workspace-id artifacts|
|
||||||
|
next if skip_nodes.member? node_name
|
||||||
|
|
||||||
|
report_info[node_name.parameterize.underscore.to_sym] = node_value
|
||||||
|
end
|
||||||
|
# Use current workspace
|
||||||
|
report_info[:workspace_id] = args[:wspace].id
|
||||||
|
|
||||||
|
# Create report, need new ID to record artifacts
|
||||||
|
report_id = report_report(report_info)
|
||||||
|
|
||||||
|
# Handle artifacts
|
||||||
|
report.elements['artifacts'].elements.each do |artifact|
|
||||||
|
artifact_opts = {}
|
||||||
|
artifact.elements.each do |attr|
|
||||||
|
skip_nodes = %w|id accessed-at|
|
||||||
|
next if skip_nodes.member? attr.name
|
||||||
|
|
||||||
|
symboled_attr = attr.name.parameterize.underscore.to_sym
|
||||||
|
artifact_opts[symboled_attr] = attr.text
|
||||||
|
end
|
||||||
|
# Use new Report as parent
|
||||||
|
artifact_opts[:report_id] = report_id
|
||||||
|
# Update to full path
|
||||||
|
artifact_opts[:file_path].gsub!(/^\./, tmp)
|
||||||
|
|
||||||
|
report_artifact(artifact_opts)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Convert the string "NULL" to actual nil
|
# Convert the string "NULL" to actual nil
|
||||||
|
|
Loading…
Reference in New Issue