mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-09 06:39:33 +00:00
Merge pull request #6482 from kellykelly3/6963-handle-manifest-bad-char
6963 - Added code to cleanup auto ingest manifest files with bad chars
This commit is contained in:
commit
a5ed18e948
@ -19,7 +19,7 @@
|
||||
<target name="retrieve-experimental" depends="resolve">
|
||||
<ivy:retrieve conf="experimental" pattern="${basedir}/release/modules/ext/[artifact]-[revision](-[classifier]).[ext]" />
|
||||
</target>
|
||||
|
||||
|
||||
<target name="retrieve-all" depends="resolve">
|
||||
<ivy:retrieve conf="*" pattern="${basedir}/release/modules/ext/[artifact]-[revision](-[classifier]).[ext]" />
|
||||
</target>
|
||||
|
@ -10,5 +10,6 @@
|
||||
<dependency conf="experimental->default" org="com.mchange" name="c3p0" rev="0.9.5"/>
|
||||
<dependency conf="experimental->default" org="com.fasterxml.jackson.core" name="jackson-core" rev="2.7.0"/>
|
||||
<dependency conf="experimental->default" org="org.swinglabs.swingx" name="swingx-all" rev="1.6.4"/>
|
||||
<dependency conf="experimental->default" org="net.sf.jtidy" name="jtidy" rev="r938"/>
|
||||
</dependencies>
|
||||
</ivy-module>
|
||||
|
@ -1,5 +1,6 @@
|
||||
file.reference.c3p0-0.9.5.jar=release/modules/ext/c3p0-0.9.5.jar
|
||||
file.reference.jackson-core-2.7.0.jar=release/modules/ext/jackson-core-2.7.0.jar
|
||||
file.reference.jtidy-r938.jar=release/modules/ext/jtidy-r938.jar
|
||||
file.reference.LGoodDatePicker-10.3.1.jar=release/modules/ext/LGoodDatePicker-10.3.1.jar
|
||||
file.reference.mchange-commons-java-0.2.9.jar=release/modules/ext/mchange-commons-java-0.2.9.jar
|
||||
file.reference.postgresql-9.4-1201-jdbc41.jar=release/modules/ext/postgresql-9.4-1201-jdbc41.jar
|
||||
|
@ -170,6 +170,10 @@
|
||||
<package>org.sleuthkit.autopsy.experimental.autoingest</package>
|
||||
<package>org.sleuthkit.autopsy.experimental.configuration</package>
|
||||
</public-packages>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/jtidy-r938.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/jtidy-r938.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<class-path-extension>
|
||||
<runtime-relative-path>ext/LGoodDatePicker-10.3.1.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/LGoodDatePicker-10.3.1.jar</binary-origin>
|
||||
|
@ -18,6 +18,9 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.experimental.autoingest;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
@ -51,56 +54,92 @@ public final class AutopsyManifestFileParser implements ManifestFileParser {
|
||||
@Override
|
||||
public boolean fileIsManifest(Path filePath) {
|
||||
boolean fileIsManifest = false;
|
||||
try {
|
||||
Path fileName = filePath.getFileName();
|
||||
if (fileName.toString().toUpperCase().endsWith(MANIFEST_FILE_NAME_SIGNATURE)) {
|
||||
Document doc = this.createManifestDOM(filePath);
|
||||
Element docElement = doc.getDocumentElement();
|
||||
fileIsManifest = docElement.getTagName().equals(ROOT_ELEM_TAG_NAME);
|
||||
}
|
||||
} catch (Exception unused) {
|
||||
fileIsManifest = false;
|
||||
|
||||
Path fileName = filePath.getFileName();
|
||||
if (fileName.toString().toUpperCase().endsWith(MANIFEST_FILE_NAME_SIGNATURE)) {
|
||||
|
||||
fileIsManifest = (ManifestFileParser.getManifestRootNode(filePath, (str) -> {
|
||||
return (str.compareToIgnoreCase(ROOT_ELEM_TAG_NAME) == 0);
|
||||
}) != null);
|
||||
}
|
||||
|
||||
return fileIsManifest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Manifest parse(Path filePath) throws ManifestFileParserException {
|
||||
Path tempPath = null;
|
||||
try {
|
||||
BasicFileAttributes attrs = Files.readAttributes(filePath, BasicFileAttributes.class);
|
||||
Date dateFileCreated = new Date(attrs.creationTime().toMillis());
|
||||
Document doc = this.createManifestDOM(filePath);
|
||||
Document doc;
|
||||
try {
|
||||
doc = ManifestFileParser.createManifestDOM(filePath);
|
||||
} catch (Exception ex) {
|
||||
// If the above call to createManifestDOM threw an exception
|
||||
// try to fix the given XML file.
|
||||
tempPath = ManifestFileParser.makeTidyManifestFile(filePath);
|
||||
doc = ManifestFileParser.createManifestDOM(tempPath);
|
||||
}
|
||||
|
||||
XPath xpath = XPathFactory.newInstance().newXPath();
|
||||
|
||||
|
||||
XPathExpression expr = xpath.compile(CASE_NAME_XPATH);
|
||||
String caseName = (String) expr.evaluate(doc, XPathConstants.STRING);
|
||||
if (caseName.isEmpty()) {
|
||||
throw new ManifestFileParserException("Case name not found, manifest is invalid");
|
||||
}
|
||||
|
||||
|
||||
expr = xpath.compile(DEVICE_ID_XPATH);
|
||||
String deviceId = (String) expr.evaluate(doc, XPathConstants.STRING);
|
||||
if (deviceId.isEmpty()) {
|
||||
deviceId = UUID.randomUUID().toString();
|
||||
}
|
||||
|
||||
|
||||
expr = xpath.compile(DATA_SOURCE_NAME_XPATH);
|
||||
String dataSourceName = (String) expr.evaluate(doc, XPathConstants.STRING);
|
||||
if (dataSourceName.isEmpty()) {
|
||||
throw new ManifestFileParserException("Data source path not found, manifest is invalid");
|
||||
throw new ManifestFileParserException("Data source path not found, manifest is invalid");
|
||||
}
|
||||
Path dataSourcePath = filePath.getParent().resolve(dataSourceName);
|
||||
|
||||
|
||||
return new Manifest(filePath, dateFileCreated, caseName, deviceId, dataSourcePath, new HashMap<>());
|
||||
} catch (Exception ex) {
|
||||
throw new ManifestFileParserException(String.format("Error parsing manifest %s", filePath), ex);
|
||||
} finally {
|
||||
if (tempPath != null) {
|
||||
tempPath.toFile().delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Document createManifestDOM(Path manifestFilePath) throws ParserConfigurationException, SAXException, IOException {
|
||||
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
|
||||
return docBuilder.parse(manifestFilePath.toFile());
|
||||
/**
|
||||
* Check to see if the given file is an autopsy auto ingest manifest file by
|
||||
* if the root element is ROOT_ELEM_TAG_NAME.
|
||||
*
|
||||
* @param filePath Path to the manifest file.
|
||||
*
|
||||
* @return True if this a well formed autopsy auto ingest manifest file.
|
||||
*/
|
||||
private boolean isAutopsyManifestFile(Path filePath) throws IOException {
|
||||
try {
|
||||
Document doc = ManifestFileParser.createManifestDOM(filePath);
|
||||
Element docElement = doc.getDocumentElement();
|
||||
return docElement.getTagName().equals(ROOT_ELEM_TAG_NAME);
|
||||
} catch (Exception unused) {
|
||||
// Double check that this isn't a manifest file that may have bad
|
||||
// characters that will be handled in the process method.
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(filePath.toFile()))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
if (line.toLowerCase().contains(ROOT_ELEM_TAG_NAME.toLowerCase())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -18,31 +18,134 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.experimental.autoingest;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.function.Predicate;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.tidy.Tidy;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* Responsible for parsing the manifest files that
|
||||
* describe cases, devices, and data sources.
|
||||
* These are used by autoingest to create cases and add
|
||||
* data sources to the correct case.
|
||||
* Responsible for parsing the manifest files that describe cases, devices, and
|
||||
* data sources. These are used by autoingest to create cases and add data
|
||||
* sources to the correct case.
|
||||
*/
|
||||
public interface ManifestFileParser {
|
||||
|
||||
|
||||
/**
|
||||
* Checks if a file is this type of manifest file
|
||||
*
|
||||
* @param filePath Path to potential manifest file
|
||||
*
|
||||
* @return True if the file is a manifest that this parser supports
|
||||
*/
|
||||
*/
|
||||
boolean fileIsManifest(Path filePath);
|
||||
|
||||
|
||||
/**
|
||||
* Parses the given file. Will only be called if
|
||||
* fileIsManifest() previously returned true.
|
||||
* Parses the given file. Will only be called if fileIsManifest() previously
|
||||
* returned true.
|
||||
*
|
||||
* @param filePath Path to manifest file
|
||||
*
|
||||
* @return Parsed results
|
||||
* @throws org.sleuthkit.autopsy.experimental.autoingest.ManifestFileParser.ManifestFileParserException
|
||||
*
|
||||
* @throws
|
||||
* org.sleuthkit.autopsy.experimental.autoingest.ManifestFileParser.ManifestFileParserException
|
||||
*/
|
||||
Manifest parse(Path filePath) throws ManifestFileParserException;
|
||||
|
||||
/**
|
||||
* Creates a "tidy" version of the given XML file in same parent directory.
|
||||
*
|
||||
* @param filePath Path to original XML file.
|
||||
*
|
||||
* @return Path to the newly created tidy version of the file.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
static Path makeTidyManifestFile(Path filePath) throws IOException {
|
||||
File tempFile = null;
|
||||
try{
|
||||
tempFile = File.createTempFile("mani", "tdy", filePath.getParent().toFile());
|
||||
|
||||
try (FileInputStream br = new FileInputStream(filePath.toFile()); FileOutputStream out = new FileOutputStream(tempFile);) {
|
||||
Tidy tidy = new Tidy();
|
||||
tidy.setXmlOut(true);
|
||||
tidy.setXmlTags(true);
|
||||
tidy.parseDOM(br, out);
|
||||
}
|
||||
|
||||
return Paths.get(tempFile.toString());
|
||||
} catch(IOException ex) {
|
||||
// If there is an exception delete the temp file.
|
||||
if(tempFile != null && tempFile.exists()) {
|
||||
tempFile.delete();
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new DOM document object for the given manifest file.
|
||||
*
|
||||
* @param manifestFilePath Fully qualified path to manifest file.
|
||||
*
|
||||
* @return DOM document object
|
||||
*
|
||||
* @throws ParserConfigurationException
|
||||
* @throws SAXException
|
||||
* @throws IOException
|
||||
*/
|
||||
static Document createManifestDOM(Path manifestFilePath) throws ParserConfigurationException, SAXException, IOException {
|
||||
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
|
||||
return docBuilder.parse(manifestFilePath.toFile());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the root node of the given Manifest XML file.
|
||||
*
|
||||
* @param filePath XML filePath
|
||||
* @param isRootTester Predicate method for testing if a string is the root node.
|
||||
*
|
||||
* @return The XML file root node or null if the node was not found or the
|
||||
* file is not an XML file.
|
||||
*/
|
||||
static String getManifestRootNode(Path filePath, Predicate<String> isRootTester) {
|
||||
Document doc;
|
||||
Path tempPath = null;
|
||||
try {
|
||||
try {
|
||||
doc = ManifestFileParser.createManifestDOM(filePath);
|
||||
} catch (Exception unused) {
|
||||
// If the above call to createManifestDOM threw an exception
|
||||
// try to fix the given XML file.
|
||||
tempPath = ManifestFileParser.makeTidyManifestFile(filePath);
|
||||
doc = ManifestFileParser.createManifestDOM(tempPath);
|
||||
}
|
||||
Element docElement = doc.getDocumentElement();
|
||||
String rootElementTag = docElement.getTagName();
|
||||
if(isRootTester.test(rootElementTag)) {
|
||||
return rootElementTag;
|
||||
}
|
||||
} catch (Exception unused) {
|
||||
// Unused exception. If an exception is thrown the given XML file
|
||||
// cannot be parsed.
|
||||
} finally {
|
||||
if (tempPath != null) {
|
||||
tempPath.toFile().delete();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public final static class ManifestFileParserException extends Exception {
|
||||
|
||||
@ -67,5 +170,5 @@ public interface ManifestFileParser {
|
||||
super(message, cause);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user