mirror of
https://github.com/elisspace/autopsy.git
synced 2026-09-06 02:24:30 +00:00
Complete major functionality for external result imports and reports in Autopsy tree
This commit is contained in:
@@ -1166,18 +1166,18 @@ public class Case implements SleuthkitCase.ErrorObserver {
|
||||
public void receiveError(String context, String errorMessage) {
|
||||
MessageNotifyUtil.Notify.error(context, errorMessage);
|
||||
}
|
||||
|
||||
// RJCTODO: Clean this up
|
||||
|
||||
/**
|
||||
* Inserts row into the reports table in the case database.
|
||||
* @param [in] relPath The path of the report file, relative to the database (case directory in Autopsy).
|
||||
* @param [in] displayName The display name for the new tag name.
|
||||
* Adds a report to the case.
|
||||
*
|
||||
* @param [in] localPath The path of the report file, must be in the case directory or one of its subdirectories.
|
||||
* @param [in] sourceModuleName The name of the module that created the report.
|
||||
* @param [in] reportName The report name, may be empty.
|
||||
* @return A Report data transfer object (DTO) for the new row.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public void addReport(String relPath, String displayName) throws TskCoreException {
|
||||
Report report = this.db.addReport(relPath, displayName);
|
||||
// RJCTODO: Fire event, perhaps with repoprt data
|
||||
*/
|
||||
public void addReport(String localPath, String srcModuleName, String reportName) throws TskCoreException {
|
||||
Report report = this.db.addReport(localPath, srcModuleName, reportName);
|
||||
Case.pcs.firePropertyChange(Events.REPORT_ADDED.toString(), null, report); // RJCTODO: Need exception firewall, maybe thread to do publishing
|
||||
}
|
||||
|
||||
|
||||
@@ -209,9 +209,9 @@ RecentFilesNode.createSheet.name.name=Name
|
||||
RecentFilesNode.createSheet.name.displayName=Name
|
||||
RecentFilesNode.createSheet.name.desc=no description
|
||||
RecentFilesNode.name.text=Recent Files
|
||||
ReportNode.displayNameProperty.name=Display Name
|
||||
ReportNode.displayNameProperty.displayName=Report Name
|
||||
ReportNode.displayNameProperty.desc=Name of the report
|
||||
ReportNode.sourceModuleNameProperty.name=Source Module Name
|
||||
ReportNode.sourceModuleNameProperty.displayName=Source Module Name
|
||||
ReportNode.sourceModuleNameProperty.desc=Name of the module that created the report
|
||||
ReportNode.createdTimeProperty.name=Created Time
|
||||
ReportNode.createdTimeProperty.displayName=Created Time
|
||||
ReportNode.createdTimeProperty.desc=Time report was created
|
||||
|
||||
@@ -18,11 +18,20 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import java.awt.Desktop;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.Action;
|
||||
import javax.swing.JOptionPane;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
@@ -37,10 +46,10 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
/**
|
||||
* Implements the Reports subtree of the Autopsy tree.
|
||||
*/
|
||||
public class Reports implements AutopsyVisitableItem {
|
||||
public final class Reports implements AutopsyVisitableItem {
|
||||
|
||||
private static final SimpleDateFormat dateFormatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T accept(AutopsyItemVisitor<T> visitor) {
|
||||
// The CreateAutopsyNodeVisitor constructs a ReportsListNode when it
|
||||
@@ -51,7 +60,7 @@ public class Reports implements AutopsyVisitableItem {
|
||||
/**
|
||||
* The root node of the Reports subtree of the Autopsy tree.
|
||||
*/
|
||||
public static class ReportsListNode extends DisplayableItemNode {
|
||||
public static final class ReportsListNode extends DisplayableItemNode {
|
||||
|
||||
private static final String DISPLAY_NAME = NbBundle.getMessage(ReportsListNode.class, "ReportsListNode.displayName");
|
||||
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/report_16.png"; //NON-NLS
|
||||
@@ -82,7 +91,7 @@ public class Reports implements AutopsyVisitableItem {
|
||||
* The child node factory that creates ReportNode children for a
|
||||
* ReportsListNode.
|
||||
*/
|
||||
private static class ReportNodeFactory extends ChildFactory<Report> {
|
||||
private static final class ReportNodeFactory extends ChildFactory<Report> {
|
||||
|
||||
ReportNodeFactory() {
|
||||
Case.addPropertyChangeListener(new PropertyChangeListener() {
|
||||
@@ -116,7 +125,7 @@ public class Reports implements AutopsyVisitableItem {
|
||||
* A leaf node in the Reports subtree of the Autopsy tree, wraps a Report
|
||||
* object.
|
||||
*/
|
||||
public static class ReportNode extends DisplayableItemNode {
|
||||
public static final class ReportNode extends DisplayableItemNode {
|
||||
|
||||
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/report_16.png"; //NON-NLS
|
||||
private final Report report;
|
||||
@@ -124,8 +133,8 @@ public class Reports implements AutopsyVisitableItem {
|
||||
ReportNode(Report report) {
|
||||
super(Children.LEAF, Lookups.fixed(report));
|
||||
this.report = report;
|
||||
super.setName(this.report.getDisplayName());
|
||||
super.setDisplayName(this.report.getDisplayName());
|
||||
super.setName(this.report.getSourceModuleName());
|
||||
super.setDisplayName(this.report.getSourceModuleName());
|
||||
this.setIconBaseWithExtension(ICON_PATH);
|
||||
}
|
||||
|
||||
@@ -136,8 +145,8 @@ public class Reports implements AutopsyVisitableItem {
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
|
||||
// The GetPopupActionsDisplayableItemNodeVisitor gets the Actions for this class.
|
||||
// The GetPreferredActionsDisplayableItemNodeVisitor RJCTODO
|
||||
// The GetPopupActionsDisplayableItemNodeVisitor calls getActions(). // RJCTODO: Try to get rid of parent collapse all
|
||||
// The GetPreferredActionsDisplayableItemNodeVisitor calls getPreferredAction().
|
||||
// The IsLeafItemVisitor returns true.
|
||||
// The ShowItemVisitor always returns true.
|
||||
return visitor.visit(this);
|
||||
@@ -151,19 +160,58 @@ public class Reports implements AutopsyVisitableItem {
|
||||
propertiesSet = Sheet.createPropertiesSet();
|
||||
sheet.put(propertiesSet);
|
||||
}
|
||||
propertiesSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ReportNode.displayNameProperty.name"),
|
||||
NbBundle.getMessage(this.getClass(), "ReportNode.displayNameProperty.displayName"),
|
||||
NbBundle.getMessage(this.getClass(), "ReportNode.displayNameProperty.desc"),
|
||||
this.report.getDisplayName()));
|
||||
propertiesSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ReportNode.sourceModuleNameProperty.name"),
|
||||
NbBundle.getMessage(this.getClass(), "ReportNode.sourceModuleNameProperty.displayName"),
|
||||
NbBundle.getMessage(this.getClass(), "ReportNode.sourceModuleNameProperty.desc"),
|
||||
this.report.getSourceModuleName()));
|
||||
propertiesSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ReportNode.createdTimeProperty.name"),
|
||||
NbBundle.getMessage(this.getClass(), "ReportNode.createdTimeProperty.displayName"),
|
||||
NbBundle.getMessage(this.getClass(), "ReportNode.createdTimeProperty.desc"),
|
||||
dateFormatter.format(new java.util.Date(this.report.getCreatedTime() * 1000)).toString()));
|
||||
dateFormatter.format(new java.util.Date(this.report.getCreatedTime() * 1000)).toString()));
|
||||
propertiesSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ReportNode.pathProperty.name"),
|
||||
NbBundle.getMessage(this.getClass(), "ReportNode.pathProperty.displayName"),
|
||||
NbBundle.getMessage(this.getClass(), "ReportNode.pathProperty.desc"),
|
||||
this.report.getPath()));
|
||||
return sheet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action[] getActions(boolean popup) {
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.addAll(Arrays.asList(super.getActions(true)));
|
||||
actions.add(new OpenReportAction());
|
||||
return actions.toArray(new Action[actions.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractAction getPreferredAction() {
|
||||
return new OpenReportAction();
|
||||
}
|
||||
|
||||
private final class OpenReportAction extends AbstractAction { // RJCTODO: Needs name for menu
|
||||
|
||||
private OpenReportAction() {
|
||||
super("Open Report"); // RJCTODO: bundle
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
File file = new File(ReportNode.this.report.getPath());
|
||||
try {
|
||||
Desktop.getDesktop().open(file);
|
||||
} catch (IOException ex) {
|
||||
// RJCTODO: Failed to open no associated editor or associated application failed to launch
|
||||
// RJCTODO: Bundle
|
||||
JOptionPane.showMessageDialog(null, "There is no associated editor for reports of this type or the associated application failed to launch.",
|
||||
"Open Report Failure", JOptionPane.ERROR_MESSAGE);
|
||||
} catch (UnsupportedOperationException ex) {
|
||||
// RJCTODO
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// RJCTODO: File does not exist
|
||||
} catch (SecurityException ex) {
|
||||
// RJCTODO: permission denied
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,6 +66,7 @@ import org.sleuthkit.autopsy.datamodel.RecentFilesFilterNode;
|
||||
import org.sleuthkit.autopsy.datamodel.RecentFilesNode;
|
||||
import org.sleuthkit.autopsy.datamodel.FileTypesNode;
|
||||
import org.sleuthkit.autopsy.datamodel.KeywordHits;
|
||||
import org.sleuthkit.autopsy.datamodel.Reports;
|
||||
import org.sleuthkit.autopsy.datamodel.Tags;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
@@ -522,6 +523,11 @@ public class DataResultFilterNode extends FilterNode {
|
||||
return openChild(khmln);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractAction visit(Reports.ReportNode reportNode) {
|
||||
return reportNode.getPreferredAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractAction defaultVisit(DisplayableItemNode c) {
|
||||
return null;
|
||||
|
||||
@@ -32,8 +32,6 @@ package org.sleuthkit.autopsy.examples;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
@@ -56,6 +54,7 @@ import org.sleuthkit.autopsy.externalresults.ExternalResultsXMLParser;
|
||||
import org.sleuthkit.autopsy.ingest.DataSourceIngestModule;
|
||||
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
|
||||
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
||||
import org.sleuthkit.autopsy.ingest.IngestMessage;
|
||||
import org.sleuthkit.autopsy.ingest.IngestModuleReferenceCounter;
|
||||
import org.sleuthkit.autopsy.ingest.IngestServices;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||
@@ -126,7 +125,9 @@ public class SampleExecutableDataSourceIngestModule implements DataSourceIngestM
|
||||
List<ErrorInfo> errors = resultsParser.getErrorInfo();
|
||||
ExternalResultsImporter importer = new ExternalResultsImporter();
|
||||
errors.addAll(importer.importResults(results));
|
||||
// RJCTODO: Report error messages to UI
|
||||
for (ErrorInfo errorInfo : errors) {
|
||||
IngestServices.getInstance().postMessage(IngestMessage.createErrorMessage(moduleName, "External Results Import Error", errorInfo.getMessage()));
|
||||
}
|
||||
progressBar.progress(2);
|
||||
} catch (TskCoreException | InterruptedException | ParserConfigurationException | TransformerException | IOException ex) {
|
||||
Logger logger = IngestServices.getInstance().getLogger(moduleName);
|
||||
@@ -139,8 +140,8 @@ public class SampleExecutableDataSourceIngestModule implements DataSourceIngestM
|
||||
|
||||
private void generateSimulatedResults(String resultsFilePath) throws ParserConfigurationException, IOException, TransformerConfigurationException, TransformerException {
|
||||
List<String> derivedFilePaths = generateSimulatedDerivedFiles();
|
||||
String reportFilePath = generateSimulatedReport();
|
||||
generateSimulatedResultsFile(derivedFilePaths, reportFilePath, resultsFilePath);
|
||||
List<String> reportFilePaths = generateSimulatedReports();
|
||||
generateSimulatedResultsFile(derivedFilePaths, reportFilePaths, resultsFilePath);
|
||||
}
|
||||
|
||||
private List<String> generateSimulatedDerivedFiles() throws IOException {
|
||||
@@ -156,10 +157,14 @@ public class SampleExecutableDataSourceIngestModule implements DataSourceIngestM
|
||||
return filePaths;
|
||||
}
|
||||
|
||||
private String generateSimulatedReport() throws IOException {
|
||||
String reportFileName = String.format("job_%d_report.txt", jobId);
|
||||
String reportContents = "This is a simulated report.";
|
||||
return generateFile(reportFileName, reportContents.getBytes());
|
||||
private List<String> generateSimulatedReports() throws IOException {
|
||||
List<String> filePaths = new ArrayList<>();
|
||||
String fileContents = "This is a simulated report.";
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
String fileName = String.format("job_%d_report_%d.txt", jobId, i);
|
||||
filePaths.add(generateFile(fileName, fileContents.getBytes()));
|
||||
}
|
||||
return filePaths;
|
||||
}
|
||||
|
||||
private String generateFile(String fileName, byte[] fileContents) throws IOException {
|
||||
@@ -175,7 +180,58 @@ public class SampleExecutableDataSourceIngestModule implements DataSourceIngestM
|
||||
return filePath;
|
||||
}
|
||||
|
||||
private void generateSimulatedResultsFile(List<String> derivedFilePaths, String reportPath, String resultsFilePath) throws ParserConfigurationException, TransformerConfigurationException, TransformerException {
|
||||
private void generateSimulatedResultsFile(List<String> derivedFilePaths, List<String> reportPaths, String resultsFilePath) throws ParserConfigurationException, TransformerConfigurationException, TransformerException {
|
||||
// SAMPLE GENERATED BY THE CODE BELOW:
|
||||
//
|
||||
// <?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
// <autopsy_results>
|
||||
// <derived_files>
|
||||
// <derived_file>
|
||||
// <local_path>C:\cases\Small\ModuleOutput\Sample Executable Ingest Module\job_1_derived_file_0.txt</local_path>
|
||||
// <parent_file>/WINDOWS/system32/ntmsapi.dll</parent_file>
|
||||
// </derived_file>
|
||||
// <derived_file>
|
||||
// <local_path>C:\cases\Small\ModuleOutput\Sample Executable Ingest Module\job_1_derived_file_1.txt</local_path>
|
||||
// <parent_file>/WINDOWS/system32/ntmsapi.dll/job_1_derived_file_0.txt</parent_file>
|
||||
// </derived_file>
|
||||
// </derived_files>
|
||||
// <artifacts>
|
||||
// <artifact type="TSK_INTERESTING_FILE_HIT">
|
||||
// <source_file>/WINDOWS/system32/ntmsapi.dll</source_file>
|
||||
// <attribute type="TSK_SET_NAME">
|
||||
// <value>SampleInterestingFilesSet</value>
|
||||
// <source_module>Sample Executable Ingest Module</source_module>
|
||||
// </attribute>
|
||||
// </artifact>
|
||||
// <artifact type="SampleArtifactType">
|
||||
// <source_file>/WINDOWS/system32/ntmsapi.dll/job_1_derived_file_0.txt</source_file>
|
||||
// <attribute type="SampleArtifactAttributeType">
|
||||
// <value type="text">One</value>
|
||||
// </attribute>
|
||||
// <attribute type="SampleArtifactAttributeType">
|
||||
// <value type="int32">2</value>
|
||||
// </attribute>
|
||||
// <attribute type="SampleArtifactAttributeType">
|
||||
// <value type="int64">3</value>
|
||||
// </attribute>
|
||||
// <attribute type="SampleArtifactAttributeType">
|
||||
// <value type="double">4.0</value>
|
||||
// </attribute>
|
||||
// </artifact>
|
||||
// </artifacts>
|
||||
// <reports>
|
||||
// <report>
|
||||
// <local_path>C:\cases\Small\ModuleOutput\Sample Executable Ingest Module\job_1_report_0.txt</local_path>
|
||||
// <source_module>Sample Executable Ingest Module</source_module>
|
||||
// <report_name>Sample Report</report_name>
|
||||
// </report>
|
||||
// <report>
|
||||
// <local_path>C:\cases\Small\ModuleOutput\Sample Executable Ingest Module\job_1_report_1.txt</local_path>
|
||||
// <source_module>Sample Executable Ingest Module</source_module>
|
||||
// </report>
|
||||
// </reports>
|
||||
// </autopsy_results>
|
||||
|
||||
// Create the XML DOM document and the root element.
|
||||
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
|
||||
@@ -190,8 +246,10 @@ public class SampleExecutableDataSourceIngestModule implements DataSourceIngestM
|
||||
// Add derived file elements to the derived files list element. Each
|
||||
// file element gets required local path and parent file child elements.
|
||||
// Note that the local path of the derived file must be to a location in
|
||||
// a subdirectory of the case directory and the parent file must be
|
||||
// specified using the path format used in the case database.
|
||||
// the case directory or a subdirectory of the case directory and the
|
||||
// parent file must be specified using the path format used in the case
|
||||
// database, e.g., /WINDOWS/system32/ntmsapi.dll, where volume, file
|
||||
// system, etc. are not in the path.
|
||||
for (int i = 0; i < derivedFilePaths.size(); ++i) {
|
||||
String filePath = derivedFilePaths.get(i);
|
||||
Element derivedFileElement = doc.createElement(ExternalResultsXMLParser.TagNames.DERIVED_FILE_ELEM.toString());
|
||||
@@ -288,21 +346,29 @@ public class SampleExecutableDataSourceIngestModule implements DataSourceIngestM
|
||||
Element reportsListElement = doc.createElement(ExternalResultsXMLParser.TagNames.REPORTS_LIST_ELEM.toString());
|
||||
rootElement.appendChild(reportsListElement);
|
||||
|
||||
// Add a report element to the reports list element.
|
||||
Element reportElement = doc.createElement(ExternalResultsXMLParser.TagNames.REPORT_ELEM.toString());
|
||||
reportsListElement.appendChild(reportElement);
|
||||
|
||||
// Add the required display name element to the report element.
|
||||
Element reportDisplayNameElement = doc.createElement(ExternalResultsXMLParser.TagNames.DISPLAY_NAME_ELEM.toString());
|
||||
reportDisplayNameElement.setTextContent("Sample Report");
|
||||
reportElement.appendChild(reportDisplayNameElement);
|
||||
|
||||
// Add the required local path element to the report element. Note that
|
||||
// the local path must be an absolute path to a location in a
|
||||
// subdirectory of the case direcotry.
|
||||
Element reportPathElement = doc.createElement(ExternalResultsXMLParser.TagNames.LOCAL_PATH_ELEM.toString());
|
||||
reportPathElement.setTextContent(reportPath);
|
||||
reportElement.appendChild(reportPathElement);
|
||||
// Add report elements to the reports list element. Each report element
|
||||
// gets required local path and source module child elements. There is
|
||||
// also an optional report name element. Note that the local path of the
|
||||
// report must be to a location in the case directory or a subdirectory
|
||||
// of the case directory and the parent file must be specified using the
|
||||
// path format used in the case database, e.g., /WINDOWS/system32/ntmsapi.dll,
|
||||
// where volume, file system, etc. are not in the path.
|
||||
for (int i = 0; i < reportPaths.size(); ++i) {
|
||||
String reportPath = reportPaths.get(i);
|
||||
Element reportElement = doc.createElement(ExternalResultsXMLParser.TagNames.REPORT_ELEM.toString());
|
||||
reportsListElement.appendChild(reportElement);
|
||||
Element reportPathElement = doc.createElement(ExternalResultsXMLParser.TagNames.LOCAL_PATH_ELEM.toString());
|
||||
reportPathElement.setTextContent(reportPath);
|
||||
reportElement.appendChild(reportPathElement);
|
||||
Element reportSourceModuleElement = doc.createElement(ExternalResultsXMLParser.TagNames.SOURCE_MODULE_ELEM.toString());
|
||||
reportSourceModuleElement.setTextContent(moduleName);
|
||||
reportElement.appendChild(reportSourceModuleElement);
|
||||
if (i == 0) {
|
||||
Element reportNameElement = doc.createElement(ExternalResultsXMLParser.TagNames.REPORT_NAME_ELEM.toString());
|
||||
reportNameElement.setTextContent("Sample Report");
|
||||
reportElement.appendChild(reportNameElement);
|
||||
}
|
||||
}
|
||||
|
||||
TransformerFactory transformerFactory = TransformerFactory.newInstance();
|
||||
Transformer transformer = transformerFactory.newTransformer();
|
||||
|
||||
@@ -79,21 +79,18 @@ class SampleFileIngestModule implements FileIngestModule {
|
||||
// modules.
|
||||
Case autopsyCase = Case.getCurrentCase();
|
||||
SleuthkitCase sleuthkitCase = autopsyCase.getSleuthkitCase();
|
||||
|
||||
// See if the attribute type has already been defined.
|
||||
try {
|
||||
// See if the attribute type has already been defined.
|
||||
attrId = sleuthkitCase.getAttrTypeID("ATTR_SAMPLE");
|
||||
} catch (TskCoreException e) {
|
||||
// If not, create the the attribute type.
|
||||
try {
|
||||
if (attrId == -1) {
|
||||
attrId = sleuthkitCase.addAttrType("ATTR_SAMPLE", "Sample Attribute");
|
||||
} catch (TskCoreException ex) {
|
||||
IngestServices ingestServices = IngestServices.getInstance();
|
||||
Logger logger = ingestServices.getLogger(SampleIngestModuleFactory.getModuleName());
|
||||
logger.log(Level.SEVERE, "Failed to create blackboard attribute", ex);
|
||||
attrId = -1;
|
||||
throw new IngestModuleException(ex.getLocalizedMessage());
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
IngestServices ingestServices = IngestServices.getInstance();
|
||||
Logger logger = ingestServices.getLogger(SampleIngestModuleFactory.getModuleName());
|
||||
logger.log(Level.SEVERE, "Failed to create blackboard attribute", ex);
|
||||
attrId = -1;
|
||||
throw new IngestModuleException(ex.getLocalizedMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,14 +57,14 @@ final public class ExternalResults {
|
||||
return Collections.unmodifiableList(artifacts);
|
||||
}
|
||||
|
||||
void addReport(String displayName, String localPath) {
|
||||
if (displayName.isEmpty()) {
|
||||
throw new IllegalArgumentException("displayName argument is empty");
|
||||
}
|
||||
void addReport(String localPath, String sourceModuleName, String reportName) {
|
||||
if (localPath.isEmpty()) {
|
||||
throw new IllegalArgumentException("localPath argument is empty");
|
||||
}
|
||||
Report report = new Report(displayName, localPath);
|
||||
if (sourceModuleName.isEmpty()) {
|
||||
throw new IllegalArgumentException("sourceModuleName argument is empty");
|
||||
}
|
||||
Report report = new Report(localPath, sourceModuleName, reportName);
|
||||
reports.add(report);
|
||||
}
|
||||
|
||||
@@ -157,21 +157,27 @@ final public class ExternalResults {
|
||||
|
||||
static final class Report {
|
||||
|
||||
private final String displayName;
|
||||
private final String localPath;
|
||||
private final String sourceModuleName;
|
||||
private final String reportName;
|
||||
|
||||
Report(String displayName, String localPath) {
|
||||
this.displayName = displayName;
|
||||
Report(String localPath, String sourceModuleName, String displayName) {
|
||||
this.localPath = localPath;
|
||||
}
|
||||
|
||||
String getDisplayName() {
|
||||
return displayName;
|
||||
this.sourceModuleName = sourceModuleName;
|
||||
this.reportName = displayName;
|
||||
}
|
||||
|
||||
String getLocalPath() {
|
||||
return localPath;
|
||||
}
|
||||
|
||||
String getSourceModuleName() {
|
||||
return sourceModuleName;
|
||||
}
|
||||
|
||||
String getReportName() {
|
||||
return reportName;
|
||||
}
|
||||
}
|
||||
|
||||
static final class DerivedFile {
|
||||
|
||||
@@ -23,7 +23,6 @@ import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
@@ -65,7 +64,9 @@ public final class ExternalResultsImporter {
|
||||
importDerivedFiles(results);
|
||||
importArtifacts(results);
|
||||
importReports(results);
|
||||
return Collections.unmodifiableList(this.errors);
|
||||
List<ErrorInfo> importErrors = new ArrayList(this.errors);
|
||||
this.errors.clear();
|
||||
return importErrors;
|
||||
}
|
||||
|
||||
private void importDerivedFiles(ExternalResults results) {
|
||||
@@ -78,7 +79,7 @@ public final class ExternalResultsImporter {
|
||||
String relativePath = this.getPathRelativeToCaseFolder(localPath);
|
||||
if (!relativePath.isEmpty()) {
|
||||
String parentFilePath = fileData.getParentPath();
|
||||
AbstractFile parentFile = findFileInCaseDatabase(results.getDataSource(), parentFilePath);
|
||||
AbstractFile parentFile = findFileInCaseDatabase(parentFilePath);
|
||||
if (parentFile != null) {
|
||||
DerivedFile derivedFile = fileManager.addDerivedFile(localFile.getName(), relativePath, localFile.length(),
|
||||
0, 0, 0, 0, // Do not currently have file times for derived files from external processes.
|
||||
@@ -110,19 +111,19 @@ public final class ExternalResultsImporter {
|
||||
try {
|
||||
// Add the artifact to the case database.
|
||||
boolean artifactTypeIsUserDefined = false;
|
||||
int artifactTypeId = caseDb.getArtifactTypeIdIfExists(artifactData.getType());
|
||||
int artifactTypeId = caseDb.getArtifactTypeID(artifactData.getType());
|
||||
if (artifactTypeId == -1) {
|
||||
artifactTypeId = caseDb.addArtifactType(artifactData.getType(), artifactData.getType());
|
||||
artifactTypeIsUserDefined = true;
|
||||
}
|
||||
Content sourceFile = findFileInCaseDatabase(results.getDataSource(), artifactData.getSourceFilePath());
|
||||
Content sourceFile = findFileInCaseDatabase(artifactData.getSourceFilePath());
|
||||
if (sourceFile != null) {
|
||||
BlackboardArtifact artifact = sourceFile.newArtifact(artifactTypeId);
|
||||
|
||||
// Add the artifact's attributes to the case database.
|
||||
Collection<BlackboardAttribute> attributes = new ArrayList<>();
|
||||
for (ExternalResults.ArtifactAttribute attributeData : artifactData.getAttributes()) {
|
||||
int attributeTypeId = caseDb.getAttrTypeIdIfExists(attributeData.getType());
|
||||
int attributeTypeId = caseDb.getAttrTypeID(attributeData.getType());
|
||||
if (attributeTypeId == -1) {
|
||||
attributeTypeId = caseDb.addAttrType(attributeData.getType(), attributeData.getType());
|
||||
}
|
||||
@@ -157,6 +158,10 @@ public final class ExternalResultsImporter {
|
||||
if (!artifactTypeIsUserDefined) {
|
||||
IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent(this.getClass().getSimpleName(), BlackboardArtifact.ARTIFACT_TYPE.fromID(artifactTypeId)));
|
||||
}
|
||||
} else {
|
||||
String errorMessage = String.format("Could not import %s artifact from %s, source file not found", artifactData.getType(), artifactData.getSourceFilePath());
|
||||
ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage);
|
||||
this.errors.add(new ErrorInfo(ExternalResultsImporter.class.getName(), errorMessage));
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
String errorMessage = String.format("Could not import %s artifact from %s, error updating case database", artifactData.getType(), artifactData.getSourceFilePath());
|
||||
@@ -172,10 +177,7 @@ public final class ExternalResultsImporter {
|
||||
try {
|
||||
File reportFile = new File(reportPath);
|
||||
if (reportFile.exists()) {
|
||||
String relativePath = this.getPathRelativeToCaseFolder(reportPath);
|
||||
if (!relativePath.isEmpty()) {
|
||||
Case.getCurrentCase().addReport(relativePath, report.getDisplayName());
|
||||
}
|
||||
Case.getCurrentCase().addReport(reportPath, report.getSourceModuleName(), report.getReportName());
|
||||
} else {
|
||||
String errorMessage = String.format("Could not import report at %s, file does not exist", reportPath);
|
||||
ExternalResultsImporter.logger.log(Level.SEVERE, errorMessage);
|
||||
@@ -189,7 +191,7 @@ public final class ExternalResultsImporter {
|
||||
}
|
||||
}
|
||||
|
||||
private AbstractFile findFileInCaseDatabase(Content dataSource, String filePath) throws TskCoreException {
|
||||
private AbstractFile findFileInCaseDatabase(String filePath) throws TskCoreException {
|
||||
AbstractFile file = null;
|
||||
// Split the path into the file name and the parent path.
|
||||
String fileName = filePath;
|
||||
@@ -203,10 +205,9 @@ public final class ExternalResultsImporter {
|
||||
String condition = "name='" + fileName + "' AND parent_path='" + parentPath + "'"; //NON-NLS
|
||||
List<AbstractFile> files = Case.getCurrentCase().getSleuthkitCase().findAllFilesWhere(condition);
|
||||
if (!files.isEmpty()) {
|
||||
if (files.size() == 1) {
|
||||
file = files.get(0);
|
||||
} else {
|
||||
String errorMessage = String.format("Parent file path %s is ambiguous", filePath);
|
||||
file = files.get(0);
|
||||
if (files.size() > 1) {
|
||||
String errorMessage = String.format("Parent file path %s is ambiguous, using first file found", filePath);
|
||||
this.recordError(errorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
package org.sleuthkit.autopsy.externalresults;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
@@ -61,7 +60,7 @@ public final class ExternalResultsXMLParser implements ExternalResultsParser {
|
||||
SOURCE_MODULE_ELEM("source_module"), //NON-NLS
|
||||
REPORTS_LIST_ELEM("reports"), //NON-NLS
|
||||
REPORT_ELEM("report"), //NON-NLS
|
||||
DISPLAY_NAME_ELEM("display_name"); //NON-NLS
|
||||
REPORT_NAME_ELEM("report_name"); //NON-NLS
|
||||
private final String text;
|
||||
|
||||
private TagNames(final String text) {
|
||||
@@ -154,7 +153,7 @@ public final class ExternalResultsXMLParser implements ExternalResultsParser {
|
||||
|
||||
@Override
|
||||
public List<ErrorInfo> getErrorInfo() {
|
||||
return Collections.unmodifiableList(this.errors);
|
||||
return new ArrayList<>(this.errors);
|
||||
}
|
||||
|
||||
private void parseDerivedFiles(Element rootElement) {
|
||||
@@ -266,17 +265,19 @@ public final class ExternalResultsXMLParser implements ExternalResultsParser {
|
||||
NodeList reportNodes = reportsListElem.getElementsByTagName(TagNames.REPORT_ELEM.toString());
|
||||
for (int j = 0; j < reportNodes.getLength(); ++j) {
|
||||
Element reportElem = (Element) reportNodes.item(j);
|
||||
// Get the display name.
|
||||
String displayName = getChildElementContent(reportElem, TagNames.DISPLAY_NAME_ELEM.toString(), true);
|
||||
if (displayName.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
// Get the local path.
|
||||
String path = getChildElementContent(reportElem, TagNames.LOCAL_PATH_ELEM.toString(), true);
|
||||
if (path.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
this.resultsData.addReport(displayName, path);
|
||||
// Get the source module.
|
||||
String sourceModule = getChildElementContent(reportElem, TagNames.SOURCE_MODULE_ELEM.toString(), true);
|
||||
if (path.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
// Get the optional report name.
|
||||
String reportName = getChildElementContent(reportElem, TagNames.REPORT_NAME_ELEM.toString(), false);
|
||||
this.resultsData.addReport(path, sourceModule, reportName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2012 Basis Technology Corp.
|
||||
* Copyright 2012-2014 Basis Technology Corp.
|
||||
*
|
||||
* Copyright 2012 42six Solutions.
|
||||
* Contact: aebadirad <at> 42six <dot> com
|
||||
@@ -25,8 +25,6 @@ package org.sleuthkit.autopsy.report;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.JPanel;
|
||||
@@ -151,11 +149,17 @@ import org.sleuthkit.datamodel.*;
|
||||
logger.log(Level.WARNING, "Could not write the temp body file report.", ex); //NON-NLS
|
||||
} finally {
|
||||
try {
|
||||
out.flush();
|
||||
out.close();
|
||||
if (out != null) {
|
||||
out.flush();
|
||||
out.close();
|
||||
Case.getCurrentCase().addReport(reportPath, "TSK Body File", "");
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.WARNING, "Could not flush and close the BufferedWriter.", ex); //NON-NLS
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
String errorMessage = String.format("Error adding %s to case as a report", reportPath); //NON-NLS
|
||||
logger.log(Level.SEVERE, errorMessage, ex);
|
||||
}
|
||||
}
|
||||
progressPanel.complete();
|
||||
} catch(TskCoreException ex) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 Basis Technology Corp.
|
||||
* Copyright 2013-2014 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -26,9 +26,11 @@ import java.util.logging.Level;
|
||||
import org.apache.poi.hssf.util.HSSFColor;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.openide.util.Exceptions;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
class ReportExcel implements TableReportModule {
|
||||
private static final Logger logger = Logger.getLogger(ReportExcel.class.getName());
|
||||
@@ -110,8 +112,12 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
try {
|
||||
out = new FileOutputStream(reportPath);
|
||||
wb.write(out);
|
||||
Case.getCurrentCase().addReport(reportPath, "Excel Report", "");
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to write Excel report.", ex); //NON-NLS
|
||||
} catch (TskCoreException ex) {
|
||||
String errorMessage = String.format("Error adding %s to case as a report", reportPath); //NON-NLS
|
||||
logger.log(Level.SEVERE, errorMessage, ex);
|
||||
} finally {
|
||||
if (out != null) {
|
||||
try {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2012 Basis Technology Corp.
|
||||
* Copyright 2012-2014 Basis Technology Corp.
|
||||
*
|
||||
* Copyright 2012 42six Solutions.
|
||||
* Contact: aebadirad <at> 42six <dot> com
|
||||
@@ -803,8 +803,9 @@ import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
|
||||
*/
|
||||
private void writeIndex() {
|
||||
Writer indexOut = null;
|
||||
String indexFilePath = path + "index.html";
|
||||
try {
|
||||
indexOut = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path + "index.html"), "UTF-8")); //NON-NLS
|
||||
indexOut = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(indexFilePath), "UTF-8")); //NON-NLS
|
||||
StringBuilder index = new StringBuilder();
|
||||
index.append("<head>\n<title>").append( //NON-NLS
|
||||
NbBundle.getMessage(this.getClass(), "ReportHTML.writeIndex.title", currentCase.getName())).append(
|
||||
@@ -820,22 +821,12 @@ import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
|
||||
index.append("</frameset>\n"); //NON-NLS
|
||||
index.append("</html>"); //NON-NLS
|
||||
indexOut.write(index.toString());
|
||||
|
||||
// RJCTODO: Add this file as a report, clean this up, make utility
|
||||
String relativePath = "";
|
||||
Path pathObj = Paths.get(path + "index.html");
|
||||
Path pathBase = Paths.get(Case.getCurrentCase().getCaseDirectory());
|
||||
try {
|
||||
Path pathRelative = pathBase.relativize(pathObj);
|
||||
relativePath = pathRelative.toString();
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// RJCTODO
|
||||
}
|
||||
Case.getCurrentCase().addReport("HTML Report", relativePath);
|
||||
Case.getCurrentCase().addReport(indexFilePath, "HTML Report", "");
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE, "Error creating Writer for index.html: {0}", ex); //NON-NLS
|
||||
} catch (TskCoreException ex) {
|
||||
Exceptions.printStackTrace(ex); // RJCTODO: Handle this
|
||||
String errorMessage = String.format("Error adding %s to case as a report", indexFilePath); //NON-NLS
|
||||
logger.log(Level.SEVERE, errorMessage, ex);
|
||||
} finally {
|
||||
try {
|
||||
if(indexOut != null) {
|
||||
|
||||
@@ -256,11 +256,13 @@ class ReportKML implements GeneralReportModule {
|
||||
FileOutputStream writer = new FileOutputStream(reportPath);
|
||||
outputter.output(kmlDocument, writer);
|
||||
writer.close();
|
||||
Case.getCurrentCase().addReport(reportPath, "KML Report", "");
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.WARNING, "Could not write the KML file.", ex); //NON-NLS
|
||||
} catch (TskCoreException ex) {
|
||||
String errorMessage = String.format("Error adding %s to case as a report", reportPath); //NON-NLS
|
||||
logger.log(Level.SEVERE, errorMessage, ex);
|
||||
}
|
||||
|
||||
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.WARNING, "Could not write the KML report.", ex); //NON-NLS
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user