From 92eeeb4473fb02c2c91fd802a564dc236e3ed30f Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Wed, 3 Feb 2016 16:32:42 -0500 Subject: [PATCH 01/50] Progress started --- .../sleuthkit/autopsy/casemodule/Case.java | 111 +++++---- .../autopsy/casemodule/CaseMetadata.java | 212 ++++++++++++++++++ 2 files changed, 267 insertions(+), 56 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 6d0aca0f6e..299af11ea0 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -219,7 +219,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * multi-user (using PostgreSql) */ @NbBundle.Messages({"Case_caseType_singleUser=Single-user case", - "Case_caseType_multiUser=Multi-user case"}) + "Case_caseType_multiUser=Multi-user case"}) public enum CaseType { SINGLE_USER_CASE(Bundle.Case_caseType_singleUser()), @@ -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 caseName The name of 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 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 - * 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 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 caseName The name of 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 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 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). + * @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). * * @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,11 +582,9 @@ 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 - * 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). */ public static void open(String caseMetadataFilePath) throws CaseActionException { logger.log(Level.INFO, "Opening case with metadata file path {0}", caseMetadataFilePath); //NON-NLS @@ -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) { @@ -710,7 +710,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * Sends out event and reopens windows if needed. * * @param imgPaths the paths of the image that being added - * @param imgId the ID of the image that being added + * @param imgId the ID of the image that being added * @param timeZone the timeZone of the image where it's added * * @deprecated As of release 4.0, replaced by {@link #notifyAddingDataSource(java.util.UUID) and @@ -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)); @@ -776,10 +776,9 @@ public class Case implements SleuthkitCase.ErrorObserver { * This should not be called from the event dispatch thread (EDT) * * @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. + * @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. */ public void notifyDataSourceAdded(Content newDataSource, UUID dataSourceId) { eventPublisher.publish(new DataSourceAddedEvent(newDataSource, dataSourceId)); @@ -894,9 +893,9 @@ public class Case implements SleuthkitCase.ErrorObserver { * This should not be called from the EDT. * * @param oldCaseName the old case name that wants to be updated - * @param oldPath the old path that wants to be updated + * @param oldPath the old path that wants to be updated * @param newCaseName the new case name - * @param newPath the new path + * @param newPath the new path */ void updateCaseName(String oldCaseName, String oldPath, String newCaseName, String newPath) throws CaseActionException { try { @@ -1317,7 +1316,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * Adds a subscriber to events from this Autopsy node and other Autopsy * nodes. * - * @param eventName The event the subscriber is interested in. + * @param eventName The event the subscriber is interested in. * @param subscriber The subscriber to add. */ public static void addEventSubscriber(String eventName, PropertyChangeListener subscriber) { @@ -1328,7 +1327,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * Adds a subscriber to events from this Autopsy node and other Autopsy * nodes. * - * @param eventName The event the subscriber is no longer interested in. + * @param eventName The event the subscriber is no longer interested in. * @param subscriber The subscriber to add. */ public static void removeEventSubscriber(String eventName, PropertyChangeListener subscriber) { @@ -1438,7 +1437,7 @@ public class Case implements SleuthkitCase.ErrorObserver { /** * to create the case directory * - * @param caseDir Path to the case directory (typically base + case name) + * @param caseDir Path to the case directory (typically base + case name) * @param caseName the case name (used only for error messages) * * @throws CaseActionException throw if could not create the case dir @@ -1452,7 +1451,7 @@ public class Case implements SleuthkitCase.ErrorObserver { /** * Create the case directory and its needed subfolders. * - * @param caseDir Path to the case directory (typically base + case name) + * @param caseDir Path to the case directory (typically base + case name) * @param caseType The type of case, single-user or multi-user * * @throws CaseActionException throw if could not create the case dir @@ -1671,10 +1670,10 @@ public class Case implements SleuthkitCase.ErrorObserver { /** * Adds a report to the case. * - * @param localPath The path of the report file, must be in the case - * directory or one of its subdirectories. + * @param localPath The path of the report file, must be in the case + * directory or one of its subdirectories. * @param srcModuleName The name of the module that created the report. - * @param reportName The report name, may be empty. + * @param reportName The report name, may be empty. * * @throws TskCoreException */ @@ -1698,9 +1697,9 @@ public class Case implements SleuthkitCase.ErrorObserver { * Deletes reports from the case - deletes it from the disk as well as the * database. * - * @param reports Collection of Report to be deleted from the case. + * @param reports Collection of Report to be deleted from the case. * @param deleteFromDisk Set true to perform reports file deletion from - * disk. + * disk. * * @throws TskCoreException */ diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java index 81e53a1fc9..034f7c41de 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java @@ -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); // ... + doc.appendChild(rootElement); + + Element crDateElement = doc.createElement(CREATED_DATE_NAME); // ... + crDateElement.appendChild(doc.createTextNode(dateFormat.format(new Date()))); + rootElement.appendChild(crDateElement); + + Element mDateElement = doc.createElement(MODIFIED_DATE_NAME); // ... + mDateElement.appendChild(doc.createTextNode(dateFormat.format(new Date()))); + rootElement.appendChild(mDateElement); + + Element autVerElement = doc.createElement(AUTOPSY_CRVERSION_NAME); // ... + autVerElement.appendChild(doc.createTextNode(System.getProperty("netbeans.buildnumber"))); + rootElement.appendChild(autVerElement); + + Element autSavedVerElement = doc.createElement(AUTOPSY_MVERSION_NAME); // ... + autSavedVerElement.appendChild(doc.createTextNode(System.getProperty("netbeans.buildnumber"))); + rootElement.appendChild(autSavedVerElement); + + Element schVerElement = doc.createElement(SCHEMA_VERSION_NAME); // ... + schVerElement.appendChild(doc.createTextNode(schemaVersion)); + rootElement.appendChild(schVerElement); + + Element caseElement = doc.createElement(CASE_ROOT_NAME); // ... + rootElement.appendChild(caseElement); + + Element nameElement = doc.createElement(NAME); // ... + nameElement.appendChild(doc.createTextNode(caseName)); + caseElement.appendChild(nameElement); + + Element numberElement = doc.createElement(NUMBER); // ... + numberElement.appendChild(doc.createTextNode(String.valueOf(caseNumber))); + caseElement.appendChild(numberElement); + + Element examinerElement = doc.createElement(EXAMINER); // ... + examinerElement.appendChild(doc.createTextNode(examiner)); + caseElement.appendChild(examinerElement); + + Element exportElement = doc.createElement(EXPORT_FOLDER_NAME); // ... + exportElement.appendChild(doc.createTextNode(EXPORT_FOLDER_RELPATH)); + exportElement.setAttribute(RELATIVE_NAME, "true"); //NON-NLS + caseElement.appendChild(exportElement); + + Element logElement = doc.createElement(LOG_FOLDER_NAME); // ... + logElement.appendChild(doc.createTextNode(LOG_FOLDER_RELPATH)); + logElement.setAttribute(RELATIVE_NAME, "true"); //NON-NLS + caseElement.appendChild(logElement); + + Element tempElement = doc.createElement(TEMP_FOLDER_NAME); // ... + tempElement.appendChild(doc.createTextNode(TEMP_FOLDER_RELPATH)); + tempElement.setAttribute(RELATIVE_NAME, "true"); //NON-NLS + caseElement.appendChild(tempElement); + + Element cacheElement = doc.createElement(CACHE_FOLDER_NAME); // ... + cacheElement.appendChild(doc.createTextNode(CACHE_FOLDER_RELPATH)); + cacheElement.setAttribute(RELATIVE_NAME, "true"); //NON-NLS + caseElement.appendChild(cacheElement); + + Element typeElement = doc.createElement(CASE_TYPE); // ... + typeElement.appendChild(doc.createTextNode(caseType.toString())); + caseElement.appendChild(typeElement); + + Element dbNameElement = doc.createElement(DATABASE_NAME); // ... + dbNameElement.appendChild(doc.createTextNode(this.caseDatabaseName)); + caseElement.appendChild(dbNameElement); + + Element indexNameElement = doc.createElement(CASE_TEXT_INDEX_NAME); // ... + 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); + } + } + } From 5ecbb9e75a57a32c84de535eccf2982f295c7b21 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Thu, 4 Feb 2016 16:48:13 -0500 Subject: [PATCH 02/50] First draft of full CaseMetadata (there are bugs) --- .../sleuthkit/autopsy/casemodule/Case.java | 26 ++- .../autopsy/casemodule/CaseMetadata.java | 168 ++++++++++++++---- 2 files changed, 147 insertions(+), 47 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 299af11ea0..3d145a6d4e 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -256,7 +256,6 @@ public class Case implements SleuthkitCase.ErrorObserver { private String number; 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) @@ -286,7 +285,6 @@ public class Case implements SleuthkitCase.ErrorObserver { this.number = number; this.examiner = examiner; this.configFilePath = configFilePath; - this.xmlcm = new XMLCaseManagement(); this.caseMetadata = caseMetadata; this.caseType = type; this.db = db; @@ -509,7 +507,7 @@ 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); + CaseMetadata metadata = CaseMetadata.create(caseType, caseName, caseNumber, examiner, caseDir, santizedCaseName, indexName); Case newCase = new Case(caseName, caseNumber, examiner, configFilePath, metadata, db, caseType); changeCase(newCase); @@ -852,7 +850,7 @@ public class Case implements SleuthkitCase.ErrorObserver { changeCase(null); try { services.close(); - this.xmlcm.close(); // close the xmlcm + this.caseMetadata.close(); // close the xmlcm this.db.close(); } catch (Exception e) { throw new CaseActionException(NbBundle.getMessage(this.getClass(), "Case.closeCase.exception.msg"), e); @@ -871,7 +869,7 @@ public class Case implements SleuthkitCase.ErrorObserver { try { - xmlcm.close(); // close the xmlcm + this.caseMetadata.close(); // close the xmlcm boolean result = deleteCaseDirectory(caseDir); // delete the directory RecentCases.getInstance().removeRecentCase(this.name, this.configFilePath); // remove it from the recent case @@ -899,7 +897,7 @@ public class Case implements SleuthkitCase.ErrorObserver { */ void updateCaseName(String oldCaseName, String oldPath, String newCaseName, String newPath) throws CaseActionException { try { - xmlcm.setCaseName(newCaseName); // set the case + caseMetadata.setCaseName(newCaseName); // set the case name = newCaseName; // change the local value eventPublisher.publish(new AutopsyEvent(Events.NAME.toString(), oldCaseName, newCaseName)); SwingUtilities.invokeLater(() -> { @@ -925,7 +923,7 @@ public class Case implements SleuthkitCase.ErrorObserver { */ void updateExaminer(String oldExaminer, String newExaminer) throws CaseActionException { try { - xmlcm.setCaseExaminer(newExaminer); // set the examiner + caseMetadata.setCaseExaminer(newExaminer); // set the examiner examiner = newExaminer; eventPublisher.publish(new AutopsyEvent(Events.EXAMINER.toString(), oldExaminer, newExaminer)); } catch (Exception e) { @@ -943,7 +941,7 @@ public class Case implements SleuthkitCase.ErrorObserver { */ void updateCaseNumber(String oldCaseNumber, String newCaseNumber) throws CaseActionException { try { - xmlcm.setCaseNumber(newCaseNumber); // set the case number + caseMetadata.setCaseNumber(newCaseNumber); // set the case number number = newCaseNumber; eventPublisher.publish(new AutopsyEvent(Events.NUMBER.toString(), oldCaseNumber, newCaseNumber)); } catch (Exception e) { @@ -1032,10 +1030,10 @@ public class Case implements SleuthkitCase.ErrorObserver { * @return caseDirectoryPath */ public String getCaseDirectory() { - if (xmlcm == null) { + if (caseMetadata == null) { return ""; } else { - return xmlcm.getCaseDirectory(); + return caseMetadata.getCaseDirectory(); } } @@ -1234,10 +1232,10 @@ public class Case implements SleuthkitCase.ErrorObserver { * @return case creation date */ public String getCreatedDate() { - if (xmlcm == null) { + if (caseMetadata == null) { return ""; } else { - return xmlcm.getCreatedDate(); + return caseMetadata.getCreatedDate(); } } @@ -1247,10 +1245,10 @@ public class Case implements SleuthkitCase.ErrorObserver { * @return Index name. */ public String getTextIndexName() { - if (xmlcm == null) { + if (caseMetadata == null) { return ""; } else { - return xmlcm.getTextIndexName(); + return caseMetadata.getCaseTextIndexName(); } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java index 034f7c41de..581c7f4049 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java @@ -99,25 +99,30 @@ public final class CaseMetadata { 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; - private final String examiner; - private final String caseDirectory; - private final String caseDatabaseName; - private final String caseTextIndexName; + private final DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss (z)"); + private Case.CaseType caseType; + private String caseName; + private String caseNumber; + private String examiner; + private String caseDirectory; + private String caseDatabaseName; + private String caseTextIndexName; + private final String createdDate; + private final String schemaVersion; 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 { + private CaseMetadata(Case.CaseType caseType, String caseName, String caseDirectory, String caseDatabaseName, String caseTextIndexName) throws CaseMetadataException { this.caseType = caseType; this.caseName = caseName; - this.caseNumber = caseNumber; - this.examiner = exainer; + this.caseNumber = ""; + this.examiner = ""; + this.createdDate = this.dateFormat.format(new Date()); this.caseDirectory = caseDirectory; this.caseDatabaseName = caseDatabaseName; this.caseTextIndexName = caseTextIndexName; - this.create(); + this.schemaVersion = "1.0"; + this.write(); + } /** @@ -126,13 +131,17 @@ public final class CaseMetadata { * @param metadataFilePath Path to the metadata (.aut) file for a case. */ public CaseMetadata(Path metadataFilePath) throws CaseMetadataException { + this(metadataFilePath.toString()); + } + + private CaseMetadata(String metadataFilePath) throws CaseMetadataException { try { /* * TODO (RC): This class should eventually replace the non-public * and unsafe XMLCaseManagement class altogether. */ XMLCaseManagement metadata = new XMLCaseManagement(); - metadata.open(metadataFilePath.toString()); + metadata.open(metadataFilePath); try { caseType = metadata.getCaseType(); } catch (NullPointerException unused) { @@ -177,10 +186,32 @@ public final class CaseMetadata { } catch (NullPointerException unused) { throw new CaseMetadataException("Case keyword search index name missing"); } + try { + this.createdDate = metadata.getCreatedDate(); + } catch (NullPointerException unused) { + throw new CaseMetadataException("Case created date element missing"); + } + try { + this.schemaVersion = metadata.getSchemaVersion(); + } catch (NullPointerException unused) { + throw new CaseMetadataException("Case created date element missing"); + } + } catch (CaseActionException ex) { throw new CaseMetadataException(ex.getLocalizedMessage(), ex); } - this.create(); + this.write(); + } + + public static CaseMetadata open(Path metadataFilePath) throws CaseMetadataException { + CaseMetadata metadata = new CaseMetadata(metadataFilePath.toString()); + return metadata; + } + + public static CaseMetadata create(Case.CaseType caseType, String caseName, String caseNumber, String examiner, String caseDirectory, String caseDatabaseName, String caseTextIndexName) throws CaseMetadataException { + CaseMetadata metadata = new CaseMetadata(caseType, caseName, caseDirectory, caseDatabaseName, caseTextIndexName); + metadata.write(); + return metadata; } /** @@ -238,15 +269,78 @@ public final class CaseMetadata { } /** - * Gets the text index name. + * Gets the date this case was created * - * @return The case text index name, will be empty for a single-user case. + * @return The date this case was created as a string */ - public String getTextIndexName() { + public String getCreatedDate() { + return this.createdDate; + } + + /** + * @param caseType the caseType to set + */ + public void setCaseType(Case.CaseType caseType) { + this.caseType = caseType; + } + + /** + * @param caseName the caseName to set + */ + public void setCaseName(String caseName) { + this.caseName = caseName; + } + + /** + * @param caseNumber the caseNumber to set + */ + public void setCaseNumber(String caseNumber) { + this.caseNumber = caseNumber; + } + + /** + * @param examiner the examiner to set + */ + public void setCaseExaminer(String examiner) { + this.examiner = examiner; + } + + /** + * @param caseDirectory the caseDirectory to set + */ + public void setCaseDirectory(String caseDirectory) { + this.caseDirectory = caseDirectory; + } + + /** + * @param caseDatabaseName the caseDatabaseName to set + */ + public void setCaseDatabaseName(String caseDatabaseName) { + this.caseDatabaseName = caseDatabaseName; + } + + /** + * @return the caseTextIndexName + */ + public String getCaseTextIndexName() { return caseTextIndexName; } - private void create() throws CaseMetadataException { + /** + * @param caseTextIndexName the caseTextIndexName to set + */ + public void setCaseTextIndexName(String caseTextIndexName) { + this.caseTextIndexName = caseTextIndexName; + } + + /** + * @return the schemaVersion + */ + public String getSchemaVersion() { + return schemaVersion; + } + + private void write() throws CaseMetadataException { DocumentBuilder docBuilder; DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); @@ -254,18 +348,16 @@ public final class CaseMetadata { 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(); + Document doc = docBuilder.newDocument(); Element rootElement = doc.createElement(TOP_ROOT_NAME); // ... doc.appendChild(rootElement); Element crDateElement = doc.createElement(CREATED_DATE_NAME); // ... - crDateElement.appendChild(doc.createTextNode(dateFormat.format(new Date()))); + crDateElement.appendChild(doc.createTextNode(this.getCreatedDate())); rootElement.appendChild(crDateElement); Element mDateElement = doc.createElement(MODIFIED_DATE_NAME); // ... @@ -281,22 +373,22 @@ public final class CaseMetadata { rootElement.appendChild(autSavedVerElement); Element schVerElement = doc.createElement(SCHEMA_VERSION_NAME); // ... - schVerElement.appendChild(doc.createTextNode(schemaVersion)); + schVerElement.appendChild(doc.createTextNode(getSchemaVersion())); rootElement.appendChild(schVerElement); Element caseElement = doc.createElement(CASE_ROOT_NAME); // ... rootElement.appendChild(caseElement); Element nameElement = doc.createElement(NAME); // ... - nameElement.appendChild(doc.createTextNode(caseName)); + nameElement.appendChild(doc.createTextNode(getCaseName())); caseElement.appendChild(nameElement); Element numberElement = doc.createElement(NUMBER); // ... - numberElement.appendChild(doc.createTextNode(String.valueOf(caseNumber))); + numberElement.appendChild(doc.createTextNode(String.valueOf(getCaseNumber()))); caseElement.appendChild(numberElement); Element examinerElement = doc.createElement(EXAMINER); // ... - examinerElement.appendChild(doc.createTextNode(examiner)); + examinerElement.appendChild(doc.createTextNode(getExaminer())); caseElement.appendChild(examinerElement); Element exportElement = doc.createElement(EXPORT_FOLDER_NAME); // ... @@ -320,21 +412,21 @@ public final class CaseMetadata { caseElement.appendChild(cacheElement); Element typeElement = doc.createElement(CASE_TYPE); // ... - typeElement.appendChild(doc.createTextNode(caseType.toString())); + typeElement.appendChild(doc.createTextNode(getCaseType().toString())); caseElement.appendChild(typeElement); Element dbNameElement = doc.createElement(DATABASE_NAME); // ... - dbNameElement.appendChild(doc.createTextNode(this.caseDatabaseName)); + dbNameElement.appendChild(doc.createTextNode(this.getCaseDatabaseName())); caseElement.appendChild(dbNameElement); Element indexNameElement = doc.createElement(CASE_TEXT_INDEX_NAME); // ... - indexNameElement.appendChild(doc.createTextNode(this.caseTextIndexName)); + indexNameElement.appendChild(doc.createTextNode(this.getCaseTextIndexName())); caseElement.appendChild(indexNameElement); - this.writeFile(); + this.writeFile(doc); } - private void writeFile() throws CaseMetadataException { - if (doc == null || caseName.equals("")) { + private void writeFile(Document doc) throws CaseMetadataException { + if (doc == null || getCaseName().equals("")) { throw new CaseMetadataException( NbBundle.getMessage(this.getClass(), "XMLCaseManagement.writeFile.exception.noCase.msg")); } @@ -372,7 +464,7 @@ public final class CaseMetadata { // preparing the output file String xmlString = sw.toString(); - File file = new File(this.caseDirectory + File.separator + caseName + ".aut"); + File file = new File(this.getCaseDirectory() + File.separator + getCaseName() + ".aut"); // write the file try { @@ -387,4 +479,14 @@ public final class CaseMetadata { } } + /** + * When user wants to close the case. This method writes any changes to the + * XML case configuration file, closes it and the document handler, and + * clears all the local variables / fields. + * + */ + public void close() throws CaseMetadataException { + write(); // write any changes to xml + } + } From ad55e8ffc9538bcfb658b4b7db554eaca37f24b9 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Fri, 5 Feb 2016 13:12:21 -0500 Subject: [PATCH 03/50] Moved open into CaseMetadata, working on making writing work. --- .../sleuthkit/autopsy/casemodule/Case.java | 2 +- .../autopsy/casemodule/CaseMetadata.java | 191 +++++++++++------- 2 files changed, 123 insertions(+), 70 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 3d145a6d4e..f608bc7af1 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -598,7 +598,7 @@ public class Case implements SleuthkitCase.ErrorObserver { /* * Get the case metadata required to open the case database. */ - CaseMetadata metadata = new CaseMetadata(Paths.get(caseMetadataFilePath)); + CaseMetadata metadata = CaseMetadata.open(Paths.get(caseMetadataFilePath)); String caseName = metadata.getCaseName(); String caseNumber = metadata.getCaseNumber(); String examiner = metadata.getExaminer(); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java index 581c7f4049..7176c074bc 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java @@ -29,6 +29,8 @@ import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import java.util.logging.Level; +import javax.swing.JOptionPane; +import javax.swing.JPanel; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -42,10 +44,22 @@ 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.AUTOPSY_CRVERSION_NAME; +import static org.sleuthkit.autopsy.casemodule.XMLCaseManagement.CASE_ROOT_NAME; +import static org.sleuthkit.autopsy.casemodule.XMLCaseManagement.CASE_TEXT_INDEX_NAME; +import static org.sleuthkit.autopsy.casemodule.XMLCaseManagement.CASE_TYPE; +import static org.sleuthkit.autopsy.casemodule.XMLCaseManagement.CREATED_DATE_NAME; +import static org.sleuthkit.autopsy.casemodule.XMLCaseManagement.DATABASE_NAME; +import static org.sleuthkit.autopsy.casemodule.XMLCaseManagement.EXAMINER; +import static org.sleuthkit.autopsy.casemodule.XMLCaseManagement.NAME; +import static org.sleuthkit.autopsy.casemodule.XMLCaseManagement.NUMBER; +import static org.sleuthkit.autopsy.casemodule.XMLCaseManagement.SCHEMA_VERSION_NAME; import static org.sleuthkit.autopsy.casemodule.XMLCaseManagement.TOP_ROOT_NAME; +import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.coreutils.Logger; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.xml.sax.SAXException; /** * Provides access to case metadata. @@ -107,8 +121,11 @@ public final class CaseMetadata { private String caseDirectory; private String caseDatabaseName; private String caseTextIndexName; - private final String createdDate; - private final String schemaVersion; + private String createdDate; + private String schemaVersion; + private String fileName; + private JPanel caller; + private final String className = this.getClass().toString(); private static final Logger logger = Logger.getLogger(CaseMetadata.class.getName()); private CaseMetadata(Case.CaseType caseType, String caseName, String caseDirectory, String caseDatabaseName, String caseTextIndexName) throws CaseMetadataException { @@ -121,6 +138,7 @@ public final class CaseMetadata { this.caseDatabaseName = caseDatabaseName; this.caseTextIndexName = caseTextIndexName; this.schemaVersion = "1.0"; + this.fileName = caseName; this.write(); } @@ -135,72 +153,7 @@ public final class CaseMetadata { } private CaseMetadata(String metadataFilePath) throws CaseMetadataException { - try { - /* - * TODO (RC): This class should eventually replace the non-public - * and unsafe XMLCaseManagement class altogether. - */ - XMLCaseManagement metadata = new XMLCaseManagement(); - metadata.open(metadataFilePath); - try { - caseType = metadata.getCaseType(); - } catch (NullPointerException unused) { - throw new CaseMetadataException("Case type element missing"); - } - try { - caseName = metadata.getCaseName(); - if (caseName.isEmpty()) { - throw new CaseMetadataException("Case name missing"); - } - } catch (NullPointerException unused) { - throw new CaseMetadataException("Case name element missing"); - } - try { - caseNumber = metadata.getCaseNumber(); - } catch (NullPointerException unused) { - throw new CaseMetadataException("Case number element missing"); - } - try { - examiner = metadata.getCaseExaminer(); - } catch (NullPointerException unused) { - throw new CaseMetadataException("Examiner element missing"); - } - try { - caseDirectory = metadata.getCaseDirectory(); - if (caseDirectory.isEmpty()) { - throw new CaseMetadataException("Case directory missing"); - } - } catch (NullPointerException unused) { - throw new CaseMetadataException("Case directory element missing"); - } - try { - caseDatabaseName = metadata.getDatabaseName(); - } catch (NullPointerException unused) { - throw new CaseMetadataException("Case database element missing"); - } - try { - caseTextIndexName = metadata.getTextIndexName(); - if (Case.CaseType.MULTI_USER_CASE == caseType && caseDatabaseName.isEmpty()) { - throw new CaseMetadataException("Case keyword search index name missing"); - } - } catch (NullPointerException unused) { - throw new CaseMetadataException("Case keyword search index name missing"); - } - try { - this.createdDate = metadata.getCreatedDate(); - } catch (NullPointerException unused) { - throw new CaseMetadataException("Case created date element missing"); - } - try { - this.schemaVersion = metadata.getSchemaVersion(); - } catch (NullPointerException unused) { - throw new CaseMetadataException("Case created date element missing"); - } - - } catch (CaseActionException ex) { - throw new CaseMetadataException(ex.getLocalizedMessage(), ex); - } - this.write(); + this.open(metadataFilePath); } public static CaseMetadata open(Path metadataFilePath) throws CaseMetadataException { @@ -464,7 +417,7 @@ public final class CaseMetadata { // preparing the output file String xmlString = sw.toString(); - File file = new File(this.getCaseDirectory() + File.separator + getCaseName() + ".aut"); + File file = new File(this.getCaseDirectory() + File.separator + this.fileName + ".aut"); // write the file try { @@ -489,4 +442,104 @@ public final class CaseMetadata { write(); // write any changes to xml } + /** + * Opens the configuration file and load the document handler Note: this is + * for the schema version 1.0 + * + * @param conFilePath the path of the XML case configuration file path + */ + public void open(String conFilePath) throws CaseMetadataException { + File file = new File(conFilePath); + Document doc; + + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder db; + try { + db = dbf.newDocumentBuilder(); + doc = db.parse(file); + } catch (ParserConfigurationException | SAXException | IOException ex) { + throw new CaseMetadataException( + NbBundle.getMessage(this.getClass(), "XMLCaseManagement.open.exception.errReadXMLFile.msg", + conFilePath), ex); + } + + doc.getDocumentElement().normalize(); + doc.getDocumentElement().normalize(); + + // TODO: Restore later +// if (!XMLUtil.xmlIsValid(doc, XMLCaseManagement.class, XSDFILE)) { +// logger.log(Level.WARNING, "Could not validate against [" + XSDFILE + "], results may not accurate"); //NON-NLS +// } + Element rootEl = doc.getDocumentElement(); + String rootName = rootEl.getNodeName(); + + // check if it's the autopsy case, if not, throws an error + if (!rootName.equals(TOP_ROOT_NAME)) { + // throw an error ... + if (RuntimeProperties.coreComponentsAreActive()) { + + JOptionPane.showMessageDialog(caller, + NbBundle.getMessage(this.getClass(), + "XMLCaseManagement.open.msgDlg.notAutCase.msg", + file.getName(), className), + NbBundle.getMessage(this.getClass(), + "XMLCaseManagement.open.msgDlg.notAutCase.title"), + JOptionPane.ERROR_MESSAGE); + } + } else { + /* + * Autopsy Created Version + */ + Element rootElement = doc.getDocumentElement(); + + String createdVersion = ((Element) rootElement.getElementsByTagName(AUTOPSY_CRVERSION_NAME).item(0)).getTextContent(); // get the created version + + // check if it has the same autopsy version as the current one + if (!createdVersion.equals(System.getProperty("netbeans.buildnumber"))) { + // if not the same version, update the saved version in the xml to the current version + rootElement.getElementsByTagName(AUTOPSY_MVERSION_NAME).item(0).setTextContent(System.getProperty("netbeans.buildnumber")); + } + + /* + * Schema Version + */ + String schemaVer = ((Element) rootElement.getElementsByTagName(SCHEMA_VERSION_NAME).item(0)).getTextContent(); + // check if it has the same schema version as the current one + if (!schemaVer.equals(schemaVersion)) { + // do something here if not the same version + // ... @Override + } + + try { + String fullFileName = file.getName(); + String fileName = fullFileName.substring(0, fullFileName.lastIndexOf(".")); // remove the extension + this.fileName = fileName; + Element caseElement = (Element) doc.getElementsByTagName(CASE_ROOT_NAME).item(0); + + String caseTypeString = ((Element) caseElement.getElementsByTagName(CASE_TYPE).item(0)).getTextContent(); + this.caseType = caseTypeString.equals("") ? Case.CaseType.SINGLE_USER_CASE : Case.CaseType.fromString(caseTypeString); + this.caseName = ((Element) caseElement.getElementsByTagName(NAME).item(0)).getTextContent(); + Element numberElement = caseElement.getElementsByTagName(NUMBER).getLength() > 0 ? (Element) caseElement.getElementsByTagName(NUMBER).item(0) : null; + this.caseNumber = numberElement != null ? numberElement.getTextContent() : ""; + Element examinerElement = caseElement.getElementsByTagName(EXAMINER).getLength() > 0 ? (Element) caseElement.getElementsByTagName(EXAMINER).item(0) : null; + this.caseNumber = numberElement != null ? examinerElement.getTextContent() : ""; + this.caseDirectory = conFilePath.substring(0, conFilePath.lastIndexOf("\\")); + if (this.caseDirectory.isEmpty()) { + throw new CaseMetadataException("Case directory missing"); + } + Element databaseNameElement = caseElement.getElementsByTagName(DATABASE_NAME).getLength() > 0 ? (Element) caseElement.getElementsByTagName(DATABASE_NAME).item(0) : null; + this.caseDatabaseName = databaseNameElement != null ? databaseNameElement.getTextContent() : ""; + Element caseTextIndexNameElement = caseElement.getElementsByTagName(CASE_TEXT_INDEX_NAME).getLength() > 0 ? (Element) caseElement.getElementsByTagName(CASE_TEXT_INDEX_NAME).item(0) : null; + this.caseTextIndexName = caseTextIndexNameElement != null ? caseTextIndexNameElement.getTextContent() : ""; + if (Case.CaseType.MULTI_USER_CASE == caseType && caseDatabaseName.isEmpty()) { + throw new CaseMetadataException("Case keyword search index name missing"); + } + this.createdDate = ((Element) rootElement.getElementsByTagName(CREATED_DATE_NAME).item(0)).getTextContent(); + this.schemaVersion = ((Element) rootElement.getElementsByTagName(SCHEMA_VERSION_NAME).item(0)).getTextContent(); + } catch (NullPointerException ex) { + throw new CaseMetadataException("Error setting case metadata when opening file.", ex); + } + } + } + } From 38f2c6cef93ee7ac7de1ee32e6d57ad2e5bcef06 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Fri, 5 Feb 2016 14:33:18 -0500 Subject: [PATCH 04/50] Made open private --- Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java index 7176c074bc..37347a58a7 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java @@ -448,7 +448,7 @@ public final class CaseMetadata { * * @param conFilePath the path of the XML case configuration file path */ - public void open(String conFilePath) throws CaseMetadataException { + private void open(String conFilePath) throws CaseMetadataException { File file = new File(conFilePath); Document doc; From 625dd9876a056ada8796d32cdfc86225b44e431f Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Fri, 5 Feb 2016 15:16:01 -0500 Subject: [PATCH 05/50] Bug fixing --- Core/src/org/sleuthkit/autopsy/casemodule/Case.java | 5 +---- Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index f608bc7af1..c7dc7850c9 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -476,9 +476,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * class with use of CaseMetadata class. */ String configFilePath = caseDir + File.separator + caseName + CASE_DOT_EXTENSION; - XMLCaseManagement xmlcm = new XMLCaseManagement(); - xmlcm.create(caseDir, caseName, examiner, caseNumber, caseType, dbName, indexName); - xmlcm.writeFile(); + CaseMetadata metadata = CaseMetadata.create(caseType, caseName, caseNumber, examiner, caseDir, santizedCaseName, indexName); /* * Create the case database. @@ -507,7 +505,6 @@ public class Case implements SleuthkitCase.ErrorObserver { }); throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.databaseConnectionInfo.error.msg"), ex); } - CaseMetadata metadata = CaseMetadata.create(caseType, caseName, caseNumber, examiner, caseDir, santizedCaseName, indexName); Case newCase = new Case(caseName, caseNumber, examiner, configFilePath, metadata, db, caseType); changeCase(newCase); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java index 37347a58a7..63aad7d984 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java @@ -163,7 +163,6 @@ public final class CaseMetadata { public static CaseMetadata create(Case.CaseType caseType, String caseName, String caseNumber, String examiner, String caseDirectory, String caseDatabaseName, String caseTextIndexName) throws CaseMetadataException { CaseMetadata metadata = new CaseMetadata(caseType, caseName, caseDirectory, caseDatabaseName, caseTextIndexName); - metadata.write(); return metadata; } From 665eb28c59013c5f97edb984b2ea8b3a83b67417 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Fri, 5 Feb 2016 16:54:12 -0500 Subject: [PATCH 06/50] Normalized --- Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java index 63aad7d984..c3dc39af54 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java @@ -374,6 +374,7 @@ public final class CaseMetadata { Element indexNameElement = doc.createElement(CASE_TEXT_INDEX_NAME); // ... indexNameElement.appendChild(doc.createTextNode(this.getCaseTextIndexName())); caseElement.appendChild(indexNameElement); + doc.normalize(); this.writeFile(doc); } From d53d34e37f65651293791709d89102b7c34db6c6 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Mon, 8 Feb 2016 10:33:53 -0500 Subject: [PATCH 07/50] Fixed up CaseMetadata writing, implemented in SingleUserCaseConverter --- .../sleuthkit/autopsy/casemodule/Case.java | 6 -- .../autopsy/casemodule/CaseMetadata.java | 66 ++++++++----------- .../casemodule/SingleUserCaseConverter.java | 18 +++-- 3 files changed, 34 insertions(+), 56 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index c7dc7850c9..72ae42f8d4 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -471,9 +471,6 @@ public class Case implements SleuthkitCase.ErrorObserver { /* * Create the case metadata (.aut) file. - * - * TODO (AUT-1885): Replace use of obsolete and unsafe XMLCaseManagement - * class with use of CaseMetadata class. */ String configFilePath = caseDir + File.separator + caseName + CASE_DOT_EXTENSION; CaseMetadata metadata = CaseMetadata.create(caseType, caseName, caseNumber, examiner, caseDir, santizedCaseName, indexName); @@ -847,7 +844,6 @@ public class Case implements SleuthkitCase.ErrorObserver { changeCase(null); try { services.close(); - this.caseMetadata.close(); // close the xmlcm this.db.close(); } catch (Exception e) { throw new CaseActionException(NbBundle.getMessage(this.getClass(), "Case.closeCase.exception.msg"), e); @@ -865,8 +861,6 @@ public class Case implements SleuthkitCase.ErrorObserver { logger.log(Level.INFO, "Deleting case.\ncaseDir: {0}", caseDir); //NON-NLS try { - - this.caseMetadata.close(); // close the xmlcm boolean result = deleteCaseDirectory(caseDir); // delete the directory RecentCases.getInstance().removeRecentCase(this.name, this.configFilePath); // remove it from the recent case diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java index c3dc39af54..3376107d27 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java @@ -44,19 +44,9 @@ 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.AUTOPSY_CRVERSION_NAME; -import static org.sleuthkit.autopsy.casemodule.XMLCaseManagement.CASE_ROOT_NAME; -import static org.sleuthkit.autopsy.casemodule.XMLCaseManagement.CASE_TEXT_INDEX_NAME; -import static org.sleuthkit.autopsy.casemodule.XMLCaseManagement.CASE_TYPE; -import static org.sleuthkit.autopsy.casemodule.XMLCaseManagement.CREATED_DATE_NAME; -import static org.sleuthkit.autopsy.casemodule.XMLCaseManagement.DATABASE_NAME; -import static org.sleuthkit.autopsy.casemodule.XMLCaseManagement.EXAMINER; -import static org.sleuthkit.autopsy.casemodule.XMLCaseManagement.NAME; -import static org.sleuthkit.autopsy.casemodule.XMLCaseManagement.NUMBER; -import static org.sleuthkit.autopsy.casemodule.XMLCaseManagement.SCHEMA_VERSION_NAME; -import static org.sleuthkit.autopsy.casemodule.XMLCaseManagement.TOP_ROOT_NAME; import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.XMLUtil; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.SAXException; @@ -229,46 +219,60 @@ public final class CaseMetadata { return this.createdDate; } + /** + * @param createdDate the createdDate to set + */ + void setCreatedDate(String createdDate) throws CaseMetadataException { + this.createdDate = createdDate; + this.write(); + } + /** * @param caseType the caseType to set */ - public void setCaseType(Case.CaseType caseType) { + public void setCaseType(Case.CaseType caseType) throws CaseMetadataException { this.caseType = caseType; + this.write(); } /** * @param caseName the caseName to set */ - public void setCaseName(String caseName) { + public void setCaseName(String caseName) throws CaseMetadataException { this.caseName = caseName; + this.write(); } /** * @param caseNumber the caseNumber to set */ - public void setCaseNumber(String caseNumber) { + public void setCaseNumber(String caseNumber) throws CaseMetadataException { this.caseNumber = caseNumber; + this.write(); } /** * @param examiner the examiner to set */ - public void setCaseExaminer(String examiner) { + public void setCaseExaminer(String examiner) throws CaseMetadataException { this.examiner = examiner; + this.write(); } /** * @param caseDirectory the caseDirectory to set */ - public void setCaseDirectory(String caseDirectory) { + public void setCaseDirectory(String caseDirectory) throws CaseMetadataException { this.caseDirectory = caseDirectory; + this.write(); } /** * @param caseDatabaseName the caseDatabaseName to set */ - public void setCaseDatabaseName(String caseDatabaseName) { + public void setCaseDatabaseName(String caseDatabaseName) throws CaseMetadataException { this.caseDatabaseName = caseDatabaseName; + this.write(); } /** @@ -281,8 +285,9 @@ public final class CaseMetadata { /** * @param caseTextIndexName the caseTextIndexName to set */ - public void setCaseTextIndexName(String caseTextIndexName) { + public void setCaseTextIndexName(String caseTextIndexName) throws CaseMetadataException { this.caseTextIndexName = caseTextIndexName; + this.write(); } /** @@ -293,18 +298,13 @@ public final class CaseMetadata { } private void write() throws CaseMetadataException { - DocumentBuilder docBuilder; - DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); - - // throw an error here + Document doc; try { - docBuilder = docFactory.newDocumentBuilder(); + doc = XMLUtil.createDocument(); } catch (ParserConfigurationException ex) { throw new CaseMetadataException( NbBundle.getMessage(this.getClass(), "XMLCaseManagement.create.exception.msg"), ex); } - - Document doc = docBuilder.newDocument(); Element rootElement = doc.createElement(TOP_ROOT_NAME); // ... doc.appendChild(rootElement); @@ -432,16 +432,6 @@ public final class CaseMetadata { } } - /** - * When user wants to close the case. This method writes any changes to the - * XML case configuration file, closes it and the document handler, and - * clears all the local variables / fields. - * - */ - public void close() throws CaseMetadataException { - write(); // write any changes to xml - } - /** * Opens the configuration file and load the document handler Note: this is * for the schema version 1.0 @@ -466,10 +456,6 @@ public final class CaseMetadata { doc.getDocumentElement().normalize(); doc.getDocumentElement().normalize(); - // TODO: Restore later -// if (!XMLUtil.xmlIsValid(doc, XMLCaseManagement.class, XSDFILE)) { -// logger.log(Level.WARNING, "Could not validate against [" + XSDFILE + "], results may not accurate"); //NON-NLS -// } Element rootEl = doc.getDocumentElement(); String rootName = rootEl.getNodeName(); @@ -534,7 +520,7 @@ public final class CaseMetadata { if (Case.CaseType.MULTI_USER_CASE == caseType && caseDatabaseName.isEmpty()) { throw new CaseMetadataException("Case keyword search index name missing"); } - this.createdDate = ((Element) rootElement.getElementsByTagName(CREATED_DATE_NAME).item(0)).getTextContent(); + this.setCreatedDate(((Element) rootElement.getElementsByTagName(CREATED_DATE_NAME).item(0)).getTextContent()); this.schemaVersion = ((Element) rootElement.getElementsByTagName(SCHEMA_VERSION_NAME).item(0)).getTextContent(); } catch (NullPointerException ex) { throw new CaseMetadataException("Error setting case metadata when opening file.", ex); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java b/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java index 2654a11c27..d156fd065b 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java @@ -165,9 +165,8 @@ public class SingleUserCaseConverter { } // Read old xml config - XMLCaseManagement oldXmlCaseManagement = new XMLCaseManagement(); - oldXmlCaseManagement.open(icd.getCaseInputFolder().resolve(icd.getAutFileName()).toString()); - if (oldXmlCaseManagement.getCaseType() == CaseType.MULTI_USER_CASE) { + CaseMetadata oldCaseMetadata = CaseMetadata.open(icd.getCaseInputFolder().resolve(icd.getAutFileName())); + if (oldCaseMetadata.getCaseType() == CaseType.MULTI_USER_CASE) { throw new Exception(NbBundle.getMessage(SingleUserCaseConverter.class, "SingleUserCaseConverter.AlreadyMultiUser")); //NON-NLS } @@ -191,15 +190,14 @@ public class SingleUserCaseConverter { copyImages(icd); // Create new .aut file - XMLCaseManagement newXmlCaseManagement = new XMLCaseManagement(); - newXmlCaseManagement.create(icd.getCaseOutputFolder().toString(), + CaseMetadata newCaseMetadata = CaseMetadata.create(CaseType.MULTI_USER_CASE, icd.getNewCaseName(), - oldXmlCaseManagement.getCaseExaminer(), - oldXmlCaseManagement.getCaseNumber(), - CaseType.MULTI_USER_CASE, dbName, solrName); - + oldCaseMetadata.getCaseNumber(), + oldCaseMetadata.getExaminer(), + icd.getCaseOutputFolder().toString(), + dbName, solrName); // Set created date. This calls writefile, no need to call it again - newXmlCaseManagement.setCreatedDate(oldXmlCaseManagement.getCreatedDate()); + newCaseMetadata.setCreatedDate(oldCaseMetadata.getCreatedDate()); // At this point the import has been finished successfully so we can delete the original case // (if requested). This *should* be fairly safe - at this point we know there was an autopsy file From 6a6f3a4a50551435323b05e52aa50c935b2b2031 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Tue, 9 Feb 2016 09:39:27 -0500 Subject: [PATCH 08/50] Updated CaseMetadata to use @Messages syntax --- .../autopsy/casemodule/CaseMetadata.java | 38 ++++++++++++------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java index 3376107d27..b9667c40ae 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java @@ -44,6 +44,7 @@ import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.XMLUtil; @@ -56,6 +57,19 @@ import org.xml.sax.SAXException; */ public final class CaseMetadata { + @Messages({ + "CaseMetadata.writeFile.exception.noCase.msg=No set case to write management file for.", + "CaseMetadata.writeFile.exception.errWriteToFile.msg=Error writing to case file", + "# {0} - case file path", + "CaseMetadata.open.exception.errReadXMLFile.msg=Error reading case XML file\\: {0}", + "# {0} - file name", + "# {1} - class name", + "CaseMetadata.open.msgDlg.notAutCase.msg=Error\\: This is not an Autopsy config file (\"{0}\").\\n\\n\\\n" + + "Detail\\: \\n\\\n" + + "Cannot open a non-Autopsy config file (at {1}).", + "CaseMetadata.open.msgDlg.notAutCase.title=Error" + }) + /** * Exception thrown by the CaseMetadata class when there is a problem * accessing the metadata for a case. @@ -119,6 +133,7 @@ public final class CaseMetadata { private static final Logger logger = Logger.getLogger(CaseMetadata.class.getName()); private CaseMetadata(Case.CaseType caseType, String caseName, String caseDirectory, String caseDatabaseName, String caseTextIndexName) throws CaseMetadataException { + this.caseType = caseType; this.caseName = caseName; this.caseNumber = ""; @@ -381,7 +396,7 @@ public final class CaseMetadata { private void writeFile(Document doc) throws CaseMetadataException { if (doc == null || getCaseName().equals("")) { throw new CaseMetadataException( - NbBundle.getMessage(this.getClass(), "XMLCaseManagement.writeFile.exception.noCase.msg")); + Bundle.CaseMetadata_writeFile_exception_noCase_msg()); } // Prepare the DOM document for writing @@ -400,7 +415,7 @@ public final class CaseMetadata { } 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); + Bundle.CaseMetadata_writeFile_exception_errWriteToFile_msg(), ex); } //Setup indenting to "pretty print" @@ -412,7 +427,7 @@ public final class CaseMetadata { } 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); + Bundle.CaseMetadata_writeFile_exception_errWriteToFile_msg(), ex); } // preparing the output file @@ -428,7 +443,7 @@ public final class CaseMetadata { } 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); + Bundle.CaseMetadata_writeFile_exception_errWriteToFile_msg(), ex); } } @@ -449,8 +464,7 @@ public final class CaseMetadata { doc = db.parse(file); } catch (ParserConfigurationException | SAXException | IOException ex) { throw new CaseMetadataException( - NbBundle.getMessage(this.getClass(), "XMLCaseManagement.open.exception.errReadXMLFile.msg", - conFilePath), ex); + Bundle.CaseMetadata_open_exception_errReadXMLFile_msg(conFilePath), ex); } doc.getDocumentElement().normalize(); @@ -465,11 +479,9 @@ public final class CaseMetadata { if (RuntimeProperties.coreComponentsAreActive()) { JOptionPane.showMessageDialog(caller, - NbBundle.getMessage(this.getClass(), - "XMLCaseManagement.open.msgDlg.notAutCase.msg", + Bundle.CaseMetadata_open_msgDlg_notAutCase_msg( file.getName(), className), - NbBundle.getMessage(this.getClass(), - "XMLCaseManagement.open.msgDlg.notAutCase.title"), + Bundle.CaseMetadata_open_msgDlg_notAutCase_title(), JOptionPane.ERROR_MESSAGE); } } else { @@ -511,19 +523,19 @@ public final class CaseMetadata { this.caseNumber = numberElement != null ? examinerElement.getTextContent() : ""; this.caseDirectory = conFilePath.substring(0, conFilePath.lastIndexOf("\\")); if (this.caseDirectory.isEmpty()) { - throw new CaseMetadataException("Case directory missing"); + throw new CaseMetadataException(Bundle.CaseMetadata_open_exception_errReadXMLFile_msg(conFilePath)); } Element databaseNameElement = caseElement.getElementsByTagName(DATABASE_NAME).getLength() > 0 ? (Element) caseElement.getElementsByTagName(DATABASE_NAME).item(0) : null; this.caseDatabaseName = databaseNameElement != null ? databaseNameElement.getTextContent() : ""; Element caseTextIndexNameElement = caseElement.getElementsByTagName(CASE_TEXT_INDEX_NAME).getLength() > 0 ? (Element) caseElement.getElementsByTagName(CASE_TEXT_INDEX_NAME).item(0) : null; this.caseTextIndexName = caseTextIndexNameElement != null ? caseTextIndexNameElement.getTextContent() : ""; if (Case.CaseType.MULTI_USER_CASE == caseType && caseDatabaseName.isEmpty()) { - throw new CaseMetadataException("Case keyword search index name missing"); + throw new CaseMetadataException(Bundle.CaseMetadata_open_exception_errReadXMLFile_msg(conFilePath)); } this.setCreatedDate(((Element) rootElement.getElementsByTagName(CREATED_DATE_NAME).item(0)).getTextContent()); this.schemaVersion = ((Element) rootElement.getElementsByTagName(SCHEMA_VERSION_NAME).item(0)).getTextContent(); } catch (NullPointerException ex) { - throw new CaseMetadataException("Error setting case metadata when opening file.", ex); + throw new CaseMetadataException(Bundle.CaseMetadata_open_exception_errReadXMLFile_msg(conFilePath), ex); } } } From 13b632594982e4a5850e543f65cce9f9f52c3b62 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Tue, 9 Feb 2016 11:00:10 -0500 Subject: [PATCH 09/50] Fixed out of synch problems --- .../autopsy/casemodule/CaseMetadata.java | 60 +++++++++++++++++-- 1 file changed, 54 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java index b9667c40ae..4ea90277fa 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java @@ -238,56 +238,98 @@ public final class CaseMetadata { * @param createdDate the createdDate to set */ void setCreatedDate(String createdDate) throws CaseMetadataException { + String oldCreatedDate = this.createdDate; this.createdDate = createdDate; - this.write(); + try { + this.write(); + } catch (CaseMetadataException ex) { + this.createdDate = oldCreatedDate; + throw ex; + } } /** * @param caseType the caseType to set */ public void setCaseType(Case.CaseType caseType) throws CaseMetadataException { + Case.CaseType oldCaseType = this.caseType; this.caseType = caseType; - this.write(); + try { + this.write(); + } catch (CaseMetadataException ex) { + this.caseType = oldCaseType; + throw ex; + } } /** * @param caseName the caseName to set */ public void setCaseName(String caseName) throws CaseMetadataException { + String oldCaseName = this.caseName; this.caseName = caseName; - this.write(); + try { + this.write(); + } catch (CaseMetadataException ex) { + this.caseName = oldCaseName; + throw ex; + } } /** * @param caseNumber the caseNumber to set */ public void setCaseNumber(String caseNumber) throws CaseMetadataException { + String oldCaseNumber = this.caseNumber; this.caseNumber = caseNumber; - this.write(); + try { + this.write(); + } catch (CaseMetadataException ex) { + this.caseNumber = oldCaseNumber; + throw ex; + } } /** * @param examiner the examiner to set */ public void setCaseExaminer(String examiner) throws CaseMetadataException { + String oldExaminer = this.examiner; this.examiner = examiner; - this.write(); + try { + this.write(); + } catch (CaseMetadataException ex) { + this.examiner = oldExaminer; + throw ex; + } } /** * @param caseDirectory the caseDirectory to set */ public void setCaseDirectory(String caseDirectory) throws CaseMetadataException { + String oldCaseDirectory = this.caseDirectory; this.caseDirectory = caseDirectory; - this.write(); + try { + this.write(); + } catch (CaseMetadataException ex) { + this.caseDirectory = oldCaseDirectory; + throw ex; + } } /** * @param caseDatabaseName the caseDatabaseName to set */ public void setCaseDatabaseName(String caseDatabaseName) throws CaseMetadataException { + String oldDbName = this.caseDatabaseName; this.caseDatabaseName = caseDatabaseName; + try { this.write(); + } catch (CaseMetadataException ex) { + this.caseDatabaseName = oldDbName; + throw ex; + } } /** @@ -301,8 +343,14 @@ public final class CaseMetadata { * @param caseTextIndexName the caseTextIndexName to set */ public void setCaseTextIndexName(String caseTextIndexName) throws CaseMetadataException { + String oldIndexName = this.caseTextIndexName; this.caseTextIndexName = caseTextIndexName; + try { this.write(); + } catch (CaseMetadataException ex) { + this.caseTextIndexName = oldIndexName; + throw ex; + } } /** From 57d652a2b2472134af5c3f2d9dfec352269d5e23 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Thu, 25 Feb 2016 13:00:58 -0500 Subject: [PATCH 10/50] Formatting fixes --- .../sleuthkit/autopsy/casemodule/Case.java | 96 ++++++++++--------- .../autopsy/casemodule/CaseMetadata.java | 4 +- 2 files changed, 53 insertions(+), 47 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 72ae42f8d4..2d0493e155 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -403,21 +403,23 @@ 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 caseName The name of 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 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 - * Throwable (null otherwise). + * @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 + * Throwable (null otherwise). * @throws CaseMetadataException if there is a problem creating the case - * metadata. + * metadata. */ public static void create(String caseDir, String caseName, String caseNumber, String examiner) throws CaseActionException, CaseMetadataException { create(caseDir, caseName, caseNumber, examiner, CaseType.SINGLE_USER_CASE); @@ -426,22 +428,23 @@ public class Case implements SleuthkitCase.ErrorObserver { /** * 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 caseName The name of 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 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 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). + * @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). * - * @throws CaseActionException if there is a problem creating the case. + * @throws CaseActionException if there is a problem creating the case. * @throws CaseMetadataException if there is a problem creating the case - * metadata. + * metadata. */ 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 @@ -574,9 +577,11 @@ 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 - * 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). */ public static void open(String caseMetadataFilePath) throws CaseActionException { logger.log(Level.INFO, "Opening case with metadata file path {0}", caseMetadataFilePath); //NON-NLS @@ -702,7 +707,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * Sends out event and reopens windows if needed. * * @param imgPaths the paths of the image that being added - * @param imgId the ID of the image that being added + * @param imgId the ID of the image that being added * @param timeZone the timeZone of the image where it's added * * @deprecated As of release 4.0, replaced by {@link #notifyAddingDataSource(java.util.UUID) and @@ -742,8 +747,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)); @@ -768,9 +773,10 @@ public class Case implements SleuthkitCase.ErrorObserver { * This should not be called from the event dispatch thread (EDT) * * @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. + * @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. */ public void notifyDataSourceAdded(Content newDataSource, UUID dataSourceId) { eventPublisher.publish(new DataSourceAddedEvent(newDataSource, dataSourceId)); @@ -882,9 +888,9 @@ public class Case implements SleuthkitCase.ErrorObserver { * This should not be called from the EDT. * * @param oldCaseName the old case name that wants to be updated - * @param oldPath the old path that wants to be updated + * @param oldPath the old path that wants to be updated * @param newCaseName the new case name - * @param newPath the new path + * @param newPath the new path */ void updateCaseName(String oldCaseName, String oldPath, String newCaseName, String newPath) throws CaseActionException { try { @@ -1305,7 +1311,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * Adds a subscriber to events from this Autopsy node and other Autopsy * nodes. * - * @param eventName The event the subscriber is interested in. + * @param eventName The event the subscriber is interested in. * @param subscriber The subscriber to add. */ public static void addEventSubscriber(String eventName, PropertyChangeListener subscriber) { @@ -1316,7 +1322,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * Adds a subscriber to events from this Autopsy node and other Autopsy * nodes. * - * @param eventName The event the subscriber is no longer interested in. + * @param eventName The event the subscriber is no longer interested in. * @param subscriber The subscriber to add. */ public static void removeEventSubscriber(String eventName, PropertyChangeListener subscriber) { @@ -1426,7 +1432,7 @@ public class Case implements SleuthkitCase.ErrorObserver { /** * to create the case directory * - * @param caseDir Path to the case directory (typically base + case name) + * @param caseDir Path to the case directory (typically base + case name) * @param caseName the case name (used only for error messages) * * @throws CaseActionException throw if could not create the case dir @@ -1440,7 +1446,7 @@ public class Case implements SleuthkitCase.ErrorObserver { /** * Create the case directory and its needed subfolders. * - * @param caseDir Path to the case directory (typically base + case name) + * @param caseDir Path to the case directory (typically base + case name) * @param caseType The type of case, single-user or multi-user * * @throws CaseActionException throw if could not create the case dir @@ -1659,10 +1665,10 @@ public class Case implements SleuthkitCase.ErrorObserver { /** * Adds a report to the case. * - * @param localPath The path of the report file, must be in the case - * directory or one of its subdirectories. + * @param localPath The path of the report file, must be in the case + * directory or one of its subdirectories. * @param srcModuleName The name of the module that created the report. - * @param reportName The report name, may be empty. + * @param reportName The report name, may be empty. * * @throws TskCoreException */ @@ -1686,9 +1692,9 @@ public class Case implements SleuthkitCase.ErrorObserver { * Deletes reports from the case - deletes it from the disk as well as the * database. * - * @param reports Collection of Report to be deleted from the case. + * @param reports Collection of Report to be deleted from the case. * @param deleteFromDisk Set true to perform reports file deletion from - * disk. + * disk. * * @throws TskCoreException */ diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java index 4ea90277fa..ff7984ec0f 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java @@ -325,7 +325,7 @@ public final class CaseMetadata { String oldDbName = this.caseDatabaseName; this.caseDatabaseName = caseDatabaseName; try { - this.write(); + this.write(); } catch (CaseMetadataException ex) { this.caseDatabaseName = oldDbName; throw ex; @@ -346,7 +346,7 @@ public final class CaseMetadata { String oldIndexName = this.caseTextIndexName; this.caseTextIndexName = caseTextIndexName; try { - this.write(); + this.write(); } catch (CaseMetadataException ex) { this.caseTextIndexName = oldIndexName; throw ex; From b87fce78523e1c98d9913ae8663ad352bb2d037c Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Fri, 26 Feb 2016 08:41:08 -0500 Subject: [PATCH 11/50] Updated case metadata code --- .../sleuthkit/autopsy/casemodule/Case.java | 49 +-- .../autopsy/casemodule/CaseMetadata.java | 307 ++++++++---------- .../casemodule/SingleUserCaseConverter.java | 1 + 3 files changed, 143 insertions(+), 214 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 2d0493e155..f6673b0611 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -421,7 +421,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @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, CaseMetadataException { + public static void create(String caseDir, String caseName, String caseNumber, String examiner) throws CaseActionException { create(caseDir, caseName, caseNumber, examiner, CaseType.SINGLE_USER_CASE); } @@ -446,7 +446,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @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, CaseMetadataException { + public static void create(String caseDir, String caseName, String caseNumber, String examiner, CaseType caseType) throws CaseActionException { logger.log(Level.INFO, "Creating case with case directory {0}, caseName {1}", new Object[]{caseDir, caseName}); //NON-NLS /* @@ -476,7 +476,12 @@ public class Case implements SleuthkitCase.ErrorObserver { * Create the case metadata (.aut) file. */ String configFilePath = caseDir + File.separator + caseName + CASE_DOT_EXTENSION; - CaseMetadata metadata = CaseMetadata.create(caseType, caseName, caseNumber, examiner, caseDir, santizedCaseName, indexName); + CaseMetadata metadata; + try { + metadata = CaseMetadata.create(caseType, caseName, caseNumber, examiner, caseDir, dbName, indexName); + } catch (CaseMetadataException ex) { + throw new CaseActionException("Could not create case", ex); + } /* * Create the case database. @@ -910,42 +915,6 @@ public class Case implements SleuthkitCase.ErrorObserver { } } - /** - * Updates the case examiner - * - * This should not be called from the EDT. - * - * @param oldExaminer the old examiner - * @param newExaminer the new examiner - */ - void updateExaminer(String oldExaminer, String newExaminer) throws CaseActionException { - try { - caseMetadata.setCaseExaminer(newExaminer); // set the examiner - examiner = newExaminer; - eventPublisher.publish(new AutopsyEvent(Events.EXAMINER.toString(), oldExaminer, newExaminer)); - } catch (Exception e) { - throw new CaseActionException(NbBundle.getMessage(this.getClass(), "Case.updateExaminer.exception.msg"), e); - } - } - - /** - * Updates the case number - * - * This should not be called from the EDT. - * - * @param oldCaseNumber the old case number - * @param newCaseNumber the new case number - */ - void updateCaseNumber(String oldCaseNumber, String newCaseNumber) throws CaseActionException { - try { - caseMetadata.setCaseNumber(newCaseNumber); // set the case number - number = newCaseNumber; - eventPublisher.publish(new AutopsyEvent(Events.NUMBER.toString(), oldCaseNumber, newCaseNumber)); - } catch (Exception e) { - throw new CaseActionException(NbBundle.getMessage(this.getClass(), "Case.updateCaseNum.exception.msg"), e); - } - } - /** * Checks whether there is a current case open. * @@ -1245,7 +1214,7 @@ public class Case implements SleuthkitCase.ErrorObserver { if (caseMetadata == null) { return ""; } else { - return caseMetadata.getCaseTextIndexName(); + return caseMetadata.getTextIndexName(); } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java index ff7984ec0f..a33ac08882 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java @@ -46,10 +46,10 @@ import javax.xml.transform.stream.StreamResult; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.core.RuntimeProperties; -import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.XMLUtil; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.w3c.dom.NodeList; import org.xml.sax.SAXException; /** @@ -67,7 +67,15 @@ public final class CaseMetadata { "CaseMetadata.open.msgDlg.notAutCase.msg=Error\\: This is not an Autopsy config file (\"{0}\").\\n\\n\\\n" + "Detail\\: \\n\\\n" + "Cannot open a non-Autopsy config file (at {1}).", - "CaseMetadata.open.msgDlg.notAutCase.title=Error" + "CaseMetadata.open.msgDlg.notAutCase.title=Error", + "CaseMetadata.open.msgDlg.noCaseHeaderTag.msg=Root element not recognized as autopsy case tag", + "CaseMetadata.open.caseRootError=Couldn't get case root", + "CaseMetadata.open.caseTypeError=Couldn't get case type", + "CaseMetadata.open.caseNameError=Couldn't get case name", + "CaseMetadata.open.caseDatabaseNameError=Couldn't get database name", + "CaseMetadata.open.caseIndexError=Couldn't get text index", + "CaseMetadata.open.createdDateError=Couldn't get created date", + "CaseMetadata.open.createdVersionError=Couldn't get created version" }) /** @@ -126,24 +134,22 @@ public final class CaseMetadata { private String caseDatabaseName; private String caseTextIndexName; private String createdDate; - private String schemaVersion; + private static String schemaVersion = "2.0"; private String fileName; - private JPanel caller; - private final String className = this.getClass().toString(); - private static final Logger logger = Logger.getLogger(CaseMetadata.class.getName()); + private String createdVersion; - private CaseMetadata(Case.CaseType caseType, String caseName, String caseDirectory, String caseDatabaseName, String caseTextIndexName) throws CaseMetadataException { + private CaseMetadata(Case.CaseType caseType, String caseName, String caseNumber, String examiner, String caseDirectory, String caseDatabaseName, String caseTextIndexName) throws CaseMetadataException { this.caseType = caseType; this.caseName = caseName; - this.caseNumber = ""; - this.examiner = ""; + this.caseNumber = caseNumber; + this.examiner = examiner; this.createdDate = this.dateFormat.format(new Date()); this.caseDirectory = caseDirectory; this.caseDatabaseName = caseDatabaseName; this.caseTextIndexName = caseTextIndexName; - this.schemaVersion = "1.0"; this.fileName = caseName; + this.createdVersion = System.getProperty("netbeans.buildnumber"); this.write(); } @@ -152,22 +158,59 @@ public final class CaseMetadata { * Constructs an object that provides access to case metadata. * * @param metadataFilePath Path to the metadata (.aut) file for a case. + * + * @deprecated Use open instead */ + @Deprecated public CaseMetadata(Path metadataFilePath) throws CaseMetadataException { this(metadataFilePath.toString()); } + /** + * Used to open a case at the given file path + * + * @param metadataFilePath the string file path for the case + * + * @throws + * org.sleuthkit.autopsy.casemodule.CaseMetadata.CaseMetadataException + */ private CaseMetadata(String metadataFilePath) throws CaseMetadataException { this.open(metadataFilePath); } + /** + * Opens a case and gives the metadata object that corresponds + * + * @param metadataFilePath The file path of the metadata file + * + * @return The case metadata for the opened case + * + * @throws + * org.sleuthkit.autopsy.casemodule.CaseMetadata.CaseMetadataException + */ public static CaseMetadata open(Path metadataFilePath) throws CaseMetadataException { CaseMetadata metadata = new CaseMetadata(metadataFilePath.toString()); return metadata; } + /** + * Creates a metadata object for a new case + * + * @param caseType The type of case + * @param caseName The name of the case + * @param caseNumber The case number + * @param examiner The name of the case examiner + * @param caseDirectory The directory of the case + * @param caseDatabaseName The name of the case db + * @param caseTextIndexName The case index name + * + * @return The metadata for the new case + * + * @throws + * org.sleuthkit.autopsy.casemodule.CaseMetadata.CaseMetadataException + */ public static CaseMetadata create(Case.CaseType caseType, String caseName, String caseNumber, String examiner, String caseDirectory, String caseDatabaseName, String caseTextIndexName) throws CaseMetadataException { - CaseMetadata metadata = new CaseMetadata(caseType, caseName, caseDirectory, caseDatabaseName, caseTextIndexName); + CaseMetadata metadata = new CaseMetadata(caseType, caseName, caseNumber, examiner, caseDirectory, caseDatabaseName, caseTextIndexName); return metadata; } @@ -234,6 +277,29 @@ public final class CaseMetadata { return this.createdDate; } + /** + * @return the createdVersion + */ + public String getCreatedVersion() { + return createdVersion; + } + + /** + * Sets the created version of this case + * + * @param createdVersion the createdVersion to set + */ + public void setCreatedVersion(String createdVersion) throws CaseMetadataException { + String oldCreatedVersion = this.createdVersion; + this.createdVersion = createdVersion; + try { + this.write(); + } catch (CaseMetadataException ex) { + this.createdDate = oldCreatedVersion; + throw ex; + } + } + /** * @param createdDate the createdDate to set */ @@ -248,24 +314,10 @@ public final class CaseMetadata { } } - /** - * @param caseType the caseType to set - */ - public void setCaseType(Case.CaseType caseType) throws CaseMetadataException { - Case.CaseType oldCaseType = this.caseType; - this.caseType = caseType; - try { - this.write(); - } catch (CaseMetadataException ex) { - this.caseType = oldCaseType; - throw ex; - } - } - /** * @param caseName the caseName to set */ - public void setCaseName(String caseName) throws CaseMetadataException { + void setCaseName(String caseName) throws CaseMetadataException { String oldCaseName = this.caseName; this.caseName = caseName; try { @@ -276,90 +328,13 @@ public final class CaseMetadata { } } - /** - * @param caseNumber the caseNumber to set - */ - public void setCaseNumber(String caseNumber) throws CaseMetadataException { - String oldCaseNumber = this.caseNumber; - this.caseNumber = caseNumber; - try { - this.write(); - } catch (CaseMetadataException ex) { - this.caseNumber = oldCaseNumber; - throw ex; - } - } - - /** - * @param examiner the examiner to set - */ - public void setCaseExaminer(String examiner) throws CaseMetadataException { - String oldExaminer = this.examiner; - this.examiner = examiner; - try { - this.write(); - } catch (CaseMetadataException ex) { - this.examiner = oldExaminer; - throw ex; - } - } - - /** - * @param caseDirectory the caseDirectory to set - */ - public void setCaseDirectory(String caseDirectory) throws CaseMetadataException { - String oldCaseDirectory = this.caseDirectory; - this.caseDirectory = caseDirectory; - try { - this.write(); - } catch (CaseMetadataException ex) { - this.caseDirectory = oldCaseDirectory; - throw ex; - } - } - - /** - * @param caseDatabaseName the caseDatabaseName to set - */ - public void setCaseDatabaseName(String caseDatabaseName) throws CaseMetadataException { - String oldDbName = this.caseDatabaseName; - this.caseDatabaseName = caseDatabaseName; - try { - this.write(); - } catch (CaseMetadataException ex) { - this.caseDatabaseName = oldDbName; - throw ex; - } - } - /** * @return the caseTextIndexName */ - public String getCaseTextIndexName() { + public String getTextIndexName() { return caseTextIndexName; } - /** - * @param caseTextIndexName the caseTextIndexName to set - */ - public void setCaseTextIndexName(String caseTextIndexName) throws CaseMetadataException { - String oldIndexName = this.caseTextIndexName; - this.caseTextIndexName = caseTextIndexName; - try { - this.write(); - } catch (CaseMetadataException ex) { - this.caseTextIndexName = oldIndexName; - throw ex; - } - } - - /** - * @return the schemaVersion - */ - public String getSchemaVersion() { - return schemaVersion; - } - private void write() throws CaseMetadataException { Document doc; try { @@ -380,7 +355,7 @@ public final class CaseMetadata { rootElement.appendChild(mDateElement); Element autVerElement = doc.createElement(AUTOPSY_CRVERSION_NAME); // ... - autVerElement.appendChild(doc.createTextNode(System.getProperty("netbeans.buildnumber"))); + autVerElement.appendChild(doc.createTextNode(this.getCreatedVersion())); rootElement.appendChild(autVerElement); Element autSavedVerElement = doc.createElement(AUTOPSY_MVERSION_NAME); // ... @@ -388,7 +363,7 @@ public final class CaseMetadata { rootElement.appendChild(autSavedVerElement); Element schVerElement = doc.createElement(SCHEMA_VERSION_NAME); // ... - schVerElement.appendChild(doc.createTextNode(getSchemaVersion())); + schVerElement.appendChild(doc.createTextNode(schemaVersion)); rootElement.appendChild(schVerElement); Element caseElement = doc.createElement(CASE_ROOT_NAME); // ... @@ -406,26 +381,6 @@ public final class CaseMetadata { examinerElement.appendChild(doc.createTextNode(getExaminer())); caseElement.appendChild(examinerElement); - Element exportElement = doc.createElement(EXPORT_FOLDER_NAME); // ... - exportElement.appendChild(doc.createTextNode(EXPORT_FOLDER_RELPATH)); - exportElement.setAttribute(RELATIVE_NAME, "true"); //NON-NLS - caseElement.appendChild(exportElement); - - Element logElement = doc.createElement(LOG_FOLDER_NAME); // ... - logElement.appendChild(doc.createTextNode(LOG_FOLDER_RELPATH)); - logElement.setAttribute(RELATIVE_NAME, "true"); //NON-NLS - caseElement.appendChild(logElement); - - Element tempElement = doc.createElement(TEMP_FOLDER_NAME); // ... - tempElement.appendChild(doc.createTextNode(TEMP_FOLDER_RELPATH)); - tempElement.setAttribute(RELATIVE_NAME, "true"); //NON-NLS - caseElement.appendChild(tempElement); - - Element cacheElement = doc.createElement(CACHE_FOLDER_NAME); // ... - cacheElement.appendChild(doc.createTextNode(CACHE_FOLDER_RELPATH)); - cacheElement.setAttribute(RELATIVE_NAME, "true"); //NON-NLS - caseElement.appendChild(cacheElement); - Element typeElement = doc.createElement(CASE_TYPE); // ... typeElement.appendChild(doc.createTextNode(getCaseType().toString())); caseElement.appendChild(typeElement); @@ -435,7 +390,7 @@ public final class CaseMetadata { caseElement.appendChild(dbNameElement); Element indexNameElement = doc.createElement(CASE_TEXT_INDEX_NAME); // ... - indexNameElement.appendChild(doc.createTextNode(this.getCaseTextIndexName())); + indexNameElement.appendChild(doc.createTextNode(this.getTextIndexName())); caseElement.appendChild(indexNameElement); doc.normalize(); this.writeFile(doc); @@ -461,7 +416,6 @@ public final class CaseMetadata { try { xformer = tfactory.newTransformer(); } catch (TransformerConfigurationException ex) { - logger.log(Level.SEVERE, "Could not setup tranformer and write case file"); //NON-NLS throw new CaseMetadataException( Bundle.CaseMetadata_writeFile_exception_errWriteToFile_msg(), ex); } @@ -473,7 +427,6 @@ public final class CaseMetadata { 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( Bundle.CaseMetadata_writeFile_exception_errWriteToFile_msg(), ex); } @@ -489,7 +442,6 @@ public final class CaseMetadata { bw.flush(); bw.close(); } catch (IOException ex) { - logger.log(Level.SEVERE, "Error writing to case file"); //NON-NLS throw new CaseMetadataException( Bundle.CaseMetadata_writeFile_exception_errWriteToFile_msg(), ex); } @@ -525,12 +477,7 @@ public final class CaseMetadata { if (!rootName.equals(TOP_ROOT_NAME)) { // throw an error ... if (RuntimeProperties.coreComponentsAreActive()) { - - JOptionPane.showMessageDialog(caller, - Bundle.CaseMetadata_open_msgDlg_notAutCase_msg( - file.getName(), className), - Bundle.CaseMetadata_open_msgDlg_notAutCase_title(), - JOptionPane.ERROR_MESSAGE); + throw new CaseMetadataException(Bundle.CaseMetadata_open_msgDlg_noCaseHeaderTag_msg()); } } else { /* @@ -545,46 +492,58 @@ public final class CaseMetadata { // if not the same version, update the saved version in the xml to the current version rootElement.getElementsByTagName(AUTOPSY_MVERSION_NAME).item(0).setTextContent(System.getProperty("netbeans.buildnumber")); } - - /* - * Schema Version - */ - String schemaVer = ((Element) rootElement.getElementsByTagName(SCHEMA_VERSION_NAME).item(0)).getTextContent(); - // check if it has the same schema version as the current one - if (!schemaVer.equals(schemaVersion)) { - // do something here if not the same version - // ... @Override + String fullFileName = file.getName(); + String fileName = fullFileName.substring(0, fullFileName.lastIndexOf(".")); // remove the extension + this.fileName = fileName; + NodeList rootNameList = doc.getElementsByTagName(CASE_ROOT_NAME); + if (rootNameList.getLength() == 0) { + throw new CaseMetadataException(Bundle.CaseMetadata_open_caseRootError()); } - - try { - String fullFileName = file.getName(); - String fileName = fullFileName.substring(0, fullFileName.lastIndexOf(".")); // remove the extension - this.fileName = fileName; - Element caseElement = (Element) doc.getElementsByTagName(CASE_ROOT_NAME).item(0); - - String caseTypeString = ((Element) caseElement.getElementsByTagName(CASE_TYPE).item(0)).getTextContent(); - this.caseType = caseTypeString.equals("") ? Case.CaseType.SINGLE_USER_CASE : Case.CaseType.fromString(caseTypeString); - this.caseName = ((Element) caseElement.getElementsByTagName(NAME).item(0)).getTextContent(); - Element numberElement = caseElement.getElementsByTagName(NUMBER).getLength() > 0 ? (Element) caseElement.getElementsByTagName(NUMBER).item(0) : null; - this.caseNumber = numberElement != null ? numberElement.getTextContent() : ""; - Element examinerElement = caseElement.getElementsByTagName(EXAMINER).getLength() > 0 ? (Element) caseElement.getElementsByTagName(EXAMINER).item(0) : null; - this.caseNumber = numberElement != null ? examinerElement.getTextContent() : ""; - this.caseDirectory = conFilePath.substring(0, conFilePath.lastIndexOf("\\")); - if (this.caseDirectory.isEmpty()) { - throw new CaseMetadataException(Bundle.CaseMetadata_open_exception_errReadXMLFile_msg(conFilePath)); - } - Element databaseNameElement = caseElement.getElementsByTagName(DATABASE_NAME).getLength() > 0 ? (Element) caseElement.getElementsByTagName(DATABASE_NAME).item(0) : null; - this.caseDatabaseName = databaseNameElement != null ? databaseNameElement.getTextContent() : ""; - Element caseTextIndexNameElement = caseElement.getElementsByTagName(CASE_TEXT_INDEX_NAME).getLength() > 0 ? (Element) caseElement.getElementsByTagName(CASE_TEXT_INDEX_NAME).item(0) : null; - this.caseTextIndexName = caseTextIndexNameElement != null ? caseTextIndexNameElement.getTextContent() : ""; - if (Case.CaseType.MULTI_USER_CASE == caseType && caseDatabaseName.isEmpty()) { - throw new CaseMetadataException(Bundle.CaseMetadata_open_exception_errReadXMLFile_msg(conFilePath)); - } - this.setCreatedDate(((Element) rootElement.getElementsByTagName(CREATED_DATE_NAME).item(0)).getTextContent()); - this.schemaVersion = ((Element) rootElement.getElementsByTagName(SCHEMA_VERSION_NAME).item(0)).getTextContent(); - } catch (NullPointerException ex) { - throw new CaseMetadataException(Bundle.CaseMetadata_open_exception_errReadXMLFile_msg(conFilePath), ex); + Element caseElement = (Element) rootNameList.item(0); + NodeList caseTypeList = caseElement.getElementsByTagName(CASE_TYPE); + if (caseTypeList.getLength() == 0) { + throw new CaseMetadataException(Bundle.CaseMetadata_open_caseTypeError()); } + String caseTypeString = ((Element) caseTypeList.item(0)).getTextContent(); + this.caseType = caseTypeString.equals("") ? Case.CaseType.SINGLE_USER_CASE : Case.CaseType.fromString(caseTypeString); + NodeList caseNameList = caseElement.getElementsByTagName(NAME); + if (caseNameList.getLength() == 0) { + throw new CaseMetadataException(Bundle.CaseMetadata_open_caseTypeError()); + } + this.caseName = ((Element) caseNameList.item(0)).getTextContent(); + Element numberElement = caseElement.getElementsByTagName(NUMBER).getLength() > 0 ? (Element) caseElement.getElementsByTagName(NUMBER).item(0) : null; + this.caseNumber = numberElement != null ? numberElement.getTextContent() : ""; + Element examinerElement = caseElement.getElementsByTagName(EXAMINER).getLength() > 0 ? (Element) caseElement.getElementsByTagName(EXAMINER).item(0) : null; + this.examiner = examinerElement != null ? examinerElement.getTextContent() : ""; + this.caseDirectory = conFilePath.substring(0, conFilePath.lastIndexOf("\\")); + if (this.caseDirectory.isEmpty()) { + throw new CaseMetadataException(Bundle.CaseMetadata_open_exception_errReadXMLFile_msg(conFilePath)); + } + NodeList databaseNameList = caseElement.getElementsByTagName(DATABASE_NAME); + if (databaseNameList.getLength() == 0) { + throw new CaseMetadataException(Bundle.CaseMetadata_open_caseDatabaseNameError()); + } + Element databaseNameElement = (Element) databaseNameList.item(0); + this.caseDatabaseName = databaseNameElement.getTextContent(); + NodeList textIndexList = caseElement.getElementsByTagName(CASE_TEXT_INDEX_NAME); + if(textIndexList.getLength() == 0) { + throw new CaseMetadataException(Bundle.CaseMetadata_open_caseIndexError()); + } + Element caseTextIndexNameElement = (Element)textIndexList.item(0); + this.caseTextIndexName = caseTextIndexNameElement.getTextContent(); + if (Case.CaseType.MULTI_USER_CASE == caseType && caseDatabaseName.isEmpty()) { + throw new CaseMetadataException(Bundle.CaseMetadata_open_exception_errReadXMLFile_msg(conFilePath)); + } + NodeList createdDateList = rootElement.getElementsByTagName(CREATED_DATE_NAME); + if(createdDateList.getLength() == 0) { + throw new CaseMetadataException(Bundle.CaseMetadata_open_createdDateError()); + } + this.setCreatedDate(((Element)createdDateList.item(0)).getTextContent()); + NodeList createdVersionList = rootElement.getElementsByTagName(AUTOPSY_CRVERSION_NAME); + if(createdVersionList.getLength() == 0) { + throw new CaseMetadataException(Bundle.CaseMetadata_open_createdVersionError()); + } + this.setCreatedVersion((((Element)createdVersionList.item(0))).getTextContent()); } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java b/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java index d156fd065b..f40fa7e09a 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java @@ -198,6 +198,7 @@ public class SingleUserCaseConverter { dbName, solrName); // Set created date. This calls writefile, no need to call it again newCaseMetadata.setCreatedDate(oldCaseMetadata.getCreatedDate()); + newCaseMetadata.setCreatedVersion(oldCaseMetadata.getCreatedVersion()); // At this point the import has been finished successfully so we can delete the original case // (if requested). This *should* be fairly safe - at this point we know there was an autopsy file From 1ee55395dc25f4ccd430a35b165a652fd9eaff90 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Fri, 26 Feb 2016 09:09:11 -0500 Subject: [PATCH 12/50] Got rid of usage of deprecated constructor --- .../org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java index c9c4d87864..c1a08d9c82 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java @@ -89,7 +89,7 @@ class CasePropertiesForm extends javax.swing.JPanel { caseDirTextArea.setText(caseDir); current = currentCase; - CaseMetadata caseMetadata = new CaseMetadata(Paths.get(currentCase.getConfigFilePath())); + CaseMetadata caseMetadata = CaseMetadata.open(Paths.get(currentCase.getConfigFilePath())); tbDbName.setText(caseMetadata.getCaseDatabaseName()); Case.CaseType caseType = caseMetadata.getCaseType(); tbDbType.setText(caseType.toString()); From 79f78b0d9ae81164906d4e2fe9e952126d811c13 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Fri, 18 Mar 2016 09:04:00 -0400 Subject: [PATCH 13/50] Fixing case metadata bugs --- .../sleuthkit/autopsy/casemodule/Case.java | 6 +- .../autopsy/casemodule/CaseMetadata.java | 56 ++++++++----------- 2 files changed, 25 insertions(+), 37 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index f6673b0611..fa6282f7a7 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -48,6 +48,7 @@ import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import org.apache.commons.io.FileUtils; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.openide.util.actions.CallableSystemAction; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.CaseMetadata.CaseMetadataException; @@ -418,8 +419,6 @@ public class Case implements SleuthkitCase.ErrorObserver { * 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 { create(caseDir, caseName, caseNumber, examiner, CaseType.SINGLE_USER_CASE); @@ -446,6 +445,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @throws CaseMetadataException if there is a problem creating the case * metadata. */ + @Messages({"Case.creationException=Could not create case: failed to make metadata file."}) public static void create(String caseDir, String caseName, String caseNumber, String examiner, CaseType caseType) throws CaseActionException { logger.log(Level.INFO, "Creating case with case directory {0}, caseName {1}", new Object[]{caseDir, caseName}); //NON-NLS @@ -480,7 +480,7 @@ public class Case implements SleuthkitCase.ErrorObserver { try { metadata = CaseMetadata.create(caseType, caseName, caseNumber, examiner, caseDir, dbName, indexName); } catch (CaseMetadataException ex) { - throw new CaseActionException("Could not create case", ex); + throw new CaseActionException(Bundle.Case_creationException(), ex); } /* diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java index a33ac08882..b5d8a0dd76 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java @@ -25,6 +25,7 @@ import java.io.IOException; import java.io.OutputStreamWriter; import java.io.StringWriter; import java.nio.file.Path; +import java.nio.file.Paths; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; @@ -95,37 +96,24 @@ 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 + private final static String XSDFILE = "CaseSchema.xsd"; //NON-NLS + private final static String TOP_ROOT_NAME = "AutopsyCase"; //NON-NLS + private 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 + private final static String NAME = "Name"; //NON-NLS + private final static String NUMBER = "Number"; //NON-NLS + private final static String EXAMINER = "Examiner"; //NON-NLS + private final static String CREATED_DATE_NAME = "CreatedDate"; //NON-NLS + private final static String MODIFIED_DATE_NAME = "ModifiedDate"; //NON-NLS + private final static String SCHEMA_VERSION_NAME = "SchemaVersion"; //NON-NLS + private final static String AUTOPSY_CRVERSION_NAME = "AutopsyCreatedVersion"; //NON-NLS + private final static String AUTOPSY_MVERSION_NAME = "AutopsySavedVersion"; //NON-NLS + private 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 final static String CASE_TYPE = "CaseType"; //NON-NLS + private final static String DATABASE_NAME = "DatabaseName"; //NON-NLS - private final DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss (z)"); + private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss (z)"); private Case.CaseType caseType; private String caseName; private String caseNumber; @@ -134,7 +122,7 @@ public final class CaseMetadata { private String caseDatabaseName; private String caseTextIndexName; private String createdDate; - private static String schemaVersion = "2.0"; + private static final String SCHEMA_VERSION = "2.0"; private String fileName; private String createdVersion; @@ -144,7 +132,7 @@ public final class CaseMetadata { this.caseName = caseName; this.caseNumber = caseNumber; this.examiner = examiner; - this.createdDate = this.dateFormat.format(new Date()); + this.createdDate = this.DATE_FORMAT.format(new Date()); this.caseDirectory = caseDirectory; this.caseDatabaseName = caseDatabaseName; this.caseTextIndexName = caseTextIndexName; @@ -289,7 +277,7 @@ public final class CaseMetadata { * * @param createdVersion the createdVersion to set */ - public void setCreatedVersion(String createdVersion) throws CaseMetadataException { + void setCreatedVersion(String createdVersion) throws CaseMetadataException { String oldCreatedVersion = this.createdVersion; this.createdVersion = createdVersion; try { @@ -351,7 +339,7 @@ public final class CaseMetadata { rootElement.appendChild(crDateElement); Element mDateElement = doc.createElement(MODIFIED_DATE_NAME); // ... - mDateElement.appendChild(doc.createTextNode(dateFormat.format(new Date()))); + mDateElement.appendChild(doc.createTextNode(DATE_FORMAT.format(new Date()))); rootElement.appendChild(mDateElement); Element autVerElement = doc.createElement(AUTOPSY_CRVERSION_NAME); // ... @@ -363,7 +351,7 @@ public final class CaseMetadata { rootElement.appendChild(autSavedVerElement); Element schVerElement = doc.createElement(SCHEMA_VERSION_NAME); // ... - schVerElement.appendChild(doc.createTextNode(schemaVersion)); + schVerElement.appendChild(doc.createTextNode(SCHEMA_VERSION)); rootElement.appendChild(schVerElement); Element caseElement = doc.createElement(CASE_ROOT_NAME); // ... @@ -433,7 +421,7 @@ public final class CaseMetadata { // preparing the output file String xmlString = sw.toString(); - File file = new File(this.getCaseDirectory() + File.separator + this.fileName + ".aut"); + File file = new File(Paths.get(this.getCaseDirectory(), this.fileName + ".aut").toString()); // write the file try { From 3359f94e93c283f610b28a63a05a8c86e3a39f35 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Fri, 18 Mar 2016 10:10:51 -0400 Subject: [PATCH 14/50] Fixed bugs in CaseMetadata --- .../sleuthkit/autopsy/casemodule/Case.java | 5 - .../autopsy/casemodule/CaseMetadata.java | 113 +++++++++--------- 2 files changed, 54 insertions(+), 64 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index e74b651f63..e44ea63ab9 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -678,11 +678,6 @@ public class Case implements SleuthkitCase.ErrorObserver { } } } - - /* - * TODO (AUT-1885): Replace use of obsolete and unsafe - * XMLCaseManagement class with use of CaseMetadata class. - */ Case openedCase = new Case(caseName, caseNumber, examiner, caseMetadataFilePath, metadata, db, caseType); changeCase(openedCase); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java index b5d8a0dd76..e6fa232a28 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java @@ -29,9 +29,6 @@ import java.nio.file.Paths; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; -import java.util.logging.Level; -import javax.swing.JOptionPane; -import javax.swing.JPanel; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; @@ -58,27 +55,6 @@ import org.xml.sax.SAXException; */ public final class CaseMetadata { - @Messages({ - "CaseMetadata.writeFile.exception.noCase.msg=No set case to write management file for.", - "CaseMetadata.writeFile.exception.errWriteToFile.msg=Error writing to case file", - "# {0} - case file path", - "CaseMetadata.open.exception.errReadXMLFile.msg=Error reading case XML file\\: {0}", - "# {0} - file name", - "# {1} - class name", - "CaseMetadata.open.msgDlg.notAutCase.msg=Error\\: This is not an Autopsy config file (\"{0}\").\\n\\n\\\n" - + "Detail\\: \\n\\\n" - + "Cannot open a non-Autopsy config file (at {1}).", - "CaseMetadata.open.msgDlg.notAutCase.title=Error", - "CaseMetadata.open.msgDlg.noCaseHeaderTag.msg=Root element not recognized as autopsy case tag", - "CaseMetadata.open.caseRootError=Couldn't get case root", - "CaseMetadata.open.caseTypeError=Couldn't get case type", - "CaseMetadata.open.caseNameError=Couldn't get case name", - "CaseMetadata.open.caseDatabaseNameError=Couldn't get database name", - "CaseMetadata.open.caseIndexError=Couldn't get text index", - "CaseMetadata.open.createdDateError=Couldn't get created date", - "CaseMetadata.open.createdVersionError=Couldn't get created version" - }) - /** * Exception thrown by the CaseMetadata class when there is a problem * accessing the metadata for a case. @@ -155,7 +131,7 @@ public final class CaseMetadata { } /** - * Used to open a case at the given file path + * Used to read a case at the given file path * * @param metadataFilePath the string file path for the case * @@ -163,7 +139,7 @@ public final class CaseMetadata { * org.sleuthkit.autopsy.casemodule.CaseMetadata.CaseMetadataException */ private CaseMetadata(String metadataFilePath) throws CaseMetadataException { - this.open(metadataFilePath); + this.read(metadataFilePath); } /** @@ -387,7 +363,8 @@ public final class CaseMetadata { private void writeFile(Document doc) throws CaseMetadataException { if (doc == null || getCaseName().equals("")) { throw new CaseMetadataException( - Bundle.CaseMetadata_writeFile_exception_noCase_msg()); + "No set case to write management file for." + ); } // Prepare the DOM document for writing @@ -405,7 +382,7 @@ public final class CaseMetadata { xformer = tfactory.newTransformer(); } catch (TransformerConfigurationException ex) { throw new CaseMetadataException( - Bundle.CaseMetadata_writeFile_exception_errWriteToFile_msg(), ex); + "Error writing to case file", ex); } //Setup indenting to "pretty print" @@ -416,7 +393,7 @@ public final class CaseMetadata { xformer.transform(source, result); } catch (TransformerException ex) { throw new CaseMetadataException( - Bundle.CaseMetadata_writeFile_exception_errWriteToFile_msg(), ex); + "Error writing to case file", ex); } // preparing the output file @@ -431,7 +408,7 @@ public final class CaseMetadata { bw.close(); } catch (IOException ex) { throw new CaseMetadataException( - Bundle.CaseMetadata_writeFile_exception_errWriteToFile_msg(), ex); + "Error writing to case file", ex); } } @@ -441,7 +418,7 @@ public final class CaseMetadata { * * @param conFilePath the path of the XML case configuration file path */ - private void open(String conFilePath) throws CaseMetadataException { + private void read(String conFilePath) throws CaseMetadataException { File file = new File(conFilePath); Document doc; @@ -452,20 +429,18 @@ public final class CaseMetadata { doc = db.parse(file); } catch (ParserConfigurationException | SAXException | IOException ex) { throw new CaseMetadataException( - Bundle.CaseMetadata_open_exception_errReadXMLFile_msg(conFilePath), ex); + "Error reading case XML file\\:" + conFilePath, ex); } - doc.getDocumentElement().normalize(); doc.getDocumentElement().normalize(); Element rootEl = doc.getDocumentElement(); String rootName = rootEl.getNodeName(); - // check if it's the autopsy case, if not, throws an error if (!rootName.equals(TOP_ROOT_NAME)) { - // throw an error ... + // throw an error because the xml is malformed if (RuntimeProperties.coreComponentsAreActive()) { - throw new CaseMetadataException(Bundle.CaseMetadata_open_msgDlg_noCaseHeaderTag_msg()); + throw new CaseMetadataException("Root element not recognized as autopsy case tag"); } } else { /* @@ -473,65 +448,85 @@ public final class CaseMetadata { */ Element rootElement = doc.getDocumentElement(); - String createdVersion = ((Element) rootElement.getElementsByTagName(AUTOPSY_CRVERSION_NAME).item(0)).getTextContent(); // get the created version - + NodeList cversionList = rootElement.getElementsByTagName(AUTOPSY_CRVERSION_NAME); + if(cversionList.getLength() == 0) { + throw new CaseMetadataException("Could not find created version in metadata"); + } + String createdVersion = cversionList.item(0).getTextContent(); // get the created version // check if it has the same autopsy version as the current one if (!createdVersion.equals(System.getProperty("netbeans.buildnumber"))) { // if not the same version, update the saved version in the xml to the current version rootElement.getElementsByTagName(AUTOPSY_MVERSION_NAME).item(0).setTextContent(System.getProperty("netbeans.buildnumber")); } + String fullFileName = file.getName(); String fileName = fullFileName.substring(0, fullFileName.lastIndexOf(".")); // remove the extension this.fileName = fileName; + NodeList rootNameList = doc.getElementsByTagName(CASE_ROOT_NAME); if (rootNameList.getLength() == 0) { - throw new CaseMetadataException(Bundle.CaseMetadata_open_caseRootError()); + throw new CaseMetadataException("Couldn't get case root"); } Element caseElement = (Element) rootNameList.item(0); + NodeList caseTypeList = caseElement.getElementsByTagName(CASE_TYPE); if (caseTypeList.getLength() == 0) { - throw new CaseMetadataException(Bundle.CaseMetadata_open_caseTypeError()); + throw new CaseMetadataException("Couldn't get case type"); } - String caseTypeString = ((Element) caseTypeList.item(0)).getTextContent(); - this.caseType = caseTypeString.equals("") ? Case.CaseType.SINGLE_USER_CASE : Case.CaseType.fromString(caseTypeString); + String caseTypeString = caseTypeList.item(0).getTextContent(); + this.caseType = Case.CaseType.fromString(caseTypeString); + if(this.caseType == null) { + throw new CaseMetadataException("Invalid case type"); + } + NodeList caseNameList = caseElement.getElementsByTagName(NAME); if (caseNameList.getLength() == 0) { - throw new CaseMetadataException(Bundle.CaseMetadata_open_caseTypeError()); + throw new CaseMetadataException("Couldn't get case name"); } - this.caseName = ((Element) caseNameList.item(0)).getTextContent(); + this.caseName = caseNameList.item(0).getTextContent(); + if(this.caseName.isEmpty()) { + throw new CaseMetadataException("Invalid case name, cannot be empty"); + } + Element numberElement = caseElement.getElementsByTagName(NUMBER).getLength() > 0 ? (Element) caseElement.getElementsByTagName(NUMBER).item(0) : null; this.caseNumber = numberElement != null ? numberElement.getTextContent() : ""; + Element examinerElement = caseElement.getElementsByTagName(EXAMINER).getLength() > 0 ? (Element) caseElement.getElementsByTagName(EXAMINER).item(0) : null; this.examiner = examinerElement != null ? examinerElement.getTextContent() : ""; + this.caseDirectory = conFilePath.substring(0, conFilePath.lastIndexOf("\\")); if (this.caseDirectory.isEmpty()) { - throw new CaseMetadataException(Bundle.CaseMetadata_open_exception_errReadXMLFile_msg(conFilePath)); + throw new CaseMetadataException("Could not get a valid case directory"); } + NodeList databaseNameList = caseElement.getElementsByTagName(DATABASE_NAME); if (databaseNameList.getLength() == 0) { - throw new CaseMetadataException(Bundle.CaseMetadata_open_caseDatabaseNameError()); + throw new CaseMetadataException("Couldn't get database name"); } Element databaseNameElement = (Element) databaseNameList.item(0); this.caseDatabaseName = databaseNameElement.getTextContent(); - NodeList textIndexList = caseElement.getElementsByTagName(CASE_TEXT_INDEX_NAME); - if(textIndexList.getLength() == 0) { - throw new CaseMetadataException(Bundle.CaseMetadata_open_caseIndexError()); - } - Element caseTextIndexNameElement = (Element)textIndexList.item(0); - this.caseTextIndexName = caseTextIndexNameElement.getTextContent(); if (Case.CaseType.MULTI_USER_CASE == caseType && caseDatabaseName.isEmpty()) { - throw new CaseMetadataException(Bundle.CaseMetadata_open_exception_errReadXMLFile_msg(conFilePath)); + throw new CaseMetadataException("Case database name cannot be empty in multi user case."); } + + NodeList textIndexList = caseElement.getElementsByTagName(CASE_TEXT_INDEX_NAME); + if (textIndexList.getLength() == 0) { + throw new CaseMetadataException("Couldn't get text index"); + } + Element caseTextIndexNameElement = (Element) textIndexList.item(0); + this.caseTextIndexName = caseTextIndexNameElement.getTextContent(); + NodeList createdDateList = rootElement.getElementsByTagName(CREATED_DATE_NAME); - if(createdDateList.getLength() == 0) { - throw new CaseMetadataException(Bundle.CaseMetadata_open_createdDateError()); + if (createdDateList.getLength() == 0) { + throw new CaseMetadataException("Couldn't get created date"); } - this.setCreatedDate(((Element)createdDateList.item(0)).getTextContent()); + this.createdDate = createdDateList.item(0).getTextContent(); + NodeList createdVersionList = rootElement.getElementsByTagName(AUTOPSY_CRVERSION_NAME); - if(createdVersionList.getLength() == 0) { - throw new CaseMetadataException(Bundle.CaseMetadata_open_createdVersionError()); + if (createdVersionList.getLength() == 0) { + throw new CaseMetadataException("Couldn't get created version"); } - this.setCreatedVersion((((Element)createdVersionList.item(0))).getTextContent()); + this.createdVersion = createdVersionList.item(0).getTextContent(); } } From c69e8de4cecc80a7f72a1553d8cd4da8d7ce19cb Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Thu, 24 Mar 2016 11:32:00 -0400 Subject: [PATCH 15/50] Updated ui for data source wizard. --- .../autopsy/casemodule/AddImageAction.java | 2 + .../AddImageWizardChooseDataSourceVisual.form | 44 ++++--------------- .../AddImageWizardChooseDataSourceVisual.java | 32 ++++---------- .../AddImageWizardIngestConfigVisual.form | 21 ++------- .../AddImageWizardIngestConfigVisual.java | 18 ++------ .../autopsy/casemodule/Bundle.properties | 6 +-- .../autopsy/casemodule/Bundle_ja.properties | 2 - 7 files changed, 28 insertions(+), 97 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java index ee30eb8283..c3c6f7da47 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java @@ -22,6 +22,7 @@ import java.awt.Component; import java.awt.Dialog; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.text.MessageFormat; import java.util.logging.Level; import javax.swing.Action; import javax.swing.ImageIcon; @@ -119,6 +120,7 @@ public final class AddImageAction extends CallableSystemAction implements Presen wizardDescriptor = new WizardDescriptor(iterator); wizardDescriptor.setTitle(NbBundle.getMessage(this.getClass(), "AddImageAction.wizard.title")); wizardDescriptor.putProperty(NAME, e); + wizardDescriptor.setTitleFormat(new MessageFormat("{0}")); if (dialog != null) { dialog.setVisible(false); // hide the old one diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.form b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.form index f010a38b65..928cb45a95 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.form @@ -34,13 +34,7 @@ - - - - - - - + @@ -48,35 +42,15 @@ - + - - - + - - - - - - - - - - - - - - - - - - @@ -88,9 +62,9 @@ - + - + @@ -105,8 +79,8 @@ - - + + @@ -132,12 +106,12 @@ - + - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java index 489c713af8..ad02d666a9 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java @@ -205,7 +205,6 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { buttonGroup1 = new javax.swing.ButtonGroup(); jLabel2 = new javax.swing.JLabel(); - nextLabel = new javax.swing.JLabel(); inputPanel = new javax.swing.JPanel(); typeTabel = new javax.swing.JLabel(); typePanel = new javax.swing.JPanel(); @@ -215,12 +214,6 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { setPreferredSize(new java.awt.Dimension(588, 328)); - org.openide.awt.Mnemonics.setLocalizedText(nextLabel, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.nextLabel.text")); // NOI18N - nextLabel.setPreferredSize(new java.awt.Dimension(514, 35)); - nextLabel.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); - - inputPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder()); - org.openide.awt.Mnemonics.setLocalizedText(typeTabel, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.typeTabel.text")); // NOI18N typePanel.setMinimumSize(new java.awt.Dimension(0, 65)); @@ -230,11 +223,11 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { typePanel.setLayout(typePanelLayout); typePanelLayout.setHorizontalGroup( typePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 544, Short.MAX_VALUE) + .addGap(0, 548, Short.MAX_VALUE) ); typePanelLayout.setVerticalGroup( typePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 173, Short.MAX_VALUE) + .addGap(0, 225, Short.MAX_VALUE) ); javax.swing.GroupLayout inputPanelLayout = new javax.swing.GroupLayout(inputPanel); @@ -248,8 +241,8 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { .addComponent(typeTabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(typeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 292, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 115, Short.MAX_VALUE)) - .addComponent(typePanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 544, Short.MAX_VALUE)) + .addGap(0, 119, Short.MAX_VALUE)) + .addComponent(typePanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 548, Short.MAX_VALUE)) .addContainerGap()) ); inputPanelLayout.setVerticalGroup( @@ -260,8 +253,8 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { .addComponent(typeTabel) .addComponent(typeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(typePanel, javax.swing.GroupLayout.DEFAULT_SIZE, 173, Short.MAX_VALUE) - .addContainerGap()) + .addComponent(typePanel, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); @@ -270,28 +263,21 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(inputPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(layout.createSequentialGroup() - .addComponent(nextLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 54, Short.MAX_VALUE))) + .addComponent(inputPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGap(39, 39, 39) + .addGap(6, 6, 6) .addComponent(inputPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 24, Short.MAX_VALUE) - .addComponent(nextLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, 0)) + .addContainerGap(44, Short.MAX_VALUE)) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup buttonGroup1; private javax.swing.JPanel inputPanel; private javax.swing.JLabel jLabel2; - private javax.swing.JLabel nextLabel; private javax.swing.JComboBox typeComboBox; private javax.swing.JPanel typePanel; private javax.swing.JLabel typeTabel; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.form b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.form index d6f2eb1302..a3138d28a4 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.form @@ -21,34 +21,19 @@ - - - - - - - - - - + + - - - - - - - @@ -64,7 +49,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.java index 1de19dd5d0..f4df6c81d6 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.java @@ -42,7 +42,6 @@ class AddImageWizardIngestConfigVisual extends JPanel { } private void customizeComponents() { - configPanel.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(0, 0, 0))); configPanel.setLayout(new BorderLayout()); configPanel.add(ingestPanel, BorderLayout.CENTER); } @@ -66,13 +65,10 @@ class AddImageWizardIngestConfigVisual extends JPanel { // //GEN-BEGIN:initComponents private void initComponents() { - subtitleLabel = new javax.swing.JLabel(); configPanel = new javax.swing.JPanel(); setPreferredSize(new java.awt.Dimension(569, 300)); - subtitleLabel.setText(org.openide.util.NbBundle.getMessage(AddImageWizardIngestConfigVisual.class, "AddImageWizardIngestConfigVisual.subtitleLabel.text")); // NOI18N - configPanel.setPreferredSize(new java.awt.Dimension(569, 400)); javax.swing.GroupLayout configPanelLayout = new javax.swing.GroupLayout(configPanel); @@ -83,31 +79,23 @@ class AddImageWizardIngestConfigVisual extends JPanel { ); configPanelLayout.setVerticalGroup( configPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 258, Short.MAX_VALUE) + .addGap(0, 275, Short.MAX_VALUE) ); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() - .addComponent(subtitleLabel) - .addContainerGap(218, Short.MAX_VALUE)) .addComponent(configPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGap(6, 6, 6) - .addComponent(subtitleLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(configPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 258, Short.MAX_VALUE) - .addContainerGap()) + .addComponent(configPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 275, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 25, Short.MAX_VALUE)) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JPanel configPanel; - private javax.swing.JLabel subtitleLabel; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index d05018d379..e47e5ecd23 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -69,11 +69,9 @@ LocalFilesPanel.selectedPaths.toolTipText= LocalFilesPanel.localFileChooser.approveButtonText=Select LocalFilesPanel.localFileChooser.approveButtonToolTipText= LocalFilesPanel.selectButton.actionCommand=Add -AddImageWizardIngestConfigVisual.subtitleLabel.text=Configure the ingest modules you would like to run on this data source. AddImageWizardAddingProgressVisual.statusLabel.text=Data source has been added to the local database. Files are being analyzed. -AddImageWizardChooseDataSourceVisual.typeTabel.text=Select source type to add: +AddImageWizardChooseDataSourceVisual.typeTabel.text=Select data source type: AddImageWizardChooseDataSourceVisual.jLabel2.text=jLabel2 -AddImageWizardChooseDataSourceVisual.nextLabel.text= Press 'Next' to analyze the input data, extract volume and file system data, and populate a local database. AddImageWizardAddingProgressVisual.progressLabel.text= AddImageWizardAddingProgressVisual.viewLogButton.text=View Log AddImageWizardAddingProgressVisual.subTitle1Label.text=Processing data source and adding it to a local database. File analysis will start when this finishes. @@ -100,7 +98,7 @@ AddImageWizardAddingProgressVisual.getName.text=Add Data Source AddImageWizardAddingProgressVisual.showErrors.critText=*Failed to add data source (critical errors encountered). Click below to view the log. AddImageWizardAddingProgressVisual.showErrors.nonCritText=*Data Source added (non-critical errors encountered). Click below to view the log. AddImageWizardChooseDataSourcePanel.moveFocusNext=Next > -AddImageWizardChooseDataSourceVisual.getName.text=Enter Data Source Information +AddImageWizardChooseDataSourceVisual.getName.text=Select Data Source AddImageWizardIngestConfigPanel.dsProcDone.noErrs.text=*Data Source added. AddImageWizardIngestConfigPanel.dsProcDone.errs.text=*Errors encountered in adding Data Source. AddImageWizardIngestConfigVisual.getName.text=Configure Ingest Modules diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties index 071aafab4c..e8df9baae7 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties @@ -53,11 +53,9 @@ LocalFilesPanel.clearButton.text=\u30af\u30ea\u30a2 LocalFilesPanel.clearButton.toolTipText=\u73fe\u5728\u9078\u629e\u3055\u308c\u3066\u3044\u308b\u30ed\u30fc\u30ab\u30eb\u30d5\u30a1\u30a4\u30eb\u30d1\u30b9\u304c\u30af\u30ea\u30a2\u3055\u308c\u307e\u3059 LocalFilesPanel.localFileChooser.approveButtonText=\u9078\u629e LocalFilesPanel.selectButton.actionCommand=\u8ffd\u52a0 -AddImageWizardIngestConfigVisual.subtitleLabel.text=\u3053\u306e\u30c7\u30fc\u30bf\u30bd\u30fc\u30b9\u306b\u5bfe\u3057\u3066\u5b9f\u884c\u3057\u305f\u3044\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb\u3092\u8a2d\u5b9a\u3057\u307e\u3059\u3002 AddImageWizardAddingProgressVisual.statusLabel.text=\u30ed\u30fc\u30ab\u30eb\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306b\u30d5\u30a1\u30a4\u30eb\u30b7\u30b9\u30c6\u30e0\u304c\u8ffd\u52a0\u3055\u308c\u307e\u3057\u305f\u3002\u30d5\u30a1\u30a4\u30eb\u3092\u89e3\u6790\u4e2d\u3067\u3059\u3002 AddImageWizardChooseDataSourceVisual.typeTabel.text=\u8ffd\u52a0\u3059\u308b\u30bd\u30fc\u30b9\u30bf\u30a4\u30d7\u3092\u9078\u629e\uff1a AddImageWizardChooseDataSourceVisual.jLabel2.text=jLabel2 -AddImageWizardChooseDataSourceVisual.nextLabel.text= \u300c\u6b21\u3078\u300d\u3092\u30af\u30ea\u30c3\u30af\u3057\u3066\u3001\u30a4\u30f3\u30d7\u30c3\u30c8\u30c7\u30fc\u30bf\u3092\u89e3\u6790\u3001\u30dc\u30ea\u30e5\u30fc\u30e0\u304a\u3088\u3073\u30d5\u30a1\u30a4\u30eb\u30b7\u30b9\u30c6\u30e0\u30c7\u30fc\u30bf\u3092\u62bd\u51fa\u3001\u30ed\u30fc\u30ab\u30eb\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306b\u30c7\u30fc\u30bf\u3092\u6295\u5165\u3002 AddImageWizardAddingProgressVisual.progressLabel.text=\uff1c\u30d7\u30ed\u30b0\u30ec\u30b9\uff1e AddImageWizardAddingProgressVisual.viewLogButton.text=\u30ed\u30b0\u3092\u8868\u793a AddImageWizardAddingProgressVisual.subTitle1Label.text=\u30ed\u30fc\u30ab\u30eb\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306b\u30d5\u30a1\u30a4\u30eb\u30b7\u30b9\u30c6\u30e0\u60c5\u5831\u3092\u8ffd\u52a0\u4e2d\u3067\u3059\u3002\u3053\u3061\u3089\u304c\u5b8c\u4e86\u6b21\u7b2c\u3001\u30d5\u30a1\u30a4\u30eb\u89e3\u6790\u304c\u59cb\u307e\u308a\u307e\u3059\u3002 From 9fdc48f8e032b5009ece8b244d7025d8b0e9ef9f Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Thu, 24 Mar 2016 16:01:22 -0400 Subject: [PATCH 16/50] Updated Dialog box for ingest modules. --- Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties | 2 +- .../org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties index ad71c7e523..e7f183a78b 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties @@ -23,7 +23,7 @@ IngestJob.progress.fileIngest.displayName=Analyzing files from {0} IngestJob.progress.fileIngest.cancelMessage=Waiting for {0} on {1} IngestJob.progress.cancelling={0} (Cancelling...) IngestJob.cancellationDialog.title=Cancel Ingest -IngestDialog.title.text=Ingest Modules +IngestDialog.title.text=Run Ingest Modules IngestDialog.startButton.title=Start IngestDialog.closeButton.title=Close IngestManager.moduleErr=Module Error diff --git a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java index 26f4fd6a11..1dc5a03307 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java @@ -138,7 +138,7 @@ public final class RunIngestModulesDialog extends JDialog { buttonPanel.add(startButton); buttonPanel.add(new javax.swing.Box.Filler(new Dimension(10, 10), new Dimension(10, 10), new Dimension(10, 10))); buttonPanel.add(closeButton); - add(buttonPanel, BorderLayout.LINE_START); + add(buttonPanel, BorderLayout.LINE_END); /** * Add a handler for when the dialog window is closed directly, From 004758e4463a99666e2c510d0954568e80c35a11 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Fri, 25 Mar 2016 09:58:55 -0400 Subject: [PATCH 17/50] Finished UI updates to ingest jobs, except for resizability of JDialog. --- .../AddImageWizardIngestConfigVisual.form | 7 +- .../AddImageWizardIngestConfigVisual.java | 6 +- .../autopsy/ingest/Bundle.properties | 6 +- .../autopsy/ingest/Bundle_ja.properties | 4 +- .../ingest/IngestJobSettingsPanel.form | 115 +++++++++++------- .../ingest/IngestJobSettingsPanel.java | 114 ++++++++++------- .../ingest/RunIngestModulesDialog.java | 9 +- 7 files changed, 160 insertions(+), 101 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.form b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.form index a3138d28a4..e1ac00d13a 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.form @@ -26,10 +26,7 @@ - - - - + @@ -49,7 +46,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.java index f4df6c81d6..93a0219bd8 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.java @@ -79,7 +79,7 @@ class AddImageWizardIngestConfigVisual extends JPanel { ); configPanelLayout.setVerticalGroup( configPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 275, Short.MAX_VALUE) + .addGap(0, 300, Short.MAX_VALUE) ); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); @@ -90,9 +90,7 @@ class AddImageWizardIngestConfigVisual extends JPanel { ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(configPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 275, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 25, Short.MAX_VALUE)) + .addComponent(configPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties index e7f183a78b..1e9c44cbe4 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties @@ -85,8 +85,6 @@ DataSourceIngestCancellationPanel.cancelCurrentModuleRadioButton.text=Cancel cur FileIngestCancellationPanel.cancelIngestJobRadioButton.text=Cancel data source ingest and file ingest FileIngestCancellationPanel.cancelFileIngestRadioButton.text=Cancel file ingest only DataSourceIngestCancellationPanel.cancelAllModulesRadioButton.text=Cancel all ingest modules -IngestJobSettingsPanel.advancedButton.actionCommand=Advanced -IngestJobSettingsPanel.advancedButton.text=Advanced IngestJobSettingsPanel.descriptionLabel.text= IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.jobID=Job ID IngestJobTableModel.colName.jobID=Job ID @@ -117,3 +115,7 @@ IngestJob.cancelReason.ingestModStartFail.text=Ingest modules startup failed IngestJob.cancelReason.outOfDiskSpace.text=Out of disk space IngestJob.cancelReason.servicesDown.text=Services Down IngestJob.cancelReason.caseClosed.text=Case closed +IngestJobSettingsPanel.jLabel1.text_1=Select Modules +IngestJobSettingsPanel.jLabel2.text=Settings for this Ingest +IngestJobSettingsPanel.globalSettingsButton.actionCommand=Advanced +IngestJobSettingsPanel.globalSettingsButton.text=Global Settings diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties index 68034d6409..130c0c3171 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties @@ -68,8 +68,6 @@ IngestProgressSnapshotDialog.title.text=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30 IngestProgressSnapshotPanel.closeButton.text=\u9589\u3058\u308b IngestProgressSnapshotPanel.refreshButton.text=\u30ea\u30d5\u30ec\u30c3\u30b7\u30e5 IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.activity=\u30a2\u30af\u30c6\u30a3\u30d3\u30c6\u30a3 -IngestJobSettingsPanel.advancedButton.actionCommand=\u30a2\u30c9\u30d0\u30f3\u30b9 -IngestJobSettingsPanel.advancedButton.text=\u30a2\u30c9\u30d0\u30f3\u30b9 ModuleTableModel.colName.duration=\u6240\u8981\u6642\u9593 IngestJob.cancellationDialog.title=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u3092\u30ad\u30e3\u30f3\u30bb\u30eb IngestJobSettings.missingModule.warning=\u4ee5\u524d\u306b\u8aad\u307f\u8fbc\u3093\u3060{0}\u30e2\u30b8\u30e5\u30fc\u30eb\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\u3002 @@ -113,3 +111,5 @@ IngestJob.cancelReason.cancelledByUser.text=\u30e6\u30fc\u30b6\u30fc\u304c\u30ad IngestJob.cancelReason.ingestModStartFail.text=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb\u306e\u8d77\u52d5\u306b\u5931\u6557 IngestJob.cancelReason.outOfDiskSpace.text=\u30c7\u30a3\u30b9\u30af\u30b9\u30da\u30fc\u30b9\u304c\u8db3\u308a\u307e\u305b\u3093 IngestJob.cancelReason.caseClosed.text=\u30b1\u30fc\u30b9\u3092\u9589\u3058\u307e\u3057\u305f +IngestJobSettingsPanel.globalSettingsButton.actionCommand=\u30a2\u30c9\u30d0\u30f3\u30b9 +IngestJobSettingsPanel.globalSettingsButton.text=\u30a2\u30c9\u30d0\u30f3\u30b9 diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form index 2f769e6f8b..e7e271eec4 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form @@ -13,7 +13,7 @@ - + @@ -31,50 +31,64 @@ - - + + - - - + + + + + + + + + + + + + + + + + - - - - - - - - - - + + - + + + + - - + + + + + + + - - - - - + - + + + + + @@ -130,49 +144,54 @@ - + - - - + + + + - + - + - + - + - - + + + + + + - + - + - + - + - + @@ -196,7 +215,7 @@ - + @@ -239,5 +258,19 @@ + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java index 78c1a214d8..dd36284cbd 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java @@ -25,6 +25,7 @@ import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.ArrayList; import java.util.List; +import javax.swing.JLabel; import javax.swing.JTable; import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionEvent; @@ -108,19 +109,22 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { if (!listSelectionModel.isSelectionEmpty()) { int index = listSelectionModel.getMinSelectionIndex(); selectedModule = modules.get(index); - simplePanel.removeAll(); + ingestSettingsPanel.removeAll(); if (null != selectedModule.getModuleSettingsPanel()) { - simplePanel.add(selectedModule.getModuleSettingsPanel()); + ingestSettingsPanel.add(selectedModule.getModuleSettingsPanel()); } - simplePanel.revalidate(); - simplePanel.repaint(); - advancedButton.setEnabled(null != selectedModule.getGlobalSettingsPanel()); + else { + ingestSettingsPanel.add(new JLabel("No per ingest settings for this module.")); + } + ingestSettingsPanel.revalidate(); + ingestSettingsPanel.repaint(); + globalSettingsButton.setEnabled(null != selectedModule.getGlobalSettingsPanel()); descriptionLabel.setText(selectedModule.getDescription()); descriptionLabel.setToolTipText(selectedModule.getDescription()); } } }); - + modulesTable.setRowSelectionInterval(0, 0); processUnallocCheckbox.setSelected(this.settings.getProcessUnallocatedSpace()); } @@ -137,18 +141,20 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { modulesScrollPane = new javax.swing.JScrollPane(); modulesTable = new javax.swing.JTable(); jPanel1 = new javax.swing.JPanel(); - advancedButton = new javax.swing.JButton(); + globalSettingsButton = new javax.swing.JButton(); jSeparator2 = new javax.swing.JSeparator(); descriptionLabel = new javax.swing.JLabel(); jScrollPane1 = new javax.swing.JScrollPane(); - simplePanel = new javax.swing.JPanel(); + ingestSettingsPanel = new javax.swing.JPanel(); jButtonSelectAll = new javax.swing.JButton(); jButtonDeselectAll = new javax.swing.JButton(); processUnallocCheckbox = new javax.swing.JCheckBox(); + jLabel1 = new javax.swing.JLabel(); + jLabel2 = new javax.swing.JLabel(); setMaximumSize(new java.awt.Dimension(5750, 3000)); setMinimumSize(new java.awt.Dimension(522, 257)); - setPreferredSize(new java.awt.Dimension(575, 300)); + setPreferredSize(new java.awt.Dimension(575, 340)); modulesScrollPane.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(160, 160, 160))); modulesScrollPane.setPreferredSize(new java.awt.Dimension(160, 160)); @@ -169,12 +175,12 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { jPanel1.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(160, 160, 160))); jPanel1.setPreferredSize(new java.awt.Dimension(338, 257)); - advancedButton.setText(org.openide.util.NbBundle.getMessage(IngestJobSettingsPanel.class, "IngestJobSettingsPanel.advancedButton.text")); // NOI18N - advancedButton.setActionCommand(org.openide.util.NbBundle.getMessage(IngestJobSettingsPanel.class, "IngestJobSettingsPanel.advancedButton.actionCommand")); // NOI18N - advancedButton.setEnabled(false); - advancedButton.addActionListener(new java.awt.event.ActionListener() { + globalSettingsButton.setText(org.openide.util.NbBundle.getMessage(IngestJobSettingsPanel.class, "IngestJobSettingsPanel.globalSettingsButton.text")); // NOI18N + globalSettingsButton.setActionCommand(org.openide.util.NbBundle.getMessage(IngestJobSettingsPanel.class, "IngestJobSettingsPanel.globalSettingsButton.actionCommand")); // NOI18N + globalSettingsButton.setEnabled(false); + globalSettingsButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - advancedButtonActionPerformed(evt); + globalSettingsButtonActionPerformed(evt); } }); @@ -183,8 +189,8 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { jScrollPane1.setBorder(null); jScrollPane1.setPreferredSize(new java.awt.Dimension(250, 180)); - simplePanel.setLayout(new javax.swing.BoxLayout(simplePanel, javax.swing.BoxLayout.PAGE_AXIS)); - jScrollPane1.setViewportView(simplePanel); + ingestSettingsPanel.setLayout(new javax.swing.BoxLayout(ingestSettingsPanel, javax.swing.BoxLayout.PAGE_AXIS)); + jScrollPane1.setViewportView(ingestSettingsPanel); javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); @@ -196,9 +202,10 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(jPanel1Layout.createSequentialGroup() - .addComponent(descriptionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 203, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(advancedButton))) + .addComponent(descriptionLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 175, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(globalSettingsButton) + .addGap(4, 4, 4))) .addContainerGap()) ); jPanel1Layout.setVerticalGroup( @@ -210,8 +217,11 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { .addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(descriptionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 24, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(advancedButton)) + .addGroup(jPanel1Layout.createSequentialGroup() + .addGap(0, 9, Short.MAX_VALUE) + .addComponent(globalSettingsButton) + .addGap(0, 11, Short.MAX_VALUE)) + .addComponent(descriptionLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addContainerGap()) ); @@ -237,6 +247,10 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { } }); + jLabel1.setText(org.openide.util.NbBundle.getMessage(IngestJobSettingsPanel.class, "IngestJobSettingsPanel.jLabel1.text_1")); // NOI18N + + jLabel2.setText(org.openide.util.NbBundle.getMessage(IngestJobSettingsPanel.class, "IngestJobSettingsPanel.jLabel2.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -244,29 +258,36 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(modulesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGap(10, 10, 10)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(modulesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGap(10, 10, 10)) + .addGroup(layout.createSequentialGroup() + .addGap(24, 24, 24) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(processUnallocCheckbox) + .addGroup(layout.createSequentialGroup() + .addComponent(jButtonSelectAll, javax.swing.GroupLayout.PREFERRED_SIZE, 86, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(18, 18, 18) + .addComponent(jButtonDeselectAll))) + .addGap(30, 30, 30))) .addGroup(layout.createSequentialGroup() - .addGap(24, 24, 24) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(processUnallocCheckbox) - .addGroup(layout.createSequentialGroup() - .addComponent(jButtonSelectAll, javax.swing.GroupLayout.PREFERRED_SIZE, 86, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18) - .addComponent(jButtonDeselectAll))) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 30, Short.MAX_VALUE))) - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 310, Short.MAX_VALUE) + .addComponent(jLabel1) + .addGap(176, 176, 176))) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel2) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 308, Short.MAX_VALUE)) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addContainerGap() + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(12, 12, 12) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel2, javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(jLabel1, javax.swing.GroupLayout.Alignment.TRAILING)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 278, Short.MAX_VALUE) - .addContainerGap()) .addGroup(layout.createSequentialGroup() .addComponent(modulesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) @@ -274,11 +295,14 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { .addComponent(jButtonDeselectAll) .addComponent(jButtonSelectAll)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(processUnallocCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)))) + .addComponent(processUnallocCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 297, Short.MAX_VALUE) + .addContainerGap()))) ); }// //GEN-END:initComponents - private void advancedButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_advancedButtonActionPerformed + private void globalSettingsButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_globalSettingsButtonActionPerformed final AdvancedConfigurationDialog dialog = new AdvancedConfigurationDialog(); dialog.addApplyButtonListener(new ActionListener() { @@ -299,7 +323,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { }); dialog.display(selectedModule.getGlobalSettingsPanel()); - }//GEN-LAST:event_advancedButtonActionPerformed + }//GEN-LAST:event_globalSettingsButtonActionPerformed private void jButtonSelectAllActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButtonSelectAllActionPerformed SelectAllModules(true); @@ -321,17 +345,19 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { } // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JButton advancedButton; private javax.swing.JLabel descriptionLabel; + private javax.swing.JButton globalSettingsButton; + private javax.swing.JPanel ingestSettingsPanel; private javax.swing.JButton jButtonDeselectAll; private javax.swing.JButton jButtonSelectAll; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel2; private javax.swing.JPanel jPanel1; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JSeparator jSeparator2; private javax.swing.JScrollPane modulesScrollPane; private javax.swing.JTable modulesTable; private javax.swing.JCheckBox processUnallocCheckbox; - private javax.swing.JPanel simplePanel; private javax.swing.ButtonGroup timeGroup; // End of variables declaration//GEN-END:variables @@ -365,7 +391,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { } String getDescription() { - return moduleTemplate.getModuleDescription(); + return "" + moduleTemplate.getModuleDescription() + ""; } void setEnabled(boolean enabled) { diff --git a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java index 1dc5a03307..1924c05a38 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java @@ -27,12 +27,14 @@ import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.ArrayList; import java.util.List; +import javax.swing.BorderFactory; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JPanel; +import javax.swing.border.EmptyBorder; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.ingest.IngestJobSettings.IngestType; import org.sleuthkit.datamodel.Content; @@ -64,6 +66,7 @@ public final class RunIngestModulesDialog extends JDialog { */ public RunIngestModulesDialog(JFrame frame, String title, boolean modal, List dataSources) { super(frame, title, modal); + frame.setResizable(true); this.dataSources.addAll(dataSources); this.ingestType = IngestType.ALL_MODULES; } @@ -134,6 +137,7 @@ public final class RunIngestModulesDialog extends JDialog { // Put the buttons in their own panel, under the settings panel. JPanel buttonPanel = new JPanel(); buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.LINE_AXIS)); + buttonPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 10)); buttonPanel.add(new javax.swing.Box.Filler(new Dimension(10, 10), new Dimension(10, 10), new Dimension(10, 10))); buttonPanel.add(startButton); buttonPanel.add(new javax.swing.Box.Filler(new Dimension(10, 10), new Dimension(10, 10), new Dimension(10, 10))); @@ -155,7 +159,6 @@ public final class RunIngestModulesDialog extends JDialog { * Show the dialog. */ pack(); - setResizable(false); setVisible(true); } @@ -196,7 +199,7 @@ public final class RunIngestModulesDialog extends JDialog { JOptionPane.showMessageDialog(null, warningMessage.toString()); } } - + /** * Constructs a dialog box that allows a user to configure and execute * analysis of one or more data sources with ingest modules. @@ -236,5 +239,5 @@ public final class RunIngestModulesDialog extends JDialog { this.dataSources.clear(); this.dataSources.addAll(dataSources); } - + } From a4280b4ea3ad526f776d35ac7e06db030292088c Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Fri, 25 Mar 2016 15:42:03 -0400 Subject: [PATCH 18/50] Update to UI --- .../autopsy/ingest/RunIngestModulesDialog.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java index 1924c05a38..9c814bfeb4 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.ingest; import java.awt.BorderLayout; import java.awt.Dimension; +import java.awt.FlowLayout; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -51,7 +52,7 @@ public final class RunIngestModulesDialog extends JDialog { private static final long serialVersionUID = 1L; private static final String TITLE = NbBundle.getMessage(RunIngestModulesDialog.class, "IngestDialog.title.text"); private final IngestType ingestType; - private static Dimension DIMENSIONS = new Dimension(500, 300); + private static Dimension DIMENSIONS = new Dimension(500, 333); private final List dataSources = new ArrayList<>(); private IngestJobSettingsPanel ingestJobSettingsPanel; @@ -66,7 +67,6 @@ public final class RunIngestModulesDialog extends JDialog { */ public RunIngestModulesDialog(JFrame frame, String title, boolean modal, List dataSources) { super(frame, title, modal); - frame.setResizable(true); this.dataSources.addAll(dataSources); this.ingestType = IngestType.ALL_MODULES; } @@ -114,7 +114,7 @@ public final class RunIngestModulesDialog extends JDialog { IngestJobSettings ingestJobSettings = new IngestJobSettings(RunIngestModulesDialog.class.getCanonicalName(), this.ingestType); RunIngestModulesDialog.showWarnings(ingestJobSettings); this.ingestJobSettingsPanel = new IngestJobSettingsPanel(ingestJobSettings); - add(this.ingestJobSettingsPanel, BorderLayout.PAGE_START); + add(this.ingestJobSettingsPanel, BorderLayout.CENTER); // Add a start ingest button. JButton startButton = new JButton(NbBundle.getMessage(this.getClass(), "IngestDialog.startButton.title")); @@ -136,13 +136,13 @@ public final class RunIngestModulesDialog extends JDialog { // Put the buttons in their own panel, under the settings panel. JPanel buttonPanel = new JPanel(); - buttonPanel.setLayout(new BoxLayout(buttonPanel, BoxLayout.LINE_AXIS)); - buttonPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 10)); - buttonPanel.add(new javax.swing.Box.Filler(new Dimension(10, 10), new Dimension(10, 10), new Dimension(10, 10))); + buttonPanel.setLayout(new FlowLayout(FlowLayout.TRAILING)); + buttonPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5)); buttonPanel.add(startButton); - buttonPanel.add(new javax.swing.Box.Filler(new Dimension(10, 10), new Dimension(10, 10), new Dimension(10, 10))); + buttonPanel.add(new javax.swing.Box.Filler(new Dimension(5, 10), new Dimension(5, 10), new Dimension(5, 10))); buttonPanel.add(closeButton); - add(buttonPanel, BorderLayout.LINE_END); + + add(buttonPanel, BorderLayout.SOUTH); /** * Add a handler for when the dialog window is closed directly, From 6f17ba5fc9d74d7449eb143d689f02df39e66e65 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Fri, 25 Mar 2016 16:32:14 -0400 Subject: [PATCH 19/50] Fixed ui resizability --- .../autopsy/ingest/Bundle.properties | 4 +- .../ingest/IngestJobSettingsPanel.form | 90 +++++++------------ .../ingest/IngestJobSettingsPanel.java | 70 ++++++--------- 3 files changed, 60 insertions(+), 104 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties index 1e9c44cbe4..26f2f22b1c 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties @@ -115,7 +115,7 @@ IngestJob.cancelReason.ingestModStartFail.text=Ingest modules startup failed IngestJob.cancelReason.outOfDiskSpace.text=Out of disk space IngestJob.cancelReason.servicesDown.text=Services Down IngestJob.cancelReason.caseClosed.text=Case closed -IngestJobSettingsPanel.jLabel1.text_1=Select Modules -IngestJobSettingsPanel.jLabel2.text=Settings for this Ingest +IngestJobSettingsPanel.globalSettingsButton.text=Global Settings +gest IngestJobSettingsPanel.globalSettingsButton.actionCommand=Advanced IngestJobSettingsPanel.globalSettingsButton.text=Global Settings diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form index e7e271eec4..d69064abb3 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form @@ -13,7 +13,7 @@ - + @@ -34,50 +34,36 @@ - - - - - - - - - - - - - - - - - + + + - - + + + + + + + + + + - - - - - + + - - - - - - + - + - + @@ -85,8 +71,8 @@ - - + + @@ -104,6 +90,9 @@ + + + @@ -148,7 +137,7 @@ - + @@ -162,19 +151,18 @@ - - + + - + - - + + + - - - + @@ -258,19 +246,5 @@ - - - - - - - - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java index dd36284cbd..334dc3ad40 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java @@ -149,14 +149,13 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { jButtonSelectAll = new javax.swing.JButton(); jButtonDeselectAll = new javax.swing.JButton(); processUnallocCheckbox = new javax.swing.JCheckBox(); - jLabel1 = new javax.swing.JLabel(); - jLabel2 = new javax.swing.JLabel(); setMaximumSize(new java.awt.Dimension(5750, 3000)); setMinimumSize(new java.awt.Dimension(522, 257)); - setPreferredSize(new java.awt.Dimension(575, 340)); + setPreferredSize(new java.awt.Dimension(585, 340)); modulesScrollPane.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(160, 160, 160))); + modulesScrollPane.setMinimumSize(new java.awt.Dimension(0, 0)); modulesScrollPane.setPreferredSize(new java.awt.Dimension(160, 160)); modulesTable.setBackground(new java.awt.Color(240, 240, 240)); @@ -202,7 +201,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(jPanel1Layout.createSequentialGroup() - .addComponent(descriptionLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 175, Short.MAX_VALUE) + .addComponent(descriptionLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(globalSettingsButton) .addGap(4, 4, 4))) @@ -212,17 +211,16 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() .addContainerGap() - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 211, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 208, Short.MAX_VALUE) + .addGap(18, 18, 18) .addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(descriptionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(jPanel1Layout.createSequentialGroup() - .addGap(0, 9, Short.MAX_VALUE) - .addComponent(globalSettingsButton) - .addGap(0, 11, Short.MAX_VALUE)) - .addComponent(descriptionLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap()) + .addGap(15, 15, 15) + .addComponent(globalSettingsButton))) + .addContainerGap(16, Short.MAX_VALUE)) ); jButtonSelectAll.setText(org.openide.util.NbBundle.getMessage(IngestJobSettingsPanel.class, "IngestJobSettingsPanel.jButtonSelectAll.text")); // NOI18N @@ -247,10 +245,6 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { } }); - jLabel1.setText(org.openide.util.NbBundle.getMessage(IngestJobSettingsPanel.class, "IngestJobSettingsPanel.jLabel1.text_1")); // NOI18N - - jLabel2.setText(org.openide.util.NbBundle.getMessage(IngestJobSettingsPanel.class, "IngestJobSettingsPanel.jLabel2.text")); // NOI18N - javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -258,35 +252,25 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addComponent(modulesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGap(10, 10, 10)) - .addGroup(layout.createSequentialGroup() - .addGap(24, 24, 24) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(processUnallocCheckbox) - .addGroup(layout.createSequentialGroup() - .addComponent(jButtonSelectAll, javax.swing.GroupLayout.PREFERRED_SIZE, 86, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18) - .addComponent(jButtonDeselectAll))) - .addGap(30, 30, 30))) .addGroup(layout.createSequentialGroup() - .addComponent(jLabel1) - .addGap(176, 176, 176))) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jLabel2) - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 308, Short.MAX_VALUE)) + .addComponent(modulesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGap(10, 10, 10)) + .addGroup(layout.createSequentialGroup() + .addGap(24, 24, 24) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(processUnallocCheckbox) + .addGroup(layout.createSequentialGroup() + .addComponent(jButtonSelectAll, javax.swing.GroupLayout.PREFERRED_SIZE, 86, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(18, 18, 18) + .addComponent(jButtonDeselectAll))) + .addGap(32, 32, 32))) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 317, Short.MAX_VALUE) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGap(12, 12, 12) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jLabel2, javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(jLabel1, javax.swing.GroupLayout.Alignment.TRAILING)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createSequentialGroup() + .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(modulesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) @@ -296,8 +280,8 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { .addComponent(jButtonSelectAll)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(processUnallocCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addGroup(layout.createSequentialGroup() - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 297, Short.MAX_VALUE) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 318, Short.MAX_VALUE) .addContainerGap()))) ); }// //GEN-END:initComponents @@ -350,8 +334,6 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { private javax.swing.JPanel ingestSettingsPanel; private javax.swing.JButton jButtonDeselectAll; private javax.swing.JButton jButtonSelectAll; - private javax.swing.JLabel jLabel1; - private javax.swing.JLabel jLabel2; private javax.swing.JPanel jPanel1; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JSeparator jSeparator2; From fed3a955e54c0935d07ce66a80e701526f94b463 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Mon, 28 Mar 2016 12:02:13 -0400 Subject: [PATCH 20/50] Updated UI for ingest --- .../autopsy/casemodule/AddImageAction.java | 4 ++++ .../AddImageWizardIngestConfigVisual.form | 4 ++-- .../AddImageWizardIngestConfigVisual.java | 4 ++-- .../sleuthkit/autopsy/ingest/Bundle.properties | 2 +- .../autopsy/ingest/IngestJobSettingsPanel.form | 18 +++++++++++++----- .../autopsy/ingest/IngestJobSettingsPanel.java | 16 +++++++++------- 6 files changed, 31 insertions(+), 17 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java index c3c6f7da47..c705cb3524 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.casemodule; import java.awt.Component; import java.awt.Dialog; +import java.awt.Dimension; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.text.MessageFormat; @@ -75,6 +76,7 @@ public final class AddImageAction extends CallableSystemAction implements Presen static final String NOFATORPHANS_PROP = "nofatorphans"; //NON-NLS static final Logger logger = Logger.getLogger(AddImageAction.class.getName()); + static final Dimension SIZE = new Dimension(825, 550); private WizardDescriptor wizardDescriptor; private WizardDescriptor.Iterator iterator; @@ -126,6 +128,8 @@ public final class AddImageAction extends CallableSystemAction implements Presen dialog.setVisible(false); // hide the old one } dialog = DialogDisplayer.getDefault().createDialog(wizardDescriptor); + Dimension d = dialog.getSize(); + dialog.setSize(SIZE); dialog.setVisible(true); dialog.toFront(); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.form b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.form index e1ac00d13a..4a117c7634 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.form @@ -26,7 +26,7 @@ - + @@ -46,7 +46,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.java index 93a0219bd8..88fdd1317d 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.java @@ -79,7 +79,7 @@ class AddImageWizardIngestConfigVisual extends JPanel { ); configPanelLayout.setVerticalGroup( configPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 300, Short.MAX_VALUE) + .addGap(0, 349, Short.MAX_VALUE) ); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); @@ -90,7 +90,7 @@ class AddImageWizardIngestConfigVisual extends JPanel { ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(configPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE) + .addComponent(configPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 349, Short.MAX_VALUE) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties index 26f2f22b1c..c0c02a8664 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties @@ -85,7 +85,6 @@ DataSourceIngestCancellationPanel.cancelCurrentModuleRadioButton.text=Cancel cur FileIngestCancellationPanel.cancelIngestJobRadioButton.text=Cancel data source ingest and file ingest FileIngestCancellationPanel.cancelFileIngestRadioButton.text=Cancel file ingest only DataSourceIngestCancellationPanel.cancelAllModulesRadioButton.text=Cancel all ingest modules -IngestJobSettingsPanel.descriptionLabel.text= IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.jobID=Job ID IngestJobTableModel.colName.jobID=Job ID IngestJobTableModel.colName.dataSource=Data Source @@ -119,3 +118,4 @@ IngestJobSettingsPanel.globalSettingsButton.text=Global Settings gest IngestJobSettingsPanel.globalSettingsButton.actionCommand=Advanced IngestJobSettingsPanel.globalSettingsButton.text=Global Settings +IngestJobSettingsPanel.descriptionLabel.text= diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form index d69064abb3..638d99b42f 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form @@ -13,7 +13,7 @@ - + @@ -72,7 +72,7 @@ - + @@ -151,10 +151,10 @@ - + - + @@ -162,7 +162,7 @@ - + @@ -177,6 +177,9 @@ + + + @@ -204,6 +207,11 @@ + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java index 334dc3ad40..21fd6ef289 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java @@ -152,7 +152,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { setMaximumSize(new java.awt.Dimension(5750, 3000)); setMinimumSize(new java.awt.Dimension(522, 257)); - setPreferredSize(new java.awt.Dimension(585, 340)); + setPreferredSize(new java.awt.Dimension(585, 349)); modulesScrollPane.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(160, 160, 160))); modulesScrollPane.setMinimumSize(new java.awt.Dimension(0, 0)); @@ -177,6 +177,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { globalSettingsButton.setText(org.openide.util.NbBundle.getMessage(IngestJobSettingsPanel.class, "IngestJobSettingsPanel.globalSettingsButton.text")); // NOI18N globalSettingsButton.setActionCommand(org.openide.util.NbBundle.getMessage(IngestJobSettingsPanel.class, "IngestJobSettingsPanel.globalSettingsButton.actionCommand")); // NOI18N globalSettingsButton.setEnabled(false); + globalSettingsButton.setMinimumSize(new java.awt.Dimension(103, 23)); globalSettingsButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { globalSettingsButtonActionPerformed(evt); @@ -188,6 +189,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { jScrollPane1.setBorder(null); jScrollPane1.setPreferredSize(new java.awt.Dimension(250, 180)); + ingestSettingsPanel.setMinimumSize(new java.awt.Dimension(0, 300)); ingestSettingsPanel.setLayout(new javax.swing.BoxLayout(ingestSettingsPanel, javax.swing.BoxLayout.PAGE_AXIS)); jScrollPane1.setViewportView(ingestSettingsPanel); @@ -203,7 +205,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { .addGroup(jPanel1Layout.createSequentialGroup() .addComponent(descriptionLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(globalSettingsButton) + .addComponent(globalSettingsButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(4, 4, 4))) .addContainerGap()) ); @@ -211,16 +213,16 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() .addContainerGap() - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 208, Short.MAX_VALUE) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 211, Short.MAX_VALUE) .addGap(18, 18, 18) .addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGap(14, 14, 14) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(descriptionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) .addGroup(jPanel1Layout.createSequentialGroup() .addGap(15, 15, 15) - .addComponent(globalSettingsButton))) - .addContainerGap(16, Short.MAX_VALUE)) + .addComponent(globalSettingsButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addGap(19, 19, 19)) ); jButtonSelectAll.setText(org.openide.util.NbBundle.getMessage(IngestJobSettingsPanel.class, "IngestJobSettingsPanel.jButtonSelectAll.text")); // NOI18N @@ -281,7 +283,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(processUnallocCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 318, Short.MAX_VALUE) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 327, Short.MAX_VALUE) .addContainerGap()))) ); }// //GEN-END:initComponents From 3fdd121a260ccc04fe476bd9323200f056bfe867 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 28 Mar 2016 17:01:19 -0400 Subject: [PATCH 21/50] Restore filetypeid/FileTypeIdModuleSettings for backwards compatibility --- .../filetypeid/FileTypeIdModuleSettings.java | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettings.java diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettings.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettings.java new file mode 100644 index 0000000000..d8cf3a51bd --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeIdModuleSettings.java @@ -0,0 +1,58 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2016 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.sleuthkit.autopsy.modules.filetypeid; + +import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; + +/** + * Ingest job options for the file type identifier ingest module instances. + * + * @deprecated This class is obsolete (files are no longer skipped for any + * reason by file typing) but it is retained for backwards compatibility because + * it was erroneously made part of the public API and so that old settings files + * can be deserialized successfully (and ignored). + */ +@Deprecated +public class FileTypeIdModuleSettings implements IngestModuleIngestJobSettings { + + private static final long serialVersionUID = 1L; + private boolean skipKnownFiles = true; + private final boolean skipSmallFiles = false; // No longer used. + + FileTypeIdModuleSettings() { + } + + FileTypeIdModuleSettings(boolean skipKnownFiles) { + this.skipKnownFiles = skipKnownFiles; + } + + @Override + public long getVersionNumber() { + return serialVersionUID; + } + + void setSkipKnownFiles(boolean enabled) { + skipKnownFiles = enabled; + } + + boolean skipKnownFiles() { + return skipKnownFiles; + } + +} From 1a6a21dbebd14be48dd301c80fca935bddc151db Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Tue, 29 Mar 2016 13:40:41 -0400 Subject: [PATCH 22/50] Moved to UI updates. --- .../autopsy/casemodule/AddImageAction.java | 2 +- .../AddImageWizardIngestConfigVisual.form | 9 ++-- .../AddImageWizardIngestConfigVisual.java | 8 ++-- .../ingest/IngestJobSettingsPanel.form | 44 ++++++++----------- .../ingest/IngestJobSettingsPanel.java | 40 ++++++++--------- .../ingest/RunIngestModulesDialog.java | 2 +- 6 files changed, 49 insertions(+), 56 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java index c705cb3524..ae57423b5b 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageAction.java @@ -76,7 +76,7 @@ public final class AddImageAction extends CallableSystemAction implements Presen static final String NOFATORPHANS_PROP = "nofatorphans"; //NON-NLS static final Logger logger = Logger.getLogger(AddImageAction.class.getName()); - static final Dimension SIZE = new Dimension(825, 550); + static final Dimension SIZE = new Dimension(875, 550); private WizardDescriptor wizardDescriptor; private WizardDescriptor.Iterator iterator; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.form b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.form index 4a117c7634..2af6e2e533 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.form @@ -21,12 +21,15 @@ - + + + + - + @@ -41,7 +44,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.java index 88fdd1317d..f1a0211425 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigVisual.java @@ -75,7 +75,7 @@ class AddImageWizardIngestConfigVisual extends JPanel { configPanel.setLayout(configPanelLayout); configPanelLayout.setHorizontalGroup( configPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 569, Short.MAX_VALUE) + .addGap(0, 609, Short.MAX_VALUE) ); configPanelLayout.setVerticalGroup( configPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -86,11 +86,13 @@ class AddImageWizardIngestConfigVisual extends JPanel { this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(configPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(configPanel, javax.swing.GroupLayout.PREFERRED_SIZE, 609, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(configPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 349, Short.MAX_VALUE) + .addComponent(configPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form index 638d99b42f..b87fc21384 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form @@ -13,7 +13,7 @@ - + @@ -35,7 +35,7 @@ - + @@ -51,7 +51,7 @@ - + @@ -72,7 +72,7 @@ - + @@ -132,18 +132,17 @@ - - - - - - - + + + + + + + - - + @@ -151,18 +150,14 @@ - + - - - - - - - - - + + + + + @@ -177,9 +172,6 @@ - - - diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java index 21fd6ef289..c2247b0ccc 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java @@ -152,7 +152,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { setMaximumSize(new java.awt.Dimension(5750, 3000)); setMinimumSize(new java.awt.Dimension(522, 257)); - setPreferredSize(new java.awt.Dimension(585, 349)); + setPreferredSize(new java.awt.Dimension(625, 400)); modulesScrollPane.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(160, 160, 160))); modulesScrollPane.setMinimumSize(new java.awt.Dimension(0, 0)); @@ -177,7 +177,6 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { globalSettingsButton.setText(org.openide.util.NbBundle.getMessage(IngestJobSettingsPanel.class, "IngestJobSettingsPanel.globalSettingsButton.text")); // NOI18N globalSettingsButton.setActionCommand(org.openide.util.NbBundle.getMessage(IngestJobSettingsPanel.class, "IngestJobSettingsPanel.globalSettingsButton.actionCommand")); // NOI18N globalSettingsButton.setEnabled(false); - globalSettingsButton.setMinimumSize(new java.awt.Dimension(103, 23)); globalSettingsButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { globalSettingsButtonActionPerformed(evt); @@ -198,31 +197,28 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { jPanel1Layout.setHorizontalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(jSeparator2, javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() + .addGroup(jPanel1Layout.createSequentialGroup() .addContainerGap() - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(jPanel1Layout.createSequentialGroup() - .addComponent(descriptionLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(globalSettingsButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(4, 4, 4))) + .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(descriptionLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 307, Short.MAX_VALUE) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(globalSettingsButton))) .addContainerGap()) ); jPanel1Layout.setVerticalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() .addContainerGap() - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 211, Short.MAX_VALUE) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 274, Short.MAX_VALUE) .addGap(18, 18, 18) .addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(14, 14, 14) - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(descriptionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(jPanel1Layout.createSequentialGroup() - .addGap(15, 15, 15) - .addComponent(globalSettingsButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addGap(19, 19, 19)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(descriptionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(globalSettingsButton) + .addContainerGap()) ); jButtonSelectAll.setText(org.openide.util.NbBundle.getMessage(IngestJobSettingsPanel.class, "IngestJobSettingsPanel.jButtonSelectAll.text")); // NOI18N @@ -255,7 +251,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(modulesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(modulesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 276, Short.MAX_VALUE) .addGap(10, 10, 10)) .addGroup(layout.createSequentialGroup() .addGap(24, 24, 24) @@ -266,7 +262,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { .addGap(18, 18, 18) .addComponent(jButtonDeselectAll))) .addGap(32, 32, 32))) - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 317, Short.MAX_VALUE) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 329, Short.MAX_VALUE) .addContainerGap()) ); layout.setVerticalGroup( @@ -283,7 +279,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(processUnallocCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 327, Short.MAX_VALUE) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 378, Short.MAX_VALUE) .addContainerGap()))) ); }// //GEN-END:initComponents @@ -375,7 +371,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { } String getDescription() { - return "" + moduleTemplate.getModuleDescription() + ""; + return moduleTemplate.getModuleDescription(); } void setEnabled(boolean enabled) { diff --git a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java index 9c814bfeb4..02ba4a7101 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java @@ -52,7 +52,7 @@ public final class RunIngestModulesDialog extends JDialog { private static final long serialVersionUID = 1L; private static final String TITLE = NbBundle.getMessage(RunIngestModulesDialog.class, "IngestDialog.title.text"); private final IngestType ingestType; - private static Dimension DIMENSIONS = new Dimension(500, 333); + private static Dimension DIMENSIONS = new Dimension(585, 400); private final List dataSources = new ArrayList<>(); private IngestJobSettingsPanel ingestJobSettingsPanel; From 117a6c4a69a5c830ed84ed6d00ae0d85eda82049 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Tue, 29 Mar 2016 14:26:24 -0400 Subject: [PATCH 23/50] UI adjustments to ingest modules panel. --- .../org/sleuthkit/autopsy/ingest/Bundle.properties | 2 +- .../autopsy/ingest/IngestJobSettingsPanel.form | 14 +++++++------- .../autopsy/ingest/IngestJobSettingsPanel.java | 10 +++++----- .../autopsy/ingest/RunIngestModulesDialog.java | 11 +++++------ 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties index c0c02a8664..89515a770f 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties @@ -118,4 +118,4 @@ IngestJobSettingsPanel.globalSettingsButton.text=Global Settings gest IngestJobSettingsPanel.globalSettingsButton.actionCommand=Advanced IngestJobSettingsPanel.globalSettingsButton.text=Global Settings -IngestJobSettingsPanel.descriptionLabel.text= +IngestJobSettingsPanel.descriptionLabel.text=kjkljklhg hjghj ghjg hjghjhjg hjghj ghj ghjg hjghgkjghghghjghjghhj gkjgkjhjhkjhkjhkjgkjghjgjhgkjgkgkjgkjhkjhkjghjfhjgkjghjgghgkjgkhg diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form index b87fc21384..b416767755 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form @@ -13,7 +13,7 @@ - + @@ -35,7 +35,7 @@ - + @@ -51,7 +51,7 @@ - + @@ -133,16 +133,16 @@ - + - - + + - + diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java index c2247b0ccc..7c3ea89ff4 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java @@ -152,7 +152,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { setMaximumSize(new java.awt.Dimension(5750, 3000)); setMinimumSize(new java.awt.Dimension(522, 257)); - setPreferredSize(new java.awt.Dimension(625, 400)); + setPreferredSize(new java.awt.Dimension(625, 450)); modulesScrollPane.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(160, 160, 160))); modulesScrollPane.setMinimumSize(new java.awt.Dimension(0, 0)); @@ -200,8 +200,8 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { .addGroup(jPanel1Layout.createSequentialGroup() .addContainerGap() .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(descriptionLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 307, Short.MAX_VALUE) + .addComponent(descriptionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 302, Short.MAX_VALUE) + .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() .addGap(0, 0, Short.MAX_VALUE) .addComponent(globalSettingsButton))) @@ -251,7 +251,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(modulesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 276, Short.MAX_VALUE) + .addComponent(modulesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 271, Short.MAX_VALUE) .addGap(10, 10, 10)) .addGroup(layout.createSequentialGroup() .addGap(24, 24, 24) @@ -262,7 +262,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { .addGap(18, 18, 18) .addComponent(jButtonDeselectAll))) .addGap(32, 32, 32))) - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 329, Short.MAX_VALUE) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 324, Short.MAX_VALUE) .addContainerGap()) ); layout.setVerticalGroup( diff --git a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java index 02ba4a7101..27ebd849c6 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java @@ -52,7 +52,6 @@ public final class RunIngestModulesDialog extends JDialog { private static final long serialVersionUID = 1L; private static final String TITLE = NbBundle.getMessage(RunIngestModulesDialog.class, "IngestDialog.title.text"); private final IngestType ingestType; - private static Dimension DIMENSIONS = new Dimension(585, 400); private final List dataSources = new ArrayList<>(); private IngestJobSettingsPanel ingestJobSettingsPanel; @@ -101,11 +100,7 @@ public final class RunIngestModulesDialog extends JDialog { /** * Center the dialog. */ - Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); - setSize(DIMENSIONS); - int width = this.getSize().width; - int height = this.getSize().height; - setLocation((screenDimension.width - width) / 2, (screenDimension.height - height) / 2); + Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();; /** * Get the default or saved ingest job settings for this context and use @@ -114,6 +109,7 @@ public final class RunIngestModulesDialog extends JDialog { IngestJobSettings ingestJobSettings = new IngestJobSettings(RunIngestModulesDialog.class.getCanonicalName(), this.ingestType); RunIngestModulesDialog.showWarnings(ingestJobSettings); this.ingestJobSettingsPanel = new IngestJobSettingsPanel(ingestJobSettings); + setPreferredSize(this.ingestJobSettingsPanel.getPreferredSize()); add(this.ingestJobSettingsPanel, BorderLayout.CENTER); // Add a start ingest button. @@ -158,6 +154,9 @@ public final class RunIngestModulesDialog extends JDialog { /** * Show the dialog. */ + int width = this.getPreferredSize().width; + int height = this.getPreferredSize().height; + setLocation((screenDimension.width - width) / 2, (screenDimension.height - height) / 2); pack(); setVisible(true); } From b3a787d1d28326bcb784d5963b7392de5a7c3741 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Tue, 29 Mar 2016 15:21:56 -0400 Subject: [PATCH 24/50] UI fixes to ingest form. --- .../AdvancedConfigurationCleanDialog.form | 4 ++++ .../org/sleuthkit/autopsy/ingest/Bundle.properties | 2 +- .../autopsy/ingest/IngestJobSettingsPanel.form | 6 +++--- .../autopsy/ingest/IngestJobSettingsPanel.java | 12 +++++++----- .../autopsy/ingest/RunIngestModulesDialog.java | 5 ++++- .../FileExtMismatchModuleSettingsPanel.form | 2 +- .../FileExtMismatchModuleSettingsPanel.java | 2 +- 7 files changed, 21 insertions(+), 12 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationCleanDialog.form b/Core/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationCleanDialog.form index 8c0236cde0..6e0df8373e 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationCleanDialog.form +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AdvancedConfigurationCleanDialog.form @@ -3,9 +3,13 @@
+ + + + diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties index 89515a770f..c0c02a8664 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties @@ -118,4 +118,4 @@ IngestJobSettingsPanel.globalSettingsButton.text=Global Settings gest IngestJobSettingsPanel.globalSettingsButton.actionCommand=Advanced IngestJobSettingsPanel.globalSettingsButton.text=Global Settings -IngestJobSettingsPanel.descriptionLabel.text=kjkljklhg hjghj ghjg hjghjhjg hjghj ghj ghjg hjghgkjghghghjghjghhj gkjgkjhjhkjhkjhkjgkjghjgjhgkjgkgkjgkjhkjhkjghjfhjgkjghjgghgkjgkhg +IngestJobSettingsPanel.descriptionLabel.text= diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form index b416767755..492db3d2d3 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form @@ -150,14 +150,14 @@ - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java index 7c3ea89ff4..db519b2d65 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java @@ -33,6 +33,7 @@ import javax.swing.event.ListSelectionListener; import javax.swing.table.AbstractTableModel; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableColumn; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.corecomponents.AdvancedConfigurationDialog; /** @@ -79,6 +80,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { return this.settings; } + @Messages({"IngestJobSettingsPanel.noPerRunSettings=No per run settings for the selected module."}) private void customizeComponents() { modulesTable.setModel(new IngestModulesTableModel()); modulesTable.setTableHeader(null); @@ -114,7 +116,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { ingestSettingsPanel.add(selectedModule.getModuleSettingsPanel()); } else { - ingestSettingsPanel.add(new JLabel("No per ingest settings for this module.")); + ingestSettingsPanel.add(new JLabel(Bundle.IngestJobSettingsPanel_noPerRunSettings())); } ingestSettingsPanel.revalidate(); ingestSettingsPanel.repaint(); @@ -200,7 +202,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { .addGroup(jPanel1Layout.createSequentialGroup() .addContainerGap() .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(descriptionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 302, Short.MAX_VALUE) + .addComponent(descriptionLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 302, Short.MAX_VALUE) .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() .addGap(0, 0, Short.MAX_VALUE) @@ -211,14 +213,14 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() .addContainerGap() - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 274, Short.MAX_VALUE) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 280, Short.MAX_VALUE) .addGap(18, 18, 18) .addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGap(8, 8, 8) .addComponent(descriptionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(globalSettingsButton) - .addContainerGap()) + .addGap(8, 8, 8)) ); jButtonSelectAll.setText(org.openide.util.NbBundle.getMessage(IngestJobSettingsPanel.class, "IngestJobSettingsPanel.jButtonSelectAll.text")); // NOI18N diff --git a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java index 27ebd849c6..84a48e44a8 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java @@ -26,6 +26,7 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; +import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.List; import javax.swing.BorderFactory; @@ -37,6 +38,7 @@ import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.border.EmptyBorder; import org.openide.util.NbBundle; +import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.ingest.IngestJobSettings.IngestType; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Directory; @@ -66,6 +68,7 @@ public final class RunIngestModulesDialog extends JDialog { */ public RunIngestModulesDialog(JFrame frame, String title, boolean modal, List dataSources) { super(frame, title, modal); + this.setIconImage(null); this.dataSources.addAll(dataSources); this.ingestType = IngestType.ALL_MODULES; } @@ -77,7 +80,7 @@ public final class RunIngestModulesDialog extends JDialog { * @param dataSources The data sources to be processed. */ public RunIngestModulesDialog(List dataSources) { - this(new JFrame(TITLE), TITLE, true, dataSources); + this((JFrame)WindowManager.getDefault().getMainWindow(), TITLE, true, dataSources); } /** diff --git a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchModuleSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchModuleSettingsPanel.form index 4974e318bd..878f2ca87b 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchModuleSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchModuleSettingsPanel.form @@ -23,7 +23,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchModuleSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchModuleSettingsPanel.java index 4ecde417ce..a59f445387 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchModuleSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/fileextmismatch/FileExtMismatchModuleSettingsPanel.java @@ -93,7 +93,7 @@ final class FileExtMismatchModuleSettingsPanel extends IngestModuleIngestJobSett .addComponent(skipTextPlain) .addComponent(skipNoExtCheckBox) .addComponent(skipKnownFiles)) - .addGap(0, 138, Short.MAX_VALUE)) + .addGap(0, 10, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) From 002a75d4865e9f994ba109e152565e1f27018b10 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Tue, 29 Mar 2016 16:41:39 -0400 Subject: [PATCH 25/50] Got expandable panel behavior working using dummy text. --- Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties | 2 +- .../sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form | 6 +++--- .../sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java | 8 ++++---- .../sleuthkit/autopsy/ingest/RunIngestModulesDialog.java | 3 +-- 4 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties index c0c02a8664..dccedb0917 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties @@ -118,4 +118,4 @@ IngestJobSettingsPanel.globalSettingsButton.text=Global Settings gest IngestJobSettingsPanel.globalSettingsButton.actionCommand=Advanced IngestJobSettingsPanel.globalSettingsButton.text=Global Settings -IngestJobSettingsPanel.descriptionLabel.text= +IngestJobSettingsPanel.descriptionLabel.text=dummmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy texxxxxxxxxxxxxxxttttttttttttttttttttttttttttttttttttttttttt diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form index 492db3d2d3..7298579aed 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.form @@ -10,7 +10,7 @@ - + @@ -72,7 +72,7 @@ - + @@ -150,7 +150,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java index db519b2d65..baf2dc37e3 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java @@ -153,7 +153,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { processUnallocCheckbox = new javax.swing.JCheckBox(); setMaximumSize(new java.awt.Dimension(5750, 3000)); - setMinimumSize(new java.awt.Dimension(522, 257)); + setMinimumSize(new java.awt.Dimension(0, 0)); setPreferredSize(new java.awt.Dimension(625, 450)); modulesScrollPane.setBorder(javax.swing.BorderFactory.createLineBorder(new java.awt.Color(160, 160, 160))); @@ -202,7 +202,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { .addGroup(jPanel1Layout.createSequentialGroup() .addContainerGap() .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(descriptionLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 302, Short.MAX_VALUE) + .addComponent(descriptionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 302, Short.MAX_VALUE) .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() .addGap(0, 0, Short.MAX_VALUE) @@ -213,7 +213,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() .addContainerGap() - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 280, Short.MAX_VALUE) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 330, Short.MAX_VALUE) .addGap(18, 18, 18) .addComponent(jSeparator2, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(8, 8, 8) @@ -281,7 +281,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(processUnallocCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 378, Short.MAX_VALUE) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, 428, Short.MAX_VALUE) .addContainerGap()))) ); }// //GEN-END:initComponents diff --git a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java index 84a48e44a8..0cf8aac221 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/RunIngestModulesDialog.java @@ -68,7 +68,6 @@ public final class RunIngestModulesDialog extends JDialog { */ public RunIngestModulesDialog(JFrame frame, String title, boolean modal, List dataSources) { super(frame, title, modal); - this.setIconImage(null); this.dataSources.addAll(dataSources); this.ingestType = IngestType.ALL_MODULES; } @@ -80,7 +79,7 @@ public final class RunIngestModulesDialog extends JDialog { * @param dataSources The data sources to be processed. */ public RunIngestModulesDialog(List dataSources) { - this((JFrame)WindowManager.getDefault().getMainWindow(), TITLE, true, dataSources); + this((JFrame) WindowManager.getDefault().getMainWindow(), TITLE, true, dataSources); } /** From f8dba2294d240bc75525dd236b0af51fe84fee41 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Wed, 30 Mar 2016 11:29:14 -0400 Subject: [PATCH 26/50] Changed label for when there are no settings. --- .../org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java index baf2dc37e3..f947c28359 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestJobSettingsPanel.java @@ -80,7 +80,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { return this.settings; } - @Messages({"IngestJobSettingsPanel.noPerRunSettings=No per run settings for the selected module."}) + @Messages({"IngestJobSettingsPanel.noPerRunSettings=The selected module has no per-run settings."}) private void customizeComponents() { modulesTable.setModel(new IngestModulesTableModel()); modulesTable.setTableHeader(null); @@ -114,8 +114,7 @@ public final class IngestJobSettingsPanel extends javax.swing.JPanel { ingestSettingsPanel.removeAll(); if (null != selectedModule.getModuleSettingsPanel()) { ingestSettingsPanel.add(selectedModule.getModuleSettingsPanel()); - } - else { + } else { ingestSettingsPanel.add(new JLabel(Bundle.IngestJobSettingsPanel_noPerRunSettings())); } ingestSettingsPanel.revalidate(); From ee7c501e67610a2b5c1a8cc5cf10c3b781c59d05 Mon Sep 17 00:00:00 2001 From: Karl Mortensen Date: Thu, 31 Mar 2016 11:11:48 -0400 Subject: [PATCH 27/50] Update some screenshots for Doxygen documentation relating to Ingest Settings --- ...sion-mismatch-detected-ingest-settings.PNG | Bin 20658 -> 48865 bytes docs/doxygen-user/images/hash-lookup.PNG | Bin 48858 -> 52212 bytes .../interesting_files_ingest_settings.PNG | Bin 21245 -> 49000 bytes .../images/keyword-search-ingest-settings.PNG | Bin 38705 -> 53486 bytes .../images/select-ingest-modules.PNG | Bin 44780 -> 41420 bytes 5 files changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/doxygen-user/images/extension-mismatch-detected-ingest-settings.PNG b/docs/doxygen-user/images/extension-mismatch-detected-ingest-settings.PNG index 3a40a5c3404b2967147ca0d1e40074093681cc8c..fba9b2f45f4406eaaf384ba03d192224cc70c456 100755 GIT binary patch literal 48865 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

9#rcW&j!Om*)T>cg6N%qt`WV?THJ=uWDe<@ zRlp?|TakySV!^4wJa^~w7x?W5s;_|G^KJEXibIu^CAl`tn6fMlt`?KK^_7i?+}3Bw zJwfRyq@2r^rEeJ!$QF6nGI4>@4rbCy34CF^sv86{4Ie+GHAqJ>>rS~cN4&0$e{ez? zIg8NMUT~(m!=G0uKLd*>-{z1Y?_9W6SCgl{jcch1%^2t3O#PC-`6{FSTG_7H)t1?@{VtG2*nc56+GlsZ_vJkZjPuJIFz=1>}NcA8wLNUXl0j z(&6MJR-O6dq4$Q{6ziJjALld^2wL3s?QDGlz5s)${_3_Vdb_r^;_z%^)T?P3lkXfqhF|Hu&ba@(8b+>Exf zVz-nwHKhZdK#a!gdT~-SAwl8r!k}e@Aq{Iab;j$w-B%bQc$MFx-OmucH9v2&v9UW- z>DIDXGeCWHef{3|(!6r)?^YV`07JBd!TWa=-f^BybrXtkPyjFsZ#jI=M~g*oCWJRO zwCE^HPcLs6mwmT}{&EAC3wxalozI#o7fv4j9byQq(k<`m>KYR|RkXG)wV7a=It$(y zSW-$pscgg;SutoVkdPnS2E< z6dMGA>@eR^-iLRY7r8%hekht{b(pbYkg8|~4sO9NcM{a5*on|8#>I~O@PQ=yvxvao zrd++(*MGmb(GQTLM!ZEFxHbvZN$oEJqQJkkLj9+)9~Qu;JlZ<4nf(bNC9(z^7z{R7 zW4!Upi-N21OD+?k^7H7~i|;uzl)_UKNX=AB5i_T78SLQZm*w*(aj!CUwPv|LD(k#9 z+nugIJ0KwAEptdaBjQbttJ@-rP2OydsPP~L#QyEf$Ruh~QFaGyd(#>rlcVX=F+|qB?NY`&>&1VaJGj%PCtBy51 zcsAGtDg3EF`dSJX5?sW=QD5F3#8&W>oP;`45xux{uxe^=8JendR7yYTE!AsD9Bg(= zeMh)IaoqP|$;-sUgJC)<*A5tmp@^I^o97 z^dW<2MYA|#y1Q@76g=h2o@(Uxk#7xuo_i5BoSmPaot?RIx3@Lz(?*Y157phy#jRvC zj8yWu)!8@iH;8(9j*qGJ!tu1+~H54d~`q&lk2KQi( zK$qLppT4k>wrTP+-twZLWmO{-a2%wMIpS$S4Ox?IVdvy4_CH|1+Rc-h)@XJkwT?*N zZ*v&-vL6Y^SPOlw6*1U*Re|Spd>U!dLm_lxNaa=Q$_QNYE%irP3fp1z8kd(o?>Q?k zE$C54v=VvewoTSvzq0F~7TcLk@$45>YPFaoa__YOSXFzb>pcU4jlic6yH?ob4_r<8 zS>U&EXZ^G1fp?|3xkJ1S8TX@ZqOX3OZjGg3`_(o~uN_aZ-|uo+`ra;c=UnS~>5ci- zx?aX=?cXM*QR4X6NO0ecXJj0By+3omTa8BG%%!5Her&=L!1p3-QEsSlZDRk-L%C$B z&%>_1RsEDTpsLGj3h7WsvR>>ss1|>hE~C^uM;YaF_~OsYRKew6mr=pBA{hy%(H1?n zb5+RKJz^7c=TkG`MqjhC{S5;i8)nda2#D9?fjm6wuuX+ti;K0SC8_1@ho2Q~{@MO9 zN!V^b?5FnbS3Lj{Hq=;(t>@8B^4?_*xHnm*L06|#zMf~tTYd~BIFl2M_qUzF?6AMW zH|hzeb_V?gLqky~vq2I>en)+ngj2T{r8`}d-CI5k;q^Z!Bz6VPKbdD3*_T%w%(_b* zJD#}dwwiqt93wGq0MNOQ9{pBrvx4c^3VvIYuHiBlPETJILpbRNrF-RNlvXT(#yCqp z1HLgYg}R7i64z?pQQj2Jmhc~|_2R-&HJ2sZGs{fRJKH(-pe}pc`^o;(^syPyvkOeB zftUQLqpp6e@}%4r);_nLeRRv)d#zQwku^NFP6w9CW?8wn&Y~OrJZxlXLV>p)u2wM? zHXd=?Q!Br9<_}ycKe`;&xi|l%RLHsdlJmIn14E{5!x^}b&Jyjxkb#UWwD(WCG+y`k zGP7R^$f=(O4hbI+uo%>AbblJ^qI_5D?K1g`lNUp^GEb+fV9sU70b3Fz&FP_NkIPyI z&i8WlwWk=1Yi~bY&S*T6>ylXUC-MvsU0ynpTlac%XuLMHZ%}``mHkS3RB88a0}&GP z+^~_UKujV#^1kto@%`n9y~xd0=%%^TZ&hiP*Ga|&jUSk@#^(jxkL0v(cL)te9?ab8Ba?im&Sxz*9 zM@lha&#l^R#jX1BBa99ezvBbGY44G+_B+`!t=-)|zng^DOKiKOZ(R2P;?uEwg(S1Z zx0_>`%k%T{k<`1S!Od+|`s#h7YndG7qXrI&)%v>IH|)G4uUaU*WboJ?JzD4SeFq95 zcUUZzC46Bi7$ZKIkWKSk%s0-OC6PRFd3DT$4oF&vsjW`l>N<5O!o!EH)_-or>ywZ= zJzD2$YA_ivuC_Q?_%$Ns7lf1fz~?M!l4-%s+JyBep6@_7=IX9QEPwcKNeZKu`nCEiaFD_1~Q?FD)rSDxq>h zAV9BLWmIge{d^si7l!{|hh=_GMc!P~DbP0)LLo+^JwXkyW8gP_SrVog4Yh|4z~^k( znVFma9^|!rd636@`SSUb$2xpr6BBBMlT99{7XQ=1Ab41OfJel@D~^)~jA^yq*4RG_#EH|zh;C5i#>dCHt;m%L9$K3a|q z2tIuOC;ULybp~i?Z=Wf=E6FZy9%T0;y1xCpe7`sN$%Z$DHBn6gz|MWX2#oW@xk^F^ z-ETWKO_dQ{KRKF_e50X0?W{3>9DG5TQ_RTzWIf7v&Gbx)40OG616oBrhIKdOyEoEC ztDeXYZ`zsJJg%6OSYNd6vFt~){*HEv#)p4(FZc=z<%zfsUyA-{g!xcnN)qeWj|@3S74;hC#u7)hQlfyC@Z8g|Mglv$Ck6;MqMRL{O(9#R6k(t?Jz&6HC7 z!NP~}jPN!MmADaBMUQD7yyOYzf&@t1R-STm$hj9J6#b<8$S z8J_qEDd%Mxj_DxZs@|1(aF3&;NrjgX@Ow8DcQNl7X9W}Hs^hWgChCH(Q#B8)AnsPG zCQIlrKErtsuU~G$a?pa%iF-G7VBP40K;iJxpV72tvL|x1clTRNEhA2Dlk#I_X%Qu# zl}p<1=1X1EG_i&-z7kz7j1wP1JvF1#4W?7_vNYmrTKmpT^d3!cvL7((VrgpR1`7tr!Ng}3K1*W2*k=z(rchk?vJy@a_HMX(eqXjpkAy3ViekDy=M4Az>8oe*n}tKKTFu literal 48858 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

eoo`elGM37#KdfBSY>9`?|Lv=< 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 diff --git a/docs/doxygen-user/images/interesting_files_ingest_settings.PNG b/docs/doxygen-user/images/interesting_files_ingest_settings.PNG index 61f78c7e26091ea39b9295ea2177431cea4dd05c..b6277a684bacb93f170ee0b7ee37d67e77f7edc7 100755 GIT binary patch literal 49000 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 YenTjIeo@=X{qR?)%sc54N#mgZ0q6@k761SM literal 21245 zcmb5WbySpH*9VM94<+GHf;55*2uMiD(47JzsdP&>5(84wE!~KK64EK%B@NQuLk{s> zp!f5<_q*QjTkHFSHC{94oNMoW_WteP-sdcXloTX!u*k5GkdSbsrNmT_kdR*^A>FgX zKnA{%Ce?HSKJMA8NJ5c{`zbbn2NV+#c@ZR}Z{eUz161G{(^l%WJrWXb>+RpY4x4;K zBqWt6X)zHs7u}tD_i~+ADSNJ)0}b!sRGuB{yF-E!jyijfetapcRik9s{Mw)**j
^y55;dPzWVsGtx< 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 diff --git a/docs/doxygen-user/images/keyword-search-ingest-settings.PNG b/docs/doxygen-user/images/keyword-search-ingest-settings.PNG index a393e24c8df372ec84808d17ece009ff534aa317..dcc7cf6028bf17b8d42d22d2ad3040129bcfd2a1 100755 GIT binary patch literal 53486 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 literal 38705 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

    LK4;FqTs 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 X@b3pt^4$IhF04FV{an^LB{Ts5ZVj)Q literal 44780 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 From d4e77f6687732ba7cf1729c575f5bbcd6826f2c0 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Thu, 31 Mar 2016 11:27:52 -0400 Subject: [PATCH 28/50] Fixed log to show complete stack trace. --- Core/src/org/sleuthkit/autopsy/coreutils/Logger.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/Logger.java b/Core/src/org/sleuthkit/autopsy/coreutils/Logger.java index dd2508a15d..d7e15168a5 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/Logger.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/Logger.java @@ -90,17 +90,21 @@ public final class Logger extends java.util.logging.Logger { fileHandler.setFormatter(new Formatter() { @Override public String format(LogRecord record) { - if (record.getThrown() != null) { + Throwable thrown = record.getThrown(); + if (thrown != null) { String stackTrace = ""; //NON-NLS - for (StackTraceElement traceElem : record.getThrown().getStackTrace()) { - stackTrace += "\t" + traceElem.toString() + "\n"; //NON-NLS + while (thrown != null) { + stackTrace += thrown.toString() + "\n"; + for (StackTraceElement traceElem : record.getThrown().getStackTrace()) { + stackTrace += "\t" + traceElem.toString() + "\n"; //NON-NLS + } + thrown = thrown.getCause(); } return (new Timestamp(record.getMillis())).toString() + " " //NON-NLS + record.getSourceClassName() + " " //NON-NLS + record.getSourceMethodName() + "\n" //NON-NLS + record.getLevel() + ": " //NON-NLS + this.formatMessage(record) + "\n" //NON-NLS - + record.getThrown().toString() + ":\n" //NON-NLS + stackTrace + "\n"; //NON-NLS } else { From 4a2deb683c5918cd68788e4197ec58eec1ed965a Mon Sep 17 00:00:00 2001 From: Karl Mortensen Date: Thu, 31 Mar 2016 11:44:09 -0400 Subject: [PATCH 29/50] update version numbers --- .../org/sleuthkit/autopsy/corecomponents/Bundle.properties | 2 +- .../core/core.jar/org/netbeans/core/startup/Bundle.properties | 2 +- .../org/netbeans/core/windows/view/ui/Bundle.properties | 2 +- docs/doxygen-user/Doxyfile | 4 ++-- docs/doxygen-user/main.dox | 2 +- docs/doxygen/Doxyfile | 4 ++-- nbproject/project.properties | 4 ++-- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties index a0aeb51314..f05e555931 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties @@ -27,7 +27,7 @@ Format_OperatingSystem_Value={0} version {1} running on {2} LBL_Copyright= URL_ON_IMG=http://www.sleuthkit.org/ -URL_ON_HELP=http://sleuthkit.org/autopsy/docs/user-docs/4.0/ +URL_ON_HELP=http://sleuthkit.org/autopsy/docs/user-docs/4.1/ FILE_FOR_LOCAL_HELP=file:/// INDEX_FOR_LOCAL_HELP=/docs/index.html diff --git a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties index 387cfb83e3..098c9e52c1 100644 --- a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties +++ b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties @@ -1,5 +1,5 @@ #Updated by build script -#Mon, 22 Feb 2016 16:37:47 -0500 +#Thu, 31 Mar 2016 11:20:09 -0400 LBL_splash_window_title=Starting Autopsy SPLASH_HEIGHT=314 SPLASH_WIDTH=538 diff --git a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties index eac00c4b67..5601dc0849 100644 --- a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties +++ b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties @@ -1,4 +1,4 @@ #Updated by build script -#Mon, 22 Feb 2016 16:37:47 -0500 +#Thu, 31 Mar 2016 11:20:09 -0400 CTL_MainWindow_Title=Autopsy 4.1.0 CTL_MainWindow_Title_No_Project=Autopsy 4.1.0 diff --git a/docs/doxygen-user/Doxyfile b/docs/doxygen-user/Doxyfile index 6a2a3f14e8..d86bbf0ac2 100755 --- a/docs/doxygen-user/Doxyfile +++ b/docs/doxygen-user/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "Autopsy User Documentation" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 4.0 +PROJECT_NUMBER = 4.1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -1025,7 +1025,7 @@ GENERATE_HTML = YES # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_OUTPUT = 4.0 +HTML_OUTPUT = 4.1 # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). diff --git a/docs/doxygen-user/main.dox b/docs/doxygen-user/main.dox index a95705d20e..067b672d64 100644 --- a/docs/doxygen-user/main.dox +++ b/docs/doxygen-user/main.dox @@ -4,7 +4,7 @@ Overview ----- -This is the User's Guide for the open source Autopsy platform. Autopsy allows you to examine a hard drive or mobile device and recover evidence from it. This guide should help you with using Autopsy. The developer's guide will help you develop your own Autopsy modules. +This is the User's Guide for the open source Autopsy platform. Autopsy allows you to examine a hard drive or mobile device and recover evidence from it. This guide should help you with using Autopsy. The developer's guide will help you develop your own Autopsy modules. Autopsy 4 (and 3) are a complete rewrite from Autopsy 2, and none of this document is relevant to Autopsy 2. diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index 8874eff27f..f6fb7a7038 100755 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "Autopsy" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 4.0 +PROJECT_NUMBER = 4.1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -1063,7 +1063,7 @@ GENERATE_HTML = YES # The default directory is: html. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_OUTPUT = api-docs/4.0/ +HTML_OUTPUT = api-docs/4.1/ # The HTML_FILE_EXTENSION tag can be used to specify the file extension for each # generated HTML page (for example: .htm, .php, .asp). diff --git a/nbproject/project.properties b/nbproject/project.properties index 8d6bea269f..1d62c7e5ca 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -6,8 +6,8 @@ app.name=${branding.token} ### if left unset, version will default to today's date app.version=4.1.0 ### build.type must be one of: DEVELOPMENT, RELEASE -#build.type=RELEASE -build.type=DEVELOPMENT +build.type=RELEASE +#build.type=DEVELOPMENT project.org.sleuthkit.autopsy.imagegallery=ImageGallery update_versions=false From c9b5a42df2aa72e731c14fa9059dabf69ed96c8e Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Thu, 31 Mar 2016 13:27:30 -0400 Subject: [PATCH 30/50] Updated syntax for displaying errors. --- .../sleuthkit/autopsy/coreutils/Logger.java | 33 +++++++------------ 1 file changed, 12 insertions(+), 21 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/Logger.java b/Core/src/org/sleuthkit/autopsy/coreutils/Logger.java index d7e15168a5..16fde58e29 100644 --- a/Core/src/org/sleuthkit/autopsy/coreutils/Logger.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/Logger.java @@ -91,29 +91,20 @@ public final class Logger extends java.util.logging.Logger { @Override public String format(LogRecord record) { Throwable thrown = record.getThrown(); - if (thrown != null) { - String stackTrace = ""; //NON-NLS - while (thrown != null) { - stackTrace += thrown.toString() + "\n"; - for (StackTraceElement traceElem : record.getThrown().getStackTrace()) { - stackTrace += "\t" + traceElem.toString() + "\n"; //NON-NLS - } - thrown = thrown.getCause(); + String stackTrace = ""; //NON-NLS + while (thrown != null) { + stackTrace += thrown.toString() + "\n"; + for (StackTraceElement traceElem : record.getThrown().getStackTrace()) { + stackTrace += "\t" + traceElem.toString() + "\n"; //NON-NLS } - return (new Timestamp(record.getMillis())).toString() + " " //NON-NLS - + record.getSourceClassName() + " " //NON-NLS - + record.getSourceMethodName() + "\n" //NON-NLS - + record.getLevel() + ": " //NON-NLS - + this.formatMessage(record) + "\n" //NON-NLS - + stackTrace - + "\n"; //NON-NLS - } else { - return (new Timestamp(record.getMillis())).toString() + " " //NON-NLS - + record.getSourceClassName() + " " //NON-NLS - + record.getSourceMethodName() + "\n" //NON-NLS - + record.getLevel() + ": " //NON-NLS - + this.formatMessage(record) + "\n"; //NON-NLS + thrown = thrown.getCause(); } + return (new Timestamp(record.getMillis())).toString() + " " //NON-NLS + + record.getSourceClassName() + " " //NON-NLS + + record.getSourceMethodName() + "\n" //NON-NLS + + record.getLevel() + ": " //NON-NLS + + this.formatMessage(record) + "\n" //NON-NLS + + stackTrace; } }); return fileHandler; From f43e250381da0a20fa3c74039a1a8eb6b1c78325 Mon Sep 17 00:00:00 2001 From: jmillman Date: Thu, 31 Mar 2016 13:42:24 -0400 Subject: [PATCH 31/50] cleanup and internationalize ThumbnailViewNode --- .../autopsy/corecomponents/ThumbnailViewNode.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewNode.java b/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewNode.java index 5ac5b95c67..1d58764315 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewNode.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/ThumbnailViewNode.java @@ -26,10 +26,12 @@ import java.util.concurrent.ExecutionException; import java.util.logging.Level; import javax.swing.SwingWorker; import javax.swing.Timer; +import org.apache.commons.lang3.StringUtils; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; import org.openide.nodes.FilterNode; import org.openide.nodes.Node; +import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.Content; @@ -58,14 +60,12 @@ class ThumbnailViewNode extends FilterNode { @Override public String getDisplayName() { - if (super.getDisplayName().length() > 15) { - return super.getDisplayName().substring(0, 15).concat("..."); - } else { - return super.getDisplayName(); - } + return StringUtils.abbreviate(super.getDisplayName(), 18); } @Override + @NbBundle.Messages({"# {0} - file name", + "ThumbnailViewNode.progressHandle.text=Generating thumbnail for {0}"}) public Image getIcon(int type) { Image icon = null; @@ -82,7 +82,7 @@ class ThumbnailViewNode extends FilterNode { } if (swingWorker == null || swingWorker.isDone()) { swingWorker = new SwingWorker() { - final private ProgressHandle progressHandle = ProgressHandleFactory.createHandle("generating thumbnail for video file " + content.getName()); + final private ProgressHandle progressHandle = ProgressHandleFactory.createHandle(Bundle.ThumbnailViewNode_progressHandle_text(content.getName())); @Override protected Image doInBackground() throws Exception { @@ -97,7 +97,7 @@ class ThumbnailViewNode extends FilterNode { iconCache = new SoftReference<>(super.get()); fireIconChange(); } catch (InterruptedException | ExecutionException ex) { - Logger.getLogger(ThumbnailViewNode.class.getName()).log(Level.SEVERE, "Error getting thumbnail icon", ex); //NON-NLS + Logger.getLogger(ThumbnailViewNode.class.getName()).log(Level.SEVERE, "Error getting thumbnail icon for " + content.getName(), ex); //NON-NLS } finally { progressHandle.finish(); if (timer != null) { From 6ef9c2b3c694852085551cabf72f4418ccbe45cb Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Thu, 31 Mar 2016 14:10:26 -0400 Subject: [PATCH 32/50] Made hash settings panel support expanding better. --- .../HashLookupModuleSettingsPanel.form | 19 ++++++++----------- .../HashLookupModuleSettingsPanel.java | 14 +++++++------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.form index 0a88eb5dc8..5fd29f9482 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.form @@ -26,7 +26,7 @@ - + @@ -47,15 +47,15 @@ - - - + + + + + - - - - + + @@ -120,9 +120,6 @@ - - - diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java index 32de8e6bf5..00eb729aad 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java @@ -321,7 +321,7 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(knownHashDbsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 272, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, Short.MAX_VALUE)) + .addGap(0, 18, Short.MAX_VALUE)) .addComponent(knownBadHashDbsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() .addGap(10, 10, 10) @@ -337,14 +337,14 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe .addGap(2, 2, 2) .addComponent(knownHashDbsLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 58, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 54, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(knownBadHashDbsLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 58, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(alwaysCalcHashesCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 35, javax.swing.GroupLayout.PREFERRED_SIZE) - .addContainerGap()) + .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 53, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(alwaysCalcHashesCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 27, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(0, 0, 0)) ); }// //GEN-END:initComponents From 6d2c46593266dc99b88bc37480a1830f96a62632 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 31 Mar 2016 14:58:15 -0400 Subject: [PATCH 33/50] Remove code to search InternalPythonModules from python/JythonModuleLoader --- .../autopsy/python/JythonModuleLoader.java | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/python/JythonModuleLoader.java b/Core/src/org/sleuthkit/autopsy/python/JythonModuleLoader.java index c9175f3754..e2ed871a11 100755 --- a/Core/src/org/sleuthkit/autopsy/python/JythonModuleLoader.java +++ b/Core/src/org/sleuthkit/autopsy/python/JythonModuleLoader.java @@ -68,19 +68,11 @@ public final class JythonModuleLoader { } private static List getInterfaceImplementations(LineFilter filter, Class interfaceClass) { - List objects = new ArrayList<>(); - Set pythonModuleDirs = new HashSet<>(); PythonInterpreter interpreter = new PythonInterpreter(); - - // add python modules from 'autospy/build/cluster/InternalPythonModules' folder - // which are copied from 'autopsy/*/release/InternalPythonModules' folders. - for (File f : InstalledFileLocator.getDefault().locateAll("InternalPythonModules", JythonModuleLoader.class.getPackage().getName(), false)) { //NON-NLS - Collections.addAll(pythonModuleDirs, f.listFiles()); - } - // add python modules from 'testuserdir/python_modules' folder - Collections.addAll(pythonModuleDirs, new File(PlatformUtil.getUserPythonModulesPath()).listFiles()); - - for (File file : pythonModuleDirs) { + List objects = new ArrayList<>(); + File pythonModulesDir = new File(PlatformUtil.getUserPythonModulesPath()); + File[] files = pythonModulesDir.listFiles(); + for (File file : files) { if (file.isDirectory()) { File[] pythonScripts = file.listFiles(new PythonScriptFileFilter()); for (File script : pythonScripts) { From ef501a61f26ba66c06a90cddfcc41d45e012c344 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 31 Mar 2016 16:48:31 -0400 Subject: [PATCH 34/50] Revert "Remove code to search InternalPythonModules from python/JythonModuleLoader" This reverts commit 6d2c46593266dc99b88bc37480a1830f96a62632. --- .../autopsy/python/JythonModuleLoader.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/python/JythonModuleLoader.java b/Core/src/org/sleuthkit/autopsy/python/JythonModuleLoader.java index e2ed871a11..c9175f3754 100755 --- a/Core/src/org/sleuthkit/autopsy/python/JythonModuleLoader.java +++ b/Core/src/org/sleuthkit/autopsy/python/JythonModuleLoader.java @@ -68,11 +68,19 @@ public final class JythonModuleLoader { } private static List getInterfaceImplementations(LineFilter filter, Class interfaceClass) { - PythonInterpreter interpreter = new PythonInterpreter(); List objects = new ArrayList<>(); - File pythonModulesDir = new File(PlatformUtil.getUserPythonModulesPath()); - File[] files = pythonModulesDir.listFiles(); - for (File file : files) { + Set pythonModuleDirs = new HashSet<>(); + PythonInterpreter interpreter = new PythonInterpreter(); + + // add python modules from 'autospy/build/cluster/InternalPythonModules' folder + // which are copied from 'autopsy/*/release/InternalPythonModules' folders. + for (File f : InstalledFileLocator.getDefault().locateAll("InternalPythonModules", JythonModuleLoader.class.getPackage().getName(), false)) { //NON-NLS + Collections.addAll(pythonModuleDirs, f.listFiles()); + } + // add python modules from 'testuserdir/python_modules' folder + Collections.addAll(pythonModuleDirs, new File(PlatformUtil.getUserPythonModulesPath()).listFiles()); + + for (File file : pythonModuleDirs) { if (file.isDirectory()) { File[] pythonScripts = file.listFiles(new PythonScriptFileFilter()); for (File script : pythonScripts) { From 82d19917a00b68748f534d08b21ca30f8f9ac318 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 31 Mar 2016 19:32:08 -0400 Subject: [PATCH 35/50] Improve custom blackboard types API of casemodule/services/Blackboard --- .../casemodule/services/Blackboard.java | 95 +++++++++++-------- 1 file changed, 55 insertions(+), 40 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Blackboard.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/Blackboard.java index 72378e7c88..b5bfdea5be 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Blackboard.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Blackboard.java @@ -1,7 +1,7 @@ /* * Sleuth Kit Data Model * - * Copyright 2011-2015 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.casemodule.services; import java.io.Closeable; import java.io.IOException; import org.openide.util.Lookup; -import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.keywordsearchservice.KeywordSearchService; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -30,87 +29,102 @@ import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskDataException; /** - * Provides utility methods for blackboard artifact indexing. + * Represents the blackboard, a place where artifacts and their attributes are + * posted. + * + * NOTE: This API of this class is under development. */ public final class Blackboard implements Closeable { /** - * Index the text associated with the given artifact. + * Indexes the text associated with the an artifact. * * @param artifact The artifact to be indexed. * - * @throws - * org.sleuthkit.autopsy.casemodule.services.Blackboard.BlackboardException + * @throws BlackboardException If there is a problem indexing the artifact. */ public void indexArtifact(BlackboardArtifact artifact) throws BlackboardException { KeywordSearchService searchService = Lookup.getDefault().lookup(KeywordSearchService.class); if (null == searchService) { - throw new BlackboardException(NbBundle.getMessage(this.getClass(), "Blackboard.keywordSearchNotFound.exception.msg")); + throw new BlackboardException("Keyword search service not found"); } - try { searchService.indexArtifact(artifact); } catch (TskCoreException ex) { - throw new BlackboardException(NbBundle.getMessage(this.getClass(), "Blackboard.unableToIndexArtifact.exception.msg"), ex); + throw new BlackboardException("Error indexing artifact", ex); } } /** - * Adds a new artifact type based upon the parameters given + * Gets an artifact type, creating it if it does not already exist. Use this + * method to define custom artifact types. * - * @param typeName The name of the new artifact type - * @param displayName The name displayed for the new attribute type - * @return A type object representing the artifact type added - * @throws - * org.sleuthkit.autopsy.casemodule.services.Blackboard.BlackboardException + * @param typeName The type name of the artifact type. + * @param displayName The display name of the artifact type. + * + * @return A type object representing the artifact type. + * + * @throws BlackboardBlackboardException If there is a problem getting or + * adding the artifact type. */ - public BlackboardArtifact.Type addArtifactType(String typeName, String displayName) throws BlackboardException { + public BlackboardArtifact.Type getOrAddArtifactType(String typeName, String displayName) throws BlackboardException { try { return Case.getCurrentCase().getSleuthkitCase().addBlackboardArtifactType(typeName, displayName); - } catch (TskCoreException | TskDataException ex) { - throw new BlackboardException("New artifact type could not be added", ex); + } catch (TskDataException typeExistsEx) { + try { + return Case.getCurrentCase().getSleuthkitCase().getArtifactType(typeName); + } catch (TskCoreException ex) { + throw new BlackboardException("Failed to get or add artifact type", ex); + } + } catch (TskCoreException ex) { + throw new BlackboardException("Failed to get or add artifact type", ex); } } /** - * Adds a new attribute type based upon the parameters given + * Gets an attribute type, creating it if it does not already exist. Use + * this method to define custom attribute types. * - * @param attrTypeString The type name of the attribute type - * @param valueType The type of any attribute of this type's value - * @param displayName The name displayed for the new attribute type - * @throws - * org.sleuthkit.autopsy.casemodule.services.Blackboard.BlackboardException + * @param typeName The type name of the attribute type. + * @param valueType The value type of the attribute type. + * @param displayName The display name of the attribute type. + * + * @return A type object representing the attribute type. + * + * @throws BlackboardBlackboardException If there is a problem getting or + * adding the attribute type. */ - public BlackboardAttribute.Type addAttributeType(String attrTypeString, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName) throws BlackboardException { + public BlackboardAttribute.Type addAttributeType(String typeName, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName) throws BlackboardException { try { - return Case.getCurrentCase().getSleuthkitCase().addArtifactAttributeType(attrTypeString, valueType, displayName); - } catch (TskDataException ex) { - throw new BlackboardException("New attribute type could not be added", ex); + return Case.getCurrentCase().getSleuthkitCase().addArtifactAttributeType(typeName, valueType, displayName); + } catch (TskDataException typeExistsEx) { + try { + return Case.getCurrentCase().getSleuthkitCase().getAttributeType(typeName); + } catch (TskCoreException ex) { + throw new BlackboardException("Failed to get or add attribute type", ex); + } } catch (TskCoreException ex) { - throw new BlackboardException("New attribute type could not be added", ex); + throw new BlackboardException("Failed to get or add attribute type", ex); } } + /** + * Cloese this blackboard and releases any resources associated with it. + * @throws IOException + */ @Override public void close() throws IOException { } /** - * Provides a system exception for the Keyword Search package. + * A blackboard exception. */ public static final class BlackboardException extends Exception { private static final long serialVersionUID = 1L; /** - * Constructs a new exception with null as its message. - */ - public BlackboardException() { - super(); - } - - /** - * Constructs a new exception with the specified message. + * Constructs a blackboard exception with the specified message. * * @param message The message. */ @@ -119,10 +133,11 @@ public final class Blackboard implements Closeable { } /** - * Constructs a new exception with the specified message and cause. + * Constructs a blackboard exception with the specified message and + * cause. * * @param message The message. - * @param cause The cause. + * @param cause The cause. */ public BlackboardException(String message, Throwable cause) { super(message, cause); From 1062cb6d1fa1505ec3f41352966f57657509d0d4 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 31 Mar 2016 19:33:08 -0400 Subject: [PATCH 36/50] Improve custom blackboard types API of casemodule/services/Blackboard --- .../org/sleuthkit/autopsy/casemodule/services/Blackboard.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Blackboard.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/Blackboard.java index b5bfdea5be..d5064e3b4e 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Blackboard.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Blackboard.java @@ -94,7 +94,7 @@ public final class Blackboard implements Closeable { * @throws BlackboardBlackboardException If there is a problem getting or * adding the attribute type. */ - public BlackboardAttribute.Type addAttributeType(String typeName, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName) throws BlackboardException { + public BlackboardAttribute.Type getOrAddAttributeType(String typeName, BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE valueType, String displayName) throws BlackboardException { try { return Case.getCurrentCase().getSleuthkitCase().addArtifactAttributeType(typeName, valueType, displayName); } catch (TskDataException typeExistsEx) { From 3ac31e455cf5fd74c3107bcc215abf2d53113427 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 31 Mar 2016 20:21:15 -0400 Subject: [PATCH 37/50] Improve custom blackboard types API of casemodule/services/Blackboard --- .../casemodule/services/Bundle.properties | 2 - .../casemodule/services/Bundle_ja.properties | 44 +++++++++---------- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties index 2d75572fd9..9353ca914b 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties @@ -19,6 +19,4 @@ TagsManager.addContentTag.noCaseWarning=Failed to publish new content tag event. TagsManager.deleteContentTag.noCaseWarning=Failed to publish content tag deleted event. There is no case open. TagsManager.addBlackboardArtifactTag.noCaseWarning=Failed to publish new blackboard artifact tag event. There is no case open. TagsManager.deleteBlackboardArtifactTag.noCaseWarning=Failed to publish blackboard artifact tag deleted event. There is no case open. -Blackboard.keywordSearchNotFound.exception.msg=Keyword search service not found. -Blackboard.unableToIndexArtifact.exception.msg=Unable to index blackboard artifact Blackboard.unableToIndexArtifact.error.msg=Unable to index blackboard artifact {0} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle_ja.properties index 186fa5f8b4..956a5e6169 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle_ja.properties @@ -1,24 +1,22 @@ -FileManager.findFiles.exception.msg=FileManager\u3092\u9589\u3058\u305F\u5F8C\u306B\u4F7F\u7528\u3092\u8A66\u307F\u307E\u3057\u305F\u3002 -FileManager.findFiles2.exception.msg=FileManager\u3092\u9589\u3058\u305F\u5F8C\u306B\u4F7F\u7528\u3092\u8A66\u307F\u307E\u3057\u305F\u3002 -FileManager.findFiles3.exception.msg=FileManager\u3092\u9589\u3058\u305F\u5F8C\u306B\u4F7F\u7528\u3092\u8A66\u307F\u307E\u3057\u305F\u3002 -FileManager.openFiles.exception.msg=FileManager\u3092\u9589\u3058\u305F\u5F8C\u306B\u4F7F\u7528\u3092\u8A66\u307F\u307E\u3057\u305F\u3002 -FileManager.addDerivedFile.exception.msg=FileManager\u3092\u9589\u3058\u305F\u5F8C\u306B\u4F7F\u7528\u3092\u8A66\u307F\u307E\u3057\u305F\u3002 -FileManager.addCarvedFile.exception.msg=FileManager\u3092\u9589\u3058\u305F\u5F8C\u306B\u4F7F\u7528\u3092\u8A66\u307F\u307E\u3057\u305F\u3002 -FileManager.addLocalFilesDirs.exception.notReadable.msg=\u8FFD\u52A0\u3059\u308B\u30ED\u30FC\u30AB\u30EB\u30D5\u30A1\u30A4\u30EB\uFF0F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306E\u4E2D\u306B\u8AAD\u307F\u53D6\u308C\u306A\u3044\u3082\u306E\u304C\uFF11\u500B\u3042\u308A\u307E\u3059\uFF1A{0}\u3001\u30D5\u30A1\u30A4\u30EB\u304C\u8FFD\u52A0\u3055\u308C\u308B\u524D\u306B\u51E6\u7406\u3092\u4E2D\u6B62\u3057\u307E\u3059 -FileManager.addLocalFilesDirs.exception.cantAdd.msg=\u30ED\u30FC\u30AB\u30EB\u30D5\u30A1\u30A4\u30EB\uFF0F\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306E\uFF11\u500B\u306F\u8FFD\u52A0\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\uFF1A{0} -FileManager.addLocalFileSetRootDir.exception.errCreateDir.msg=\u30ED\u30FC\u30AB\u30EB\u30D5\u30A1\u30A4\u30EB\u30BB\u30C3\u30C8\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u3092\u4F5C\u6210\u4E2D\u306B\u30A8\u30E9\u30FC\u304C\u8D77\u3053\u308A\u307E\u3057\u305F\uFF1A {0} -FileManager.addLocalDirInt.exception.closed.msg=FileManager\u3092\u9589\u3058\u305F\u5F8C\u306B\u4F7F\u7528\u3092\u8A66\u307F\u307E\u3057\u305F\u3002 -FileManager.addLocalDirInt.exception.doesntExist.msg=\u5B58\u5728\u3057\u306A\u3044\u30ED\u30FC\u30AB\u30EB\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306E\u8FFD\u52A0\u3092\u8A66\u307F\u307E\u3057\u305F\: {0} -FileManager.addLocalDirInt.exception.notReadable.msg=\u8AAD\u307F\u53D6\u308A\u3067\u304D\u306A\u3044\u30ED\u30FC\u30AB\u30EB\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u306E\u8FFD\u52A0\u3092\u8A66\u307F\u307E\u3057\u305F\: {0} -FileManager.addLocalDirInt2.exception.closed.msg=FileManager\u3092\u9589\u3058\u305F\u5F8C\u306B\u4F7F\u7528\u3092\u8A66\u307F\u307E\u3057\u305F\u3002 -TagsManager.addContentTag.exception.beginByteOffsetOOR.msg=beginByteOffset \= {0} \u30B3\u30F3\u30C6\u30F3\u30C4\u30B5\u30A4\u30BA\u7BC4\u56F2(0 - {1})\u306E\u5916\u3067\u3059 -TagsManager.addContentTag.exception.endByteOffsetOOR.msg=endByteOffset \= {0} \u30B3\u30F3\u30C6\u30F3\u30C4\u30B5\u30A4\u30BA\u7BC4\u56F2(0 - {1})\u306E\u5916\u3067\u3059 +FileManager.findFiles.exception.msg=FileManager\u3092\u9589\u3058\u305f\u5f8c\u306b\u4f7f\u7528\u3092\u8a66\u307f\u307e\u3057\u305f\u3002 +FileManager.findFiles2.exception.msg=FileManager\u3092\u9589\u3058\u305f\u5f8c\u306b\u4f7f\u7528\u3092\u8a66\u307f\u307e\u3057\u305f\u3002 +FileManager.findFiles3.exception.msg=FileManager\u3092\u9589\u3058\u305f\u5f8c\u306b\u4f7f\u7528\u3092\u8a66\u307f\u307e\u3057\u305f\u3002 +FileManager.openFiles.exception.msg=FileManager\u3092\u9589\u3058\u305f\u5f8c\u306b\u4f7f\u7528\u3092\u8a66\u307f\u307e\u3057\u305f\u3002 +FileManager.addDerivedFile.exception.msg=FileManager\u3092\u9589\u3058\u305f\u5f8c\u306b\u4f7f\u7528\u3092\u8a66\u307f\u307e\u3057\u305f\u3002 +FileManager.addCarvedFile.exception.msg=FileManager\u3092\u9589\u3058\u305f\u5f8c\u306b\u4f7f\u7528\u3092\u8a66\u307f\u307e\u3057\u305f\u3002 +FileManager.addLocalFilesDirs.exception.notReadable.msg=\u8ffd\u52a0\u3059\u308b\u30ed\u30fc\u30ab\u30eb\u30d5\u30a1\u30a4\u30eb\uff0f\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u4e2d\u306b\u8aad\u307f\u53d6\u308c\u306a\u3044\u3082\u306e\u304c\uff11\u500b\u3042\u308a\u307e\u3059\uff1a{0}\u3001\u30d5\u30a1\u30a4\u30eb\u304c\u8ffd\u52a0\u3055\u308c\u308b\u524d\u306b\u51e6\u7406\u3092\u4e2d\u6b62\u3057\u307e\u3059 +FileManager.addLocalFilesDirs.exception.cantAdd.msg=\u30ed\u30fc\u30ab\u30eb\u30d5\u30a1\u30a4\u30eb\uff0f\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\uff11\u500b\u306f\u8ffd\u52a0\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\uff1a{0} +FileManager.addLocalFileSetRootDir.exception.errCreateDir.msg=\u30ed\u30fc\u30ab\u30eb\u30d5\u30a1\u30a4\u30eb\u30bb\u30c3\u30c8\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3092\u4f5c\u6210\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u8d77\u3053\u308a\u307e\u3057\u305f\uff1a {0} +FileManager.addLocalDirInt.exception.closed.msg=FileManager\u3092\u9589\u3058\u305f\u5f8c\u306b\u4f7f\u7528\u3092\u8a66\u307f\u307e\u3057\u305f\u3002 +FileManager.addLocalDirInt.exception.doesntExist.msg=\u5b58\u5728\u3057\u306a\u3044\u30ed\u30fc\u30ab\u30eb\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u8ffd\u52a0\u3092\u8a66\u307f\u307e\u3057\u305f\: {0} +FileManager.addLocalDirInt.exception.notReadable.msg=\u8aad\u307f\u53d6\u308a\u3067\u304d\u306a\u3044\u30ed\u30fc\u30ab\u30eb\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u8ffd\u52a0\u3092\u8a66\u307f\u307e\u3057\u305f\: {0} +FileManager.addLocalDirInt2.exception.closed.msg=FileManager\u3092\u9589\u3058\u305f\u5f8c\u306b\u4f7f\u7528\u3092\u8a66\u307f\u307e\u3057\u305f\u3002 +TagsManager.addContentTag.exception.beginByteOffsetOOR.msg=beginByteOffset \= {0} \u30b3\u30f3\u30c6\u30f3\u30c4\u30b5\u30a4\u30ba\u7bc4\u56f2(0 - {1})\u306e\u5916\u3067\u3059 +TagsManager.addContentTag.exception.endByteOffsetOOR.msg=endByteOffset \= {0} \u30b3\u30f3\u30c6\u30f3\u30c4\u30b5\u30a4\u30ba\u7bc4\u56f2(0 - {1})\u306e\u5916\u3067\u3059 TagsManager.addContentTag.exception.endLTbegin.msg=endByteOffset < beginByteOffset -TagsManager.predefTagNames.bookmark.text=\u30D6\u30C3\u30AF\u30DE\u30FC\u30AF -TagsManager.addContentTag.noCaseWarning=\u65B0\u3057\u3044\u30BF\u30B0\u30A4\u30D9\u30F3\u30C8\u3092\u30D1\u30D6\u30EA\u30C3\u30B7\u30E5\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u958B\u3044\u3066\u3044\u308B\u30B1\u30FC\u30B9\u304C\u3042\u308A\u307E\u305B\u3093\u3002 -TagsManager.deleteContentTag.noCaseWarning=\u524A\u9664\u3055\u308C\u305F\u30A4\u30D9\u30F3\u30C8\u306E\u30BF\u30B0\u306E\u30B3\u30F3\u30C6\u30F3\u30C4\u3092\u30D1\u30D6\u30EA\u30C3\u30B7\u30E5\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u958B\u3044\u3066\u3044\u308B\u30B1\u30FC\u30B9\u304C\u3042\u308A\u307E\u305B\u3093\u3002 -TagsManager.addBlackboardArtifactTag.noCaseWarning=\u30A4\u30D9\u30F3\u30C8\u306E\u30BF\u30B0\u306E\u65B0\u3057\u3044blackboard\u30A2\u30FC\u30C6\u30A3\u30D5\u30A1\u30AF\u30C8\u3092\u30D1\u30D6\u30EA\u30C3\u30B7\u30E5\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u958B\u3044\u3066\u3044\u308B\u30B1\u30FC\u30B9\u304C\u3042\u308A\u307E\u305B\u3093\u3002 -TagsManager.deleteBlackboardArtifactTag.noCaseWarning=\u524A\u9664\u3055\u308C\u305F\u30A4\u30D9\u30F3\u30C8\u306E\u30BF\u30B0\u306E\u65B0\u3057\u3044blackboard\u30A2\u30FC\u30C6\u30A3\u30D5\u30A1\u30AF\u30C8\u3092\u30D1\u30D6\u30EA\u30C3\u30B7\u30E5\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u958B\u3044\u3066\u3044\u308B\u30B1\u30FC\u30B9\u304C\u3042\u308A\u307E\u305B\u3093\u3002 -Blackboard.keywordSearchNotFound.exception.msg=\u30AD\u30FC\u30EF\u30FC\u30C9\u691C\u7D22\u30B5\u30FC\u30D3\u30B9\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F\u3002 -Blackboard.unableToIndexArtifact.exception.msg=blackboard\u30A2\u30FC\u30C6\u30A3\u30D5\u30A1\u30AF\u30C8\u3092\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002 -Blackboard.unableToIndexArtifact.error.msg=blackboard\u30A2\u30FC\u30C6\u30A3\u30D5\u30A1\u30AF\u30C8{0}\u3092\u30A4\u30F3\u30C7\u30C3\u30AF\u30B9\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002 \ No newline at end of file +TagsManager.predefTagNames.bookmark.text=\u30d6\u30c3\u30af\u30de\u30fc\u30af +TagsManager.addContentTag.noCaseWarning=\u65b0\u3057\u3044\u30bf\u30b0\u30a4\u30d9\u30f3\u30c8\u3092\u30d1\u30d6\u30ea\u30c3\u30b7\u30e5\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u958b\u3044\u3066\u3044\u308b\u30b1\u30fc\u30b9\u304c\u3042\u308a\u307e\u305b\u3093\u3002 +TagsManager.deleteContentTag.noCaseWarning=\u524a\u9664\u3055\u308c\u305f\u30a4\u30d9\u30f3\u30c8\u306e\u30bf\u30b0\u306e\u30b3\u30f3\u30c6\u30f3\u30c4\u3092\u30d1\u30d6\u30ea\u30c3\u30b7\u30e5\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u958b\u3044\u3066\u3044\u308b\u30b1\u30fc\u30b9\u304c\u3042\u308a\u307e\u305b\u3093\u3002 +TagsManager.addBlackboardArtifactTag.noCaseWarning=\u30a4\u30d9\u30f3\u30c8\u306e\u30bf\u30b0\u306e\u65b0\u3057\u3044blackboard\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u3092\u30d1\u30d6\u30ea\u30c3\u30b7\u30e5\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u958b\u3044\u3066\u3044\u308b\u30b1\u30fc\u30b9\u304c\u3042\u308a\u307e\u305b\u3093\u3002 +TagsManager.deleteBlackboardArtifactTag.noCaseWarning=\u524a\u9664\u3055\u308c\u305f\u30a4\u30d9\u30f3\u30c8\u306e\u30bf\u30b0\u306e\u65b0\u3057\u3044blackboard\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8\u3092\u30d1\u30d6\u30ea\u30c3\u30b7\u30e5\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u958b\u3044\u3066\u3044\u308b\u30b1\u30fc\u30b9\u304c\u3042\u308a\u307e\u305b\u3093\u3002 +Blackboard.unableToIndexArtifact.error.msg=blackboard\u30a2\u30fc\u30c6\u30a3\u30d5\u30a1\u30af\u30c8{0}\u3092\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002 \ No newline at end of file From 1f8e17f2c557d394807b387c02ebca855862ca0d Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 1 Apr 2016 16:38:52 -0400 Subject: [PATCH 38/50] An artifact indexing/keyword search feature to NEWS for release 4.1.0 --- NEWS.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS.txt b/NEWS.txt index 2922552cf5..a4aece14bd 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -2,6 +2,7 @@ Improvements: - VMWare virtual machine files (vmdk) and Microsoft Virtual Hard Drives (vhd) can be added as data sources. - New core ingest module detects vmdk and vhd files embedded in other data sources and adds them as data sources. +- Text associated with artifacts posted to the blackboard is indexed and searched for keywords. - Custom (user-defined) blackboard artifact and attribute types displayed in UI and included reports. - File size and MIME type conditions can be specified for interesting files rules. - File size and MIME type conditions can be specified for file search by attributes. From 9c3cbc809b4f2a5d73f942463604b14ccc8acc66 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 4 Apr 2016 13:03:13 -0400 Subject: [PATCH 39/50] Remove redundant logging of ingest module start up errors --- .../autopsy/ingest/DataSourceIngestJob.java | 57 +++++++++++-------- .../autopsy/ingest/IngestManager.java | 4 +- 2 files changed, 34 insertions(+), 27 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java index 2004674df7..3156314076 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -288,7 +288,7 @@ final class DataSourceIngestJob { String getExecutionContext() { return this.settings.getExecutionContext(); } - + /** * Gets the data source to be ingested by this job. * @@ -379,38 +379,45 @@ final class DataSourceIngestJob { private List startUpIngestPipelines() { List errors = new ArrayList<>(); - // Start up the first stage data source ingest pipeline. + /* + * Start the data-source-level ingest module pipelines. + */ errors.addAll(this.firstStageDataSourceIngestPipeline.startUp()); - - // Start up the second stage data source ingest pipeline. errors.addAll(this.secondStageDataSourceIngestPipeline.startUp()); - // Start up the file ingest pipelines (one per file ingest thread). - for (FileIngestPipeline pipeline : this.fileIngestPipelinesQueue) { - errors.addAll(pipeline.startUp()); - if (!errors.isEmpty()) { - // If there are start up errors, the ingest job will not proceed - // and the errors will ultimately be reported to the user for - // possible remedy so shut down the pipelines now that an - // attempt has been made to start up the data source ingest - // pipeline and at least one copy of the file ingest pipeline. - // pipeline. There is no need to complete starting up all of the - // file ingest pipeline copies since any additional start up - // errors are likely redundant. - while (!this.fileIngestPipelinesQueue.isEmpty()) { - pipeline = this.fileIngestPipelinesQueue.poll(); - if (pipeline.isRunning()) { - List shutDownErrors = pipeline.shutDown(); - if (!shutDownErrors.isEmpty()) { - logIngestModuleErrors(shutDownErrors); + /* + * If the data-source-level ingest pipelines were successfully started, + * start the Start the file-level ingest pipelines (one per file ingest + * thread). + */ + if (errors.isEmpty()) { + for (FileIngestPipeline pipeline : this.fileIngestPipelinesQueue) { + errors.addAll(pipeline.startUp()); + if (!errors.isEmpty()) { + /* + * If there are start up errors, the ingest job will not + * proceed, so shut down any file ingest pipelines that did + * start up. + */ + while (!this.fileIngestPipelinesQueue.isEmpty()) { + FileIngestPipeline startedPipeline = this.fileIngestPipelinesQueue.poll(); + if (startedPipeline.isRunning()) { + List shutDownErrors = startedPipeline.shutDown(); + if (!shutDownErrors.isEmpty()) { + /* + * The start up errors will ultimately be + * reported to the user for possible remedy, but + * the shut down errors are logged here. + */ + logIngestModuleErrors(shutDownErrors); + } } } + break; } - break; } } - logIngestModuleErrors(errors); return errors; } diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java index c196caba8a..0e82461c28 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestManager.java @@ -556,9 +556,9 @@ public class IngestManager { this.jobsById.remove(job.getId()); } for (IngestModuleError error : errors) { - logger.log(Level.SEVERE, String.format("Error starting %s ingest module", error.getModuleDisplayName()), error.getModuleError()); //NON-NLS + logger.log(Level.SEVERE, String.format("Error starting %s ingest module for job %d", error.getModuleDisplayName(), job.getId()), error.getModuleError()); //NON-NLS } - IngestManager.logger.log(Level.INFO, "Ingest job {0} could not be started", job.getId()); //NON-NLS + IngestManager.logger.log(Level.SEVERE, "Ingest job {0} could not be started", job.getId()); //NON-NLS if (RuntimeProperties.coreComponentsAreActive()) { EventQueue.invokeLater(new Runnable() { From 5bb7332450a16181b531452163579cd5ad0cf046 Mon Sep 17 00:00:00 2001 From: jmillman Date: Mon, 4 Apr 2016 17:03:20 -0400 Subject: [PATCH 40/50] fix copying of filters --- .../sleuthkit/autopsy/timeline/filters/DataSourcesFilter.java | 1 + .../org/sleuthkit/autopsy/timeline/filters/HashHitsFilter.java | 1 + Core/src/org/sleuthkit/autopsy/timeline/filters/TagsFilter.java | 1 + 3 files changed, 3 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/DataSourcesFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/DataSourcesFilter.java index 02318310f1..b02279b2e3 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/DataSourcesFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/DataSourcesFilter.java @@ -37,6 +37,7 @@ public class DataSourcesFilter extends UnionFilter { public DataSourcesFilter copyOf() { final DataSourcesFilter filterCopy = new DataSourcesFilter(); filterCopy.setSelected(isSelected()); + filterCopy.setDisabled(isDisabled()); //add a copy of each subfilter this.getSubFilters().forEach((DataSourceFilter t) -> { filterCopy.addSubFilter(t.copyOf()); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/HashHitsFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/HashHitsFilter.java index b7a13184f7..7404663716 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/HashHitsFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/HashHitsFilter.java @@ -30,6 +30,7 @@ public class HashHitsFilter extends UnionFilter { public HashHitsFilter copyOf() { HashHitsFilter filterCopy = new HashHitsFilter(); filterCopy.setSelected(isSelected()); + filterCopy.setDisabled(isDisabled()); //add a copy of each subfilter this.getSubFilters().forEach((HashSetFilter t) -> { filterCopy.addSubFilter(t.copyOf()); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/TagsFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/TagsFilter.java index 1ab69a3909..bcf00d2d23 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/TagsFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/TagsFilter.java @@ -31,6 +31,7 @@ public class TagsFilter extends UnionFilter { public TagsFilter copyOf() { TagsFilter filterCopy = new TagsFilter(); filterCopy.setSelected(isSelected()); + filterCopy.setDisabled(isDisabled()); //add a copy of each subfilter this.getSubFilters().forEach((TagNameFilter t) -> { filterCopy.addSubFilter(t.copyOf()); From cf5c4b6ca70f39240317b6b46464c5001d4b1968 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Tue, 5 Apr 2016 09:51:20 -0400 Subject: [PATCH 41/50] Began updates to CaseMetadata --- .../autopsy/casemodule/CaseMetadata.java | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java index e6fa232a28..0a9880b480 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2015 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -51,7 +51,7 @@ import org.w3c.dom.NodeList; import org.xml.sax.SAXException; /** - * Provides access to case metadata. + * Provides access to the case metadata stored in the case metadata file. */ public final class CaseMetadata { @@ -75,7 +75,6 @@ public final class CaseMetadata { private final static String XSDFILE = "CaseSchema.xsd"; //NON-NLS private final static String TOP_ROOT_NAME = "AutopsyCase"; //NON-NLS private final static String CASE_ROOT_NAME = "Case"; //NON-NLS - // general metadata about the case file private final static String NAME = "Name"; //NON-NLS private final static String NUMBER = "Number"; //NON-NLS private final static String EXAMINER = "Examiner"; //NON-NLS @@ -85,7 +84,6 @@ public final class CaseMetadata { private final static String AUTOPSY_CRVERSION_NAME = "AutopsyCreatedVersion"; //NON-NLS private final static String AUTOPSY_MVERSION_NAME = "AutopsySavedVersion"; //NON-NLS private final static String CASE_TEXT_INDEX_NAME = "TextIndexName"; //NON-NLS - // folders inside case directory private final static String CASE_TYPE = "CaseType"; //NON-NLS private final static String DATABASE_NAME = "DatabaseName"; //NON-NLS @@ -449,7 +447,7 @@ public final class CaseMetadata { Element rootElement = doc.getDocumentElement(); NodeList cversionList = rootElement.getElementsByTagName(AUTOPSY_CRVERSION_NAME); - if(cversionList.getLength() == 0) { + if (cversionList.getLength() == 0) { throw new CaseMetadataException("Could not find created version in metadata"); } String createdVersion = cversionList.item(0).getTextContent(); // get the created version @@ -458,47 +456,47 @@ public final class CaseMetadata { // if not the same version, update the saved version in the xml to the current version rootElement.getElementsByTagName(AUTOPSY_MVERSION_NAME).item(0).setTextContent(System.getProperty("netbeans.buildnumber")); } - + String fullFileName = file.getName(); String fileName = fullFileName.substring(0, fullFileName.lastIndexOf(".")); // remove the extension this.fileName = fileName; - + NodeList rootNameList = doc.getElementsByTagName(CASE_ROOT_NAME); if (rootNameList.getLength() == 0) { throw new CaseMetadataException("Couldn't get case root"); } Element caseElement = (Element) rootNameList.item(0); - + NodeList caseTypeList = caseElement.getElementsByTagName(CASE_TYPE); if (caseTypeList.getLength() == 0) { throw new CaseMetadataException("Couldn't get case type"); } String caseTypeString = caseTypeList.item(0).getTextContent(); this.caseType = Case.CaseType.fromString(caseTypeString); - if(this.caseType == null) { + if (this.caseType == null) { throw new CaseMetadataException("Invalid case type"); } - + NodeList caseNameList = caseElement.getElementsByTagName(NAME); if (caseNameList.getLength() == 0) { throw new CaseMetadataException("Couldn't get case name"); } this.caseName = caseNameList.item(0).getTextContent(); - if(this.caseName.isEmpty()) { + if (this.caseName.isEmpty()) { throw new CaseMetadataException("Invalid case name, cannot be empty"); } - + Element numberElement = caseElement.getElementsByTagName(NUMBER).getLength() > 0 ? (Element) caseElement.getElementsByTagName(NUMBER).item(0) : null; this.caseNumber = numberElement != null ? numberElement.getTextContent() : ""; - + Element examinerElement = caseElement.getElementsByTagName(EXAMINER).getLength() > 0 ? (Element) caseElement.getElementsByTagName(EXAMINER).item(0) : null; this.examiner = examinerElement != null ? examinerElement.getTextContent() : ""; - + this.caseDirectory = conFilePath.substring(0, conFilePath.lastIndexOf("\\")); if (this.caseDirectory.isEmpty()) { throw new CaseMetadataException("Could not get a valid case directory"); } - + NodeList databaseNameList = caseElement.getElementsByTagName(DATABASE_NAME); if (databaseNameList.getLength() == 0) { throw new CaseMetadataException("Couldn't get database name"); @@ -508,20 +506,20 @@ public final class CaseMetadata { if (Case.CaseType.MULTI_USER_CASE == caseType && caseDatabaseName.isEmpty()) { throw new CaseMetadataException("Case database name cannot be empty in multi user case."); } - + NodeList textIndexList = caseElement.getElementsByTagName(CASE_TEXT_INDEX_NAME); if (textIndexList.getLength() == 0) { throw new CaseMetadataException("Couldn't get text index"); } Element caseTextIndexNameElement = (Element) textIndexList.item(0); this.caseTextIndexName = caseTextIndexNameElement.getTextContent(); - + NodeList createdDateList = rootElement.getElementsByTagName(CREATED_DATE_NAME); if (createdDateList.getLength() == 0) { throw new CaseMetadataException("Couldn't get created date"); } this.createdDate = createdDateList.item(0).getTextContent(); - + NodeList createdVersionList = rootElement.getElementsByTagName(AUTOPSY_CRVERSION_NAME); if (createdVersionList.getLength() == 0) { throw new CaseMetadataException("Couldn't get created version"); From c7e7822cf74eefb1939f758341990d3b017caf3a Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Tue, 5 Apr 2016 11:45:56 -0400 Subject: [PATCH 42/50] Updated CaseMetadata class semantics. --- .../sleuthkit/autopsy/casemodule/Case.java | 49 +- .../casemodule/CaseConfigFileInterface.java | 52 -- .../autopsy/casemodule/CaseMetadata.java | 47 +- .../autopsy/casemodule/CaseOpenAction.java | 2 +- .../casemodule/CasePropertiesForm.java | 80 +- .../autopsy/casemodule/CaseSchema.xsd | 124 --- .../casemodule/SingleUserCaseConverter.java | 6 +- .../autopsy/casemodule/XMLCaseManagement.java | 814 ------------------ .../autopsy/corecomponents/Installer.java | 3 +- 9 files changed, 75 insertions(+), 1102 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/CaseConfigFileInterface.java delete mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/CaseSchema.xsd delete mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/XMLCaseManagement.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 99eac9d6a2..bac25b1653 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -269,11 +269,8 @@ public class Case implements SleuthkitCase.ErrorObserver { private final SleuthkitCase db; // Track the current case (only set with changeCase() method) private static Case currentCase = null; - private final CaseType caseType; private final Services services; private static final Logger logger = Logger.getLogger(Case.class.getName()); - static final String CASE_EXTENSION = "aut"; //NON-NLS - static final String CASE_DOT_EXTENSION = "." + CASE_EXTENSION; private final static String CACHE_FOLDER = "Cache"; //NON-NLS private final static String EXPORT_FOLDER = "Export"; //NON-NLS private final static String LOG_FOLDER = "Log"; //NON-NLS @@ -295,7 +292,6 @@ public class Case implements SleuthkitCase.ErrorObserver { this.examiner = examiner; this.configFilePath = configFilePath; this.caseMetadata = caseMetadata; - this.caseType = type; this.db = db; this.services = new Services(db); } @@ -421,12 +417,12 @@ public class Case implements SleuthkitCase.ErrorObserver { * @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 - * Throwable (null otherwise). + * @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 + * Throwable (null otherwise). */ public static void create(String caseDir, String caseName, String caseNumber, String examiner) throws CaseActionException { create(caseDir, caseName, caseNumber, examiner, CaseType.SINGLE_USER_CASE); @@ -483,10 +479,10 @@ public class Case implements SleuthkitCase.ErrorObserver { /* * Create the case metadata (.aut) file. */ - String configFilePath = caseDir + File.separator + caseName + CASE_DOT_EXTENSION; + String configFilePath = caseDir + File.separator + caseName + CaseMetadata.getFileExtension(); CaseMetadata metadata; try { - metadata = CaseMetadata.create(caseType, caseName, caseNumber, examiner, caseDir, dbName, indexName); + metadata = CaseMetadata.create(caseDir, caseType, caseName, caseNumber, examiner, dbName, indexName); } catch (CaseMetadataException ex) { throw new CaseActionException(Bundle.Case_creationException(), ex); } @@ -602,8 +598,8 @@ public class Case implements SleuthkitCase.ErrorObserver { /* * Verify the extension of the case metadata file. */ - if (!caseMetadataFilePath.endsWith(CASE_DOT_EXTENSION)) { - throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.open.exception.checkFile.msg", CASE_DOT_EXTENSION)); + if (!caseMetadataFilePath.endsWith(CaseMetadata.getFileExtension())) { + throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.open.exception.checkFile.msg", CaseMetadata.getFileExtension())); } try { @@ -900,7 +896,7 @@ public class Case implements SleuthkitCase.ErrorObserver { */ void updateCaseName(String oldCaseName, String oldPath, String newCaseName, String newPath) throws CaseActionException { try { - caseMetadata.setCaseName(newCaseName); // set the case + getCaseMetadata().setCaseName(newCaseName); // set the case name = newCaseName; // change the local value eventPublisher.publish(new AutopsyEvent(Events.NAME.toString(), oldCaseName, newCaseName)); SwingUtilities.invokeLater(() -> { @@ -952,6 +948,13 @@ public class Case implements SleuthkitCase.ErrorObserver { return autopsyVer; } + /** + * @return the caseMetadata + */ + CaseMetadata getCaseMetadata() { + return caseMetadata; + } + /** * Gets the application name * @@ -997,10 +1000,10 @@ public class Case implements SleuthkitCase.ErrorObserver { * @return caseDirectoryPath */ public String getCaseDirectory() { - if (caseMetadata == null) { + if (getCaseMetadata() == null) { return ""; } else { - return caseMetadata.getCaseDirectory(); + return getCaseMetadata().getCaseDirectory(); } } @@ -1010,7 +1013,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @return */ public CaseType getCaseType() { - return this.caseType; + return this.getCaseMetadata().getCaseType(); } /** @@ -1128,7 +1131,7 @@ public class Case implements SleuthkitCase.ErrorObserver { private String getHostDirectory() { String caseDirectory = getCaseDirectory(); Path hostPath; - if (caseType == CaseType.MULTI_USER_CASE) { + if (getCaseMetadata().getCaseType() == CaseType.MULTI_USER_CASE) { hostPath = Paths.get(caseDirectory, NetworkUtils.getLocalHostName()); } else { hostPath = Paths.get(caseDirectory); @@ -1199,10 +1202,10 @@ public class Case implements SleuthkitCase.ErrorObserver { * @return case creation date */ public String getCreatedDate() { - if (caseMetadata == null) { + if (getCaseMetadata() == null) { return ""; } else { - return caseMetadata.getCreatedDate(); + return getCaseMetadata().getCreatedDate(); } } @@ -1212,10 +1215,10 @@ public class Case implements SleuthkitCase.ErrorObserver { * @return Index name. */ public String getTextIndexName() { - if (caseMetadata == null) { + if (getCaseMetadata() == null) { return ""; } else { - return caseMetadata.getTextIndexName(); + return getCaseMetadata().getTextIndexName(); } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseConfigFileInterface.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseConfigFileInterface.java deleted file mode 100644 index 8b7964a76e..0000000000 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseConfigFileInterface.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.casemodule; - -/** - * NOTE: NOTHING ACTUALLY USES THIS - * - * The interface for the classes that edit the case configuration file - */ -//TODO: check that this can just be deleted. -interface CaseConfigFileInterface { - - public void open(String conFilePath) throws Exception; // opens the confiuation store (XML, DB...) - - public void writeFile() throws Exception; // writes out the configuration to store - - public void close() throws Exception; // close and clear the document handler -// public int[] getImageIDs() throws Exception; // returns a list of image IDs and names -// public int getNextImageID() throws Exception; // returns the next free ID to be assigned to new image, and increments the internal counter - - // all the get and set methods - public String getCaseName() throws Exception; // get the case name - - public void setCaseName(String caseName) throws Exception; // set the case name - - public String getCaseNumber() throws Exception; // get the case number - - public void setCaseNumber(String caseNumber) throws Exception; // set the case number - - public String getCaseExaminer() throws Exception; // get the examiner - - public void setCaseExaminer(String examiner) throws Exception; // set the examiner - - // public void getXXX(); // methods to get the case attributes - // public void setXXX(); // methods to set the case attributes -} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java index 0a9880b480..e8fb7fa6e2 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java @@ -72,7 +72,6 @@ public final class CaseMetadata { } } - private final static String XSDFILE = "CaseSchema.xsd"; //NON-NLS private final static String TOP_ROOT_NAME = "AutopsyCase"; //NON-NLS private final static String CASE_ROOT_NAME = "Case"; //NON-NLS private final static String NAME = "Name"; //NON-NLS @@ -86,6 +85,8 @@ public final class CaseMetadata { private final static String CASE_TEXT_INDEX_NAME = "TextIndexName"; //NON-NLS private final static String CASE_TYPE = "CaseType"; //NON-NLS private final static String DATABASE_NAME = "DatabaseName"; //NON-NLS + private static final String SCHEMA_VERSION = "2.0"; + private static final String FILE_EXTENSION = ".aut"; private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss (z)"); private Case.CaseType caseType; @@ -96,7 +97,6 @@ public final class CaseMetadata { private String caseDatabaseName; private String caseTextIndexName; private String createdDate; - private static final String SCHEMA_VERSION = "2.0"; private String fileName; private String createdVersion; @@ -106,7 +106,7 @@ public final class CaseMetadata { this.caseName = caseName; this.caseNumber = caseNumber; this.examiner = examiner; - this.createdDate = this.DATE_FORMAT.format(new Date()); + this.createdDate = CaseMetadata.DATE_FORMAT.format(new Date()); this.caseDirectory = caseDirectory; this.caseDatabaseName = caseDatabaseName; this.caseTextIndexName = caseTextIndexName; @@ -116,18 +116,6 @@ public final class CaseMetadata { } - /** - * Constructs an object that provides access to case metadata. - * - * @param metadataFilePath Path to the metadata (.aut) file for a case. - * - * @deprecated Use open instead - */ - @Deprecated - public CaseMetadata(Path metadataFilePath) throws CaseMetadataException { - this(metadataFilePath.toString()); - } - /** * Used to read a case at the given file path * @@ -150,7 +138,7 @@ public final class CaseMetadata { * @throws * org.sleuthkit.autopsy.casemodule.CaseMetadata.CaseMetadataException */ - public static CaseMetadata open(Path metadataFilePath) throws CaseMetadataException { + static CaseMetadata open(Path metadataFilePath) throws CaseMetadataException { CaseMetadata metadata = new CaseMetadata(metadataFilePath.toString()); return metadata; } @@ -171,7 +159,7 @@ public final class CaseMetadata { * @throws * org.sleuthkit.autopsy.casemodule.CaseMetadata.CaseMetadataException */ - public static CaseMetadata create(Case.CaseType caseType, String caseName, String caseNumber, String examiner, String caseDirectory, String caseDatabaseName, String caseTextIndexName) throws CaseMetadataException { + static CaseMetadata create(String caseDirectory, Case.CaseType caseType, String caseName, String caseNumber, String examiner, String caseDatabaseName, String caseTextIndexName) throws CaseMetadataException { CaseMetadata metadata = new CaseMetadata(caseType, caseName, caseNumber, examiner, caseDirectory, caseDatabaseName, caseTextIndexName); return metadata; } @@ -217,7 +205,7 @@ public final class CaseMetadata { * * @return The case directory. */ - public String getCaseDirectory() { + String getCaseDirectory() { return caseDirectory; } @@ -235,7 +223,7 @@ public final class CaseMetadata { * * @return The date this case was created as a string */ - public String getCreatedDate() { + String getCreatedDate() { return this.createdDate; } @@ -246,6 +234,13 @@ public final class CaseMetadata { return createdVersion; } + /** + * @return the FILE_EXTENSION + */ + public static String getFileExtension() { + return FILE_EXTENSION; + } + /** * Sets the created version of this case * @@ -396,7 +391,7 @@ public final class CaseMetadata { // preparing the output file String xmlString = sw.toString(); - File file = new File(Paths.get(this.getCaseDirectory(), this.fileName + ".aut").toString()); + File file = new File(Paths.get(this.getCaseDirectory(), this.fileName + getFileExtension()).toString()); // write the file try { @@ -528,4 +523,16 @@ public final class CaseMetadata { } } + /** + * Constructs an object that provides access to case metadata. + * + * @param metadataFilePath Path to the metadata (.aut) file for a case. + * + * @deprecated Use open instead + */ + @Deprecated + public CaseMetadata(Path metadataFilePath) throws CaseMetadataException { + this(metadataFilePath.toString()); + } + } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java index f879393558..80f89c0fab 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseOpenAction.java @@ -54,7 +54,7 @@ public final class CaseOpenAction implements ActionListener { * Constructs an action that opens an existing case. */ public CaseOpenAction() { - caseMetadataFileFilter = new FileNameExtensionFilter(NbBundle.getMessage(CaseOpenAction.class, "CaseOpenAction.autFilter.title", Version.getName(), Case.CASE_DOT_EXTENSION), Case.CASE_EXTENSION); + caseMetadataFileFilter = new FileNameExtensionFilter(NbBundle.getMessage(CaseOpenAction.class, "CaseOpenAction.autFilter.title", Version.getName(), CaseMetadata.getFileExtension()), CaseMetadata.getFileExtension().substring(1)); fileChooser.setDragEnabled(false); fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); fileChooser.setMultiSelectionEnabled(false); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java index 99d9754094..ca8fa2e8da 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,7 +24,6 @@ */ package org.sleuthkit.autopsy.casemodule; -import java.awt.*; import java.nio.file.Paths; import java.awt.event.ActionListener; import java.io.File; @@ -41,9 +40,8 @@ import org.openide.NotifyDescriptor; import org.openide.util.actions.CallableSystemAction; /** - * The form where user can change / update the properties of the current case. - * - * @author jantonius + * The form where user can change / update the properties of the current case + * metadata. */ class CasePropertiesForm extends javax.swing.JPanel { @@ -89,7 +87,7 @@ class CasePropertiesForm extends javax.swing.JPanel { caseDirTextArea.setText(caseDir); current = currentCase; - CaseMetadata caseMetadata = CaseMetadata.open(Paths.get(currentCase.getConfigFilePath())); + CaseMetadata caseMetadata = currentCase.getCaseMetadata(); tbDbName.setText(caseMetadata.getCaseDatabaseName()); Case.CaseType caseType = caseMetadata.getCaseType(); tbDbType.setText(caseType.getLocalizedDisplayName()); @@ -103,15 +101,16 @@ class CasePropertiesForm extends javax.swing.JPanel { // create the headers and add all the rows // Header names are internationalized via the generated code, do not overwrite. - String[] headers = {imagesTable.getColumnName(0), - imagesTable.getColumnName(1)}; + String[] headers = {imagesTable.getColumnName(0), + imagesTable.getColumnName(1)}; String[][] rows = new String[totalImages][]; int i = 0; for (long key : imgPaths.keySet()) { String path = imgPaths.get(key); String shortenPath = shrinkPath(path, 70); - rows[i++] = new String[]{shortenPath}; + rows[i] = new String[]{shortenPath}; + i++; } // create the table inside with the imgPaths information @@ -124,61 +123,17 @@ class CasePropertiesForm extends javax.swing.JPanel { } }; imagesTable.setModel(model); - -// // set the size of the remove column -// TableColumn removeCol = imagesTable.getColumnModel().getColumn(lastColumn); -// removeCol.setPreferredWidth(75); -// removeCol.setMaxWidth(75); -// removeCol.setMinWidth(75); -// removeCol.setResizable(false); -// // create the delete action to remove the image from the current case -// Action delete = new AbstractAction() -// { -// @Override -// public void actionPerformed(ActionEvent e) -// { -// // get the image path -// JTable table = (JTable)e.getSource(); -// int modelRow = Integer.valueOf(e.getActionCommand()); -// String removeColumn = table.getValueAt(modelRow, lastColumn).toString(); -// // get the image ID -// int selectedID = Integer.parseInt(removeColumn.substring(0, removeColumn.indexOf('|'))); -// String imagePath = removeColumn.substring(removeColumn.indexOf('|') + 1); -// -// // throw the confirmation first -// String confMsg = "Are you sure want to remove image \"" + imagePath + "\" from this case?"; -// NotifyDescriptor d = new NotifyDescriptor.Confirmation(confMsg, "Create directory", NotifyDescriptor.YES_NO_OPTION, NotifyDescriptor.WARNING_MESSAGE); -// d.setValue(NotifyDescriptor.NO_OPTION); -// -// Object res = DialogDisplayer.getDefault().notify(d); -// // if user select "Yes" -// if(res != null && res == DialogDescriptor.YES_OPTION){ -// // remove the image in the case class and in the xml config file -// try { -// current.removeImage(selectedID, imagePath); -// } catch (Exception ex) { -// Logger.getLogger(CasePropertiesForm.class.getName()).log(Level.WARNING, "Error: couldn't remove image.", ex); -// } -// // remove the row of the image path -// ((DefaultTableModel)table.getModel()).removeRow(modelRow); -// } -// } -// }; -// -// ButtonColumn buttonColumn = new ButtonColumn(imagesTable, delete, 1, "Remove"); -// buttonColumn.setMnemonic(KeyEvent.VK_D); } - /** - * In this generated code below, there are 2 strings "Path" and "Remove" that are - * table column headers in the DefaultTableModel. When this model is generated, - * it puts the hard coded English strings into the generated code. And then about 15 - * lines later, it separately internationalizes them using: - * imagesTable.getColumnModel().getColumn(0).setHeaderValue(). - * There is no way to prevent the GUI designer from putting the hard coded - * English strings into the generated code. So, they remain, and are not used. + /** + * In this generated code below, there are 2 strings "Path" and "Remove" + * that are table column headers in the DefaultTableModel. When this model + * is generated, it puts the hard coded English strings into the generated + * code. And then about 15 lines later, it separately internationalizes them + * using: imagesTable.getColumnModel().getColumn(0).setHeaderValue(). There + * is no way to prevent the GUI designer from putting the hard coded English + * strings into the generated code. So, they remain, and are not used. */ - /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always @@ -429,9 +384,6 @@ class CasePropertiesForm extends javax.swing.JPanel { private void updateCaseNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_updateCaseNameButtonActionPerformed String oldCaseName = Case.getCurrentCase().getName(); String newCaseName = caseNameTextField.getText(); - //String oldPath = caseDirTextArea.getText() + File.separator + oldCaseName + ".aut"; - //String newPath = caseDirTextArea.getText() + File.separator + newCaseName + ".aut"; - // check if the old and new case name is not equal if (!oldCaseName.equals(newCaseName)) { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseSchema.xsd b/Core/src/org/sleuthkit/autopsy/casemodule/CaseSchema.xsd deleted file mode 100644 index 63c9aa49df..0000000000 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseSchema.xsd +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java b/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java index f40fa7e09a..b6a2298a4a 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java @@ -46,7 +46,7 @@ import org.sleuthkit.autopsy.coreutils.NetworkUtils; public class SingleUserCaseConverter { private static final String AUTOPSY_DB_FILE = "autopsy.db"; //NON-NLS - private static final String DOTAUT = ".aut"; //NON-NLS + private static final String DOTAUT = CaseMetadata.getFileExtension(); //NON-NLS private static final String TIMELINE_FOLDER = "Timeline"; //NON-NLS private static final String TIMELINE_FILE = "events.db"; //NON-NLS private static final String POSTGRES_DEFAULT_DB_NAME = "postgres"; //NON-NLS @@ -190,11 +190,11 @@ public class SingleUserCaseConverter { copyImages(icd); // Create new .aut file - CaseMetadata newCaseMetadata = CaseMetadata.create(CaseType.MULTI_USER_CASE, + CaseMetadata newCaseMetadata = CaseMetadata.create(icd.getCaseOutputFolder().toString(), + CaseType.MULTI_USER_CASE, icd.getNewCaseName(), oldCaseMetadata.getCaseNumber(), oldCaseMetadata.getExaminer(), - icd.getCaseOutputFolder().toString(), dbName, solrName); // Set created date. This calls writefile, no need to call it again newCaseMetadata.setCreatedDate(oldCaseMetadata.getCreatedDate()); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/XMLCaseManagement.java b/Core/src/org/sleuthkit/autopsy/casemodule/XMLCaseManagement.java deleted file mode 100644 index d1e6b87a3a..0000000000 --- a/Core/src/org/sleuthkit/autopsy/casemodule/XMLCaseManagement.java +++ /dev/null @@ -1,814 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2012-2015 Basis Technology Corp. - * Contact: carrier sleuthkit org - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.sleuthkit.autopsy.casemodule; - -import java.io.*; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.logging.Level; -import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.xml.parsers.*; -import javax.xml.transform.*; -import javax.xml.transform.dom.*; -import javax.xml.transform.stream.*; -import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.casemodule.Case.CaseType; -import org.sleuthkit.autopsy.core.RuntimeProperties; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.w3c.dom.*; -import org.xml.sax.SAXException; - -/** - * - * This class is used to create, access, and modify the XML configuration file, - * where we store the information about the case and image(s). This class uses - * the document handler to store the information about the case. The document - * handler will be created / opened when the case configuration file is created/ - * opened. - * - * @author jantonius - */ -class XMLCaseManagement implements CaseConfigFileInterface { - - 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 - // the document - private Document doc; - // general info - private final DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss (z)"); - private String caseDirPath; // case directory path - private String caseName; // case name - private String caseNumber; // case number - private String examiner; // examiner name - private final String schemaVersion = "1.0"; - private final String autopsySavedVersion; - private CaseType caseType; // The type of case: local or shared - private String dbName; // The name of the database - private String textIndexName; // The name of the index where extracted text is stored. - - // for error handling - private JPanel caller; - private final String className = this.getClass().toString(); - private static final Logger logger = Logger.getLogger(XMLCaseManagement.class.getName()); - - /** - * The constructor - */ - public XMLCaseManagement() { - autopsySavedVersion = System.getProperty("netbeans.buildnumber"); - } - - /** - * Sets the case directory path of the case directory on the local variable - * - * @param givenPath the new path to be stored as case directory path - */ - private void setCaseDirPath(String givenPath) { - caseDirPath = givenPath; // change this to change the xml file if needed - } - - /** - * Sets the case Name on the XML configuration file - * - * @param givenCaseName the new case name to be set - */ - @Override - public void setCaseName(String givenCaseName) throws CaseActionException { - // change this to change the xml file if needed - Element nameElement = (Element) getCaseElement().getElementsByTagName(NAME).item(0); - nameElement.setTextContent(givenCaseName); - doc.normalize(); - - // edit the modified data - String newDate = dateFormat.format(new Date()); - Element rootEl = getRootElement(); - rootEl.getElementsByTagName(MODIFIED_DATE_NAME).item(0).setTextContent(newDate); - - writeFile(); - - } - - /** - * Sets the case number on the XML configuration file - * - * @param givenCaseNumber the new case number to be set - */ - @Override - public void setCaseNumber(String givenCaseNumber) throws CaseActionException { - // change this to change the xml file if needed - Element nameElement = (Element) getCaseElement().getElementsByTagName(NUMBER).item(0); - nameElement.setTextContent(String.valueOf(givenCaseNumber)); - doc.normalize(); - - // edit the modified data - String newDate = dateFormat.format(new Date()); - Element rootEl = getRootElement(); - rootEl.getElementsByTagName(MODIFIED_DATE_NAME).item(0).setTextContent(newDate); - - writeFile(); - - } - - /** - * Sets the created date on the XML configuration file. This method is for - * preserving the created date when converting a case from single-user to - * multi-user. - * - * @param createdDate the date the case was originally created - * - * @throws org.sleuthkit.autopsy.casemodule.CaseActionException - */ - public void setCreatedDate(String createdDate) throws CaseActionException { - String newDate = dateFormat.format(new Date()); - Element rootEl = getRootElement(); - rootEl.getElementsByTagName(CREATED_DATE_NAME).item(0).setTextContent(createdDate); - rootEl.getElementsByTagName(MODIFIED_DATE_NAME).item(0).setTextContent(newDate); - writeFile(); - } - - /** - * Sets the examiner on the XML configuration file - * - * @param givenExaminer the new examiner to be set - */ - @Override - public void setCaseExaminer(String givenExaminer) throws CaseActionException { - // change this to change the xml file if needed - Element nameElement = (Element) getCaseElement().getElementsByTagName(EXAMINER).item(0); - nameElement.setTextContent(givenExaminer); - doc.normalize(); - - // edit the modified data - String newDate = dateFormat.format(new Date()); - Element rootEl = getRootElement(); - rootEl.getElementsByTagName(MODIFIED_DATE_NAME).item(0).setTextContent(newDate); - - writeFile(); - - } - - /** - * Sets the case name internally (on local variable in this class) - * - * @param givenCaseName the new case name - */ - private void setName(String givenCaseName) { - caseName = givenCaseName; // change this to change the xml file if needed - } - - /** - * Sets the case number internally (on local variable in this class) - * - * @param givenCaseNumber the new case number - */ - private void setNumber(String givenCaseNumber) { - caseNumber = givenCaseNumber; // change this to change the xml file if needed - } - - /** - * Sets the case type internally (on local variable in this class) - * - * @param givenCaseType the new case type - */ - private void setCaseType(CaseType givenCaseType) { - caseType = givenCaseType; // change this to change the xml file if needed - } - - /** - * Gets the case Type from the document handler. Defaults to local if it - * can't figure it out. - * - * @return caseType from the document handler - */ - public CaseType getCaseType() { - if (doc == null) { - return CaseType.SINGLE_USER_CASE; - } else { - if (getCaseElement().getElementsByTagName(CASE_TYPE).getLength() > 0) { - Element nameElement = (Element) getCaseElement().getElementsByTagName(CASE_TYPE).item(0); - return CaseType.fromString(nameElement.getTextContent()); - } else { - return CaseType.SINGLE_USER_CASE; - } - } - } - - /** - * Sets the database name internally (on local variable in this class) - * - * @param givenDbName the new db name - */ - private void setDatabaseName(String givenDbName) { - dbName = givenDbName; // change this to change the xml file if needed - } - - /** - * Gets the database name from the document handler - * - * @return the database name - */ - public String getDatabaseName() { - if (doc == null) { - return ""; - } else { - if (getCaseElement().getElementsByTagName(DATABASE_NAME).getLength() > 0) { - Element nameElement = (Element) getCaseElement().getElementsByTagName(DATABASE_NAME).item(0); - return nameElement.getTextContent(); - } else { - return ""; /// couldn't find one, so return a blank name - } - } - } - - /** - * Sets the text index name internally (on local variable in this class) - * - * @param textIndexName the new name for the index where extracted text is - * stored for the case. - */ - private void setTextIndexName(String textIndexName) { - this.textIndexName = textIndexName; // change this to change the xml file if needed - } - - /** - * Gets the name of the index where extracted text is stored. - * - * @return the index name - */ - public String getTextIndexName() { - if (doc == null) { - return ""; - } else { - if (getCaseElement().getElementsByTagName(CASE_TEXT_INDEX_NAME).getLength() > 0) { - Element nameElement = (Element) getCaseElement().getElementsByTagName(CASE_TEXT_INDEX_NAME).item(0); - return nameElement.getTextContent(); - } else { - return ""; /// couldn't find one, so return a blank index name - } - } - } - - /** - * Sets the examiner name internally (on local variable in this class) - * - * @param givenExaminer the new examiner - */ - private void setExaminer(String givenExaminer) { - examiner = givenExaminer; // change this to change the xml file if needed - } - - /** - * Gets the case Name from the document handler - * - * @return caseName the case name from the document handler - */ - @Override - public String getCaseName() { - if (doc == null) { - return ""; - } else { - Element nameElement = (Element) getCaseElement().getElementsByTagName(NAME).item(0); - String result = nameElement.getTextContent(); - return result; - } - } - - /** - * Gets the case Number from the document handler - * - * @return caseNumber the case number from the document handler - */ - @Override - public String getCaseNumber() { - if (doc == null) { - return ""; - } else { - Element numberElement = (Element) getCaseElement().getElementsByTagName(NUMBER).item(0); - String result = "-1"; - if (numberElement != null) { - result = numberElement.getTextContent(); - } - return result; - } - } - - /** - * Gets the examiner from the document handler - * - * @return examiner the examiner from the document handler - */ - @Override - public String getCaseExaminer() { - if (doc == null) { - return ""; - } else { - Element examinerElement = (Element) getCaseElement().getElementsByTagName(EXAMINER).item(0); - String result = ""; - if (examinerElement != null) { - result = examinerElement.getTextContent(); - } - return result; - } - } - - /** - * Gets the case directory path that's stored in this class - * - * @return caseDirPath the case directory path - */ - public String getCaseDirectory() { - if (doc == null) { - return ""; - } else { - return caseDirPath; - } - // Note: change this to get the case name from the xml file if needed - } - - /** - * Gets the Root Element from the document handler - * - * @return rootElement the root element on the document handler - */ - private Element getRootElement() { - if (doc != null) { - return doc.getDocumentElement(); - } else { - return null; // should throw error or exception - } - } - - /** - * Gets the created Date from the document handler - * - * @return createdDate the creation date of this case - */ - public String getCreatedDate() { - if (doc != null) { - Element crDateElement = (Element) getRootElement().getElementsByTagName(CREATED_DATE_NAME).item(0); - return crDateElement.getTextContent(); - } else { - return ""; // should throw error or exception - } - } - - /** - * Gets the Modified Date from the document handler - * - * @return modifiedDate the modification date of this case - */ - protected String getModifiedDate() { - if (doc != null) { - Element mDateElement = (Element) getRootElement().getElementsByTagName(MODIFIED_DATE_NAME).item(0); - return mDateElement.getTextContent(); - } else { - return ""; // should throw error or exception - } - } - - /** - * Gets the Autopsy Created Version from the document handler - * - * @return createdVersion the version of autopsy when this case was created - */ - protected String getCreatedVersion() { - if (doc != null) { - Element crVerElement = (Element) getRootElement().getElementsByTagName(AUTOPSY_CRVERSION_NAME).item(0); - return crVerElement.getTextContent(); - } else { - return ""; // should throw error or exception - } - } - - /** - * Gets the Autopsy Saved Version from the document handler - * - * @return savedVersion the latest version of autopsy when this case is - * saved - */ - protected String getSavedVersion() { - if (doc != null) { - Element mVerElement = (Element) getRootElement().getElementsByTagName(AUTOPSY_MVERSION_NAME).item(0); - return mVerElement.getTextContent(); - } else { - return ""; // should throw error or exception - } - } - - /** - * Gets the Schema Version from the document handler - * - * @return schemaVersion the schema version of this XML configuration file - */ - protected String getSchemaVersion() { - if (doc != null) { - Element schemaVerElement = (Element) getRootElement().getElementsByTagName(SCHEMA_VERSION_NAME).item(0); - return schemaVerElement.getTextContent(); - } else { - return ""; // should throw error or exception - } - } - - /** - * Gets the Case Element from the document handler - * - * @return caseElement the "Case" element - */ - private Element getCaseElement() { - if (doc != null) { - return (Element) doc.getElementsByTagName(CASE_ROOT_NAME).item(0); - } else { - return null; // should throw error or exception - } - } - - /** - * Gets the full path to the log directory - * - * @return logDir the full path of the "Log" directory - */ - protected String getLogDir() { - if (doc != null) { - Element logElement = (Element) getCaseElement().getElementsByTagName(LOG_FOLDER_NAME).item(0); - if (logElement.getAttribute(RELATIVE_NAME).equals(RELATIVE_TRUE)) { - return caseDirPath + File.separator + logElement.getTextContent(); - } else { - return logElement.getTextContent(); - } - } else { - return ""; // should throw error or exception - } - } - - /** - * Gets the full path to the temp directory - * - * @return tempDir the full path of the "Temp" directory - */ - protected String getTempDir() { - if (doc != null) { - Element tempElement = (Element) getCaseElement().getElementsByTagName(TEMP_FOLDER_NAME).item(0); - if (tempElement.getAttribute(RELATIVE_NAME).equals(RELATIVE_TRUE)) { - return caseDirPath + File.separator + tempElement.getTextContent(); - } else { - return tempElement.getTextContent(); - } - } else { - return ""; // should throw error or exception - } - } - - /** - * Gets the full path to the Export directory - * - * @return exportDir the full path of the "Export" directory - */ - protected String getExportDir() { - if (doc != null) { - Element exportElement = (Element) getCaseElement().getElementsByTagName(EXPORT_FOLDER_NAME).item(0); - if (exportElement.getAttribute(RELATIVE_NAME).equals(RELATIVE_TRUE)) { - return caseDirPath + File.separator + exportElement.getTextContent(); - } else { - return exportElement.getTextContent(); - } - } else { - return ""; // should throw error or exception - } - } - - /** - * Gets the full path to the Cache directory - * - * @return cacheDir the full path of the "Cache" directory - */ - protected String getCacheDir() { - if (doc != null) { - Element cacheElement = (Element) getCaseElement().getElementsByTagName(CACHE_FOLDER_NAME).item(0); - if (cacheElement.getAttribute(RELATIVE_NAME).equals(RELATIVE_TRUE)) { - return caseDirPath + File.separator + cacheElement.getTextContent(); - } else { - return cacheElement.getTextContent(); - } - } else { - return ""; // should throw error or exception - } - } - - /** - * Initialize the basic values for a new case management file. Note: this is - * the schema version 1.0 - * - * @param dirPath case directory path - * @param caseName the name of the config file to be located in the - * case directory - * @param examiner examiner for the case (optional, can be empty string - * @param caseNumber case number (optional), can be empty - * @param dbName the name of the database. Could be a local path, - * could be a Postgre db name. - * @param textIndexName The name of the index where extracted text is - * stored. - */ - public void create(String dirPath, String caseName, String examiner, String caseNumber, CaseType caseType, String dbName, String textIndexName) throws CaseActionException { - clear(); // clear the previous data - - // set the case Name and Directory and the parent directory - setCaseDirPath(dirPath); - setName(caseName); - setExaminer(examiner); - setNumber(caseNumber); - setCaseType(caseType); - setDatabaseName(dbName); - setTextIndexName(textIndexName); - DocumentBuilder docBuilder; - DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); - - // throw an error here - try { - docBuilder = docFactory.newDocumentBuilder(); - } catch (ParserConfigurationException ex) { - clear(); - throw new CaseActionException( - NbBundle.getMessage(this.getClass(), "XMLCaseManagement.create.exception.msg"), ex); - } - - doc = docBuilder.newDocument(); - Element rootElement = doc.createElement(TOP_ROOT_NAME); // ... - doc.appendChild(rootElement); - - Element crDateElement = doc.createElement(CREATED_DATE_NAME); // ... - crDateElement.appendChild(doc.createTextNode(dateFormat.format(new Date()))); - rootElement.appendChild(crDateElement); - - Element mDateElement = doc.createElement(MODIFIED_DATE_NAME); // ... - mDateElement.appendChild(doc.createTextNode(dateFormat.format(new Date()))); - rootElement.appendChild(mDateElement); - - Element autVerElement = doc.createElement(AUTOPSY_CRVERSION_NAME); // ... - autVerElement.appendChild(doc.createTextNode(autopsySavedVersion)); - rootElement.appendChild(autVerElement); - - Element autSavedVerElement = doc.createElement(AUTOPSY_MVERSION_NAME); // ... - autSavedVerElement.appendChild(doc.createTextNode(autopsySavedVersion)); - rootElement.appendChild(autSavedVerElement); - - Element schVerElement = doc.createElement(SCHEMA_VERSION_NAME); // ... - schVerElement.appendChild(doc.createTextNode(schemaVersion)); - rootElement.appendChild(schVerElement); - - Element caseElement = doc.createElement(CASE_ROOT_NAME); // ... - rootElement.appendChild(caseElement); - - Element nameElement = doc.createElement(NAME); // ... - nameElement.appendChild(doc.createTextNode(caseName)); - caseElement.appendChild(nameElement); - - Element numberElement = doc.createElement(NUMBER); // ... - numberElement.appendChild(doc.createTextNode(String.valueOf(caseNumber))); - caseElement.appendChild(numberElement); - - Element examinerElement = doc.createElement(EXAMINER); // ... - examinerElement.appendChild(doc.createTextNode(examiner)); - caseElement.appendChild(examinerElement); - - Element exportElement = doc.createElement(EXPORT_FOLDER_NAME); // ... - exportElement.appendChild(doc.createTextNode(EXPORT_FOLDER_RELPATH)); - exportElement.setAttribute(RELATIVE_NAME, "true"); //NON-NLS - caseElement.appendChild(exportElement); - - Element logElement = doc.createElement(LOG_FOLDER_NAME); // ... - logElement.appendChild(doc.createTextNode(LOG_FOLDER_RELPATH)); - logElement.setAttribute(RELATIVE_NAME, "true"); //NON-NLS - caseElement.appendChild(logElement); - - Element tempElement = doc.createElement(TEMP_FOLDER_NAME); // ... - tempElement.appendChild(doc.createTextNode(TEMP_FOLDER_RELPATH)); - tempElement.setAttribute(RELATIVE_NAME, "true"); //NON-NLS - caseElement.appendChild(tempElement); - - Element cacheElement = doc.createElement(CACHE_FOLDER_NAME); // ... - cacheElement.appendChild(doc.createTextNode(CACHE_FOLDER_RELPATH)); - cacheElement.setAttribute(RELATIVE_NAME, "true"); //NON-NLS - caseElement.appendChild(cacheElement); - - Element typeElement = doc.createElement(CASE_TYPE); // ... - typeElement.appendChild(doc.createTextNode(caseType.toString())); - caseElement.appendChild(typeElement); - - Element dbNameElement = doc.createElement(DATABASE_NAME); // ... - dbNameElement.appendChild(doc.createTextNode(dbName)); - caseElement.appendChild(dbNameElement); - - Element indexNameElement = doc.createElement(CASE_TEXT_INDEX_NAME); // ... - indexNameElement.appendChild(doc.createTextNode(textIndexName)); - caseElement.appendChild(indexNameElement); - - // write more code if needed ... - } - - /** - * Writes the case management file to disk (from document handler to .aut - * file) - * - */ - @Override - public void writeFile() throws CaseActionException { - if (doc == null || caseName.equals("")) { - throw new CaseActionException( - 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 CaseActionException( - 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 CaseActionException( - NbBundle.getMessage(this.getClass(), "XMLCaseManagement.writeFile.exception.errWriteToFile.msg"), ex); - } - - // preparing the output file - String xmlString = sw.toString(); - File file = new File(caseDirPath + 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 CaseActionException( - NbBundle.getMessage(this.getClass(), "XMLCaseManagement.writeFile.exception.errWriteToFile.msg"), ex); - } - } - - /** - * Opens the configuration file and load the document handler Note: this is - * for the schema version 1.0 - * - * @param conFilePath the path of the XML case configuration file path - */ - @Override - public void open(String conFilePath) throws CaseActionException { - clear(); - File file = new File(conFilePath); - - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - DocumentBuilder db; - try { - db = dbf.newDocumentBuilder(); - doc = db.parse(file); - } catch (ParserConfigurationException | SAXException | IOException ex) { - throw new CaseActionException( - NbBundle.getMessage(this.getClass(), "XMLCaseManagement.open.exception.errReadXMLFile.msg", - conFilePath), ex); - } - - doc.getDocumentElement().normalize(); - doc.getDocumentElement().normalize(); - - // TODO: Restore later -// if (!XMLUtil.xmlIsValid(doc, XMLCaseManagement.class, XSDFILE)) { -// logger.log(Level.WARNING, "Could not validate against [" + XSDFILE + "], results may not accurate"); //NON-NLS -// } - Element rootEl = doc.getDocumentElement(); - String rootName = rootEl.getNodeName(); - - // check if it's the autopsy case, if not, throws an error - if (!rootName.equals(TOP_ROOT_NAME)) { - // throw an error ... - clear(); - if (RuntimeProperties.coreComponentsAreActive()) { - - JOptionPane.showMessageDialog(caller, - NbBundle.getMessage(this.getClass(), - "XMLCaseManagement.open.msgDlg.notAutCase.msg", - file.getName(), className), - NbBundle.getMessage(this.getClass(), - "XMLCaseManagement.open.msgDlg.notAutCase.title"), - JOptionPane.ERROR_MESSAGE); - } - } else { - /* - * Autopsy Created Version - */ - String createdVersion = getCreatedVersion(); // get the created version - - // check if it has the same autopsy version as the current one - if (!createdVersion.equals(autopsySavedVersion)) { - // if not the same version, update the saved version in the xml to the current version - getRootElement().getElementsByTagName(AUTOPSY_MVERSION_NAME).item(0).setTextContent(autopsySavedVersion); - } - - /* - * Schema Version - */ - String schemaVer = getSchemaVersion(); - // check if it has the same schema version as the current one - if (!schemaVer.equals(schemaVersion)) { - // do something here if not the same version - // ... @Override - } - - // set the case Directory and Name - setCaseDirPath(file.getParent()); - String fullFileName = file.getName(); - String fileName = fullFileName.substring(0, fullFileName.lastIndexOf(".")); // remove the extension - setName(fileName); - } - } - - /** - * When user wants to close the case. This method writes any changes to the - * XML case configuration file, closes it and the document handler, and - * clears all the local variables / fields. - * - */ - @Override - public void close() throws CaseActionException { - writeFile(); // write any changes to xml - clear(); - } - - /** - * Clear the internal structures / variables - */ - private void clear() { - doc = null; - caseDirPath = ""; - caseName = ""; - caseNumber = ""; - examiner = ""; - caseType = CaseType.SINGLE_USER_CASE; - dbName = ""; - textIndexName = ""; - } -} diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java b/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java index 9121ad4d23..21e4cb1195 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Installer.java @@ -35,6 +35,7 @@ import org.openide.util.Lookup; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.CaseActionException; +import org.sleuthkit.autopsy.casemodule.CaseMetadata; import org.sleuthkit.autopsy.casemodule.OpenFromArguments; import org.sleuthkit.autopsy.coreutils.Logger; @@ -78,7 +79,7 @@ public class Installer extends ModuleInstall { if (processor instanceof OpenFromArguments) { OpenFromArguments argsProcessor = (OpenFromArguments) processor; final String caseFile = argsProcessor.getDefaultArg(); - if (caseFile != null && !caseFile.equals("") && caseFile.endsWith(".aut") && new File(caseFile).exists()) { //NON-NLS + if (caseFile != null && !caseFile.equals("") && caseFile.endsWith(CaseMetadata.getFileExtension()) && new File(caseFile).exists()) { //NON-NLS new Thread(() -> { try { Case.open(caseFile); From d8759a53be68f3ef2b78fe58e36f1237b842ca4b Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Tue, 5 Apr 2016 15:26:04 -0400 Subject: [PATCH 43/50] Moved towards just having case metadata for data in case. --- .../sleuthkit/autopsy/casemodule/Case.java | 38 +++---------------- .../autopsy/casemodule/CaseMetadata.java | 2 +- 2 files changed, 7 insertions(+), 33 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index bac25b1653..c3dce8d9d4 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -261,10 +261,6 @@ public class Case implements SleuthkitCase.ErrorObserver { } }; - private String name; - private String number; - private String examiner; - private String configFilePath; private final CaseMetadata caseMetadata; private final SleuthkitCase db; // Track the current case (only set with changeCase() method) @@ -286,11 +282,7 @@ public class Case implements SleuthkitCase.ErrorObserver { /** * Constructor for the Case class */ - 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; + private Case(CaseMetadata caseMetadata, SleuthkitCase db) { this.caseMetadata = caseMetadata; this.db = db; this.services = new Services(db); @@ -362,7 +354,7 @@ public class Case implements SleuthkitCase.ErrorObserver { NbBundle.getMessage(Case.class, "IntervalErrorReport.ErrorText")); doCaseChange(currentCase); SwingUtilities.invokeLater(() -> { - RecentCases.getInstance().addRecentCase(currentCase.name, currentCase.configFilePath); // update the recent cases + RecentCases.getInstance().addRecentCase(currentCase.getName(), currentCase.g()); // update the recent cases }); if (CaseType.MULTI_USER_CASE == newCase.getCaseType()) { try { @@ -515,7 +507,7 @@ public class Case implements SleuthkitCase.ErrorObserver { throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.databaseConnectionInfo.error.msg"), ex); } - Case newCase = new Case(caseName, caseNumber, examiner, configFilePath, metadata, db, caseType); + Case newCase = new Case(metadata, db); changeCase(newCase); } @@ -674,7 +666,7 @@ public class Case implements SleuthkitCase.ErrorObserver { } } } - Case openedCase = new Case(caseName, caseNumber, examiner, caseMetadataFilePath, metadata, db, caseType); + Case openedCase = new Case(metadata, db); changeCase(openedCase); } catch (CaseMetadataException ex) { @@ -871,7 +863,7 @@ public class Case implements SleuthkitCase.ErrorObserver { try { boolean result = deleteCaseDirectory(caseDir); // delete the directory - RecentCases.getInstance().removeRecentCase(this.name, this.configFilePath); // remove it from the recent case + RecentCases.getInstance().removeRecentCase(this.caseMetadata.getCaseName(), this.caseMetadata.getCaseDirectory()); // remove it from the recent case Case.changeCase(null); if (result == false) { throw new CaseActionException( @@ -897,7 +889,7 @@ public class Case implements SleuthkitCase.ErrorObserver { void updateCaseName(String oldCaseName, String oldPath, String newCaseName, String newPath) throws CaseActionException { try { getCaseMetadata().setCaseName(newCaseName); // set the case - name = newCaseName; // change the local value + caseMetadata.setCaseName(newCaseName); // change the local value eventPublisher.publish(new AutopsyEvent(Events.NAME.toString(), oldCaseName, newCaseName)); SwingUtilities.invokeLater(() -> { try { @@ -921,24 +913,6 @@ public class Case implements SleuthkitCase.ErrorObserver { return currentCase != null; } - /** - * Uses the given path to store it as the configuration file path - * - * @param givenPath the given config file path - */ - private void setConfigFilePath(String givenPath) { - configFilePath = givenPath; - } - - /** - * Get the config file path in the given path - * - * @return configFilePath the path of the configuration file - */ - String getConfigFilePath() { - return configFilePath; - } - /** * Returns the current version of Autopsy * diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java index e8fb7fa6e2..f97d89c1b5 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java @@ -230,7 +230,7 @@ public final class CaseMetadata { /** * @return the createdVersion */ - public String getCreatedVersion() { + String getCreatedVersion() { return createdVersion; } From 6c08ea496a1586ef354d03afd23538f5e4be6a09 Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 5 Apr 2016 15:44:57 -0400 Subject: [PATCH 44/50] fix further bug related filter copying/equality --- .../autopsy/timeline/datamodel/FilteredEventsModel.java | 7 +------ .../sleuthkit/autopsy/timeline/filters/CompoundFilter.java | 4 +--- .../autopsy/timeline/filters/DataSourcesFilter.java | 2 +- .../sleuthkit/autopsy/timeline/filters/HashHitsFilter.java | 2 +- .../org/sleuthkit/autopsy/timeline/filters/TagsFilter.java | 2 +- .../org/sleuthkit/autopsy/timeline/filters/TypeFilter.java | 2 +- 6 files changed, 6 insertions(+), 13 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java b/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java index 14a0d878f8..bf161241b1 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/datamodel/FilteredEventsModel.java @@ -23,7 +23,6 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; import java.util.logging.Level; import javafx.beans.Observable; @@ -150,11 +149,7 @@ public final class FilteredEventsModel { final ZoomParams zoomParams = requestedZoomParamters.get(); if (zoomParams != null) { - if (zoomParams.getTypeZoomLevel().equals(requestedTypeZoom.get()) == false - || zoomParams.getDescriptionLOD().equals(requestedLOD.get()) == false - || zoomParams.getFilter().equals(requestedFilter.get()) == false - || Objects.equals(zoomParams.getTimeRange(), requestedTimeRange.get()) == false) { - + synchronized (FilteredEventsModel.this) { requestedTypeZoom.set(zoomParams.getTypeZoomLevel()); requestedFilter.set(zoomParams.getFilter()); requestedTimeRange.set(zoomParams.getTimeRange()); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/CompoundFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/CompoundFilter.java index dff26b1e61..9996e0f2c7 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/CompoundFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/CompoundFilter.java @@ -93,9 +93,7 @@ public abstract class CompoundFilter extends Abstr for (int i = 0; i < oneFilter.getSubFilters().size(); i++) { final SubFilterType subFilter = oneFilter.getSubFilters().get(i); final SubFilterType otherSubFilter = otherFilter.getSubFilters().get(i); - if (subFilter.equals(otherSubFilter) == false - || subFilter.isDisabled() != otherSubFilter.isDisabled() - || subFilter.isSelected() != otherSubFilter.isSelected()) { + if (subFilter.equals(otherSubFilter) == false) { return false; } } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/DataSourcesFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/DataSourcesFilter.java index b02279b2e3..3a52535327 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/DataSourcesFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/DataSourcesFilter.java @@ -88,7 +88,7 @@ public class DataSourcesFilter extends UnionFilter { } final DataSourcesFilter other = (DataSourcesFilter) obj; - if (isSelected() != other.isSelected()) { + if (isActive() != other.isActive()) { return false; } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/HashHitsFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/HashHitsFilter.java index 7404663716..81b8566860 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/HashHitsFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/HashHitsFilter.java @@ -66,7 +66,7 @@ public class HashHitsFilter extends UnionFilter { } final HashHitsFilter other = (HashHitsFilter) obj; - if (isSelected() != other.isSelected()) { + if (isActive() != other.isActive()) { return false; } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/TagsFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/TagsFilter.java index bcf00d2d23..4787da89f3 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/TagsFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/TagsFilter.java @@ -67,7 +67,7 @@ public class TagsFilter extends UnionFilter { } final TagsFilter other = (TagsFilter) obj; - if (isSelected() != other.isSelected()) { + if (isActive() != other.isActive()) { return false; } diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/TypeFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/TypeFilter.java index 85a299e5fc..bc2c84bae0 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/TypeFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/TypeFilter.java @@ -126,7 +126,7 @@ public class TypeFilter extends UnionFilter { } final TypeFilter other = (TypeFilter) obj; - if (isSelected() != other.isSelected()) { + if (isActive() != other.isActive()) { return false; } From 4a2753393f0de6e51b3390b5c508a9fdf1517ebc Mon Sep 17 00:00:00 2001 From: jmillman Date: Tue, 5 Apr 2016 16:10:40 -0400 Subject: [PATCH 45/50] update copyright --- .../timeline/filters/CompoundFilter.java | 7 ++----- .../timeline/filters/DataSourcesFilter.java | 2 +- .../timeline/filters/HashHitsFilter.java | 19 ++++++++++++++++--- .../autopsy/timeline/filters/TagsFilter.java | 19 ++++++++++++++++--- .../autopsy/timeline/filters/TypeFilter.java | 2 +- .../autopsy/timeline/filters/UnionFilter.java | 2 +- 6 files changed, 37 insertions(+), 14 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/CompoundFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/CompoundFilter.java index 9996e0f2c7..bd88a6d90b 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/CompoundFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/CompoundFilter.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014-15 Basis Technology Corp. + * Copyright 2014-16 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,10 +33,7 @@ import javafx.collections.ObservableList; * a {@link CompoundFilter} uses listeners to enforce the following * relationships between it and its sub-filters: *
      - * if a filter becomes active, and all its sub-filters were inactive, make - * them all active - * if a filter becomes inactive and all its sub-filters were active, make - * them all inactive + * if a filter becomes inactive disable all of its subfilters * if a sub-filter changes active state set the parent filter active if any * of its sub-filters are active. *
    diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/DataSourcesFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/DataSourcesFilter.java index 3a52535327..0da318e80d 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/DataSourcesFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/DataSourcesFilter.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2015-16 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/HashHitsFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/HashHitsFilter.java index 81b8566860..371f32dcdc 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/HashHitsFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/HashHitsFilter.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2015-16 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.sleuthkit.autopsy.timeline.filters; diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/TagsFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/TagsFilter.java index 4787da89f3..4c92a3b02a 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/TagsFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/TagsFilter.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2015-16 Basis Technology Corp. + * Contact: carrier sleuthkit org + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.sleuthkit.autopsy.timeline.filters; diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/TypeFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/TypeFilter.java index bc2c84bae0..4968e92e80 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/TypeFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/TypeFilter.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-15 Basis Technology Corp. + * Copyright 2013-16 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/Core/src/org/sleuthkit/autopsy/timeline/filters/UnionFilter.java b/Core/src/org/sleuthkit/autopsy/timeline/filters/UnionFilter.java index 07ef904e75..27bec42c72 100644 --- a/Core/src/org/sleuthkit/autopsy/timeline/filters/UnionFilter.java +++ b/Core/src/org/sleuthkit/autopsy/timeline/filters/UnionFilter.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014-15 Basis Technology Corp. + * Copyright 2014-16 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); From 8e07b91e81bb6ce04da1150e2c5f599cc120cbce Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Wed, 6 Apr 2016 09:51:17 -0400 Subject: [PATCH 46/50] Moved case directory into case class. --- .../sleuthkit/autopsy/casemodule/Case.java | 54 ++++++++----------- .../autopsy/casemodule/CaseDeleteAction.java | 3 +- .../autopsy/casemodule/CaseMetadata.java | 34 ++++++------ 3 files changed, 38 insertions(+), 53 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index c3dce8d9d4..57d0481ed7 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -263,6 +263,7 @@ public class Case implements SleuthkitCase.ErrorObserver { private final CaseMetadata caseMetadata; private final SleuthkitCase db; + private final String caseDirectory; // Track the current case (only set with changeCase() method) private static Case currentCase = null; private final Services services; @@ -282,10 +283,11 @@ public class Case implements SleuthkitCase.ErrorObserver { /** * Constructor for the Case class */ - private Case(CaseMetadata caseMetadata, SleuthkitCase db) { + private Case(CaseMetadata caseMetadata, SleuthkitCase db, String caseDirectory) { this.caseMetadata = caseMetadata; this.db = db; this.services = new Services(db); + this.caseDirectory = caseDirectory; } /** @@ -354,7 +356,7 @@ public class Case implements SleuthkitCase.ErrorObserver { NbBundle.getMessage(Case.class, "IntervalErrorReport.ErrorText")); doCaseChange(currentCase); SwingUtilities.invokeLater(() -> { - RecentCases.getInstance().addRecentCase(currentCase.getName(), currentCase.g()); // update the recent cases + RecentCases.getInstance().addRecentCase(currentCase.getName(), currentCase.getConfigFilePath()); // update the recent cases }); if (CaseType.MULTI_USER_CASE == newCase.getCaseType()) { try { @@ -438,8 +440,6 @@ public class Case implements SleuthkitCase.ErrorObserver { * (null otherwise). * * @throws CaseActionException if there is a problem creating the case. - * @throws CaseMetadataException if there is a problem creating the case - * metadata. */ @Messages({"Case.creationException=Could not create case: failed to make metadata file."}) public static void create(String caseDir, String caseName, String caseNumber, String examiner, CaseType caseType) throws CaseActionException { @@ -471,7 +471,6 @@ public class Case implements SleuthkitCase.ErrorObserver { /* * Create the case metadata (.aut) file. */ - String configFilePath = caseDir + File.separator + caseName + CaseMetadata.getFileExtension(); CaseMetadata metadata; try { metadata = CaseMetadata.create(caseDir, caseType, caseName, caseNumber, examiner, dbName, indexName); @@ -507,7 +506,7 @@ public class Case implements SleuthkitCase.ErrorObserver { throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.databaseConnectionInfo.error.msg"), ex); } - Case newCase = new Case(metadata, db); + Case newCase = new Case(metadata, db, caseDir); changeCase(newCase); } @@ -599,24 +598,23 @@ public class Case implements SleuthkitCase.ErrorObserver { * Get the case metadata required to open the case database. */ CaseMetadata metadata = CaseMetadata.open(Paths.get(caseMetadataFilePath)); - String caseName = metadata.getCaseName(); - String caseNumber = metadata.getCaseNumber(); - String examiner = metadata.getExaminer(); CaseType caseType = metadata.getCaseType(); - String caseDir = metadata.getCaseDirectory(); /* * Open the case database. */ SleuthkitCase db; + String caseDir; if (caseType == CaseType.SINGLE_USER_CASE) { - String dbPath = Paths.get(caseDir, "autopsy.db").toString(); //NON-NLS + String dbPath = metadata.getCaseDatabaseName(); //NON-NLS db = SleuthkitCase.openCase(dbPath); + caseDir = new File(dbPath).getParent(); } else { if (!UserPreferences.getIsMultiUserModeEnabled()) { throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.open.exception.multiUserCaseNotEnabled")); } try { + caseDir = new File(metadata.getConfigFilePath()).getParent(); db = SleuthkitCase.openCase(metadata.getCaseDatabaseName(), UserPreferences.getDatabaseConnectionInfo(), caseDir); } catch (UserPreferencesException ex) { throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.databaseConnectionInfo.error.msg"), ex); @@ -666,7 +664,7 @@ public class Case implements SleuthkitCase.ErrorObserver { } } } - Case openedCase = new Case(metadata, db); + Case openedCase = new Case(metadata, db, caseDir); changeCase(openedCase); } catch (CaseMetadataException ex) { @@ -837,6 +835,10 @@ public class Case implements SleuthkitCase.ErrorObserver { return this.db; } + public String getConfigFilePath() { + return this.caseMetadata.getConfigFilePath(); + } + /** * Closes this case. This methods close the xml and clear all the fields. */ @@ -863,7 +865,7 @@ public class Case implements SleuthkitCase.ErrorObserver { try { boolean result = deleteCaseDirectory(caseDir); // delete the directory - RecentCases.getInstance().removeRecentCase(this.caseMetadata.getCaseName(), this.caseMetadata.getCaseDirectory()); // remove it from the recent case + RecentCases.getInstance().removeRecentCase(this.caseMetadata.getCaseName(), this.caseMetadata.getConfigFilePath()); // remove it from the recent case Case.changeCase(null); if (result == false) { throw new CaseActionException( @@ -947,7 +949,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @return name */ public String getName() { - return name; + return caseMetadata.getCaseName(); } /** @@ -956,7 +958,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @return number */ public String getNumber() { - return number; + return caseMetadata.getCaseNumber(); } /** @@ -965,7 +967,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @return examiner */ public String getExaminer() { - return examiner; + return caseMetadata.getExaminer(); } /** @@ -974,11 +976,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @return caseDirectoryPath */ public String getCaseDirectory() { - if (getCaseMetadata() == null) { - return ""; - } else { - return getCaseMetadata().getCaseDirectory(); - } + return this.caseDirectory; } /** @@ -1176,11 +1174,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @return case creation date */ public String getCreatedDate() { - if (getCaseMetadata() == null) { - return ""; - } else { - return getCaseMetadata().getCreatedDate(); - } + return getCaseMetadata().getCreatedDate(); } /** @@ -1189,11 +1183,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @return Index name. */ public String getTextIndexName() { - if (getCaseMetadata() == null) { - return ""; - } else { - return getCaseMetadata().getTextIndexName(); - } + return getCaseMetadata().getTextIndexName(); } /** @@ -1556,7 +1546,7 @@ public class Case implements SleuthkitCase.ErrorObserver { if (RuntimeProperties.coreComponentsAreActive()) { SwingUtilities.invokeLater(() -> { - updateMainWindowTitle(currentCase.name); + updateMainWindowTitle(currentCase.getName()); }); } else { SwingUtilities.invokeLater(() -> { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java index 54920ec79e..6ec7c79222 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseDeleteAction.java @@ -81,8 +81,7 @@ final class CaseDeleteAction extends CallableSystemAction { @Override public void actionPerformed(ActionEvent e) { Case currentCase = Case.getCurrentCase(); - File configFile = new File(currentCase.getConfigFilePath()); - File caseFolder = new File(configFile.getParent()); + File caseFolder = new File(currentCase.getCaseDirectory()); String caseName = currentCase.getName(); if (!caseFolder.exists()) { // throw an error diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java index f97d89c1b5..ec496ac055 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java @@ -93,25 +93,25 @@ public final class CaseMetadata { private String caseName; private String caseNumber; private String examiner; - private String caseDirectory; private String caseDatabaseName; private String caseTextIndexName; private String createdDate; private String fileName; private String createdVersion; + private final String configFilePath; - private CaseMetadata(Case.CaseType caseType, String caseName, String caseNumber, String examiner, String caseDirectory, String caseDatabaseName, String caseTextIndexName) throws CaseMetadataException { + private CaseMetadata(String caseDirectory, Case.CaseType caseType, String caseName, String caseNumber, String examiner, String caseDatabaseName, String caseTextIndexName) throws CaseMetadataException { this.caseType = caseType; this.caseName = caseName; this.caseNumber = caseNumber; this.examiner = examiner; this.createdDate = CaseMetadata.DATE_FORMAT.format(new Date()); - this.caseDirectory = caseDirectory; this.caseDatabaseName = caseDatabaseName; this.caseTextIndexName = caseTextIndexName; this.fileName = caseName; this.createdVersion = System.getProperty("netbeans.buildnumber"); + configFilePath = Paths.get(caseDirectory, caseName + FILE_EXTENSION).toString(); this.write(); } @@ -125,6 +125,7 @@ public final class CaseMetadata { * org.sleuthkit.autopsy.casemodule.CaseMetadata.CaseMetadataException */ private CaseMetadata(String metadataFilePath) throws CaseMetadataException { + this.configFilePath = metadataFilePath; this.read(metadataFilePath); } @@ -160,7 +161,7 @@ public final class CaseMetadata { * org.sleuthkit.autopsy.casemodule.CaseMetadata.CaseMetadataException */ static CaseMetadata create(String caseDirectory, Case.CaseType caseType, String caseName, String caseNumber, String examiner, String caseDatabaseName, String caseTextIndexName) throws CaseMetadataException { - CaseMetadata metadata = new CaseMetadata(caseType, caseName, caseNumber, examiner, caseDirectory, caseDatabaseName, caseTextIndexName); + CaseMetadata metadata = new CaseMetadata(caseDirectory, caseType, caseName, caseNumber, examiner, caseDatabaseName, caseTextIndexName); return metadata; } @@ -191,6 +192,15 @@ public final class CaseMetadata { return caseNumber; } + /** + * Gets the path to the metadata file file + * + * @return The path to the metadata file + */ + public String getConfigFilePath() { + return configFilePath; + } + /** * Gets the examiner. * @@ -200,15 +210,6 @@ public final class CaseMetadata { return examiner; } - /** - * Gets the case directory. - * - * @return The case directory. - */ - String getCaseDirectory() { - return caseDirectory; - } - /** * Gets the case database name. * @@ -391,7 +392,7 @@ public final class CaseMetadata { // preparing the output file String xmlString = sw.toString(); - File file = new File(Paths.get(this.getCaseDirectory(), this.fileName + getFileExtension()).toString()); + File file = new File(this.configFilePath); // write the file try { @@ -487,11 +488,6 @@ public final class CaseMetadata { Element examinerElement = caseElement.getElementsByTagName(EXAMINER).getLength() > 0 ? (Element) caseElement.getElementsByTagName(EXAMINER).item(0) : null; this.examiner = examinerElement != null ? examinerElement.getTextContent() : ""; - this.caseDirectory = conFilePath.substring(0, conFilePath.lastIndexOf("\\")); - if (this.caseDirectory.isEmpty()) { - throw new CaseMetadataException("Could not get a valid case directory"); - } - NodeList databaseNameList = caseElement.getElementsByTagName(DATABASE_NAME); if (databaseNameList.getLength() == 0) { throw new CaseMetadataException("Couldn't get database name"); From a4b7728939ccc3d0f783c5d7bff99c192eaa1c9c Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 6 Apr 2016 23:48:29 -0400 Subject: [PATCH 47/50] Fix and improve casemodule/CaseMetadata --- .../autopsy/casemodule/Bundle.properties | 8 - .../autopsy/casemodule/Bundle_ja.properties | 8 - .../sleuthkit/autopsy/casemodule/Case.java | 38 +- .../autopsy/casemodule/CaseMetadata.java | 859 ++++++++---------- .../casemodule/CasePropertiesForm.java | 4 +- .../autopsy/casemodule/RecentCases.java | 2 +- .../casemodule/SingleUserCaseConverter.java | 6 +- .../netbeans/core/startup/Bundle.properties | 2 +- .../core/windows/view/ui/Bundle.properties | 2 +- 9 files changed, 430 insertions(+), 499 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index d05018d379..6ddaca4ead 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -219,14 +219,6 @@ RecentItems.openRecentCase.msgDlg.text=Case {0} no longer exists. StartupWindow.title.text=Welcome UpdateRecentCases.menuItem.clearRecentCases.text=Clear Recent Cases UpdateRecentCases.menuItem.empty=-Empty- -XMLCaseManagement.create.exception.msg=Error setting up Case XML file, -XMLCaseManagement.writeFile.exception.noCase.msg=No set case to write management file for. -XMLCaseManagement.writeFile.exception.errWriteToFile.msg=Error writing to case file -XMLCaseManagement.open.exception.errReadXMLFile.msg=Error reading case XML file\: {0} -XMLCaseManagement.open.msgDlg.notAutCase.msg=Error\: This is not an Autopsy config file ("{0}").\n\n\ -Detail\: \n\ -Cannot open a non-Autopsy config file (at {1}). -XMLCaseManagement.open.msgDlg.notAutCase.title=Error AddImageWizardIngestConfigPanel.CANCEL_BUTTON.text=Cancel ImageFilePanel.errorLabel.text=Error Label DataSourceOnCDriveError.text=Warning\: Path to multi-user data source is on "C\:" drive diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties index 071aafab4c..e7e2a02c5c 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle_ja.properties @@ -178,14 +178,6 @@ RecentItems.openRecentCase.msgDlg.text=\u30a8\u30e9\u30fc\uff1a\u30b1\u30fc\u30b StartupWindow.title.text=\u3088\u3046\u3053\u305d UpdateRecentCases.menuItem.clearRecentCases.text=\u6700\u8fd1\u958b\u3044\u305f\u30b1\u30fc\u30b9\u3092\u30af\u30ea\u30a2 UpdateRecentCases.menuItem.empty=-\u7a7a\u767d- -XMLCaseManagement.create.exception.msg=\u30b1\u30fc\u30b9XML\u30d5\u30a1\u30a4\u30eb\u306e\u8a2d\u5b9a\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3001 -XMLCaseManagement.writeFile.exception.noCase.msg=\u30de\u30cd\u30b8\u30e1\u30f3\u30c8\u30d5\u30a1\u30a4\u30eb\u3092\u66f8\u304f\u5fc5\u8981\u304c\u3042\u308b\u30b1\u30fc\u30b9\u304c\u3042\u308a\u307e\u305b\u3093\u3002 -XMLCaseManagement.writeFile.exception.errWriteToFile.msg=\u30b1\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb\u3078\u306e\u66f8\u304d\u8fbc\u307f\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f -XMLCaseManagement.open.exception.errReadXMLFile.msg=\u30b1\u30fc\u30b9XML\u30d5\u30a1\u30a4\u30eb\u306e\u8aad\u307f\u53d6\u308a\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\uff1a{0} -XMLCaseManagement.open.msgDlg.notAutCase.msg=\u30a8\u30e9\u30fc\uff1aAutopsy\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb("{0}")\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002\n\n\ -\u8a73\u7d30\uff1a\n\ -Autopsy\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u4ee5\u5916\u306f(at {1})\u3067\u958b\u3051\u307e\u305b\u3093\u3002 -XMLCaseManagement.open.msgDlg.notAutCase.title=\u30a8\u30e9\u30fc ImageFilePanel.noFatOrphansCheckbox.text=FAT\u30d5\u30a1\u30a4\u30eb\u30b7\u30b9\u30c6\u30e0\u306e\u30aa\u30fc\u30d5\u30a1\u30f3\u30d5\u30a1\u30a4\u30eb\u306f\u7121\u8996 LocalDiskPanel.noFatOrphansCheckbox.text=FAT\u30d5\u30a1\u30a4\u30eb\u30b7\u30b9\u30c6\u30e0\u306e\u30aa\u30fc\u30d5\u30a1\u30f3\u30d5\u30a1\u30a4\u30eb\u306f\u7121\u8996 AddImageWizardIngestConfigPanel.CANCEL_BUTTON.text=\u30ad\u30e3\u30f3\u30bb\u30eb diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 57d0481ed7..f871fff696 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -263,7 +263,6 @@ public class Case implements SleuthkitCase.ErrorObserver { private final CaseMetadata caseMetadata; private final SleuthkitCase db; - private final String caseDirectory; // Track the current case (only set with changeCase() method) private static Case currentCase = null; private final Services services; @@ -283,11 +282,10 @@ public class Case implements SleuthkitCase.ErrorObserver { /** * Constructor for the Case class */ - private Case(CaseMetadata caseMetadata, SleuthkitCase db, String caseDirectory) { + private Case(CaseMetadata caseMetadata, SleuthkitCase db) { this.caseMetadata = caseMetadata; this.db = db; this.services = new Services(db); - this.caseDirectory = caseDirectory; } /** @@ -356,7 +354,7 @@ public class Case implements SleuthkitCase.ErrorObserver { NbBundle.getMessage(Case.class, "IntervalErrorReport.ErrorText")); doCaseChange(currentCase); SwingUtilities.invokeLater(() -> { - RecentCases.getInstance().addRecentCase(currentCase.getName(), currentCase.getConfigFilePath()); // update the recent cases + RecentCases.getInstance().addRecentCase(currentCase.getName(), currentCase.getCaseMetadata().getFilePath().toString()); // update the recent cases }); if (CaseType.MULTI_USER_CASE == newCase.getCaseType()) { try { @@ -473,7 +471,7 @@ public class Case implements SleuthkitCase.ErrorObserver { */ CaseMetadata metadata; try { - metadata = CaseMetadata.create(caseDir, caseType, caseName, caseNumber, examiner, dbName, indexName); + metadata = new CaseMetadata(caseDir, caseType, caseName, caseNumber, examiner, dbName, indexName); } catch (CaseMetadataException ex) { throw new CaseActionException(Bundle.Case_creationException(), ex); } @@ -506,7 +504,7 @@ public class Case implements SleuthkitCase.ErrorObserver { throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.databaseConnectionInfo.error.msg"), ex); } - Case newCase = new Case(metadata, db, caseDir); + Case newCase = new Case(metadata, db); changeCase(newCase); } @@ -597,7 +595,7 @@ public class Case implements SleuthkitCase.ErrorObserver { /* * Get the case metadata required to open the case database. */ - CaseMetadata metadata = CaseMetadata.open(Paths.get(caseMetadataFilePath)); + CaseMetadata metadata = new CaseMetadata(Paths.get(caseMetadataFilePath)); CaseType caseType = metadata.getCaseType(); /* @@ -606,7 +604,7 @@ public class Case implements SleuthkitCase.ErrorObserver { SleuthkitCase db; String caseDir; if (caseType == CaseType.SINGLE_USER_CASE) { - String dbPath = metadata.getCaseDatabaseName(); //NON-NLS + String dbPath = metadata.getCaseDatabase(); //NON-NLS db = SleuthkitCase.openCase(dbPath); caseDir = new File(dbPath).getParent(); } else { @@ -614,8 +612,7 @@ public class Case implements SleuthkitCase.ErrorObserver { throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.open.exception.multiUserCaseNotEnabled")); } try { - caseDir = new File(metadata.getConfigFilePath()).getParent(); - db = SleuthkitCase.openCase(metadata.getCaseDatabaseName(), UserPreferences.getDatabaseConnectionInfo(), caseDir); + db = SleuthkitCase.openCase(metadata.getCaseDatabase(), UserPreferences.getDatabaseConnectionInfo(), metadata.getCaseDirectory()); } catch (UserPreferencesException ex) { throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.databaseConnectionInfo.error.msg"), ex); } @@ -664,7 +661,7 @@ public class Case implements SleuthkitCase.ErrorObserver { } } } - Case openedCase = new Case(metadata, db, caseDir); + Case openedCase = new Case(metadata, db); changeCase(openedCase); } catch (CaseMetadataException ex) { @@ -835,10 +832,6 @@ public class Case implements SleuthkitCase.ErrorObserver { return this.db; } - public String getConfigFilePath() { - return this.caseMetadata.getConfigFilePath(); - } - /** * Closes this case. This methods close the xml and clear all the fields. */ @@ -865,7 +858,7 @@ public class Case implements SleuthkitCase.ErrorObserver { try { boolean result = deleteCaseDirectory(caseDir); // delete the directory - RecentCases.getInstance().removeRecentCase(this.caseMetadata.getCaseName(), this.caseMetadata.getConfigFilePath()); // remove it from the recent case + RecentCases.getInstance().removeRecentCase(this.caseMetadata.getCaseName(), this.caseMetadata.getFilePath().toString()); // remove it from the recent case Case.changeCase(null); if (result == false) { throw new CaseActionException( @@ -976,7 +969,7 @@ public class Case implements SleuthkitCase.ErrorObserver { * @return caseDirectoryPath */ public String getCaseDirectory() { - return this.caseDirectory; + return caseMetadata.getCaseDirectory(); } /** @@ -1679,4 +1672,15 @@ public class Case implements SleuthkitCase.ErrorObserver { return hasData; } + /** + * Gets the full path to the case metadata file for this case. + * + * @return configFilePath The case metadata file path. + * @deprecated Use getCaseMetadata and CaseMetadata.getFilePath instead. + */ + @Deprecated + String getConfigFilePath() { + return getCaseMetadata().getFilePath().toString(); + } + } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java index ec496ac055..bf0862ba02 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java @@ -19,7 +19,6 @@ 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; @@ -36,14 +35,10 @@ 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 org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.coreutils.XMLUtil; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -55,9 +50,403 @@ import org.xml.sax.SAXException; */ public final class CaseMetadata { + private static final String FILE_EXTENSION = ".aut"; + private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss (z)"); + private static final String SCHEMA_VERSION_ONE = "1.0"; + private final static String CREATED_BY_VERSION_ELEMENT_NAME = "AutopsyCreatedVersion"; //NON-NLS + private final static String CASE_DATABASE_NAME_ELEMENT_NAME = "DatabaseName"; //NON-NLS + private static final String CURRENT_SCHEMA_VERSION = "2.0"; + private final static String ROOT_ELEMENT_NAME = "AutopsyCase"; //NON-NLS + private final static String SCHEMA_VERSION_ELEMENT_NAME = "SchemaVersion"; //NON-NLS + private final static String CREATED_DATE_ELEMENT_NAME = "CreatedDate"; //NON-NLS + private final static String MODIFIED_DATE_ELEMENT_NAME = "ModifiedDate"; //NON-NLS + private final static String CREATED_BY_BUILD_ELEMENT_NAME = "CreatedByBuild"; //NON-NLS + private final static String SAVED_BY_BUILD_ELEMENT_NAME = "SavedByBuild"; //NON-NLS + private final static String CASE_ELEMENT_NAME = "Case"; //NON-NLS + private final static String CASE_NAME_ELEMENT_NAME = "Name"; //NON-NLS + private final static String CASE_NUMBER_ELEMENT_NAME = "Number"; //NON-NLS + private final static String EXAMINER_ELEMENT_NAME = "Examiner"; //NON-NLS + private final static String CASE_TYPE_ELEMENT_NAME = "CaseType"; //NON-NLS + private final static String CASE_DATABASE_ELEMENT_NAME = "Database"; //NON-NLS + private final static String TEXT_INDEX_NAME_ELEMENT = "TextIndexName"; //NON-NLS + private final Path metadataFilePath; + private Case.CaseType caseType; + private String caseName; + private String caseNumber; + private String examiner; + private String caseDatabase; + private String textIndexName; + private String createdDate; + private String createdByBuild; + + /** + * Gets the file extension used for case metadata files. + * + * @return The file extension. + */ + public static String getFileExtension() { + return FILE_EXTENSION; + } + + /** + * Constructs an object that provides access to the case metadata stored in + * a new case metadata file. + * + * @param caseDirectory The case directory. + * @param caseType The type of case. + * @param caseName The name of the case. + * @param caseNumber The case number. + * @param examiner The name of the case examiner. + * @param caseDatabase For a single-user case, the full path to the + * case database file. For a multi-user case, the + * case database name. + * @param caseTextIndexName The text index name. + * + * @throws CaseMetadataException If the new case metadata file cannot be + * created. + */ + CaseMetadata(String caseDirectory, Case.CaseType caseType, String caseName, String caseNumber, String examiner, String caseDatabase, String caseTextIndexName) throws CaseMetadataException { + metadataFilePath = Paths.get(caseDirectory, caseName + FILE_EXTENSION); + this.caseType = caseType; + this.caseName = caseName; + this.caseNumber = caseNumber; + this.examiner = examiner; + this.caseDatabase = caseDatabase; + this.textIndexName = caseTextIndexName; + createdByBuild = System.getProperty("netbeans.buildnumber"); + createdDate = CaseMetadata.DATE_FORMAT.format(new Date()); + writeToFile(); + } + + /** + * Constructs an object that provides access to the case metadata stored in + * an existing case metadata file. + * + * @param metadataFilePath The full path to the case metadata file. + * + * @throws CaseMetadataException If the new case metadata file cannot be + * read. + */ + public CaseMetadata(Path metadataFilePath) throws CaseMetadataException { + this.metadataFilePath = metadataFilePath; + readFromFile(); + } + + /** + * Gets the full path to the case metadata file. + * + * @return The path to the metadata file + */ + Path getFilePath() { + return metadataFilePath; + } + + /** + * Gets the case directory. + * + * @return The case directory. + */ + public String getCaseDirectory() { + return this.metadataFilePath.getParent().toString(); + } + + /** + * Gets the case type. + * + * @return The case type. + */ + public Case.CaseType getCaseType() { + return this.caseType; + } + + /** + * Gets the case display name. + * + * @return The case display name. + */ + public String getCaseName() { + return caseName; + } + + /** + * Sets the case display name. This does not change the name of the case + * directory, the case database, or the text index name. + * + * @param caseName A case display name. + */ + void setCaseName(String caseName) throws CaseMetadataException { + String oldCaseName = this.caseName; + this.caseName = caseName; + try { + this.writeToFile(); + } catch (CaseMetadataException ex) { + this.caseName = oldCaseName; + throw ex; + } + } + + /** + * Gets the case number. + * + * @return The case number, may be empty. + */ + public String getCaseNumber() { + return caseNumber; + } + + /** + * Gets the examiner. + * + * @return The examiner, may be empty. + */ + public String getExaminer() { + return examiner; + } + + /** + * Gets a string identifying the case database. + * + * @return For a single-user case, the full path to the case database file. + * For a multi-user case, the case database name. + */ + public String getCaseDatabase() { + return caseDatabase; + } + + /** + * Gets the text index name. + * + * @return The name of the text index for the case. + */ + public String getTextIndexName() { + return textIndexName; + } + + /** + * Gets the date the case was created. + * + * @return The date this case was created as a string + */ + String getCreatedDate() { + return this.createdDate; + } + + /** + * Sets the date the case was created. Used for preserving the case creation + * date during single-user to multi-user case conversion. + * + * @param createdDate The date the case was created as a string. + */ + void setCreatedDate(String createdDate) throws CaseMetadataException { + String oldCreatedDate = this.createdDate; + this.createdDate = createdDate; + try { + this.writeToFile(); + } catch (CaseMetadataException ex) { + this.createdDate = oldCreatedDate; + throw ex; + } + } + + /** + * Gets the build that created the case. + * + * @return A build identifier. + */ + String getCreatedByBuild() { + return createdByBuild; + } + + /** + * Gets the build that created the case. Used for preserving the case + * creation build during single-user to multi-user case conversion. + * + * @param buildVersion An build version identifier. + */ + void setCreatedByBuild(String buildVersion) throws CaseMetadataException { + String oldCreatedByVersion = this.createdByBuild; + this.createdByBuild = buildVersion; + try { + this.writeToFile(); + } catch (CaseMetadataException ex) { + this.createdByBuild = oldCreatedByVersion; + throw ex; + } + } + + /** + * Writes the case metadata to the metadata file. + * + * @throws CaseMetadataException If there is an error writing to the case + * metadata file. + */ + private void writeToFile() throws CaseMetadataException { + try { + /* + * Create the XML DOM. + */ + Document doc = XMLUtil.createDocument(); + createXMLDOM(doc); + doc.normalize(); + + /* + * Prepare the DOM for pretty printing to the metadata file. + */ + Source source = new DOMSource(doc); + StringWriter stringWriter = new StringWriter(); + Result streamResult = new StreamResult(stringWriter); + Transformer transformer = TransformerFactory.newInstance().newTransformer(); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //NON-NLS + transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2"); //NON-NLS + transformer.transform(source, streamResult); + + /* + * Write the DOM to the metadata file. + */ + try (BufferedWriter fileWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(metadataFilePath.toFile())))) { + fileWriter.write(stringWriter.toString()); + fileWriter.flush(); + } + + } catch (ParserConfigurationException | TransformerException | IOException ex) { + throw new CaseMetadataException(String.format("Error writing to case metadata file %s", metadataFilePath), ex); + } + } + + /* + * Creates an XML DOM from the case metadata. + */ + private void createXMLDOM(Document doc) { + /* + * Create the root element and its children. + */ + Element rootElement = doc.createElement(ROOT_ELEMENT_NAME); + doc.appendChild(rootElement); + createChildElement(doc, rootElement, SCHEMA_VERSION_ELEMENT_NAME, CURRENT_SCHEMA_VERSION); + createChildElement(doc, rootElement, CREATED_DATE_ELEMENT_NAME, this.getCreatedDate()); + createChildElement(doc, rootElement, MODIFIED_DATE_ELEMENT_NAME, DATE_FORMAT.format(new Date())); + createChildElement(doc, rootElement, CREATED_BY_BUILD_ELEMENT_NAME, this.getCreatedByBuild()); + createChildElement(doc, rootElement, SAVED_BY_BUILD_ELEMENT_NAME, System.getProperty("netbeans.buildnumber")); + Element caseElement = doc.createElement(CASE_ELEMENT_NAME); + rootElement.appendChild(caseElement); + + /* + * Create the children of the case element. + */ + createChildElement(doc, caseElement, CASE_NAME_ELEMENT_NAME, this.getCaseName()); + createChildElement(doc, caseElement, CASE_NUMBER_ELEMENT_NAME, this.getCaseNumber()); + createChildElement(doc, caseElement, EXAMINER_ELEMENT_NAME, this.getExaminer()); + createChildElement(doc, caseElement, CASE_TYPE_ELEMENT_NAME, this.getCaseType().toString()); + createChildElement(doc, caseElement, CASE_DATABASE_ELEMENT_NAME, this.getCaseDatabaseName()); + createChildElement(doc, caseElement, TEXT_INDEX_NAME_ELEMENT, this.getTextIndexName()); + } + + /** + * Creates an XML element for the case metadata XML DOM. + * + * @param doc The document. + * @param parentElement The parent element of the element to be created. + * @param elementName The name of the element to be created. + * @param elementContent The text content of the element to be created, may + * be empty. + */ + private void createChildElement(Document doc, Element parentElement, String elementName, String elementContent) { + Element element = doc.createElement(elementName); + element.appendChild(doc.createTextNode(elementContent)); + parentElement.appendChild(element); + } + + /** + * Reads the case metadata from the metadata file. + * + * @throws CaseMetadataException If there is an error reading from the case + * metadata file. + */ + private void readFromFile() throws CaseMetadataException { + try { + /* + * Parse the file into an XML DOM and get the root element. + */ + DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + Document doc = builder.parse(this.getFilePath().toFile()); + doc.getDocumentElement().normalize(); + Element rootElement = doc.getDocumentElement(); + if (!rootElement.getNodeName().equals(ROOT_ELEMENT_NAME)) { + throw new CaseMetadataException("Case metadata file corrupted"); + } + + /* + * Get the content of the relevant children of the root element. + */ + String schemaVersion = getElementTextContent(rootElement, SCHEMA_VERSION_ELEMENT_NAME, true); + this.createdDate = getElementTextContent(rootElement, CREATED_DATE_ELEMENT_NAME, true); + if (schemaVersion.equals(SCHEMA_VERSION_ONE)) { + this.createdByBuild = getElementTextContent(rootElement, CREATED_BY_VERSION_ELEMENT_NAME, true); + } else { + this.createdByBuild = getElementTextContent(rootElement, CREATED_BY_BUILD_ELEMENT_NAME, true); + } + + /* + * Get the content of the children of the case element. + */ + NodeList caseElements = doc.getElementsByTagName(CASE_ELEMENT_NAME); + if (caseElements.getLength() == 0) { + throw new CaseMetadataException("Case metadata file corrupted"); + } + Element caseElement = (Element) caseElements.item(0); + this.caseName = getElementTextContent(caseElement, CASE_NAME_ELEMENT_NAME, true); + this.caseNumber = getElementTextContent(caseElement, CASE_NUMBER_ELEMENT_NAME, false); + this.examiner = getElementTextContent(caseElement, EXAMINER_ELEMENT_NAME, false); + this.caseType = Case.CaseType.fromString(getElementTextContent(caseElement, CASE_TYPE_ELEMENT_NAME, true)); + if (null == this.caseType) { + throw new CaseMetadataException("Case metadata file corrupted"); + } + if (schemaVersion.equals(SCHEMA_VERSION_ONE)) { + this.caseDatabase = getElementTextContent(caseElement, CASE_DATABASE_NAME_ELEMENT_NAME, true); + } else { + this.caseDatabase = getElementTextContent(caseElement, CASE_DATABASE_ELEMENT_NAME, true); + } + this.textIndexName = getElementTextContent(caseElement, TEXT_INDEX_NAME_ELEMENT, true); + + /* + * Update the file to the current schema, if necessary. + */ + if (!schemaVersion.equals(CURRENT_SCHEMA_VERSION)) { + writeToFile(); + } + + } catch (ParserConfigurationException | SAXException | IOException ex) { + throw new CaseMetadataException(String.format("Error reading from case metadata file %s", metadataFilePath), ex); + } + } + + /** + * Gets the text content of an XML element. + * + * @param parentElement The parent element. + * @param elementName The element name. + * @param contentIsRequired Whether or not the content is required. + * + * @return The text content, may be empty if not required. + * + * @throws CaseMetadataException If the element is missing or content is + * required and it is empty. + */ + private String getElementTextContent(Element parentElement, String elementName, boolean contentIsRequired) throws CaseMetadataException { + NodeList elementsList = parentElement.getElementsByTagName(elementName); + if (elementsList.getLength() == 0) { + throw new CaseMetadataException(String.format("Missing %s element from case metadata file %s", elementName, metadataFilePath)); + } + String textContent = elementsList.item(0).getTextContent(); + if (textContent.isEmpty() && contentIsRequired) { + throw new CaseMetadataException(String.format("Empty %s element in case metadata file %s", elementName, metadataFilePath)); + } + return textContent; + } + /** * Exception thrown by the CaseMetadata class when there is a problem - * accessing the metadata for a case. + * accessing the metadata for a case. */ public final static class CaseMetadataException extends Exception { @@ -72,463 +461,17 @@ public final class CaseMetadata { } } - private final static String TOP_ROOT_NAME = "AutopsyCase"; //NON-NLS - private final static String CASE_ROOT_NAME = "Case"; //NON-NLS - private final static String NAME = "Name"; //NON-NLS - private final static String NUMBER = "Number"; //NON-NLS - private final static String EXAMINER = "Examiner"; //NON-NLS - private final static String CREATED_DATE_NAME = "CreatedDate"; //NON-NLS - private final static String MODIFIED_DATE_NAME = "ModifiedDate"; //NON-NLS - private final static String SCHEMA_VERSION_NAME = "SchemaVersion"; //NON-NLS - private final static String AUTOPSY_CRVERSION_NAME = "AutopsyCreatedVersion"; //NON-NLS - private final static String AUTOPSY_MVERSION_NAME = "AutopsySavedVersion"; //NON-NLS - private final static String CASE_TEXT_INDEX_NAME = "TextIndexName"; //NON-NLS - private final static String CASE_TYPE = "CaseType"; //NON-NLS - private final static String DATABASE_NAME = "DatabaseName"; //NON-NLS - private static final String SCHEMA_VERSION = "2.0"; - private static final String FILE_EXTENSION = ".aut"; - - private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss (z)"); - private Case.CaseType caseType; - private String caseName; - private String caseNumber; - private String examiner; - private String caseDatabaseName; - private String caseTextIndexName; - private String createdDate; - private String fileName; - private String createdVersion; - private final String configFilePath; - - private CaseMetadata(String caseDirectory, Case.CaseType caseType, String caseName, String caseNumber, String examiner, String caseDatabaseName, String caseTextIndexName) throws CaseMetadataException { - - this.caseType = caseType; - this.caseName = caseName; - this.caseNumber = caseNumber; - this.examiner = examiner; - this.createdDate = CaseMetadata.DATE_FORMAT.format(new Date()); - this.caseDatabaseName = caseDatabaseName; - this.caseTextIndexName = caseTextIndexName; - this.fileName = caseName; - this.createdVersion = System.getProperty("netbeans.buildnumber"); - configFilePath = Paths.get(caseDirectory, caseName + FILE_EXTENSION).toString(); - this.write(); - - } - /** - * Used to read a case at the given file path + * Gets a string identifying the case database. * - * @param metadataFilePath the string file path for the case + * @return For a single-user case, the full path to the case database file. + * For a multi-user case, the case database name. * - * @throws - * org.sleuthkit.autopsy.casemodule.CaseMetadata.CaseMetadataException - */ - private CaseMetadata(String metadataFilePath) throws CaseMetadataException { - this.configFilePath = metadataFilePath; - this.read(metadataFilePath); - } - - /** - * Opens a case and gives the metadata object that corresponds - * - * @param metadataFilePath The file path of the metadata file - * - * @return The case metadata for the opened case - * - * @throws - * org.sleuthkit.autopsy.casemodule.CaseMetadata.CaseMetadataException - */ - static CaseMetadata open(Path metadataFilePath) throws CaseMetadataException { - CaseMetadata metadata = new CaseMetadata(metadataFilePath.toString()); - return metadata; - } - - /** - * Creates a metadata object for a new case - * - * @param caseType The type of case - * @param caseName The name of the case - * @param caseNumber The case number - * @param examiner The name of the case examiner - * @param caseDirectory The directory of the case - * @param caseDatabaseName The name of the case db - * @param caseTextIndexName The case index name - * - * @return The metadata for the new case - * - * @throws - * org.sleuthkit.autopsy.casemodule.CaseMetadata.CaseMetadataException - */ - static CaseMetadata create(String caseDirectory, Case.CaseType caseType, String caseName, String caseNumber, String examiner, String caseDatabaseName, String caseTextIndexName) throws CaseMetadataException { - CaseMetadata metadata = new CaseMetadata(caseDirectory, caseType, caseName, caseNumber, examiner, caseDatabaseName, caseTextIndexName); - return metadata; - } - - /** - * Gets the case type. - * - * @return The case type. - */ - public Case.CaseType getCaseType() { - return this.caseType; - } - - /** - * Gets the case name. - * - * @return The case name. - */ - public String getCaseName() { - return caseName; - } - - /** - * Gets the case number. - * - * @return The case number, may be empty. - */ - public String getCaseNumber() { - return caseNumber; - } - - /** - * Gets the path to the metadata file file - * - * @return The path to the metadata file - */ - public String getConfigFilePath() { - return configFilePath; - } - - /** - * Gets the examiner. - * - * @return The examiner, may be empty. - */ - public String getExaminer() { - return examiner; - } - - /** - * Gets the case database name. - * - * @return The case database name, will be empty for a single-user case. - */ - public String getCaseDatabaseName() { - return caseDatabaseName; - } - - /** - * Gets the date this case was created - * - * @return The date this case was created as a string - */ - String getCreatedDate() { - return this.createdDate; - } - - /** - * @return the createdVersion - */ - String getCreatedVersion() { - return createdVersion; - } - - /** - * @return the FILE_EXTENSION - */ - public static String getFileExtension() { - return FILE_EXTENSION; - } - - /** - * Sets the created version of this case - * - * @param createdVersion the createdVersion to set - */ - void setCreatedVersion(String createdVersion) throws CaseMetadataException { - String oldCreatedVersion = this.createdVersion; - this.createdVersion = createdVersion; - try { - this.write(); - } catch (CaseMetadataException ex) { - this.createdDate = oldCreatedVersion; - throw ex; - } - } - - /** - * @param createdDate the createdDate to set - */ - void setCreatedDate(String createdDate) throws CaseMetadataException { - String oldCreatedDate = this.createdDate; - this.createdDate = createdDate; - try { - this.write(); - } catch (CaseMetadataException ex) { - this.createdDate = oldCreatedDate; - throw ex; - } - } - - /** - * @param caseName the caseName to set - */ - void setCaseName(String caseName) throws CaseMetadataException { - String oldCaseName = this.caseName; - this.caseName = caseName; - try { - this.write(); - } catch (CaseMetadataException ex) { - this.caseName = oldCaseName; - throw ex; - } - } - - /** - * @return the caseTextIndexName - */ - public String getTextIndexName() { - return caseTextIndexName; - } - - private void write() throws CaseMetadataException { - Document doc; - try { - doc = XMLUtil.createDocument(); - } catch (ParserConfigurationException ex) { - throw new CaseMetadataException( - NbBundle.getMessage(this.getClass(), "XMLCaseManagement.create.exception.msg"), ex); - } - Element rootElement = doc.createElement(TOP_ROOT_NAME); // ... - doc.appendChild(rootElement); - - Element crDateElement = doc.createElement(CREATED_DATE_NAME); // ... - crDateElement.appendChild(doc.createTextNode(this.getCreatedDate())); - rootElement.appendChild(crDateElement); - - Element mDateElement = doc.createElement(MODIFIED_DATE_NAME); // ... - mDateElement.appendChild(doc.createTextNode(DATE_FORMAT.format(new Date()))); - rootElement.appendChild(mDateElement); - - Element autVerElement = doc.createElement(AUTOPSY_CRVERSION_NAME); // ... - autVerElement.appendChild(doc.createTextNode(this.getCreatedVersion())); - rootElement.appendChild(autVerElement); - - Element autSavedVerElement = doc.createElement(AUTOPSY_MVERSION_NAME); // ... - autSavedVerElement.appendChild(doc.createTextNode(System.getProperty("netbeans.buildnumber"))); - rootElement.appendChild(autSavedVerElement); - - Element schVerElement = doc.createElement(SCHEMA_VERSION_NAME); // ... - schVerElement.appendChild(doc.createTextNode(SCHEMA_VERSION)); - rootElement.appendChild(schVerElement); - - Element caseElement = doc.createElement(CASE_ROOT_NAME); // ... - rootElement.appendChild(caseElement); - - Element nameElement = doc.createElement(NAME); // ... - nameElement.appendChild(doc.createTextNode(getCaseName())); - caseElement.appendChild(nameElement); - - Element numberElement = doc.createElement(NUMBER); // ... - numberElement.appendChild(doc.createTextNode(String.valueOf(getCaseNumber()))); - caseElement.appendChild(numberElement); - - Element examinerElement = doc.createElement(EXAMINER); // ... - examinerElement.appendChild(doc.createTextNode(getExaminer())); - caseElement.appendChild(examinerElement); - - Element typeElement = doc.createElement(CASE_TYPE); // ... - typeElement.appendChild(doc.createTextNode(getCaseType().toString())); - caseElement.appendChild(typeElement); - - Element dbNameElement = doc.createElement(DATABASE_NAME); // ... - dbNameElement.appendChild(doc.createTextNode(this.getCaseDatabaseName())); - caseElement.appendChild(dbNameElement); - - Element indexNameElement = doc.createElement(CASE_TEXT_INDEX_NAME); // ... - indexNameElement.appendChild(doc.createTextNode(this.getTextIndexName())); - caseElement.appendChild(indexNameElement); - doc.normalize(); - this.writeFile(doc); - } - - private void writeFile(Document doc) throws CaseMetadataException { - if (doc == null || getCaseName().equals("")) { - throw new CaseMetadataException( - "No set case to write management file for." - ); - } - - // 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) { - throw new CaseMetadataException( - "Error writing to case file", 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) { - throw new CaseMetadataException( - "Error writing to case file", ex); - } - - // preparing the output file - String xmlString = sw.toString(); - File file = new File(this.configFilePath); - - // write the file - try { - BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file))); - bw.write(xmlString); - bw.flush(); - bw.close(); - } catch (IOException ex) { - throw new CaseMetadataException( - "Error writing to case file", ex); - } - } - - /** - * Opens the configuration file and load the document handler Note: this is - * for the schema version 1.0 - * - * @param conFilePath the path of the XML case configuration file path - */ - private void read(String conFilePath) throws CaseMetadataException { - File file = new File(conFilePath); - Document doc; - - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - DocumentBuilder db; - try { - db = dbf.newDocumentBuilder(); - doc = db.parse(file); - } catch (ParserConfigurationException | SAXException | IOException ex) { - throw new CaseMetadataException( - "Error reading case XML file\\:" + conFilePath, ex); - } - - doc.getDocumentElement().normalize(); - - Element rootEl = doc.getDocumentElement(); - String rootName = rootEl.getNodeName(); - - if (!rootName.equals(TOP_ROOT_NAME)) { - // throw an error because the xml is malformed - if (RuntimeProperties.coreComponentsAreActive()) { - throw new CaseMetadataException("Root element not recognized as autopsy case tag"); - } - } else { - /* - * Autopsy Created Version - */ - Element rootElement = doc.getDocumentElement(); - - NodeList cversionList = rootElement.getElementsByTagName(AUTOPSY_CRVERSION_NAME); - if (cversionList.getLength() == 0) { - throw new CaseMetadataException("Could not find created version in metadata"); - } - String createdVersion = cversionList.item(0).getTextContent(); // get the created version - // check if it has the same autopsy version as the current one - if (!createdVersion.equals(System.getProperty("netbeans.buildnumber"))) { - // if not the same version, update the saved version in the xml to the current version - rootElement.getElementsByTagName(AUTOPSY_MVERSION_NAME).item(0).setTextContent(System.getProperty("netbeans.buildnumber")); - } - - String fullFileName = file.getName(); - String fileName = fullFileName.substring(0, fullFileName.lastIndexOf(".")); // remove the extension - this.fileName = fileName; - - NodeList rootNameList = doc.getElementsByTagName(CASE_ROOT_NAME); - if (rootNameList.getLength() == 0) { - throw new CaseMetadataException("Couldn't get case root"); - } - Element caseElement = (Element) rootNameList.item(0); - - NodeList caseTypeList = caseElement.getElementsByTagName(CASE_TYPE); - if (caseTypeList.getLength() == 0) { - throw new CaseMetadataException("Couldn't get case type"); - } - String caseTypeString = caseTypeList.item(0).getTextContent(); - this.caseType = Case.CaseType.fromString(caseTypeString); - if (this.caseType == null) { - throw new CaseMetadataException("Invalid case type"); - } - - NodeList caseNameList = caseElement.getElementsByTagName(NAME); - if (caseNameList.getLength() == 0) { - throw new CaseMetadataException("Couldn't get case name"); - } - this.caseName = caseNameList.item(0).getTextContent(); - if (this.caseName.isEmpty()) { - throw new CaseMetadataException("Invalid case name, cannot be empty"); - } - - Element numberElement = caseElement.getElementsByTagName(NUMBER).getLength() > 0 ? (Element) caseElement.getElementsByTagName(NUMBER).item(0) : null; - this.caseNumber = numberElement != null ? numberElement.getTextContent() : ""; - - Element examinerElement = caseElement.getElementsByTagName(EXAMINER).getLength() > 0 ? (Element) caseElement.getElementsByTagName(EXAMINER).item(0) : null; - this.examiner = examinerElement != null ? examinerElement.getTextContent() : ""; - - NodeList databaseNameList = caseElement.getElementsByTagName(DATABASE_NAME); - if (databaseNameList.getLength() == 0) { - throw new CaseMetadataException("Couldn't get database name"); - } - Element databaseNameElement = (Element) databaseNameList.item(0); - this.caseDatabaseName = databaseNameElement.getTextContent(); - if (Case.CaseType.MULTI_USER_CASE == caseType && caseDatabaseName.isEmpty()) { - throw new CaseMetadataException("Case database name cannot be empty in multi user case."); - } - - NodeList textIndexList = caseElement.getElementsByTagName(CASE_TEXT_INDEX_NAME); - if (textIndexList.getLength() == 0) { - throw new CaseMetadataException("Couldn't get text index"); - } - Element caseTextIndexNameElement = (Element) textIndexList.item(0); - this.caseTextIndexName = caseTextIndexNameElement.getTextContent(); - - NodeList createdDateList = rootElement.getElementsByTagName(CREATED_DATE_NAME); - if (createdDateList.getLength() == 0) { - throw new CaseMetadataException("Couldn't get created date"); - } - this.createdDate = createdDateList.item(0).getTextContent(); - - NodeList createdVersionList = rootElement.getElementsByTagName(AUTOPSY_CRVERSION_NAME); - if (createdVersionList.getLength() == 0) { - throw new CaseMetadataException("Couldn't get created version"); - } - this.createdVersion = createdVersionList.item(0).getTextContent(); - } - } - - /** - * Constructs an object that provides access to case metadata. - * - * @param metadataFilePath Path to the metadata (.aut) file for a case. - * - * @deprecated Use open instead + * @deprecated Use getCaseDatabase instead. */ @Deprecated - public CaseMetadata(Path metadataFilePath) throws CaseMetadataException { - this(metadataFilePath.toString()); + public String getCaseDatabaseName() { + return getCaseDatabase(); } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java index ca8fa2e8da..2f024e724a 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java @@ -88,7 +88,7 @@ class CasePropertiesForm extends javax.swing.JPanel { current = currentCase; CaseMetadata caseMetadata = currentCase.getCaseMetadata(); - tbDbName.setText(caseMetadata.getCaseDatabaseName()); + tbDbName.setText(caseMetadata.getCaseDatabase()); Case.CaseType caseType = caseMetadata.getCaseType(); tbDbType.setText(caseType.getLocalizedDisplayName()); if (caseType == Case.CaseType.SINGLE_USER_CASE) { @@ -421,7 +421,7 @@ class CasePropertiesForm extends javax.swing.JPanel { Object res = DialogDisplayer.getDefault().notify(d); if (res != null && res == DialogDescriptor.YES_OPTION) { // if user select "Yes" - String oldPath = current.getConfigFilePath(); + String oldPath = current.getCaseMetadata().getFilePath().toString(); try { current.updateCaseName(oldCaseName, oldPath, newCaseName, oldPath); } catch (Exception ex) { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/RecentCases.java b/Core/src/org/sleuthkit/autopsy/casemodule/RecentCases.java index 2baaf28590..2204da444a 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/RecentCases.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/RecentCases.java @@ -408,7 +408,7 @@ final class RecentCases extends CallableSystemAction implements Presenter.Menu { String[] casePaths = new String[LENGTH]; String currentCasePath = null; try { - currentCasePath = Case.getCurrentCase().getConfigFilePath(); + currentCasePath = Case.getCurrentCase().getCaseMetadata().getFilePath().toString(); } catch (IllegalStateException ex) { // in case there is no current case. } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java b/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java index b6a2298a4a..458cd642dc 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java @@ -165,7 +165,7 @@ public class SingleUserCaseConverter { } // Read old xml config - CaseMetadata oldCaseMetadata = CaseMetadata.open(icd.getCaseInputFolder().resolve(icd.getAutFileName())); + CaseMetadata oldCaseMetadata = new CaseMetadata(icd.getCaseInputFolder().resolve(icd.getAutFileName())); if (oldCaseMetadata.getCaseType() == CaseType.MULTI_USER_CASE) { throw new Exception(NbBundle.getMessage(SingleUserCaseConverter.class, "SingleUserCaseConverter.AlreadyMultiUser")); //NON-NLS } @@ -190,7 +190,7 @@ public class SingleUserCaseConverter { copyImages(icd); // Create new .aut file - CaseMetadata newCaseMetadata = CaseMetadata.create(icd.getCaseOutputFolder().toString(), + CaseMetadata newCaseMetadata = new CaseMetadata(icd.getCaseOutputFolder().toString(), CaseType.MULTI_USER_CASE, icd.getNewCaseName(), oldCaseMetadata.getCaseNumber(), @@ -198,7 +198,7 @@ public class SingleUserCaseConverter { dbName, solrName); // Set created date. This calls writefile, no need to call it again newCaseMetadata.setCreatedDate(oldCaseMetadata.getCreatedDate()); - newCaseMetadata.setCreatedVersion(oldCaseMetadata.getCreatedVersion()); + newCaseMetadata.setCreatedByBuild(oldCaseMetadata.getCreatedByBuild()); // At this point the import has been finished successfully so we can delete the original case // (if requested). This *should* be fairly safe - at this point we know there was an autopsy file diff --git a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties index 387cfb83e3..5e2bf552f3 100644 --- a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties +++ b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties @@ -1,5 +1,5 @@ #Updated by build script -#Mon, 22 Feb 2016 16:37:47 -0500 +#Wed, 06 Apr 2016 23:42:27 -0400 LBL_splash_window_title=Starting Autopsy SPLASH_HEIGHT=314 SPLASH_WIDTH=538 diff --git a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties index eac00c4b67..cc4a7ca40c 100644 --- a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties +++ b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties @@ -1,4 +1,4 @@ #Updated by build script -#Mon, 22 Feb 2016 16:37:47 -0500 +#Wed, 06 Apr 2016 23:42:27 -0400 CTL_MainWindow_Title=Autopsy 4.1.0 CTL_MainWindow_Title_No_Project=Autopsy 4.1.0 From e678491a5127197377b538542569df3292b39b20 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 7 Apr 2016 13:48:41 -0400 Subject: [PATCH 48/50] Keyword search core mgmt: improve logging, document known issue, fix for headless runs --- .../autopsy/keywordsearch/KeywordSearch.java | 47 +++++++-- .../autopsy/keywordsearch/Server.java | 99 +++++++++++++------ 2 files changed, 105 insertions(+), 41 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearch.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearch.java index 0433f99e7e..cdd027472f 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearch.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearch.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2015 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,12 +22,14 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.IOException; +import java.nio.file.Paths; import java.util.logging.FileHandler; import java.util.logging.Level; import java.util.logging.Logger; import java.util.logging.SimpleFormatter; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.keywordsearch.KeywordSearchResultFactory.BlackboardResultWriter; @@ -110,33 +112,60 @@ public class KeywordSearch { } /** - * Listener to swap cores when the case changes + * Listener to create/open and close Solr cores when cases are + * created/opened and closed. */ static class CaseChangeListener implements PropertyChangeListener { @Override public void propertyChange(PropertyChangeEvent evt) { + /* + * TODO (AUT-2081): There is a Solr core unloading bug, fixed in + * Solr 5.4, that results in the co-existence of a core.properties + * file and a core.properties.unloaded file in the core instance + * directory when a core is closed/unloaded. When this happens, + * subsequent core open/load attempts will fail. The workaround for + * single-user cases is to close and reopen Autopsy so that a new + * server instance gets spun up. + */ if (evt.getPropertyName().equals(Case.Events.CURRENT_CASE.toString())) { if (null != evt.getOldValue()) { + /* + * A case is being closed. + */ Case closedCase = (Case) evt.getOldValue(); try { BlackboardResultWriter.stopAllWriters(); - Thread.sleep(2000); // TODO (RC): This is a fragile way to wait here. + /* + * TODO (AUT-2084): The following code + * KeywordSearch.CaseChangeListener gambles that any + * BlackboardResultWriters (SwingWorkers) will complete + * in less than roughly two seconds + */ + Thread.sleep(2000); server.closeCore(); } catch (Exception ex) { - String caseName = closedCase.getName(); - logger.log(Level.SEVERE, String.format("Failed to close core for %s", caseName), ex); //NON-NLS - MessageNotifyUtil.Notify.error(NbBundle.getMessage(KeywordSearch.class, "KeywordSearch.closeCore.notification.msg"), ex.getMessage()); + String caseId = Paths.get(closedCase.getCaseDirectory(), closedCase.getName()).toString(); + logger.log(Level.SEVERE, String.format("Failed to close core for %s", caseId), ex); //NON-NLS + if (RuntimeProperties.coreComponentsAreActive()) { + MessageNotifyUtil.Notify.error(NbBundle.getMessage(KeywordSearch.class, "KeywordSearch.closeCore.notification.msg"), ex.getMessage()); + } } } + if (null != evt.getNewValue()) { + /* + * A case is being created/opened. + */ Case openedCase = (Case) evt.getNewValue(); try { server.openCoreForCase(openedCase); } catch (Exception ex) { - String caseName = openedCase.getName(); - logger.log(Level.SEVERE, String.format("Failed to open or create core for %s", caseName), ex); //NON-NLS - MessageNotifyUtil.Notify.error(NbBundle.getMessage(KeywordSearch.class, "KeywordSearch.openCore.notification.msg"), ex.getMessage()); + String caseId = Paths.get(openedCase.getCaseDirectory(), openedCase.getName()).toString(); + logger.log(Level.SEVERE, String.format("Failed to open or create core for %s", caseId), ex); //NON-NLS + if (RuntimeProperties.coreComponentsAreActive()) { + MessageNotifyUtil.Notify.error(NbBundle.getMessage(KeywordSearch.class, "KeywordSearch.openCore.notification.msg"), ex.getMessage()); + } } } } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java index 312c600d7a..ef7e3ed76b 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Server.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2015 Basis Technology Corp. + * Copyright 2011-2016 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -66,14 +66,16 @@ import org.apache.solr.common.SolrException; import org.sleuthkit.autopsy.casemodule.Case.CaseType; import org.sleuthkit.autopsy.coreutils.UNCPathUtilities; import org.sleuthkit.autopsy.core.UserPreferences; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; /** - * Handles for keeping track of a Solr server and its cores + * Handles management of a either a local or centralized Solr server and its + * cores. */ public class Server { - // field names that are used in SOLR schema + /** + * Solr document field names. + */ public static enum Schema { ID { @@ -148,6 +150,7 @@ public class Server { } }, }; + public static final String HL_ANALYZE_CHARS_UNLIMITED = "500000"; //max 1MB in a chunk. use -1 for unlimited, but -1 option may not be supported (not documented) //max content size we can send to Solr public static final long MAX_CONTENT_SIZE = 1L * 1024 * 1024 * 1024; @@ -196,7 +199,7 @@ public class Server { */ Server() { initSettings(); - + this.localSolrServer = new HttpSolrServer("http://localhost:" + currentSolrServerPort + "/solr"); //NON-NLS serverAction = new ServerAction(); solrFolder = InstalledFileLocator.getDefault().locate("solr", Server.class.getPackage().getName(), false); //NON-NLS @@ -204,7 +207,7 @@ public class Server { currentCoreLock = new ReentrantReadWriteLock(true); uncPathUtilities = new UNCPathUtilities(); - + logger.log(Level.INFO, "Created Server instance"); //NON-NLS } @@ -596,11 +599,13 @@ public class Server { * ** Convenience methods for use while we only open one case at a time *** */ /** - * Opens or creates a core (index) for a case. + * Creates/opens a Solr core (index) for a case. * - * @param theCase the case for which the core is to be opened or created. + * @param theCase The case for which the core is to be created/opened. * - * @throws KeywordSearchModuleException + * + * @throws KeywordSearchModuleException If an error occurs while + * creating/opening the core. */ void openCoreForCase(Case theCase) throws KeywordSearchModuleException { currentCoreLock.writeLock().lock(); @@ -630,6 +635,15 @@ public class Server { currentCoreLock.writeLock().lock(); try { if (null != currentCore) { + /* + * TODO (AUT-2081): There is a Solr core unloading bug, fixed in + * Solr 5.4, that will result in the co-existence of a + * core.properties file and a core.properties.unloaded file in + * the core instance directory when the following code executes. + * When this happens, subsequent open/load attempts will fail. + * The workaround for single-user cases is to close and reopen + * Autopsy so that a new server instance gets spun up. + */ currentCore.close(); currentCore = null; serverAction.putValue(CORE_EVT, CORE_EVT_STATES.STOPPED); @@ -655,7 +669,7 @@ public class Server { * * @return absolute path to index dir */ - String getIndexDirPath(Case theCase) { + String geCoreDataDirPath(Case theCase) { String indexDir = theCase.getModuleDirectory() + File.separator + "keywordsearch" + File.separator + "data"; //NON-NLS if (uncPathUtilities != null) { // if we can check for UNC paths, do so, otherwise just return the indexDir @@ -676,11 +690,14 @@ public class Server { * ** end single-case specific methods *** */ /** - * Open a core for the given case + * Creates/opens a Solr core (index) for a case. * - * @param theCase the case to open core for + * @param theCase The case for which the core is to be created/opened. * - * @return + * @return An object representing the created/opened core. + * + * @throws KeywordSearchModuleException If an error occurs while + * creating/opening the core. */ private Core openCore(Case theCase) throws KeywordSearchModuleException { try { @@ -692,11 +709,12 @@ public class Server { currentSolrServer = new HttpSolrServer("http://" + host + ":" + port + "/solr"); //NON-NLS } connectToSolrServer(currentSolrServer); + } catch (SolrServerException | IOException ex) { throw new KeywordSearchModuleException(NbBundle.getMessage(Server.class, "Server.connect.exception.msg"), ex); } - String dataDir = getIndexDirPath(theCase); + String dataDir = geCoreDataDirPath(theCase); String coreName = theCase.getTextIndexName(); return this.openCore(coreName.isEmpty() ? DEFAULT_CORE_NAME : coreName, new File(dataDir), theCase.getCaseType()); } @@ -1050,12 +1068,17 @@ public class Server { } /** - * Open a new core + * Creates/opens a Solr core (index) for a case. * - * @param coreName name to refer to the core by in Solr - * @param dataDir directory to load/store the core data from/to + * @param coreName The core name. + * @param dataDir The data directory for the core. + * @param caseType The type of the case (single-user or multi-user) for + * which the core is being created/opened. * - * @return new core + * @return An object representing the created/opened core. + * + * @throws KeywordSearchModuleException If an error occurs while + * creating/opening the core. */ private Core openCore(String coreName, File dataDir, CaseType caseType) throws KeywordSearchModuleException { @@ -1064,14 +1087,25 @@ public class Server { dataDir.mkdirs(); } - //handle a possible scenario when server process might not be fully started if (!this.isRunning()) { - logger.log(Level.WARNING, "Core open requested, but server not yet running"); //NON-NLS - throw new KeywordSearchModuleException( - NbBundle.getMessage(this.getClass(), "Server.openCore.exception.msg")); + logger.log(Level.SEVERE, "Core create/open requested, but server not yet running"); //NON-NLS + throw new KeywordSearchModuleException(NbBundle.getMessage(this.getClass(), "Server.openCore.exception.msg")); } - if (!coreExistsOnServer(coreName)) { + if (!coreIsLoaded(coreName)) { + /* + * The core either does not exist or it is not loaded. Make a + * request that will cause the core to be created if it does not + * exist or loaded if it already exists. + * + * TODO (AUT-2081): There is a Solr core unloading bug, fixed in + * Solr 5.4, that results in the co-existence of a + * core.properties file and a core.properties.unloaded file in + * the core instance directory when a core is unloaded. When + * this happens, this code will fail. The workaround for + * single-user cases is to close and reopen Autopsy so that a + * new server instance gets spun up. + */ CoreAdminRequest.Create createCoreRequest = new CoreAdminRequest.Create(); createCoreRequest.setDataDir(dataDir.getAbsolutePath()); createCoreRequest.setCoreName(coreName); @@ -1088,8 +1122,7 @@ public class Server { return new Core(coreName, caseType); } catch (SolrServerException | SolrException | IOException ex) { - throw new KeywordSearchModuleException( - NbBundle.getMessage(this.getClass(), "Server.openCore.exception.cantOpen.msg"), ex); + throw new KeywordSearchModuleException(NbBundle.getMessage(this.getClass(), "Server.openCore.exception.cantOpen.msg"), ex); } } @@ -1106,17 +1139,19 @@ public class Server { } /** - * Determines whether or not a Solr core instance exists on the current Solr - * server. + * Determines whether or not a particular Solr core exists and is loaded. * - * @param coreName the name of the core. + * @param coreName The name of the core. * - * @return true or false. + * @return True if the core exists and is loaded, false if the core does not + * exist or is not loaded * - * @throws SolrServerException - * @throws IOException + * @throws SolrServerException If there is a problem communicating with the + * Solr server. + * @throws IOException If there is a problem communicating with the + * Solr server. */ - private boolean coreExistsOnServer(String coreName) throws SolrServerException, IOException { + private boolean coreIsLoaded(String coreName) throws SolrServerException, IOException { CoreAdminResponse response = CoreAdminRequest.getStatus(coreName, currentSolrServer); return response.getCoreStatus(coreName).get("instanceDir") != null; //NON-NLS } From cf6f49edaea088b8d4ee1c9553943a3463b869a2 Mon Sep 17 00:00:00 2001 From: Oliver Spohngellert Date: Thu, 7 Apr 2016 15:32:07 -0400 Subject: [PATCH 49/50] Updated autopsy to align with changes to getMatchingArtifacts --- .../autopsy/recentactivity/SearchEngineURLQueryAnalyzer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/SearchEngineURLQueryAnalyzer.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/SearchEngineURLQueryAnalyzer.java index fdd1a018cd..ff45f2efb8 100644 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/SearchEngineURLQueryAnalyzer.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/SearchEngineURLQueryAnalyzer.java @@ -277,8 +277,8 @@ class SearchEngineURLQueryAnalyzer extends Extract { int totalQueries = 0; try { //from blackboard_artifacts - Collection listArtifacts = currentCase.getSleuthkitCase().getMatchingArtifacts("WHERE (artifact_type_id = '" + ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID() //NON-NLS - + "' OR artifact_type_id = '" + ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID() + "') "); //List of every 'web_history' and 'bookmark' artifact NON-NLS + Collection listArtifacts = currentCase.getSleuthkitCase().getMatchingArtifacts("WHERE (blackboard_artifacts.artifact_type_id = '" + ARTIFACT_TYPE.TSK_WEB_BOOKMARK.getTypeID() //NON-NLS + + "' OR blackboard_artifacts.artifact_type_id = '" + ARTIFACT_TYPE.TSK_WEB_HISTORY.getTypeID() + "') "); //List of every 'web_history' and 'bookmark' artifact NON-NLS logger.log(Level.INFO, "Processing {0} blackboard artifacts.", listArtifacts.size()); //NON-NLS for (BlackboardArtifact artifact : listArtifacts) { From d241e0882be59ac592110ca9fd5a84d4cada26c8 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 8 Apr 2016 12:01:17 -0400 Subject: [PATCH 50/50] casemodule/CaseMetadata: Record software version, refine API --- .../sleuthkit/autopsy/casemodule/Case.java | 4 +- .../autopsy/casemodule/CaseMetadata.java | 119 ++++++++++-------- .../casemodule/CasePropertiesForm.java | 6 +- .../casemodule/SingleUserCaseConverter.java | 2 +- 4 files changed, 72 insertions(+), 59 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index f871fff696..2d1d0c0a03 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -604,7 +604,7 @@ public class Case implements SleuthkitCase.ErrorObserver { SleuthkitCase db; String caseDir; if (caseType == CaseType.SINGLE_USER_CASE) { - String dbPath = metadata.getCaseDatabase(); //NON-NLS + String dbPath = metadata.getCaseDatabasePath(); //NON-NLS db = SleuthkitCase.openCase(dbPath); caseDir = new File(dbPath).getParent(); } else { @@ -612,7 +612,7 @@ public class Case implements SleuthkitCase.ErrorObserver { throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.open.exception.multiUserCaseNotEnabled")); } try { - db = SleuthkitCase.openCase(metadata.getCaseDatabase(), UserPreferences.getDatabaseConnectionInfo(), metadata.getCaseDirectory()); + db = SleuthkitCase.openCase(metadata.getCaseDatabaseName(), UserPreferences.getDatabaseConnectionInfo(), metadata.getCaseDirectory()); } catch (UserPreferencesException ex) { throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.databaseConnectionInfo.error.msg"), ex); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java index bf0862ba02..bd07a3deaf 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CaseMetadata.java @@ -39,6 +39,7 @@ import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; +import org.sleuthkit.autopsy.coreutils.Version; import org.sleuthkit.autopsy.coreutils.XMLUtil; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -53,22 +54,23 @@ public final class CaseMetadata { private static final String FILE_EXTENSION = ".aut"; private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss (z)"); private static final String SCHEMA_VERSION_ONE = "1.0"; - private final static String CREATED_BY_VERSION_ELEMENT_NAME = "AutopsyCreatedVersion"; //NON-NLS + private final static String AUTOPSY_CREATED_VERSION_ELEMENT_NAME = "AutopsyCreatedVersion"; //NON-NLS private final static String CASE_DATABASE_NAME_ELEMENT_NAME = "DatabaseName"; //NON-NLS + private final static String TEXT_INDEX_NAME_ELEMENT = "TextIndexName"; //NON-NLS private static final String CURRENT_SCHEMA_VERSION = "2.0"; private final static String ROOT_ELEMENT_NAME = "AutopsyCase"; //NON-NLS private final static String SCHEMA_VERSION_ELEMENT_NAME = "SchemaVersion"; //NON-NLS private final static String CREATED_DATE_ELEMENT_NAME = "CreatedDate"; //NON-NLS private final static String MODIFIED_DATE_ELEMENT_NAME = "ModifiedDate"; //NON-NLS - private final static String CREATED_BY_BUILD_ELEMENT_NAME = "CreatedByBuild"; //NON-NLS - private final static String SAVED_BY_BUILD_ELEMENT_NAME = "SavedByBuild"; //NON-NLS + private final static String AUTOPSY_CREATED_BY_ELEMENT_NAME = "CreatedByAutopsyVersion"; //NON-NLS + private final static String AUTOPSY_SAVED_BY_ELEMENT_NAME = "SavedByAutopsyVersion"; //NON-NLS private final static String CASE_ELEMENT_NAME = "Case"; //NON-NLS private final static String CASE_NAME_ELEMENT_NAME = "Name"; //NON-NLS private final static String CASE_NUMBER_ELEMENT_NAME = "Number"; //NON-NLS private final static String EXAMINER_ELEMENT_NAME = "Examiner"; //NON-NLS private final static String CASE_TYPE_ELEMENT_NAME = "CaseType"; //NON-NLS private final static String CASE_DATABASE_ELEMENT_NAME = "Database"; //NON-NLS - private final static String TEXT_INDEX_NAME_ELEMENT = "TextIndexName"; //NON-NLS + private final static String TEXT_INDEX_ELEMENT = "TextIndex"; //NON-NLS private final Path metadataFilePath; private Case.CaseType caseType; private String caseName; @@ -77,7 +79,7 @@ public final class CaseMetadata { private String caseDatabase; private String textIndexName; private String createdDate; - private String createdByBuild; + private String createdByVersion; /** * Gets the file extension used for case metadata files. @@ -90,7 +92,7 @@ public final class CaseMetadata { /** * Constructs an object that provides access to the case metadata stored in - * a new case metadata file. + * a new case metadata file that is created using the supplied metadata. * * @param caseDirectory The case directory. * @param caseType The type of case. @@ -113,7 +115,7 @@ public final class CaseMetadata { this.examiner = examiner; this.caseDatabase = caseDatabase; this.textIndexName = caseTextIndexName; - createdByBuild = System.getProperty("netbeans.buildnumber"); + createdByVersion = Version.getVersion(); createdDate = CaseMetadata.DATE_FORMAT.format(new Date()); writeToFile(); } @@ -147,7 +149,7 @@ public final class CaseMetadata { * @return The case directory. */ public String getCaseDirectory() { - return this.metadataFilePath.getParent().toString(); + return metadataFilePath.getParent().toString(); } /** @@ -156,7 +158,7 @@ public final class CaseMetadata { * @return The case type. */ public Case.CaseType getCaseType() { - return this.caseType; + return caseType; } /** @@ -175,10 +177,10 @@ public final class CaseMetadata { * @param caseName A case display name. */ void setCaseName(String caseName) throws CaseMetadataException { - String oldCaseName = this.caseName; + String oldCaseName = caseName; this.caseName = caseName; try { - this.writeToFile(); + writeToFile(); } catch (CaseMetadataException ex) { this.caseName = oldCaseName; throw ex; @@ -204,13 +206,32 @@ public final class CaseMetadata { } /** - * Gets a string identifying the case database. + * Gets the name of the case case database. * - * @return For a single-user case, the full path to the case database file. - * For a multi-user case, the case database name. + * @return The case database name. */ - public String getCaseDatabase() { - return caseDatabase; + public String getCaseDatabaseName() { + if (caseType == Case.CaseType.MULTI_USER_CASE) { + return caseDatabase; + } else { + return Paths.get(caseDatabase).getFileName().toString(); + } + } + + /** + * Gets the full path to the case database file if the case is a single-user + * case. + * + * @return The full path to the case database file for a single-user case. + * + * @throws UnsupportedOperationException If called for a multi-user case. + */ + public String getCaseDatabasePath() throws UnsupportedOperationException { + if (caseType == Case.CaseType.SINGLE_USER_CASE) { + return caseDatabase; + } else { + throw new UnsupportedOperationException(); + } } /** @@ -228,7 +249,7 @@ public final class CaseMetadata { * @return The date this case was created as a string */ String getCreatedDate() { - return this.createdDate; + return createdDate; } /** @@ -238,10 +259,10 @@ public final class CaseMetadata { * @param createdDate The date the case was created as a string. */ void setCreatedDate(String createdDate) throws CaseMetadataException { - String oldCreatedDate = this.createdDate; + String oldCreatedDate = createdDate; this.createdDate = createdDate; try { - this.writeToFile(); + writeToFile(); } catch (CaseMetadataException ex) { this.createdDate = oldCreatedDate; throw ex; @@ -249,27 +270,27 @@ public final class CaseMetadata { } /** - * Gets the build that created the case. + * Gets the Autopsy version that created the case. * * @return A build identifier. */ - String getCreatedByBuild() { - return createdByBuild; + String getCreatedByVersion() { + return createdByVersion; } /** - * Gets the build that created the case. Used for preserving the case - * creation build during single-user to multi-user case conversion. + * Sets the Autopsy version that created the case. Used for preserving this + * metadata during single-user to multi-user case conversion. * * @param buildVersion An build version identifier. */ - void setCreatedByBuild(String buildVersion) throws CaseMetadataException { - String oldCreatedByVersion = this.createdByBuild; - this.createdByBuild = buildVersion; + void setCreatedByVersion(String buildVersion) throws CaseMetadataException { + String oldCreatedByVersion = this.createdByVersion; + this.createdByVersion = buildVersion; try { this.writeToFile(); } catch (CaseMetadataException ex) { - this.createdByBuild = oldCreatedByVersion; + this.createdByVersion = oldCreatedByVersion; throw ex; } } @@ -323,22 +344,22 @@ public final class CaseMetadata { Element rootElement = doc.createElement(ROOT_ELEMENT_NAME); doc.appendChild(rootElement); createChildElement(doc, rootElement, SCHEMA_VERSION_ELEMENT_NAME, CURRENT_SCHEMA_VERSION); - createChildElement(doc, rootElement, CREATED_DATE_ELEMENT_NAME, this.getCreatedDate()); + createChildElement(doc, rootElement, CREATED_DATE_ELEMENT_NAME, createdDate); createChildElement(doc, rootElement, MODIFIED_DATE_ELEMENT_NAME, DATE_FORMAT.format(new Date())); - createChildElement(doc, rootElement, CREATED_BY_BUILD_ELEMENT_NAME, this.getCreatedByBuild()); - createChildElement(doc, rootElement, SAVED_BY_BUILD_ELEMENT_NAME, System.getProperty("netbeans.buildnumber")); + createChildElement(doc, rootElement, AUTOPSY_CREATED_BY_ELEMENT_NAME, createdByVersion); + createChildElement(doc, rootElement, AUTOPSY_SAVED_BY_ELEMENT_NAME, Version.getVersion()); Element caseElement = doc.createElement(CASE_ELEMENT_NAME); rootElement.appendChild(caseElement); /* * Create the children of the case element. */ - createChildElement(doc, caseElement, CASE_NAME_ELEMENT_NAME, this.getCaseName()); - createChildElement(doc, caseElement, CASE_NUMBER_ELEMENT_NAME, this.getCaseNumber()); - createChildElement(doc, caseElement, EXAMINER_ELEMENT_NAME, this.getExaminer()); - createChildElement(doc, caseElement, CASE_TYPE_ELEMENT_NAME, this.getCaseType().toString()); - createChildElement(doc, caseElement, CASE_DATABASE_ELEMENT_NAME, this.getCaseDatabaseName()); - createChildElement(doc, caseElement, TEXT_INDEX_NAME_ELEMENT, this.getTextIndexName()); + createChildElement(doc, caseElement, CASE_NAME_ELEMENT_NAME, caseName); + createChildElement(doc, caseElement, CASE_NUMBER_ELEMENT_NAME, caseNumber); + createChildElement(doc, caseElement, EXAMINER_ELEMENT_NAME, examiner); + createChildElement(doc, caseElement, CASE_TYPE_ELEMENT_NAME, caseType.toString()); + createChildElement(doc, caseElement, CASE_DATABASE_ELEMENT_NAME, caseDatabase); + createChildElement(doc, caseElement, TEXT_INDEX_ELEMENT, textIndexName); } /** @@ -381,9 +402,9 @@ public final class CaseMetadata { String schemaVersion = getElementTextContent(rootElement, SCHEMA_VERSION_ELEMENT_NAME, true); this.createdDate = getElementTextContent(rootElement, CREATED_DATE_ELEMENT_NAME, true); if (schemaVersion.equals(SCHEMA_VERSION_ONE)) { - this.createdByBuild = getElementTextContent(rootElement, CREATED_BY_VERSION_ELEMENT_NAME, true); + this.createdByVersion = getElementTextContent(rootElement, AUTOPSY_CREATED_VERSION_ELEMENT_NAME, true); } else { - this.createdByBuild = getElementTextContent(rootElement, CREATED_BY_BUILD_ELEMENT_NAME, true); + this.createdByVersion = getElementTextContent(rootElement, AUTOPSY_CREATED_BY_ELEMENT_NAME, true); } /* @@ -403,10 +424,11 @@ public final class CaseMetadata { } if (schemaVersion.equals(SCHEMA_VERSION_ONE)) { this.caseDatabase = getElementTextContent(caseElement, CASE_DATABASE_NAME_ELEMENT_NAME, true); + this.textIndexName = getElementTextContent(caseElement, TEXT_INDEX_NAME_ELEMENT, true); } else { this.caseDatabase = getElementTextContent(caseElement, CASE_DATABASE_ELEMENT_NAME, true); + this.textIndexName = getElementTextContent(caseElement, TEXT_INDEX_ELEMENT, true); } - this.textIndexName = getElementTextContent(caseElement, TEXT_INDEX_NAME_ELEMENT, true); /* * Update the file to the current schema, if necessary. @@ -414,7 +436,7 @@ public final class CaseMetadata { if (!schemaVersion.equals(CURRENT_SCHEMA_VERSION)) { writeToFile(); } - + } catch (ParserConfigurationException | SAXException | IOException ex) { throw new CaseMetadataException(String.format("Error reading from case metadata file %s", metadataFilePath), ex); } @@ -446,7 +468,7 @@ public final class CaseMetadata { /** * Exception thrown by the CaseMetadata class when there is a problem - * accessing the metadata for a case. + * accessing the metadata for a case. */ public final static class CaseMetadataException extends Exception { @@ -461,17 +483,4 @@ public final class CaseMetadata { } } - /** - * Gets a string identifying the case database. - * - * @return For a single-user case, the full path to the case database file. - * For a multi-user case, the case database name. - * - * @deprecated Use getCaseDatabase instead. - */ - @Deprecated - public String getCaseDatabaseName() { - return getCaseDatabase(); - } - } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java index 2f024e724a..537cd0f3d2 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesForm.java @@ -88,7 +88,11 @@ class CasePropertiesForm extends javax.swing.JPanel { current = currentCase; CaseMetadata caseMetadata = currentCase.getCaseMetadata(); - tbDbName.setText(caseMetadata.getCaseDatabase()); + if (caseMetadata.getCaseType() == Case.CaseType.SINGLE_USER_CASE) { + tbDbName.setText(caseMetadata.getCaseDatabasePath()); + } else { + tbDbName.setText(caseMetadata.getCaseDatabaseName()); + } Case.CaseType caseType = caseMetadata.getCaseType(); tbDbType.setText(caseType.getLocalizedDisplayName()); if (caseType == Case.CaseType.SINGLE_USER_CASE) { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java b/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java index 458cd642dc..95d94d1f23 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/SingleUserCaseConverter.java @@ -198,7 +198,7 @@ public class SingleUserCaseConverter { dbName, solrName); // Set created date. This calls writefile, no need to call it again newCaseMetadata.setCreatedDate(oldCaseMetadata.getCreatedDate()); - newCaseMetadata.setCreatedByBuild(oldCaseMetadata.getCreatedByBuild()); + newCaseMetadata.setCreatedByVersion(oldCaseMetadata.getCreatedByVersion()); // At this point the import has been finished successfully so we can delete the original case // (if requested). This *should* be fairly safe - at this point we know there was an autopsy file