Progress started

This commit is contained in:
Oliver Spohngellert 2016-02-03 16:32:42 -05:00
parent 78b5381171
commit 92eeeb4473
2 changed files with 267 additions and 56 deletions

View File

@ -257,6 +257,7 @@ public class Case implements SleuthkitCase.ErrorObserver {
private String examiner;
private String configFilePath;
private final XMLCaseManagement xmlcm;
private final CaseMetadata caseMetadata;
private final SleuthkitCase db;
// Track the current case (only set with changeCase() method)
private static Case currentCase = null;
@ -280,12 +281,13 @@ public class Case implements SleuthkitCase.ErrorObserver {
/**
* Constructor for the Case class
*/
private Case(String name, String number, String examiner, String configFilePath, XMLCaseManagement xmlcm, SleuthkitCase db, CaseType type) {
private Case(String name, String number, String examiner, String configFilePath, CaseMetadata caseMetadata, SleuthkitCase db, CaseType type) {
this.name = name;
this.number = number;
this.examiner = examiner;
this.configFilePath = configFilePath;
this.xmlcm = xmlcm;
this.xmlcm = new XMLCaseManagement();
this.caseMetadata = caseMetadata;
this.caseType = type;
this.db = db;
this.services = new Services(db);
@ -403,46 +405,47 @@ public class Case implements SleuthkitCase.ErrorObserver {
/**
* Creates a single-user new case.
*
* @param caseDir The full path of the case directory. It will be created
* if it doesn't already exist; if it exists, it should
* have been created using Case.createCaseDirectory() to
* ensure that the required sub-directories aere created.
* @param caseDir The full path of the case directory. It will be created if
* it doesn't already exist; if it exists, it should have been created using
* Case.createCaseDirectory() to ensure that the required sub-directories
* aere created.
* @param caseName The name of case.
* @param caseNumber The case number, can be the empty string.
* @param examiner The examiner to associate with the case, can be the
* empty string.
* @param examiner The examiner to associate with the case, can be the empty
* string.
*
* @throws CaseActionException if there is a problem creating the case. The
* exception will have a user-friendly message
* and may be a wrapper for a lower-level
* exception. If so,
* CaseActionException.getCause will return a
* exception will have a user-friendly message and may be a wrapper for a
* lower-level exception. If so, CaseActionException.getCause will return a
* Throwable (null otherwise).
* @throws CaseMetadataException if there is a problem creating the case
* metadata.
*/
public static void create(String caseDir, String caseName, String caseNumber, String examiner) throws CaseActionException {
public static void create(String caseDir, String caseName, String caseNumber, String examiner) throws CaseActionException, CaseMetadataException {
create(caseDir, caseName, caseNumber, examiner, CaseType.SINGLE_USER_CASE);
}
/**
* Creates a new case.
*
* @param caseDir The full path of the case directory. It will be created
* if it doesn't already exist; if it exists, it should
* have been created using Case.createCaseDirectory() to
* ensure that the required sub-directories aere created.
* @param caseDir The full path of the case directory. It will be created if
* it doesn't already exist; if it exists, it should have been created using
* Case.createCaseDirectory() to ensure that the required sub-directories
* aere created.
* @param caseName The name of case.
* @param caseNumber The case number, can be the empty string.
* @param examiner The examiner to associate with the case, can be the
* empty string.
* @param examiner The examiner to associate with the case, can be the empty
* string.
* @param caseType The type of case (single-user or multi-user). The
* exception will have a user-friendly message and may be
* a wrapper for a lower-level exception. If so,
* CaseActionException.getCause will return a Throwable
* (null otherwise).
* exception will have a user-friendly message and may be a wrapper for a
* lower-level exception. If so, CaseActionException.getCause will return a
* Throwable (null otherwise).
*
* @throws CaseActionException if there is a problem creating the case.
* @throws CaseMetadataException if there is a problem creating the case
* metadata.
*/
public static void create(String caseDir, String caseName, String caseNumber, String examiner, CaseType caseType) throws CaseActionException {
public static void create(String caseDir, String caseName, String caseNumber, String examiner, CaseType caseType) throws CaseActionException, CaseMetadataException {
logger.log(Level.INFO, "Creating case with case directory {0}, caseName {1}", new Object[]{caseDir, caseName}); //NON-NLS
/*
@ -506,8 +509,9 @@ public class Case implements SleuthkitCase.ErrorObserver {
});
throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.databaseConnectionInfo.error.msg"), ex);
}
CaseMetadata metadata = new CaseMetadata(caseType, caseName, caseNumber, examiner, caseDir, dbName, indexName);
Case newCase = new Case(caseName, caseNumber, examiner, configFilePath, xmlcm, db, caseType);
Case newCase = new Case(caseName, caseNumber, examiner, configFilePath, metadata, db, caseType);
changeCase(newCase);
}
@ -578,10 +582,8 @@ public class Case implements SleuthkitCase.ErrorObserver {
* @param caseMetadataFilePath The path of the case metadata file.
*
* @throws CaseActionException if there is a problem opening the case. The
* exception will have a user-friendly message
* and may be a wrapper for a lower-level
* exception. If so,
* CaseActionException.getCause will return a
* exception will have a user-friendly message and may be a wrapper for a
* lower-level exception. If so, CaseActionException.getCause will return a
* Throwable (null otherwise).
*/
public static void open(String caseMetadataFilePath) throws CaseActionException {
@ -671,9 +673,7 @@ public class Case implements SleuthkitCase.ErrorObserver {
* TODO (AUT-1885): Replace use of obsolete and unsafe
* XMLCaseManagement class with use of CaseMetadata class.
*/
XMLCaseManagement xmlcm = new XMLCaseManagement();
xmlcm.open(caseMetadataFilePath);
Case openedCase = new Case(caseName, caseNumber, examiner, caseMetadataFilePath, xmlcm, db, caseType);
Case openedCase = new Case(caseName, caseNumber, examiner, caseMetadataFilePath, metadata, db, caseType);
changeCase(openedCase);
} catch (CaseMetadataException ex) {
@ -750,8 +750,8 @@ public class Case implements SleuthkitCase.ErrorObserver {
* This should not be called from the event dispatch thread (EDT)
*
* @param dataSourceId A unique identifier for the data source. This UUID
* should be used to call notifyNewDataSource() after
* the data source is added.
* should be used to call notifyNewDataSource() after the data source is
* added.
*/
public void notifyAddingDataSource(UUID dataSourceId) {
eventPublisher.publish(new AddingDataSourceEvent(dataSourceId));
@ -777,9 +777,8 @@ public class Case implements SleuthkitCase.ErrorObserver {
*
* @param newDataSource New data source added.
* @param dataSourceId A unique identifier for the data source. Should be
* the same UUID used to call
* notifyAddingNewDataSource() when the process of
* adding the data source began.
* the same UUID used to call notifyAddingNewDataSource() when the process
* of adding the data source began.
*/
public void notifyDataSourceAdded(Content newDataSource, UUID dataSourceId) {
eventPublisher.publish(new DataSourceAddedEvent(newDataSource, dataSourceId));

View File

@ -18,7 +18,34 @@
*/
package org.sleuthkit.autopsy.casemodule;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.nio.file.Path;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Level;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.openide.util.NbBundle;
import static org.sleuthkit.autopsy.casemodule.XMLCaseManagement.TOP_ROOT_NAME;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
/**
* Provides access to case metadata.
@ -42,6 +69,37 @@ public final class CaseMetadata {
}
}
final static String XSDFILE = "CaseSchema.xsd"; //NON-NLS
final static String TOP_ROOT_NAME = "AutopsyCase"; //NON-NLS
final static String CASE_ROOT_NAME = "Case"; //NON-NLS
// general metadata about the case file
final static String NAME = "Name"; //NON-NLS
final static String NUMBER = "Number"; //NON-NLS
final static String EXAMINER = "Examiner"; //NON-NLS
final static String CREATED_DATE_NAME = "CreatedDate"; //NON-NLS
final static String MODIFIED_DATE_NAME = "ModifiedDate"; //NON-NLS
final static String SCHEMA_VERSION_NAME = "SchemaVersion"; //NON-NLS
final static String AUTOPSY_CRVERSION_NAME = "AutopsyCreatedVersion"; //NON-NLS
final static String AUTOPSY_MVERSION_NAME = "AutopsySavedVersion"; //NON-NLS
final static String CASE_TEXT_INDEX_NAME = "TextIndexName"; //NON-NLS
// folders inside case directory
final static String LOG_FOLDER_NAME = "LogFolder"; //NON-NLS
final static String LOG_FOLDER_RELPATH = "Log"; //NON-NLS
final static String TEMP_FOLDER_NAME = "TempFolder"; //NON-NLS
final static String TEMP_FOLDER_RELPATH = "Temp"; //NON-NLS
final static String EXPORT_FOLDER_NAME = "ExportFolder"; //NON-NLS
final static String EXPORT_FOLDER_RELPATH = "Export"; //NON-NLS
final static String CACHE_FOLDER_NAME = "CacheFolder"; //NON-NLS
final static String CACHE_FOLDER_RELPATH = "Cache"; //NON-NLS
final static String CASE_TYPE = "CaseType"; //NON-NLS
final static String DATABASE_NAME = "DatabaseName"; //NON-NLS
// folders attribute
final static String RELATIVE_NAME = "Relative"; // relevant path info NON-NLS
// folder attr values
final static String RELATIVE_TRUE = "true"; // if it's a relative path NON-NLS
final static String RELATIVE_FALSE = "false"; // if it's not a relative path NON-NLS
private Document doc;
private final Case.CaseType caseType;
private final String caseName;
private final String caseNumber;
@ -49,6 +107,18 @@ public final class CaseMetadata {
private final String caseDirectory;
private final String caseDatabaseName;
private final String caseTextIndexName;
private static final Logger logger = Logger.getLogger(CaseMetadata.class.getName());
public CaseMetadata(Case.CaseType caseType, String caseName, String caseNumber, String exainer, String caseDirectory, String caseDatabaseName, String caseTextIndexName) throws CaseMetadataException {
this.caseType = caseType;
this.caseName = caseName;
this.caseNumber = caseNumber;
this.examiner = exainer;
this.caseDirectory = caseDirectory;
this.caseDatabaseName = caseDatabaseName;
this.caseTextIndexName = caseTextIndexName;
this.create();
}
/**
* Constructs an object that provides access to case metadata.
@ -110,6 +180,7 @@ public final class CaseMetadata {
} catch (CaseActionException ex) {
throw new CaseMetadataException(ex.getLocalizedMessage(), ex);
}
this.create();
}
/**
@ -175,4 +246,145 @@ public final class CaseMetadata {
return caseTextIndexName;
}
private void create() throws CaseMetadataException {
DocumentBuilder docBuilder;
DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
// throw an error here
try {
docBuilder = docFactory.newDocumentBuilder();
} catch (ParserConfigurationException ex) {
clear();
throw new CaseMetadataException(
NbBundle.getMessage(this.getClass(), "XMLCaseManagement.create.exception.msg"), ex);
}
DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss (z)");
doc = docBuilder.newDocument();
Element rootElement = doc.createElement(TOP_ROOT_NAME); // <AutopsyCase> ... </AutopsyCase>
doc.appendChild(rootElement);
Element crDateElement = doc.createElement(CREATED_DATE_NAME); // <CreatedDate> ... </CreatedDate>
crDateElement.appendChild(doc.createTextNode(dateFormat.format(new Date())));
rootElement.appendChild(crDateElement);
Element mDateElement = doc.createElement(MODIFIED_DATE_NAME); // <ModifedDate> ... </ModifedDate>
mDateElement.appendChild(doc.createTextNode(dateFormat.format(new Date())));
rootElement.appendChild(mDateElement);
Element autVerElement = doc.createElement(AUTOPSY_CRVERSION_NAME); // <AutopsyVersion> ... </AutopsyVersion>
autVerElement.appendChild(doc.createTextNode(System.getProperty("netbeans.buildnumber")));
rootElement.appendChild(autVerElement);
Element autSavedVerElement = doc.createElement(AUTOPSY_MVERSION_NAME); // <AutopsySavedVersion> ... </AutopsySavedVersion>
autSavedVerElement.appendChild(doc.createTextNode(System.getProperty("netbeans.buildnumber")));
rootElement.appendChild(autSavedVerElement);
Element schVerElement = doc.createElement(SCHEMA_VERSION_NAME); // <SchemaVersion> ... </SchemaVersion>
schVerElement.appendChild(doc.createTextNode(schemaVersion));
rootElement.appendChild(schVerElement);
Element caseElement = doc.createElement(CASE_ROOT_NAME); // <Case> ... </Case>
rootElement.appendChild(caseElement);
Element nameElement = doc.createElement(NAME); // <Name> ... </Name>
nameElement.appendChild(doc.createTextNode(caseName));
caseElement.appendChild(nameElement);
Element numberElement = doc.createElement(NUMBER); // <Number> ... </Number>
numberElement.appendChild(doc.createTextNode(String.valueOf(caseNumber)));
caseElement.appendChild(numberElement);
Element examinerElement = doc.createElement(EXAMINER); // <Examiner> ... </Examiner>
examinerElement.appendChild(doc.createTextNode(examiner));
caseElement.appendChild(examinerElement);
Element exportElement = doc.createElement(EXPORT_FOLDER_NAME); // <ExportFolder> ... </ExportFolder>
exportElement.appendChild(doc.createTextNode(EXPORT_FOLDER_RELPATH));
exportElement.setAttribute(RELATIVE_NAME, "true"); //NON-NLS
caseElement.appendChild(exportElement);
Element logElement = doc.createElement(LOG_FOLDER_NAME); // <LogFolder> ... </LogFolder>
logElement.appendChild(doc.createTextNode(LOG_FOLDER_RELPATH));
logElement.setAttribute(RELATIVE_NAME, "true"); //NON-NLS
caseElement.appendChild(logElement);
Element tempElement = doc.createElement(TEMP_FOLDER_NAME); // <TempFolder> ... </TempFolder>
tempElement.appendChild(doc.createTextNode(TEMP_FOLDER_RELPATH));
tempElement.setAttribute(RELATIVE_NAME, "true"); //NON-NLS
caseElement.appendChild(tempElement);
Element cacheElement = doc.createElement(CACHE_FOLDER_NAME); // <CacheFolder> ... </CacheFolder>
cacheElement.appendChild(doc.createTextNode(CACHE_FOLDER_RELPATH));
cacheElement.setAttribute(RELATIVE_NAME, "true"); //NON-NLS
caseElement.appendChild(cacheElement);
Element typeElement = doc.createElement(CASE_TYPE); // <CaseType> ... </CaseType>
typeElement.appendChild(doc.createTextNode(caseType.toString()));
caseElement.appendChild(typeElement);
Element dbNameElement = doc.createElement(DATABASE_NAME); // <DatabaseName> ... </DatabaseName>
dbNameElement.appendChild(doc.createTextNode(this.caseDatabaseName));
caseElement.appendChild(dbNameElement);
Element indexNameElement = doc.createElement(CASE_TEXT_INDEX_NAME); // <TextIndexName> ... </TextIndexName>
indexNameElement.appendChild(doc.createTextNode(this.caseTextIndexName));
caseElement.appendChild(indexNameElement);
this.writeFile();
}
private void writeFile() throws CaseMetadataException {
if (doc == null || caseName.equals("")) {
throw new CaseMetadataException(
NbBundle.getMessage(this.getClass(), "XMLCaseManagement.writeFile.exception.noCase.msg"));
}
// Prepare the DOM document for writing
Source source = new DOMSource(doc);
// Prepare the data for the output file
StringWriter sw = new StringWriter();
Result result = new StreamResult(sw);
// Write the DOM document to the file
Transformer xformer;// = TransformerFactory.newInstance().newTransformer();
TransformerFactory tfactory = TransformerFactory.newInstance();
try {
xformer = tfactory.newTransformer();
} catch (TransformerConfigurationException ex) {
logger.log(Level.SEVERE, "Could not setup tranformer and write case file"); //NON-NLS
throw new CaseMetadataException(
NbBundle.getMessage(this.getClass(), "XMLCaseManagement.writeFile.exception.errWriteToFile.msg"), ex);
}
//Setup indenting to "pretty print"
xformer.setOutputProperty(OutputKeys.INDENT, "yes"); //NON-NLS
xformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); //NON-NLS
try {
xformer.transform(source, result);
} catch (TransformerException ex) {
logger.log(Level.SEVERE, "Could not run tranformer and write case file"); //NON-NLS
throw new CaseMetadataException(
NbBundle.getMessage(this.getClass(), "XMLCaseManagement.writeFile.exception.errWriteToFile.msg"), ex);
}
// preparing the output file
String xmlString = sw.toString();
File file = new File(this.caseDirectory + File.separator + caseName + ".aut");
// write the file
try {
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)));
bw.write(xmlString);
bw.flush();
bw.close();
} catch (IOException ex) {
logger.log(Level.SEVERE, "Error writing to case file"); //NON-NLS
throw new CaseMetadataException(
NbBundle.getMessage(this.getClass(), "XMLCaseManagement.writeFile.exception.errWriteToFile.msg"), ex);
}
}
}