diff --git a/Core/ivy.xml b/Core/ivy.xml
index f20453a141..cbe45d8c33 100644
--- a/Core/ivy.xml
+++ b/Core/ivy.xml
@@ -23,6 +23,8 @@
+
+
diff --git a/Core/nbproject/project.properties b/Core/nbproject/project.properties
index 1b0a695edd..89bf4a93d7 100644
--- a/Core/nbproject/project.properties
+++ b/Core/nbproject/project.properties
@@ -18,8 +18,8 @@ file.reference.sevenzipjbinding.jar=release/modules/ext/sevenzipjbinding.jar
file.reference.sqlite-jdbc-3.8.11.jar=release\\modules\\ext\\sqlite-jdbc-3.8.11.jar
file.reference.StixLib.jar=release/modules/ext/StixLib.jar
file.reference.bcprov-jdk15on-1.54.jar=release/modules/ext/bcprov-jdk15on-1.54.jar
-file.reference.jackcess-2.1.8.jar=release/modules/ext/jackcess-2.1.8.jar
-file.reference.jackcess-encrypt-2.1.2.jar=release/modules/ext/jackcess-encrypt-2.1.2.jar
+file.reference.jackcess-2.2.0.jar=release/modules/ext/jackcess-2.2.0.jar
+file.reference.jackcess-encrypt-2.1.4.jar=release/modules/ext/jackcess-encrypt-2.1.4.jar
file.reference.jempbox-1.8.13.jar=release/modules/ext/jempbox-1.8.13.jar
file.reference.javax.ws.rs-api-2.0.1.jar=release/modules/ext/javax.ws.rs-api-2.0.1.jar
file.reference.cxf-core-3.0.16.jar=release/modules/ext/cxf-core-3.0.16.jar
@@ -29,7 +29,7 @@ file.reference.cxf-rt-transports-http-3.0.16.jar=release/modules/ext/cxf-rt-tran
file.reference.fontbox-2.0.8.jar=release/modules/ext/fontbox-2.0.8.jar
file.reference.pdfbox-2.0.8.jar=release/modules/ext/pdfbox-2.0.8.jar
file.reference.pdfbox-tools-2.0.8.jar=release/modules/ext/pdfbox-tools-2.0.8.jar
-file.reference.sleuthkit-postgresql-4.6.3.jar=release/modules/ext/sleuthkit-postgresql-4.6.3.jar
+file.reference.sleuthkit-postgresql-4.6.4.jar=release/modules/ext/sleuthkit-postgresql-4.6.4.jar
file.reference.tika-core-1.17.jar=release/modules/ext/tika-core-1.17.jar
file.reference.tika-parsers-1.17.jar=release/modules/ext/tika-parsers-1.17.jar
file.reference.curator-client-2.8.0.jar=release/modules/ext/curator-client-2.8.0.jar
diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml
index d142e0b8c9..04732e7873 100644
--- a/Core/nbproject/project.xml
+++ b/Core/nbproject/project.xml
@@ -338,12 +338,12 @@
org.sleuthkit.autopsy.modules.vmextractororg.sleuthkit.autopsy.progressorg.sleuthkit.autopsy.report
- org.sleuthkit.autopsy.tabulardatareader
+ org.sleuthkit.autopsy.texttranslationorg.sleuthkit.datamodel
- ext/jackcess-2.1.8.jar
- release/modules/ext/jackcess-2.1.8.jar
+ ext/jackcess-2.2.0.jar
+ release/modules/ext/jackcess-2.2.0.jarext/zookeeper-3.4.6.jar
@@ -394,8 +394,8 @@
release/modules/ext/sevenzipjbinding.jar
- ext/sleuthkit-postgresql-4.6.3.jar
- release/modules/ext/sleuthkit-postgresql-4.6.3.jar
+ ext/sleuthkit-postgresql-4.6.4.jar
+ release/modules/ext/sleuthkit-postgresql-4.6.4.jarext/mchange-commons-java-0.2.9.jar
@@ -482,8 +482,8 @@
release\modules\ext\commons-pool2-2.4.2.jar
- ext/jackcess-encrypt-2.1.2.jar
- release/modules/ext/jackcess-encrypt-2.1.2.jar
+ ext/jackcess-encrypt-2.1.4.jar
+ release/modules/ext/jackcess-encrypt-2.1.4.jarext/jsoup-1.10.3.jar
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java
index 7fc542399c..d4141a1b99 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java
@@ -122,6 +122,7 @@ import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TimelineManager;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskUnsupportedSchemaVersionException;
+import org.sleuthkit.autopsy.coreutils.StopWatch;
/**
* An Autopsy case. Currently, only one case at a time may be open.
@@ -744,11 +745,15 @@ public class Case {
"Case.exceptionMessage.cannotGetLockToDeleteCase=Cannot delete case because it is open for another user or there is a problem with the coordination service."
})
public static void deleteCase(CaseMetadata metadata) throws CaseActionException {
+ StopWatch stopWatch = new StopWatch();
+ stopWatch.start();
synchronized (caseActionSerializationLock) {
if (null != currentCase) {
throw new CaseActionException(Bundle.Case_exceptionMessage_cannotDeleteCurrentCase());
}
}
+ stopWatch.stop();
+ logger.log(Level.INFO, String.format("Used %d s to acquire caseActionSerializationLock (Java monitor in Case class) for %s (%s) in %s", stopWatch.getElapsedTimeSecs(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
/*
* Set up either a GUI progress indicator without a cancel button (can't
@@ -770,10 +775,19 @@ public class Case {
* cannot be deleted if another node has it open.
*/
progressIndicator.progress(Bundle.Case_progressMessage_checkingForOtherUser());
+ stopWatch.reset();
+ stopWatch.start();
try (CoordinationService.Lock dirLock = CoordinationService.getInstance().tryGetExclusiveLock(CategoryNode.CASES, metadata.getCaseDirectory())) {
- assert (null != dirLock);
- deleteCase(metadata, progressIndicator);
+ stopWatch.stop();
+ logger.log(Level.INFO, String.format("Used %d s to acquire case directory coordination service lock for %s (%s) in %s", stopWatch.getElapsedTimeSecs(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
+ if (dirLock != null) {
+ deleteCase(metadata, progressIndicator);
+ } else {
+ throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireDirLock());
+ }
} catch (CoordinationServiceException ex) {
+ stopWatch.stop();
+ logger.log(Level.INFO, String.format("Used %d s to fail to acquire case directory coordination service lock for %s (%s) in %s", stopWatch.getElapsedTimeSecs(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
throw new CaseActionException(Bundle.Case_exceptionMessage_cannotGetLockToDeleteCase(), ex);
}
}
@@ -983,11 +997,13 @@ public class Case {
"Case.exceptionMessage.errorsDeletingCase=Errors occured while deleting the case. See the application log for details"
})
private static void deleteCase(CaseMetadata metadata, ProgressIndicator progressIndicator) throws CaseActionException {
+ StopWatch stopWatch = new StopWatch();
boolean errorsOccurred = false;
if (CaseType.MULTI_USER_CASE == metadata.getCaseType()) {
/*
* Delete the case database from the database server.
*/
+ stopWatch.start();
try {
progressIndicator.progress(Bundle.Case_progressMessage_deletingCaseDatabase());
CaseDbConnectionInfo db;
@@ -997,10 +1013,14 @@ public class Case {
Statement statement = connection.createStatement();) {
String deleteCommand = "DROP DATABASE \"" + metadata.getCaseDatabaseName() + "\""; //NON-NLS
statement.execute(deleteCommand);
+ stopWatch.stop();
+ logger.log(Level.INFO, String.format("Used %d s to delete case database for %s (%s) in %s", stopWatch.getElapsedTimeSecs(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
}
} catch (UserPreferencesException | ClassNotFoundException | SQLException ex) {
logger.log(Level.SEVERE, String.format("Failed to delete case database %s for %s (%s) in %s", metadata.getCaseDatabaseName(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()), ex);
errorsOccurred = true;
+ stopWatch.stop();
+ logger.log(Level.INFO, String.format("Used %d s to fail delete case database for %s (%s) in %s", stopWatch.getElapsedTimeSecs(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
}
}
@@ -1010,10 +1030,16 @@ public class Case {
progressIndicator.progress(Bundle.Case_progressMessage_deletingTextIndex());
for (KeywordSearchService searchService : Lookup.getDefault().lookupAll(KeywordSearchService.class)) {
try {
+ stopWatch.reset();
+ stopWatch.start();
searchService.deleteTextIndex(metadata);
+ stopWatch.stop();
+ logger.log(Level.INFO, String.format("Used %d s to delete text index for %s (%s) in %s", stopWatch.getElapsedTimeSecs(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
} catch (KeywordSearchServiceException ex) {
logger.log(Level.SEVERE, String.format("Failed to delete text index for %s (%s) in %s", metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()), ex);
errorsOccurred = true;
+ stopWatch.stop();
+ logger.log(Level.INFO, String.format("Used %d s to fail to delete text index for %s (%s) in %s", stopWatch.getElapsedTimeSecs(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
}
}
@@ -1021,9 +1047,16 @@ public class Case {
* Delete the case directory.
*/
progressIndicator.progress(Bundle.Case_progressMessage_deletingCaseDirectory());
+ stopWatch.reset();
+ stopWatch.start();
if (!FileUtil.deleteDir(new File(metadata.getCaseDirectory()))) {
logger.log(Level.SEVERE, String.format("Failed to delete case directory for %s (%s) in %s", metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
errorsOccurred = true;
+ stopWatch.stop();
+ logger.log(Level.INFO, String.format("Used %d s to fail to delete case directory for %s (%s) in %s", stopWatch.getElapsedTimeSecs(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
+ } else {
+ stopWatch.stop();
+ logger.log(Level.INFO, String.format("Used %d s to delete case directory for %s (%s) in %s", stopWatch.getElapsedTimeSecs(), metadata.getCaseDisplayName(), metadata.getCaseName(), metadata.getCaseDirectory()));
}
/*
@@ -1839,7 +1872,7 @@ public class Case {
progressIndicator.progress(Bundle.Case_progressMessage_preparingToOpenCaseResources());
acquireSharedCaseDirLock(metadata.getCaseDirectory());
try (CoordinationService.Lock resourcesLock = acquireExclusiveCaseResourcesLock(metadata.getCaseDirectory())) {
- assert (null != resourcesLock);
+ assert(resourcesLock != null); // Use reference to avoid compile time warning.
open(isNewCase, progressIndicator);
} catch (CaseActionException ex) {
releaseSharedCaseDirLock(getMetadata().getCaseDirectory());
@@ -2417,7 +2450,7 @@ public class Case {
* @throws CaseActionException with a user-friendly message if the lock
* cannot be acquired.
*/
- @Messages({"Case.creationException.couldNotAcquireDirLock=Failed to get lock on case directory."})
+ @Messages({"Case.creationException.couldNotAcquireDirLock=Failed to get lock on case directory"})
private void acquireSharedCaseDirLock(String caseDir) throws CaseActionException {
try {
caseDirLock = CoordinationService.getInstance().tryGetSharedLock(CategoryNode.CASES, caseDir, DIR_LOCK_TIMOUT_HOURS, TimeUnit.HOURS);
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java
index a095341c37..fed329769e 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java
@@ -21,8 +21,6 @@ package org.sleuthkit.autopsy.casemodule;
import java.io.File;
import java.util.Calendar;
import java.util.List;
-import java.util.SimpleTimeZone;
-import java.util.TimeZone;
import java.util.logging.Level;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
@@ -39,6 +37,7 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
import org.sleuthkit.autopsy.coreutils.PathValidator;
+import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
/**
* Panel for adding an image file such as .img, .E0x, .00x, etc. Allows the user
@@ -72,11 +71,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
initComponents();
// Populate the drop down list of time zones
- for (String id : SimpleTimeZone.getAvailableIDs()) {
- timeZoneComboBox.addItem(timeZoneToString(TimeZone.getTimeZone(id)));
- }
- // set the selected timezone to the current timezone
- timeZoneComboBox.setSelectedItem(timeZoneToString(Calendar.getInstance().getTimeZone()));
+ createTimeZoneList();
// Populate the drop down list of sector size options
for (String choice : SECTOR_SIZE_CHOICES) {
@@ -95,6 +90,20 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
}
}
+ /**
+ * Creates the drop down list for the time zones and defaults the selection
+ * to the local machine time zone.
+ */
+ private void createTimeZoneList() {
+ List timeZoneList = TimeZoneUtils.createTimeZoneList();
+ for (String timeZone : timeZoneList) {
+ timeZoneComboBox.addItem(timeZone);
+ }
+
+ // set the selected timezone
+ timeZoneComboBox.setSelectedItem(TimeZoneUtils.createTimeZoneString(Calendar.getInstance().getTimeZone()));
+ }
+
/**
* Creates and returns an instance of a ImageFilePanel.
*
@@ -348,21 +357,6 @@ public class ImageFilePanel extends JPanel implements DocumentListener {
}
}
- /**
- * Get a string representation of a TimeZone for use in the drop down list.
- *
- * @param zone The TimeZone to make a string for
- *
- * @return A string representation of a TimeZone for use in the drop down
- * list.
- */
- static private String timeZoneToString(TimeZone zone) {
- int offset = zone.getRawOffset() / 1000;
- int hour = offset / 3600;
- int minutes = (offset % 3600) / 60;
- return String.format("(GMT%+d:%02d) %s", hour, minutes, zone.getID()); //NON-NLS
- }
-
@Override
public void insertUpdate(DocumentEvent e) {
updateHelper();
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java
index c5c8fb32fb..ba5e4fab92 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java
@@ -21,8 +21,7 @@ package org.sleuthkit.autopsy.casemodule;
import java.io.File;
import java.nio.file.Paths;
import java.util.Calendar;
-import java.util.SimpleTimeZone;
-import java.util.TimeZone;
+import java.util.List;
import java.util.logging.Level;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
@@ -32,6 +31,7 @@ import org.sleuthkit.autopsy.coreutils.LocalDisk;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
+import org.sleuthkit.autopsy.coreutils.TimeZoneUtils;
import org.sleuthkit.autopsy.imagewriter.ImageWriterSettings;
/**
@@ -469,36 +469,13 @@ final class LocalDiskPanel extends JPanel {
* to the local machine time zone.
*/
public void createTimeZoneList() {
- // load and add all timezone
- String[] ids = SimpleTimeZone.getAvailableIDs();
- for (String id : ids) {
- TimeZone zone = TimeZone.getTimeZone(id);
- int offset = zone.getRawOffset() / 1000;
- int hour = offset / 3600;
- int minutes = (offset % 3600) / 60;
- String item = String.format("(GMT%+d:%02d) %s", hour, minutes, id); //NON-NLS
-
- /*
- * DateFormat dfm = new SimpleDateFormat("z");
- * dfm.setTimeZone(zone); boolean hasDaylight =
- * zone.useDaylightTime(); String first = dfm.format(new Date(2010,
- * 1, 1)); String second = dfm.format(new Date(2011, 6, 6)); int mid
- * = hour * -1; String result = first + Integer.toString(mid);
- * if(hasDaylight){ result = result + second; }
- * timeZoneComboBox.addItem(item + " (" + result + ")");
- */
- timeZoneComboBox.addItem(item);
+ List timeZoneList = TimeZoneUtils.createTimeZoneList();
+ for (String timeZone : timeZoneList) {
+ timeZoneComboBox.addItem(timeZone);
}
- // get the current timezone
- TimeZone thisTimeZone = Calendar.getInstance().getTimeZone();
- int thisOffset = thisTimeZone.getRawOffset() / 1000;
- int thisHour = thisOffset / 3600;
- int thisMinutes = (thisOffset % 3600) / 60;
- String formatted = String.format("(GMT%+d:%02d) %s", thisHour, thisMinutes, thisTimeZone.getID()); //NON-NLS
// set the selected timezone
- timeZoneComboBox.setSelectedItem(formatted);
-
+ timeZoneComboBox.setSelectedItem(TimeZoneUtils.createTimeZoneString(Calendar.getInstance().getTimeZone()));
}
/**
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java
index 8d6dcffdd9..4d5e3eac36 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java
@@ -369,7 +369,7 @@ public class LocalFilesDSProcessor implements DataSourceProcessor, AutoIngestDat
@Override
public void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) {
List filePaths = Arrays.asList(new String[]{dataSourcePath.toString()});
- run(deviceId, deviceId, filePaths, progressMonitor, callBack);
+ run(deviceId, "", filePaths, progressMonitor, callBack);
}
/**
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java
index d919706be6..5a2521ef8e 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java
@@ -492,6 +492,7 @@ public class FileManager implements Closeable {
}
}
trans.commit();
+ trans = null;
/*
* Publish content added events for the added files and directories.
@@ -502,15 +503,14 @@ public class FileManager implements Closeable {
return dataSource;
- } catch (TskCoreException ex) {
+ } finally {
if (null != trans) {
try {
trans.rollback();
- } catch (TskCoreException ex2) {
- LOGGER.log(Level.SEVERE, String.format("Failed to rollback transaction after exception: %s", ex.getMessage()), ex2);
+ } catch (TskCoreException ex) {
+ LOGGER.log(Level.SEVERE, "Failed to rollback transaction after exception", ex);
}
}
- throw ex;
}
}
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java
index c6301bfb89..191d1c3bc6 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java
@@ -127,7 +127,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
}
} else if (jmi.equals(showCommonalityMenuItem)) {
showCommonalityDetails();
- }
+ }
}
};
@@ -419,7 +419,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
}
// we can correlate based on the MD5 if it is enabled
- if (this.file != null && EamDb.isEnabled()) {
+ if (this.file != null && EamDb.isEnabled() && this.file.getSize() > 0) {
try {
List artifactTypes = EamDb.getInstance().getDefinedCorrelationTypes();
@@ -430,13 +430,14 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
CorrelationCase corCase = EamDb.getInstance().getCase(Case.getCurrentCase());
try {
ret.add(new CorrelationAttributeInstance(
- md5,
aType,
+ md5,
corCase,
CorrelationDataSource.fromTSKDataSource(corCase, file.getDataSource()),
file.getParentPath() + file.getName(),
"",
- file.getKnown()));
+ file.getKnown(),
+ file.getId()));
} catch (CorrelationAttributeNormalizationException ex) {
LOGGER.log(Level.INFO, String.format("Unable to check create CorrelationAttribtueInstance for value %s and type %s.", md5, aType.toString()), ex);
}
@@ -447,27 +448,23 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
} catch (EamDbException | TskCoreException ex) {
LOGGER.log(Level.SEVERE, "Error connecting to DB", ex); // NON-NLS
}
-
- } else {
-
- // If EamDb not enabled, get the Files default correlation type to allow Other Occurances to be enabled.
- if (this.file != null) {
- String md5 = this.file.getMd5Hash();
- if (md5 != null && !md5.isEmpty()) {
- try {
- final CorrelationAttributeInstance.Type fileAttributeType
- = CorrelationAttributeInstance.getDefaultCorrelationTypes()
- .stream()
- .filter(attrType -> attrType.getId() == CorrelationAttributeInstance.FILES_TYPE_ID)
- .findAny()
- .get();
-
- ret.add(new CorrelationAttributeInstance(fileAttributeType, md5));
- } catch (EamDbException ex) {
- LOGGER.log(Level.SEVERE, "Error connecting to DB", ex); // NON-NLS
- } catch (CorrelationAttributeNormalizationException ex) {
- LOGGER.log(Level.INFO, String.format("Unable to create CorrelationAttributeInstance for value %s", md5), ex); // NON-NLS
- }
+ // If EamDb not enabled, get the Files default correlation type to allow Other Occurances to be enabled.
+ } else if (this.file != null && this.file.getSize() > 0) {
+ String md5 = this.file.getMd5Hash();
+ if (md5 != null && !md5.isEmpty()) {
+ try {
+ final CorrelationAttributeInstance.Type fileAttributeType
+ = CorrelationAttributeInstance.getDefaultCorrelationTypes()
+ .stream()
+ .filter(attrType -> attrType.getId() == CorrelationAttributeInstance.FILES_TYPE_ID)
+ .findAny()
+ .get();
+ //The Central Repository is not enabled
+ ret.add(new CorrelationAttributeInstance(fileAttributeType, md5, null, null, "", "", TskData.FileKnown.UNKNOWN, this.file.getId()));
+ } catch (EamDbException ex) {
+ LOGGER.log(Level.SEVERE, "Error connecting to DB", ex); // NON-NLS
+ } catch (CorrelationAttributeNormalizationException ex) {
+ LOGGER.log(Level.INFO, String.format("Unable to create CorrelationAttributeInstance for value %s", md5), ex); // NON-NLS
}
}
}
@@ -515,9 +512,9 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
* artifact. If the central repo is not enabled, this will only return files
* from the current case with matching MD5 hashes.
*
- * @param corAttr CorrelationAttribute to query for
+ * @param corAttr CorrelationAttribute to query for
* @param dataSourceName Data source to filter results
- * @param deviceId Device Id to filter results
+ * @param deviceId Device Id to filter results
*
* @return A collection of correlated artifact instances
*/
@@ -580,7 +577,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
* Get all other abstract files in the current case with the same MD5 as the
* selected node.
*
- * @param corAttr The CorrelationAttribute containing the MD5 to search for
+ * @param corAttr The CorrelationAttribute containing the MD5 to search for
* @param openCase The current case
*
* @return List of matching AbstractFile objects
@@ -657,11 +654,9 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
// - The central repo is disabled and the backing file has a valid MD5 hash
this.file = this.getAbstractFileFromNode(node);
if (EamDb.isEnabled()) {
- return this.file != null
- && this.file.getSize() > 0
- && !getCorrelationAttributesFromNode(node).isEmpty();
+ return !getCorrelationAttributesFromNode(node).isEmpty();
} else {
- return this.file != null
+ return this.file != null
&& this.file.getSize() > 0
&& ((this.file.getMd5Hash() != null) && (!this.file.getMd5Hash().isEmpty()));
}
@@ -733,8 +728,8 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi
* Adjust a given column for the text provided.
*
* @param columnIndex The index of the column to adjust.
- * @param text The text whose length will be used to adjust the column
- * width.
+ * @param text The text whose length will be used to adjust the
+ * column width.
*/
private void setColumnWidthToText(int columnIndex, String text) {
TableColumn column = otherCasesTable.getColumnModel().getColumn(columnIndex);
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java
index 68e5b4f8c2..c2b10f8295 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java
@@ -808,9 +808,9 @@ abstract class AbstractSqlEamDb implements EamDb {
String sql
= "INSERT INTO "
+ tableName
- + "(case_id, data_source_id, value, file_path, known_status, comment) "
+ + "(case_id, data_source_id, value, file_path, known_status, comment, file_obj_id) "
+ "VALUES ((SELECT id FROM cases WHERE case_uid=? LIMIT 1), "
- + "(SELECT id FROM data_sources WHERE device_id=? AND case_id=? LIMIT 1), ?, ?, ?, ?) "
+ + "(SELECT id FROM data_sources WHERE device_id=? AND case_id=? LIMIT 1), ?, ?, ?, ?, ?) "
+ getConflictClause();
try {
@@ -824,11 +824,13 @@ abstract class AbstractSqlEamDb implements EamDb {
preparedStatement.setString(4, eamArtifact.getCorrelationValue());
preparedStatement.setString(5, eamArtifact.getFilePath().toLowerCase());
preparedStatement.setByte(6, eamArtifact.getKnownStatus().getFileKnownValue());
+
if ("".equals(eamArtifact.getComment())) {
preparedStatement.setNull(7, Types.INTEGER);
} else {
preparedStatement.setString(7, eamArtifact.getComment());
}
+ preparedStatement.setLong(8, eamArtifact.getFileObjectId());
preparedStatement.executeUpdate();
}
@@ -900,6 +902,8 @@ abstract class AbstractSqlEamDb implements EamDb {
+ ".id,"
+ tableName
+ ".value,"
+ + tableName
+ + ".file_obj_id,"
+ " cases.case_name, cases.case_uid, data_sources.id AS data_source_id, data_sources.name, device_id, file_path, known_status, comment, data_sources.case_id FROM "
+ tableName
+ " LEFT JOIN cases ON "
@@ -963,6 +967,8 @@ abstract class AbstractSqlEamDb implements EamDb {
+ ".id, "
+ tableName
+ ".value,"
+ + tableName
+ + ".file_obj_id,"
+ " cases.case_name, cases.case_uid, data_sources.id AS data_source_id, data_sources.name, device_id, file_path, known_status, comment, data_sources.case_id FROM "
+ tableName
+ " LEFT JOIN cases ON "
@@ -1229,9 +1235,9 @@ abstract class AbstractSqlEamDb implements EamDb {
String sql
= "INSERT INTO "
+ tableName
- + " (case_id, data_source_id, value, file_path, known_status, comment) "
+ + " (case_id, data_source_id, value, file_path, known_status, comment, file_obj_id) "
+ "VALUES ((SELECT id FROM cases WHERE case_uid=? LIMIT 1), "
- + "(SELECT id FROM data_sources WHERE device_id=? AND case_id=? LIMIT 1), ?, ?, ?, ?) "
+ + "(SELECT id FROM data_sources WHERE device_id=? AND case_id=? LIMIT 1), ?, ?, ?, ?, ?) "
+ getConflictClause();
bulkPs = conn.prepareStatement(sql);
@@ -1275,6 +1281,7 @@ abstract class AbstractSqlEamDb implements EamDb {
} else {
bulkPs.setString(7, eamArtifact.getComment());
}
+ bulkPs.setLong(8, eamArtifact.getFileObjectId());
bulkPs.addBatch();
} else {
logger.log(Level.WARNING, ("Artifact value too long for central repository."
@@ -1439,6 +1446,68 @@ abstract class AbstractSqlEamDb implements EamDb {
}
}
+ /**
+ * Find a correlation attribute in the Central Repository database given the
+ * instance type, case, data source, object id.
+ *
+ * @param type The type of instance.
+ * @param correlationCase The case tied to the instance.
+ * @param correlationDataSource The data source tied to the instance.
+ * @param objectID The object id of the file tied to the
+ * instance.
+ *
+ * @return The correlation attribute if it exists; otherwise null.
+ *
+ * @throws EamDbException
+ */
+ @Override
+ public CorrelationAttributeInstance getCorrelationAttributeInstance(CorrelationAttributeInstance.Type type, CorrelationCase correlationCase,
+ CorrelationDataSource correlationDataSource, long objectID) throws EamDbException, CorrelationAttributeNormalizationException {
+
+ if (correlationCase == null) {
+ throw new EamDbException("Correlation case is null");
+ }
+
+ Connection conn = connect();
+
+ PreparedStatement preparedStatement = null;
+ ResultSet resultSet = null;
+ CorrelationAttributeInstance correlationAttributeInstance = null;
+
+ try {
+
+ String tableName = EamDbUtil.correlationTypeToInstanceTableName(type);
+ String sql
+ = "SELECT id, value, file_path, known_status, comment FROM "
+ + tableName
+ + " WHERE case_id=?"
+ + " AND file_obj_id=?";
+
+ preparedStatement = conn.prepareStatement(sql);
+ preparedStatement.setInt(1, correlationCase.getID());
+ preparedStatement.setInt(2, (int) objectID);
+ resultSet = preparedStatement.executeQuery();
+ if (resultSet.next()) {
+ int instanceId = resultSet.getInt(1);
+ String value = resultSet.getString(2);
+ String filePath = resultSet.getString(3);
+ int knownStatus = resultSet.getInt(4);
+ String comment = resultSet.getString(5);
+
+ correlationAttributeInstance = new CorrelationAttributeInstance(type, value,
+ instanceId, correlationCase, correlationDataSource, filePath, comment, TskData.FileKnown.valueOf((byte) knownStatus), objectID);
+ }
+ } catch (SQLException ex) {
+ throw new EamDbException("Error getting notable artifact instances.", ex); // NON-NLS
+ } finally {
+ EamDbUtil.closeStatement(preparedStatement);
+ EamDbUtil.closeResultSet(resultSet);
+ EamDbUtil.closeConnection(conn);
+ }
+
+ return correlationAttributeInstance;
+ }
+
/**
* Find a correlation attribute in the Central Repository database given the
* instance type, case, data source, value, and file path.
@@ -1495,9 +1564,9 @@ abstract class AbstractSqlEamDb implements EamDb {
int instanceId = resultSet.getInt(1);
int knownStatus = resultSet.getInt(2);
String comment = resultSet.getString(3);
-
+ //null objectId used because we only fall back to using this method when objectID was not available
correlationAttributeInstance = new CorrelationAttributeInstance(type, value,
- instanceId, correlationCase, correlationDataSource, filePath, comment, TskData.FileKnown.valueOf((byte) knownStatus));
+ instanceId, correlationCase, correlationDataSource, filePath, comment, TskData.FileKnown.valueOf((byte) knownStatus), null);
}
} catch (SQLException ex) {
throw new EamDbException("Error getting notable artifact instances.", ex); // NON-NLS
@@ -1637,6 +1706,8 @@ abstract class AbstractSqlEamDb implements EamDb {
+ ".id, "
+ tableName
+ ".value, "
+ + tableName
+ + ".file_obj_id,"
+ "cases.case_name, cases.case_uid, data_sources.id AS data_source_id, data_sources.name, device_id, file_path, known_status, comment, data_sources.case_id FROM "
+ tableName
+ " LEFT JOIN cases ON "
@@ -1694,7 +1765,7 @@ abstract class AbstractSqlEamDb implements EamDb {
String tableName = EamDbUtil.correlationTypeToInstanceTableName(aType);
String sql
- = "SELECT cases.case_name, cases.case_uid, data_sources.name, device_id, file_path, known_status, comment, data_sources.case_id, id, value FROM "
+ = "SELECT cases.case_name, cases.case_uid, data_sources.name, device_id, file_path, known_status, comment, data_sources.case_id, id, value, file_obj_id FROM "
+ tableName
+ " LEFT JOIN cases ON "
+ tableName
@@ -2960,14 +3031,9 @@ abstract class AbstractSqlEamDb implements EamDb {
resultSet.getString("poc_phone"));
}
- CorrelationCase eamCase = new CorrelationCase(resultSet.getInt("case_id"), resultSet.getString("case_uid"), resultSet.getString("case_name"));
- eamCase.setOrg(eamOrg);
- eamCase.setCreationDate(resultSet.getString("creation_date"));
- eamCase.setCaseNumber(resultSet.getString("case_number"));
- eamCase.setExaminerName(resultSet.getString("examiner_name"));
- eamCase.setExaminerEmail(resultSet.getString("examiner_email"));
- eamCase.setExaminerPhone(resultSet.getString("examiner_phone"));
- eamCase.setNotes(resultSet.getString("notes"));
+ CorrelationCase eamCase = new CorrelationCase(resultSet.getInt("case_id"), resultSet.getString("case_uid"), eamOrg, resultSet.getString("case_name"),
+ resultSet.getString("creation_date"), resultSet.getString("case_number"), resultSet.getString("examiner_name"),
+ resultSet.getString("examiner_email"), resultSet.getString("examiner_phone"), resultSet.getString("notes"));
return eamCase;
}
@@ -3017,7 +3083,6 @@ abstract class AbstractSqlEamDb implements EamDb {
if (null == resultSet) {
return null;
}
- // @@@ We should have data source ID in the previous query instead of passing -1 into the below constructor
return new CorrelationAttributeInstance(
aType,
resultSet.getString("value"),
@@ -3026,8 +3091,8 @@ abstract class AbstractSqlEamDb implements EamDb {
new CorrelationDataSource(resultSet.getInt("case_id"), resultSet.getInt("data_source_id"), resultSet.getString("device_id"), resultSet.getString("name")),
resultSet.getString("file_path"),
resultSet.getString("comment"),
- TskData.FileKnown.valueOf(resultSet.getByte("known_status"))
- );
+ TskData.FileKnown.valueOf(resultSet.getByte("known_status")),
+ resultSet.getLong("file_obj_id"));
}
private EamOrganization getEamOrganizationFromResultSet(ResultSet resultSet) throws SQLException {
@@ -3075,6 +3140,18 @@ abstract class AbstractSqlEamDb implements EamDb {
);
}
+ /**
+ * Determine if a specific column already exists in a specific table
+ *
+ * @param tableName the table to check for the specified column
+ * @param columnName the name of the column to check for
+ *
+ * @return true if the column exists, false if the column does not exist
+ *
+ * @throws EamDbException
+ */
+ abstract boolean doesColumnExist(Connection conn, String tableName, String columnName) throws SQLException;
+
/**
* Upgrade the schema of the database (if needed)
*
@@ -3085,6 +3162,7 @@ abstract class AbstractSqlEamDb implements EamDb {
ResultSet resultSet = null;
Statement statement = null;
+ PreparedStatement preparedStatement = null;
Connection conn = null;
try {
@@ -3119,6 +3197,10 @@ abstract class AbstractSqlEamDb implements EamDb {
logger.log(Level.INFO, "Central Repository is up to date");
return;
}
+ if (dbSchemaVersion.compareTo(CURRENT_DB_SCHEMA_VERSION) > 0) {
+ logger.log(Level.INFO, "Central Repository is of newer version than software creates");
+ return;
+ }
// Update from 1.0 to 1.1
if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 1)) < 0) {
@@ -3131,7 +3213,71 @@ abstract class AbstractSqlEamDb implements EamDb {
// regardless of whether this succeeds.
EamDbUtil.insertDefaultOrganization(conn);
}
+ //Update to 1.2
+ if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 2)) < 0) {
+ EamDbPlatformEnum selectedPlatform = EamDbPlatformEnum.getSelectedPlatform();
+ final String addObjectIdColumnTemplate = "ALTER TABLE %s ADD COLUMN file_obj_id INTEGER;"; //NON-NLS
+ final String addSsidTableTemplate;
+ final String addCaseIdIndexTemplate;
+ final String addDataSourceIdIndexTemplate;
+ final String addValueIndexTemplate;
+ final String addKnownStatusIndexTemplate;
+ final String addObjectIdIndexTemplate;
+
+ final String addAttributeSql;
+ //get the data base specific code for creating a new _instance table
+ switch (selectedPlatform) {
+ case POSTGRESQL:
+ addAttributeSql = "INSERT INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?) " + getConflictClause(); //NON-NLS
+
+ addSsidTableTemplate = PostgresEamDbSettings.getCreateArtifactInstancesTableTemplate();
+ addCaseIdIndexTemplate = PostgresEamDbSettings.getAddCaseIdIndexTemplate();
+ addDataSourceIdIndexTemplate = PostgresEamDbSettings.getAddDataSourceIdIndexTemplate();
+ addValueIndexTemplate = PostgresEamDbSettings.getAddValueIndexTemplate();
+ addKnownStatusIndexTemplate = PostgresEamDbSettings.getAddKnownStatusIndexTemplate();
+ addObjectIdIndexTemplate = PostgresEamDbSettings.getAddObjectIdIndexTemplate();
+ break;
+ case SQLITE:
+ addAttributeSql = "INSERT OR IGNORE INTO correlation_types(id, display_name, db_table_name, supported, enabled) VALUES (?, ?, ?, ?, ?)"; //NON-NLS
+
+ addSsidTableTemplate = SqliteEamDbSettings.getCreateArtifactInstancesTableTemplate();
+ addCaseIdIndexTemplate = SqliteEamDbSettings.getAddCaseIdIndexTemplate();
+ addDataSourceIdIndexTemplate = SqliteEamDbSettings.getAddDataSourceIdIndexTemplate();
+ addValueIndexTemplate = SqliteEamDbSettings.getAddValueIndexTemplate();
+ addKnownStatusIndexTemplate = SqliteEamDbSettings.getAddKnownStatusIndexTemplate();
+ addObjectIdIndexTemplate = SqliteEamDbSettings.getAddObjectIdIndexTemplate();
+ break;
+ default:
+ throw new EamDbException("Currently selected database platform \"" + selectedPlatform.name() + "\" can not be upgraded.");
+ }
+ //update central repository to be able to store new correlation attributes
+ final String wirelessNetworsDbTableName = "wireless_networks";
+ final String wirelessNetworksTableInstanceName = wirelessNetworsDbTableName + "_instances";
+ //add the wireless_networks attribute to the correlation_types table
+ preparedStatement = conn.prepareStatement(addAttributeSql);
+ preparedStatement.setInt(1, CorrelationAttributeInstance.SSID_TYPE_ID);
+ preparedStatement.setString(2, Bundle.CorrelationType_SSID_displayName());
+ preparedStatement.setString(3, wirelessNetworsDbTableName);
+ preparedStatement.setInt(4, 1);
+ preparedStatement.setInt(5, 1);
+ preparedStatement.execute();
+ //create a new wireless_networks_instances table and add indexes for its columns
+ statement.execute(String.format(addSsidTableTemplate, wirelessNetworksTableInstanceName, wirelessNetworksTableInstanceName));
+ statement.execute(String.format(addCaseIdIndexTemplate, wirelessNetworksTableInstanceName, wirelessNetworksTableInstanceName));
+ statement.execute(String.format(addDataSourceIdIndexTemplate, wirelessNetworksTableInstanceName, wirelessNetworksTableInstanceName));
+ statement.execute(String.format(addValueIndexTemplate, wirelessNetworksTableInstanceName, wirelessNetworksTableInstanceName));
+ statement.execute(String.format(addKnownStatusIndexTemplate, wirelessNetworksTableInstanceName, wirelessNetworksTableInstanceName));
+ //add file_obj_id column to _instances table which do not already have it
+ String instance_type_dbname;
+ for (CorrelationAttributeInstance.Type type : CorrelationAttributeInstance.getDefaultCorrelationTypes()) {
+ instance_type_dbname = EamDbUtil.correlationTypeToInstanceTableName(type);
+ if (!doesColumnExist(conn, instance_type_dbname, "file_obj_id")) {
+ statement.execute(String.format(addObjectIdColumnTemplate, instance_type_dbname)); //NON-NLS
+ }
+ statement.execute(String.format(addObjectIdIndexTemplate, instance_type_dbname, instance_type_dbname));
+ }
+ }
if (!updateSchemaVersion(conn)) {
throw new EamDbException("Error updating schema version");
}
@@ -3149,6 +3295,7 @@ abstract class AbstractSqlEamDb implements EamDb {
throw ex;
} finally {
EamDbUtil.closeResultSet(resultSet);
+ EamDbUtil.closeStatement(preparedStatement);
EamDbUtil.closeStatement(statement);
EamDbUtil.closeConnection(conn);
}
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeInstance.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeInstance.java
index c26134c5b8..8fd6b4170e 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeInstance.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeInstance.java
@@ -48,46 +48,18 @@ public class CorrelationAttributeInstance implements Serializable {
private String filePath;
private String comment;
private TskData.FileKnown knownStatus;
+ private Long objectId;
public CorrelationAttributeInstance(
- String correlationValue,
CorrelationAttributeInstance.Type correlationType,
- CorrelationCase eamCase,
- CorrelationDataSource eamDataSource,
- String filePath
- ) throws EamDbException, CorrelationAttributeNormalizationException {
- this(correlationType, correlationValue, -1, eamCase, eamDataSource, filePath, null, TskData.FileKnown.UNKNOWN);
- }
-
- public CorrelationAttributeInstance(
String correlationValue,
- CorrelationAttributeInstance.Type correlationType,
CorrelationCase eamCase,
CorrelationDataSource eamDataSource,
String filePath,
String comment,
- TskData.FileKnown knownStatus
- ) throws EamDbException, CorrelationAttributeNormalizationException {
- this(correlationType, correlationValue, -1, eamCase, eamDataSource, filePath, comment, knownStatus);
- }
-
- public CorrelationAttributeInstance(
- Type correlationType,
- String correlationValue,
- CorrelationCase correlationCase,
- CorrelationDataSource fromTSKDataSource,
- String string) throws EamDbException, CorrelationAttributeNormalizationException {
- this(correlationType, correlationValue, -1, correlationCase, fromTSKDataSource, string, "", TskData.FileKnown.UNKNOWN);
- }
-
- /**
- * NOTE: Only used for when EamDB is NOT enabled.
- *
- * @param aType CorrelationAttributeInstance.Type
- * @param value correlation value
- */
- public CorrelationAttributeInstance(Type aType, String value) throws EamDbException, CorrelationAttributeNormalizationException {
- this(aType, value, -1, null, null, "", "", TskData.FileKnown.UNKNOWN);
+ TskData.FileKnown knownStatus,
+ long fileObjectId) throws EamDbException, CorrelationAttributeNormalizationException {
+ this(correlationType, correlationValue, -1, eamCase, eamDataSource, filePath, comment, knownStatus, fileObjectId);
}
CorrelationAttributeInstance(
@@ -98,7 +70,8 @@ public class CorrelationAttributeInstance implements Serializable {
CorrelationDataSource eamDataSource,
String filePath,
String comment,
- TskData.FileKnown knownStatus
+ TskData.FileKnown knownStatus,
+ Long fileObjectId
) throws EamDbException, CorrelationAttributeNormalizationException {
if (filePath == null) {
throw new EamDbException("file path is null");
@@ -113,6 +86,7 @@ public class CorrelationAttributeInstance implements Serializable {
this.filePath = filePath.toLowerCase();
this.comment = comment;
this.knownStatus = knownStatus;
+ this.objectId = fileObjectId;
}
public Boolean equals(CorrelationAttributeInstance otherInstance) {
@@ -145,14 +119,6 @@ public class CorrelationAttributeInstance implements Serializable {
return correlationValue;
}
- /**
- * @param correlationValue the correlationValue to set
- */
- public void setCorrelationValue(String correlationValue) {
- // Lower-case all values to normalize and improve correlation hits, going forward make sure this makes sense for all correlation types
- this.correlationValue = correlationValue.toLowerCase();
- }
-
/**
* @return the correlation Type
*/
@@ -160,18 +126,11 @@ public class CorrelationAttributeInstance implements Serializable {
return correlationType;
}
- /**
- * @param correlationType the correlation Type to set
- */
- public void setCorrelationType(Type correlationType) {
- this.correlationType = correlationType;
- }
-
/**
* Is this a database instance?
*
* @return True if the instance ID is greater or equal to zero; otherwise
- * false.
+ * false.
*/
public boolean isDatabaseInstance() {
return (ID >= 0);
@@ -234,30 +193,42 @@ public class CorrelationAttributeInstance implements Serializable {
* as notable and should never be set to KNOWN.
*
* @param knownStatus Should be BAD if the item is tagged as notable,
- * UNKNOWN otherwise
+ * UNKNOWN otherwise
*/
public void setKnownStatus(TskData.FileKnown knownStatus) {
this.knownStatus = knownStatus;
}
+ /**
+ * Get the objectId of the file associated with the correlation attribute or
+ * NULL if the objectId is not available.
+ *
+ * @return the objectId of the file
+ */
+ public Long getFileObjectId() {
+ return objectId;
+ }
+
// Type ID's for Default Correlation Types
public static final int FILES_TYPE_ID = 0;
public static final int DOMAIN_TYPE_ID = 1;
public static final int EMAIL_TYPE_ID = 2;
public static final int PHONE_TYPE_ID = 3;
public static final int USBID_TYPE_ID = 4;
+ public static final int SSID_TYPE_ID = 5;
/**
* Load the default correlation types
*
* @throws EamDbException if the Type's dbTableName has invalid
- * characters/format
+ * characters/format
*/
@Messages({"CorrelationType.FILES.displayName=Files",
"CorrelationType.DOMAIN.displayName=Domains",
"CorrelationType.EMAIL.displayName=Email Addresses",
"CorrelationType.PHONE.displayName=Phone Numbers",
- "CorrelationType.USBID.displayName=USB Devices"})
+ "CorrelationType.USBID.displayName=USB Devices",
+ "CorrelationType.SSID.displayName=Wireless Networks"})
public static List getDefaultCorrelationTypes() throws EamDbException {
List DEFAULT_CORRELATION_TYPES = new ArrayList<>();
DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(FILES_TYPE_ID, Bundle.CorrelationType_FILES_displayName(), "file", true, true)); // NON-NLS
@@ -265,6 +236,7 @@ public class CorrelationAttributeInstance implements Serializable {
DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(EMAIL_TYPE_ID, Bundle.CorrelationType_EMAIL_displayName(), "email_address", true, true)); // NON-NLS
DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(PHONE_TYPE_ID, Bundle.CorrelationType_PHONE_displayName(), "phone_number", true, true)); // NON-NLS
DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(USBID_TYPE_ID, Bundle.CorrelationType_USBID_displayName(), "usb_devices", true, true)); // NON-NLS
+ DEFAULT_CORRELATION_TYPES.add(new CorrelationAttributeInstance.Type(SSID_TYPE_ID, Bundle.CorrelationType_SSID_displayName(), "wireless_networks", true, true)); // NON-NLS
return DEFAULT_CORRELATION_TYPES;
}
@@ -283,13 +255,14 @@ public class CorrelationAttributeInstance implements Serializable {
/**
*
- * @param typeId Unique ID for this Correlation Type
+ * @param typeId Unique ID for this Correlation Type
* @param displayName Name of this type displayed in the UI.
* @param dbTableName Central repository db table where data of this
- * type is stored. Must start with a lowercase letter and only contain
- * lowercase letters, numbers, and '_' characters.
- * @param supported Is this Type currently supported
- * @param enabled Is this Type currently enabled.
+ * type is stored. Must start with a lowercase letter
+ * and only contain lowercase letters, numbers, and
+ * '_' characters.
+ * @param supported Is this Type currently supported
+ * @param enabled Is this Type currently enabled.
*/
public Type(int typeId, String displayName, String dbTableName, Boolean supported, Boolean enabled) throws EamDbException {
if (dbTableName == null) {
@@ -312,10 +285,11 @@ public class CorrelationAttributeInstance implements Serializable {
*
* @param displayName Name of this type displayed in the UI.
* @param dbTableName Central repository db table where data of this
- * type is stored Must start with a lowercase letter and only contain
- * lowercase letters, numbers, and '_' characters.
- * @param supported Is this Type currently supported
- * @param enabled Is this Type currently enabled.
+ * type is stored Must start with a lowercase letter
+ * and only contain lowercase letters, numbers, and
+ * '_' characters.
+ * @param supported Is this Type currently supported
+ * @param enabled Is this Type currently enabled.
*/
public Type(String displayName, String dbTableName, Boolean supported, Boolean enabled) throws EamDbException {
this(-1, displayName, dbTableName, supported, enabled);
@@ -477,8 +451,8 @@ public class CorrelationAttributeInstance implements Serializable {
* custom_instances)
*
* @param dbTableName the dbTableName to set. Must start with lowercase
- * letter and can only contain lowercase letters, numbers, and '_'
- * characters.
+ * letter and can only contain lowercase letters,
+ * numbers, and '_' characters.
*
* @throws EamDbException if dbTableName contains invalid characters
*/
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeNormalizer.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeNormalizer.java
index 772e1c517e..4ce04769c8 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeNormalizer.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeNormalizer.java
@@ -63,6 +63,8 @@ final public class CorrelationAttributeNormalizer {
return normalizePhone(data);
case CorrelationAttributeInstance.USBID_TYPE_ID:
return normalizeUsbId(data);
+ case CorrelationAttributeInstance.SSID_TYPE_ID:
+ return data;
default:
final String errorMessage = String.format(
"Validator function not found for attribute type: %s",
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java
index 30d539e87f..7d098fc590 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java
@@ -54,9 +54,9 @@ public class EamArtifactUtil {
* EamArtifact with a single EamArtifactInstance within. If not, return
* null.
*
- * @param bbArtifact BlackboardArtifact to examine
+ * @param bbArtifact BlackboardArtifact to examine
* @param checkEnabled If true, only create a CorrelationAttribute if it is
- * enabled
+ * enabled
*
* @return List of EamArtifacts
*/
@@ -93,10 +93,10 @@ public class EamArtifactUtil {
* based on the data in the blackboard artifact.
*
* @param correlationType The Central Repository artifact type to create
- * @param bbArtifact The blackboard artifact to pull data from
+ * @param bbArtifact The blackboard artifact to pull data from
*
* @return the new EamArtifact, or null if one was not created because
- * bbArtifact did not contain the needed data
+ * bbArtifact did not contain the needed data
*/
private static CorrelationAttributeInstance makeInstanceFromBlackboardArtifact(CorrelationAttributeInstance.Type correlationType,
BlackboardArtifact bbArtifact) throws EamDbException {
@@ -159,13 +159,14 @@ public class EamArtifactUtil {
return null;
}
}
-
} else if (correlationType.getId() == CorrelationAttributeInstance.USBID_TYPE_ID
&& BlackboardArtifact.ARTIFACT_TYPE.TSK_DEVICE_ATTACHED.getTypeID() == artifactTypeID) {
value = bbArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DEVICE_ID)).getValueString();
+ } else if (correlationType.getId() == CorrelationAttributeInstance.SSID_TYPE_ID
+ && BlackboardArtifact.ARTIFACT_TYPE.TSK_WIFI_NETWORK.getTypeID() == artifactTypeID) {
+ value = bbArtifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SSID)).getValueString();
}
-
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Error getting attribute while getting type from BlackboardArtifact.", ex); // NON-NLS
return null;
@@ -185,9 +186,10 @@ public class EamArtifactUtil {
* Uses the determined type and vallue, then looks up instance details to
* create proper CorrelationAttributeInstance.
*
- * @param bbArtifact the blackboard artifatc
+ * @param bbArtifact the blackboard artifact
* @param correlationType the given type
- * @param value the artifact value
+ * @param value the artifact value
+ *
* @return CorrelationAttributeInstance from details
*/
private static CorrelationAttributeInstance makeCorrelationAttributeInstanceUsingTypeValue(BlackboardArtifact bbArtifact, CorrelationAttributeInstance.Type correlationType, String value) {
@@ -205,14 +207,14 @@ public class EamArtifactUtil {
correlationCase = EamDb.getInstance().newCase(Case.getCurrentCaseThrows());
}
return new CorrelationAttributeInstance(
- value,
correlationType,
+ value,
correlationCase,
CorrelationDataSource.fromTSKDataSource(correlationCase, bbSourceFile.getDataSource()),
bbSourceFile.getParentPath() + bbSourceFile.getName(),
"",
- TskData.FileKnown.UNKNOWN
- );
+ TskData.FileKnown.UNKNOWN,
+ bbSourceFile.getId());
} catch (TskCoreException | EamDbException | CorrelationAttributeNormalizationException ex) {
logger.log(Level.SEVERE, "Error creating artifact instance.", ex); // NON-NLS
@@ -245,8 +247,6 @@ public class EamArtifactUtil {
CorrelationAttributeInstance.Type type;
CorrelationCase correlationCase;
CorrelationDataSource correlationDataSource;
- String value;
- String filePath;
try {
type = EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID);
@@ -256,8 +256,6 @@ public class EamArtifactUtil {
return null;
}
correlationDataSource = CorrelationDataSource.fromTSKDataSource(correlationCase, file.getDataSource());
- value = file.getMd5Hash();
- filePath = (file.getParentPath() + file.getName()).toLowerCase();
} catch (TskCoreException | EamDbException ex) {
logger.log(Level.SEVERE, "Error retrieving correlation attribute.", ex);
return null;
@@ -268,13 +266,26 @@ public class EamArtifactUtil {
CorrelationAttributeInstance correlationAttributeInstance;
try {
- correlationAttributeInstance = EamDb.getInstance().getCorrelationAttributeInstance(type, correlationCase, correlationDataSource, value, filePath);
+ correlationAttributeInstance = EamDb.getInstance().getCorrelationAttributeInstance(type, correlationCase, correlationDataSource, file.getId());
} catch (EamDbException | CorrelationAttributeNormalizationException ex) {
logger.log(Level.WARNING, String.format(
"Correlation attribute could not be retrieved for '%s' (id=%d): %s",
content.getName(), content.getId(), ex.getMessage()));
return null;
}
+ //if there was no correlation attribute found for the item using object_id then check for attributes added with schema 1,1 which lack object_id
+ if (correlationAttributeInstance == null) {
+ String value = file.getMd5Hash();
+ String filePath = (file.getParentPath() + file.getName()).toLowerCase();
+ try {
+ correlationAttributeInstance = EamDb.getInstance().getCorrelationAttributeInstance(type, correlationCase, correlationDataSource, value, filePath);
+ } catch (EamDbException | CorrelationAttributeNormalizationException ex) {
+ logger.log(Level.WARNING, String.format(
+ "Correlation attribute could not be retrieved for '%s' (id=%d): %s",
+ content.getName(), content.getId(), ex.getMessage()));
+ return null;
+ }
+ }
return correlationAttributeInstance;
}
@@ -317,12 +328,16 @@ public class EamArtifactUtil {
if (null == correlationCase) {
correlationCase = EamDb.getInstance().newCase(Case.getCurrentCaseThrows());
}
+
return new CorrelationAttributeInstance(
filesType,
af.getMd5Hash(),
correlationCase,
CorrelationDataSource.fromTSKDataSource(correlationCase, af.getDataSource()),
- af.getParentPath() + af.getName());
+ af.getParentPath() + af.getName(),
+ "",
+ TskData.FileKnown.UNKNOWN,
+ af.getId());
} catch (TskCoreException | EamDbException | CorrelationAttributeNormalizationException ex) {
logger.log(Level.SEVERE, "Error making correlation attribute.", ex);
@@ -340,7 +355,7 @@ public class EamArtifactUtil {
* @param file The file to test
*
* @return true if the file should be added to the central repo, false
- * otherwise
+ * otherwise
*/
public static boolean isSupportedAbstractFileType(AbstractFile file) {
if (file == null) {
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java
index c7e385928d..95584d0ebe 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java
@@ -31,11 +31,10 @@ import org.sleuthkit.datamodel.CaseDbSchemaVersionNumber;
*/
public interface EamDb {
- public static final int SCHEMA_VERSION = 1;
+ public static final int SCHEMA_VERSION = 2;
public static final CaseDbSchemaVersionNumber CURRENT_DB_SCHEMA_VERSION
- = new CaseDbSchemaVersionNumber(1, 1);
-
-
+ = new CaseDbSchemaVersionNumber(1, 2);
+
/**
* Get the instance
*
@@ -183,13 +182,14 @@ public interface EamDb {
* @return The retrieved case
*/
CorrelationCase getCaseById(int caseId) throws EamDbException;
+
/**
* Retrieves cases that are in DB.
*
* @return List of cases
*/
List getCases() throws EamDbException;
-
+
/**
* Creates new Data Source in the database
*
@@ -208,18 +208,17 @@ public interface EamDb {
*/
CorrelationDataSource getDataSource(CorrelationCase correlationCase, String dataSourceDeviceId) throws EamDbException;
-
/**
* Retrieves Data Source details based on data source ID
*
- * @param correlationCase the current CorrelationCase used for ensuring
- * uniqueness of DataSource
- * @param dataSourceId the data source ID number
+ * @param correlationCase the current CorrelationCase used for ensuring
+ * uniqueness of DataSource
+ * @param dataSourceId the data source ID number
*
* @return The data source
*/
CorrelationDataSource getDataSourceById(CorrelationCase correlationCase, int dataSourceId) throws EamDbException;
-
+
/**
* Retrieves data sources that are in DB
*
@@ -245,7 +244,7 @@ public interface EamDb {
* @return List of artifact instances for a given type/value
*/
List getArtifactInstancesByTypeValue(CorrelationAttributeInstance.Type aType, String value) throws EamDbException, CorrelationAttributeNormalizationException;
-
+
/**
* Retrieves eamArtifact instances from the database that are associated
* with the aType and filePath
@@ -314,8 +313,8 @@ public interface EamDb {
/**
* Adds an eamArtifact to an internal list to be later added to DB. Artifact
- can have 1 or more Artifact Instances. Insert will be triggered by a
- threshold or a call to commitAttributeInstancesBulk().
+ * can have 1 or more Artifact Instances. Insert will be triggered by a
+ * threshold or a call to commitAttributeInstancesBulk().
*
* @param eamArtifact The artifact to add
*/
@@ -323,7 +322,7 @@ public interface EamDb {
/**
* Executes a bulk insert of the eamArtifacts added from the
- addAttributeInstanceBulk() method
+ * addAttributeInstanceBulk() method
*/
void commitAttributeInstancesBulk() throws EamDbException;
@@ -346,6 +345,9 @@ public interface EamDb {
/**
* Find a correlation attribute in the Central Repository database given the
* instance type, case, data source, value, and file path.
+ *
+ * Method exists to support instances added using Central Repository version 1,1 and
+ * older
*
* @param type The type of instance.
* @param correlationCase The case tied to the instance.
@@ -354,12 +356,28 @@ public interface EamDb {
* @param filePath The file path tied to the instance.
*
* @return The correlation attribute if it exists; otherwise null.
- *
+ *
* @throws EamDbException
*/
CorrelationAttributeInstance getCorrelationAttributeInstance(CorrelationAttributeInstance.Type type, CorrelationCase correlationCase,
CorrelationDataSource correlationDataSource, String value, String filePath) throws EamDbException, CorrelationAttributeNormalizationException;
+ /**
+ * Find a correlation attribute in the Central Repository database given the
+ * instance type, case, data source, object id.
+ *
+ * @param type The type of instance.
+ * @param correlationCase The case tied to the instance.
+ * @param correlationDataSource The data source tied to the instance.
+ * @param objectID The object id of the file tied to the instance.
+ *
+ * @return The correlation attribute if it exists; otherwise null.
+ *
+ * @throws EamDbException
+ */
+ CorrelationAttributeInstance getCorrelationAttributeInstance(CorrelationAttributeInstance.Type type, CorrelationCase correlationCase,
+ CorrelationDataSource correlationDataSource, long objectID) throws EamDbException, CorrelationAttributeNormalizationException;
+
/**
* Sets an eamArtifact instance to the given known status. If eamArtifact
* exists, it is updated. If eamArtifact does not exist nothing happens
@@ -383,12 +401,15 @@ public interface EamDb {
/**
* Gets list of matching eamArtifact instances that have knownStatus =
* "Bad".
- *
+ *
* @param aType EamArtifact.Type to search for
+ *
* @return List with 0 or more matching eamArtifact instances.
+ *
* @throws EamDbException
*/
List getArtifactInstancesKnownBad(CorrelationAttributeInstance.Type aType) throws EamDbException;
+
/**
* Count matching eamArtifacts instances that have knownStatus = "Bad".
*
@@ -490,7 +511,7 @@ public interface EamDb {
*
* @param eamOrg The organization to add
*
- * @return The organization with the org ID set.
+ * @return The organization with the org ID set.
*
* @throws EamDbException
*/
@@ -700,18 +721,20 @@ public interface EamDb {
/**
* Process the Artifact instance in the EamDb
*
- * @param type EamArtifact.Type to search for
+ * @param type EamArtifact.Type to search for
* @param instanceTableCallback callback to process the instance
+ *
* @throws EamDbException
*/
void processInstanceTable(CorrelationAttributeInstance.Type type, InstanceTableCallback instanceTableCallback) throws EamDbException;
-
+
/**
* Process the Artifact instance in the EamDb
*
- * @param type EamArtifact.Type to search for
+ * @param type EamArtifact.Type to search for
* @param instanceTableCallback callback to process the instance
- * @param whereClause query string to execute
+ * @param whereClause query string to execute
+ *
* @throws EamDbException
*/
void processInstanceTableWhere(CorrelationAttributeInstance.Type type, String whereClause, InstanceTableCallback instanceTableCallback) throws EamDbException;
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDb.java
index 97abd1dec9..769b49bfd3 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDb.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDb.java
@@ -19,6 +19,7 @@
package org.sleuthkit.autopsy.centralrepository.datamodel;
import java.sql.Connection;
+import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.concurrent.TimeUnit;
@@ -29,8 +30,7 @@ import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.Logger;
/**
- * Central Repository database implementation using Postgres as a
- * backend
+ * Central Repository database implementation using Postgres as a backend
*/
final class PostgresEamDb extends AbstractSqlEamDb {
@@ -47,10 +47,11 @@ final class PostgresEamDb extends AbstractSqlEamDb {
/**
* Get the singleton instance of PostgresEamDb
- *
+ *
* @return the singleton instance of PostgresEamDb
- *
- * @throws EamDbException if one or more default correlation type(s) have an invalid db table name.
+ *
+ * @throws EamDbException if one or more default correlation type(s) have an
+ * invalid db table name.
*/
public synchronized static PostgresEamDb getInstance() throws EamDbException {
if (instance == null) {
@@ -61,9 +62,10 @@ final class PostgresEamDb extends AbstractSqlEamDb {
}
/**
- *
- * @throws EamDbException if the AbstractSqlEamDb class has one or more default
- * correlation type(s) having an invalid db table name.
+ *
+ * @throws EamDbException if the AbstractSqlEamDb class has one or more
+ * default correlation type(s) having an invalid db
+ * table name.
*/
private PostgresEamDb() throws EamDbException {
dbSettings = new PostgresEamDbSettings();
@@ -73,8 +75,8 @@ final class PostgresEamDb extends AbstractSqlEamDb {
@Override
public void shutdownConnections() throws EamDbException {
try {
- synchronized(this) {
- if(connectionPool != null){
+ synchronized (this) {
+ if (connectionPool != null) {
connectionPool.close();
connectionPool = null; // force it to be re-created on next connect()
}
@@ -148,7 +150,7 @@ final class PostgresEamDb extends AbstractSqlEamDb {
connectionURL.append(dbSettings.getPort());
connectionURL.append("/");
connectionURL.append(dbSettings.getDbName());
-
+
connectionPool.setUrl(connectionURL.toString());
connectionPool.setUsername(dbSettings.getUserName());
connectionPool.setPassword(dbSettings.getPassword());
@@ -189,31 +191,34 @@ final class PostgresEamDb extends AbstractSqlEamDb {
protected String getConflictClause() {
return CONFLICT_CLAUSE;
}
-
+
/**
- * Gets an exclusive lock (if applicable).
- * Will return the lock if successful, null if unsuccessful because locking
- * isn't supported, and throw an exception if we should have been able to get the
- * lock but failed (meaning the database is in use).
+ * Gets an exclusive lock (if applicable). Will return the lock if
+ * successful, null if unsuccessful because locking isn't supported, and
+ * throw an exception if we should have been able to get the lock but failed
+ * (meaning the database is in use).
+ *
* @return the lock, or null if locking is not supported
- * @throws EamDbException if the coordination service is running but we fail to get the lock
+ *
+ * @throws EamDbException if the coordination service is running but we fail
+ * to get the lock
*/
@Override
- public CoordinationService.Lock getExclusiveMultiUserDbLock() throws EamDbException{
+ public CoordinationService.Lock getExclusiveMultiUserDbLock() throws EamDbException {
try {
// First check if multi user mode is enabled - if not there's no point trying to get a lock
- if( ! UserPreferences.getIsMultiUserModeEnabled()){
+ if (!UserPreferences.getIsMultiUserModeEnabled()) {
return null;
}
-
+
String databaseNodeName = dbSettings.getHost() + "_" + dbSettings.getDbName();
CoordinationService.Lock lock = CoordinationService.getInstance().tryGetExclusiveLock(CoordinationService.CategoryNode.CENTRAL_REPO, databaseNodeName, 5, TimeUnit.MINUTES);
- if(lock != null){
+ if (lock != null) {
return lock;
}
throw new EamDbException("Error acquiring database lock");
- } catch (InterruptedException ex){
+ } catch (InterruptedException ex) {
throw new EamDbException("Error acquiring database lock");
} catch (CoordinationService.CoordinationServiceException ex) {
// This likely just means the coordination service isn't running, which is ok
@@ -221,4 +226,23 @@ final class PostgresEamDb extends AbstractSqlEamDb {
}
}
+ @Override
+ boolean doesColumnExist(Connection conn, String tableName, String columnName) throws SQLException {
+ final String objectIdColumnExistsTemplate = "SELECT EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name='%s' AND column_name='%s')"; //NON-NLS
+ ResultSet resultSet = null;
+ Statement statement = null;
+ boolean columnExists = false;
+ try {
+ statement = conn.createStatement();
+ resultSet = statement.executeQuery(String.format(objectIdColumnExistsTemplate, tableName, columnName));
+ if (resultSet.next()) {
+ columnExists = resultSet.getBoolean(1);
+ }
+ } finally {
+ EamDbUtil.closeResultSet(resultSet);
+ EamDbUtil.closeStatement(statement);
+ }
+ return columnExists;
+ }
+
}
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java
index 77ab8c23db..8183f445e3 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java
@@ -35,8 +35,9 @@ import org.sleuthkit.autopsy.coreutils.TextConverterException;
/**
* Settings for the Postgres implementation of the Central Repository database
- *
- * NOTE: This is public scope because the options panel calls it directly to set/get
+ *
+ * NOTE: This is public scope because the options panel calls it directly to
+ * set/get
*/
public final class PostgresEamDbSettings {
@@ -266,7 +267,7 @@ public final class PostgresEamDbSettings {
return true;
}
-
+
public boolean deleteDatabase() {
Connection conn = getEphemeralConnection(true);
if (null == conn) {
@@ -391,26 +392,13 @@ public final class PostgresEamDbSettings {
createCorrelationTypesTable.append("CONSTRAINT correlation_types_names UNIQUE (display_name, db_table_name)");
createCorrelationTypesTable.append(")");
- // Each "%s" will be replaced with the relevant TYPE_instances table name.
- StringBuilder createArtifactInstancesTableTemplate = new StringBuilder();
- createArtifactInstancesTableTemplate.append("CREATE TABLE IF NOT EXISTS %s (");
- createArtifactInstancesTableTemplate.append("id SERIAL PRIMARY KEY,");
- createArtifactInstancesTableTemplate.append("case_id integer NOT NULL,");
- createArtifactInstancesTableTemplate.append("data_source_id integer NOT NULL,");
- createArtifactInstancesTableTemplate.append("value text NOT NULL,");
- createArtifactInstancesTableTemplate.append("file_path text NOT NULL,");
- createArtifactInstancesTableTemplate.append("known_status integer NOT NULL,");
- createArtifactInstancesTableTemplate.append("comment text,");
- createArtifactInstancesTableTemplate.append("CONSTRAINT %s_multi_unique_ UNIQUE (data_source_id, value, file_path),");
- createArtifactInstancesTableTemplate.append("foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL,");
- createArtifactInstancesTableTemplate.append("foreign key (data_source_id) references data_sources(id) ON UPDATE SET NULL ON DELETE SET NULL");
- createArtifactInstancesTableTemplate.append(")");
+ String createArtifactInstancesTableTemplate = getCreateArtifactInstancesTableTemplate();
- // Each "%s" will be replaced with the relevant TYPE_instances table name.
- String instancesIdx1 = "CREATE INDEX IF NOT EXISTS %s_case_id ON %s (case_id)";
- String instancesIdx2 = "CREATE INDEX IF NOT EXISTS %s_data_source_id ON %s (data_source_id)";
- String instancesIdx3 = "CREATE INDEX IF NOT EXISTS %s_value ON %s (value)";
- String instancesIdx4 = "CREATE INDEX IF NOT EXISTS %s_value_known_status ON %s (value, known_status)";
+ String instancesCaseIdIdx = getAddCaseIdIndexTemplate();
+ String instancesDatasourceIdIdx = getAddDataSourceIdIndexTemplate();
+ String instancesValueIdx = getAddValueIndexTemplate();
+ String instancesKnownStatusIdx = getAddKnownStatusIndexTemplate();
+ String instancesObjectIdIdx = getAddObjectIdIndexTemplate();
StringBuilder createDbInfoTable = new StringBuilder();
createDbInfoTable.append("CREATE TABLE IF NOT EXISTS db_info (");
@@ -447,25 +435,26 @@ public final class PostgresEamDbSettings {
// Create a separate instance and reference table for each correlation type
List DEFAULT_CORRELATION_TYPES = CorrelationAttributeInstance.getDefaultCorrelationTypes();
-
+
String reference_type_dbname;
String instance_type_dbname;
for (CorrelationAttributeInstance.Type type : DEFAULT_CORRELATION_TYPES) {
reference_type_dbname = EamDbUtil.correlationTypeToReferenceTableName(type);
instance_type_dbname = EamDbUtil.correlationTypeToInstanceTableName(type);
-
- stmt.execute(String.format(createArtifactInstancesTableTemplate.toString(), instance_type_dbname, instance_type_dbname));
- stmt.execute(String.format(instancesIdx1, instance_type_dbname, instance_type_dbname));
- stmt.execute(String.format(instancesIdx2, instance_type_dbname, instance_type_dbname));
- stmt.execute(String.format(instancesIdx3, instance_type_dbname, instance_type_dbname));
- stmt.execute(String.format(instancesIdx4, instance_type_dbname, instance_type_dbname));
+
+ stmt.execute(String.format(createArtifactInstancesTableTemplate, instance_type_dbname, instance_type_dbname));
+ stmt.execute(String.format(instancesCaseIdIdx, instance_type_dbname, instance_type_dbname));
+ stmt.execute(String.format(instancesDatasourceIdIdx, instance_type_dbname, instance_type_dbname));
+ stmt.execute(String.format(instancesValueIdx, instance_type_dbname, instance_type_dbname));
+ stmt.execute(String.format(instancesKnownStatusIdx, instance_type_dbname, instance_type_dbname));
+ stmt.execute(String.format(instancesObjectIdIdx, instance_type_dbname, instance_type_dbname));
// FUTURE: allow more than the FILES type
if (type.getId() == CorrelationAttributeInstance.FILES_TYPE_ID) {
stmt.execute(String.format(createReferenceTypesTableTemplate.toString(), reference_type_dbname, reference_type_dbname));
stmt.execute(String.format(referenceTypesIdx1, reference_type_dbname, reference_type_dbname));
stmt.execute(String.format(referenceTypesIdx2, reference_type_dbname, reference_type_dbname));
- }
+ }
}
} catch (SQLException ex) {
@@ -480,6 +469,97 @@ public final class PostgresEamDbSettings {
return true;
}
+ /**
+ * Get the template String for creating a new _instances table in a Postgres
+ * central repository. %s will exist in the template where the name of the
+ * new table will be addedd.
+ *
+ * @return a String which is a template for cretating a new _instances table
+ */
+ static String getCreateArtifactInstancesTableTemplate() {
+ // Each "%s" will be replaced with the relevant TYPE_instances table name.
+ StringBuilder createArtifactInstancesTableTemplate = new StringBuilder();
+ createArtifactInstancesTableTemplate.append("CREATE TABLE IF NOT EXISTS %s (");
+ createArtifactInstancesTableTemplate.append("id SERIAL PRIMARY KEY,");
+ createArtifactInstancesTableTemplate.append("case_id integer NOT NULL,");
+ createArtifactInstancesTableTemplate.append("data_source_id integer NOT NULL,");
+ createArtifactInstancesTableTemplate.append("value text NOT NULL,");
+ createArtifactInstancesTableTemplate.append("file_path text NOT NULL,");
+ createArtifactInstancesTableTemplate.append("known_status integer NOT NULL,");
+ createArtifactInstancesTableTemplate.append("comment text,");
+ createArtifactInstancesTableTemplate.append("file_obj_id integer,");
+ createArtifactInstancesTableTemplate.append("CONSTRAINT %s_multi_unique_ UNIQUE (data_source_id, value, file_path),");
+ createArtifactInstancesTableTemplate.append("foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL,");
+ createArtifactInstancesTableTemplate.append("foreign key (data_source_id) references data_sources(id) ON UPDATE SET NULL ON DELETE SET NULL");
+ createArtifactInstancesTableTemplate.append(")");
+ return createArtifactInstancesTableTemplate.toString();
+ }
+
+ /**
+ * Get the template for creating an index on the case_id column of an
+ * instance table. %s will exist in the template where the name of the new
+ * table will be addedd.
+ *
+ * @return a String which is a template for adding an index to the case_id
+ * column of a _instances table
+ */
+ static String getAddCaseIdIndexTemplate() {
+ // Each "%s" will be replaced with the relevant TYPE_instances table name.
+ return "CREATE INDEX IF NOT EXISTS %s_case_id ON %s (case_id)";
+ }
+
+ /**
+ * Get the template for creating an index on the data_source_id column of an
+ * instance table. %s will exist in the template where the name of the new
+ * table will be addedd.
+ *
+ * @return a String which is a template for adding an index to the
+ * data_source_id column of a _instances table
+ */
+ static String getAddDataSourceIdIndexTemplate() {
+ // Each "%s" will be replaced with the relevant TYPE_instances table name.
+ return "CREATE INDEX IF NOT EXISTS %s_data_source_id ON %s (data_source_id)";
+ }
+
+ /**
+ * Get the template for creating an index on the value column of an instance
+ * table. %s will exist in the template where the name of the new table will
+ * be addedd.
+ *
+ * @return a String which is a template for adding an index to the value
+ * column of a _instances table
+ */
+ static String getAddValueIndexTemplate() {
+ // Each "%s" will be replaced with the relevant TYPE_instances table name.
+ return "CREATE INDEX IF NOT EXISTS %s_value ON %s (value)";
+ }
+
+ /**
+ * Get the template for creating an index on the known_status column of an
+ * instance table. %s will exist in the template where the name of the new
+ * table will be addedd.
+ *
+ * @return a String which is a template for adding an index to the
+ * known_status column of a _instances table
+ */
+ static String getAddKnownStatusIndexTemplate() {
+ // Each "%s" will be replaced with the relevant TYPE_instances table name.
+ return "CREATE INDEX IF NOT EXISTS %s_value_known_status ON %s (value, known_status)";
+ }
+
+ /**
+ * Get the template for creating an index on the file_obj_id column of an
+ * instance table. %s will exist in the template where the name of the new
+ * table will be addedd.
+ *
+ * @return a String which is a template for adding an index to the file_obj_id
+ * column of a _instances table
+ */
+ static String getAddObjectIdIndexTemplate() {
+ // Each "%s" will be replaced with the relevant TYPE_instances table name.
+ return "CREATE INDEX IF NOT EXISTS %s_file_obj_id ON %s (file_obj_id)";
+ }
+
public boolean insertDefaultDatabaseContent() {
Connection conn = getEphemeralConnection(false);
if (null == conn) {
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java
index a75f4648ff..6468801a57 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java
@@ -19,6 +19,7 @@
package org.sleuthkit.autopsy.centralrepository.datamodel;
import java.sql.Connection;
+import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Arrays;
@@ -57,7 +58,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* @return the singleton instance of SqliteEamDb
*
* @throws EamDbException if one or more default correlation type(s) have an
- * invalid db table name.
+ * invalid db table name.
*/
public synchronized static SqliteEamDb getInstance() throws EamDbException {
if (instance == null) {
@@ -70,7 +71,8 @@ final class SqliteEamDb extends AbstractSqlEamDb {
/**
*
* @throws EamDbException if the AbstractSqlEamDb class has one or more
- * default correlation type(s) having an invalid db table name.
+ * default correlation type(s) having an invalid db
+ * table name.
*/
private SqliteEamDb() throws EamDbException {
dbSettings = new SqliteEamDbSettings();
@@ -205,7 +207,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
/**
* Add a new name/value pair in the db_info table.
*
- * @param name Key to set
+ * @param name Key to set
* @param value Value to set
*
* @throws EamDbException
@@ -242,7 +244,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
/**
* Update the value for a name in the name/value db_info table.
*
- * @param name Name to find
+ * @param name Name to find
* @param value Value to assign to name.
*
* @throws EamDbException
@@ -372,8 +374,8 @@ final class SqliteEamDb extends AbstractSqlEamDb {
/**
* Retrieves Data Source details based on data source device ID
*
- * @param correlationCase the current CorrelationCase used for ensuring
- * uniqueness of DataSource
+ * @param correlationCase the current CorrelationCase used for ensuring
+ * uniqueness of DataSource
* @param dataSourceDeviceId the data source device ID number
*
* @return The data source
@@ -387,13 +389,13 @@ final class SqliteEamDb extends AbstractSqlEamDb {
releaseSharedLock();
}
}
-
+
/**
* Retrieves Data Source details based on data source ID
*
- * @param correlationCase the current CorrelationCase used for ensuring
- * uniqueness of DataSource
- * @param dataSourceId the data source ID number
+ * @param correlationCase the current CorrelationCase used for ensuring
+ * uniqueness of DataSource
+ * @param dataSourceId the data source ID number
*
* @return The data source
*/
@@ -461,7 +463,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* Retrieves eamArtifact instances from the database that are associated
* with the aType and filePath
*
- * @param aType EamArtifact.Type to search for
+ * @param aType EamArtifact.Type to search for
* @param filePath File path to search for
*
* @return List of 0 or more EamArtifactInstances
@@ -486,7 +488,8 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* @param value The value to search for
*
* @return Number of artifact instances having ArtifactType and
- * ArtifactValue.
+ * ArtifactValue.
+ *
* @throws EamDbException
*/
@Override
@@ -518,6 +521,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* @param value The value to search for
*
* @return Number of unique tuples
+ *
* @throws EamDbException
*/
@Override
@@ -545,11 +549,11 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* associated with the caseDisplayName and dataSource of the given
* eamArtifact instance.
*
- * @param caseUUID Case ID to search for
+ * @param caseUUID Case ID to search for
* @param dataSourceID Data source ID to search for
*
* @return Number of artifact instances having caseDisplayName and
- * dataSource
+ * dataSource
*/
@Override
public Long getCountArtifactInstancesByCaseDataSource(String caseUUID, String dataSourceID) throws EamDbException {
@@ -563,7 +567,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
/**
* Executes a bulk insert of the eamArtifacts added from the
- addAttributeInstanceBulk() method
+ * addAttributeInstanceBulk() method
*/
@Override
public void commitAttributeInstancesBulk() throws EamDbException {
@@ -596,7 +600,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
*
* @param eamArtifact Artifact containing exactly one (1) ArtifactInstance.
* @param knownStatus The status to change the artifact to. Should never be
- * KNOWN
+ * KNOWN
*/
@Override
public void setAttributeInstanceKnownStatus(CorrelationAttributeInstance eamArtifact, TskData.FileKnown knownStatus) throws EamDbException {
@@ -633,7 +637,9 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* "Bad".
*
* @param aType EamArtifact.Type to search for
+ *
* @return List with 0 or more matching eamArtifact instances.
+ *
* @throws EamDbException
*/
@Override
@@ -672,7 +678,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* @param value Value to search for
*
* @return List of cases containing this artifact with instances marked as
- * bad
+ * bad
*
* @throws EamDbException
*/
@@ -690,6 +696,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* Remove a reference set and all values contained in it.
*
* @param referenceSetID
+ *
* @throws EamDbException
*/
@Override
@@ -708,6 +715,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* @param value
* @param referenceSetID
* @param correlationTypeID
+ *
* @return true if the hash is found in the reference set
*/
@Override
@@ -723,8 +731,9 @@ final class SqliteEamDb extends AbstractSqlEamDb {
/**
* Process the Artifact instance in the EamDb
*
- * @param type EamArtifact.Type to search for
+ * @param type EamArtifact.Type to search for
* @param instanceTableCallback callback to process the instance
+ *
* @throws EamDbException
*/
@Override
@@ -736,12 +745,13 @@ final class SqliteEamDb extends AbstractSqlEamDb {
releaseSharedLock();
}
}
-
+
/**
* Process the Artifact instance in the EamDb
*
- * @param type EamArtifact.Type to search for
+ * @param type EamArtifact.Type to search for
* @param instanceTableCallback callback to process the instance
+ *
* @throws EamDbException
*/
@Override
@@ -752,7 +762,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
} finally {
releaseSharedLock();
}
- }
+ }
/**
* Check whether a reference set with the given name/version is in the
@@ -761,7 +771,9 @@ final class SqliteEamDb extends AbstractSqlEamDb {
*
* @param referenceSetName
* @param version
+ *
* @return true if a matching set is found
+ *
* @throws EamDbException
*/
@Override
@@ -928,7 +940,8 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* Add a new reference instance
*
* @param eamGlobalFileInstance The reference instance to add
- * @param correlationType Correlation Type that this Reference Instance is
+ * @param correlationType Correlation Type that this Reference
+ * Instance is
*
* @throws EamDbException
*/
@@ -960,7 +973,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
/**
* Get all reference entries having a given correlation type and value
*
- * @param aType Type to use for matching
+ * @param aType Type to use for matching
* @param aValue Value to use for matching
*
* @return List of all global file instances with a type and value
@@ -1001,7 +1014,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* artifacts.
*
* @return List of EamArtifact.Type's. If none are defined in the database,
- * the default list will be returned.
+ * the default list will be returned.
*
* @throws EamDbException
*/
@@ -1020,7 +1033,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* artifacts.
*
* @return List of enabled EamArtifact.Type's. If none are defined in the
- * database, the default list will be returned.
+ * database, the default list will be returned.
*
* @throws EamDbException
*/
@@ -1039,7 +1052,7 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* correlate artifacts.
*
* @return List of supported EamArtifact.Type's. If none are defined in the
- * database, the default list will be returned.
+ * database, the default list will be returned.
*
* @throws EamDbException
*/
@@ -1111,8 +1124,9 @@ final class SqliteEamDb extends AbstractSqlEamDb {
* (meaning the database is in use).
*
* @return the lock, or null if locking is not supported
+ *
* @throws EamDbException if the coordination service is running but we fail
- * to get the lock
+ * to get the lock
*/
@Override
public CoordinationService.Lock getExclusiveMultiUserDbLock() throws EamDbException {
@@ -1156,4 +1170,26 @@ final class SqliteEamDb extends AbstractSqlEamDb {
rwLock.readLock().unlock();
}
+ @Override
+ boolean doesColumnExist(Connection conn, String tableName, String columnName) throws SQLException {
+ final String tableInfoQueryTemplate = "PRAGMA table_info(%s)"; //NON-NLS
+ ResultSet resultSet = null;
+ Statement statement = null;
+ boolean columnExists = false;
+ try {
+ statement = conn.createStatement();
+ resultSet = statement.executeQuery(String.format(tableInfoQueryTemplate, tableName));
+ while (resultSet.next()) {
+ // the second value ( 2 ) is the column name
+ if (resultSet.getString(2).equals(columnName)) {
+ columnExists = true;
+ break;
+ }
+ }
+ } finally {
+ EamDbUtil.closeResultSet(resultSet);
+ EamDbUtil.closeStatement(statement);
+ }
+ return columnExists;
+ }
}
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java
index 4894a570e6..8b034149fc 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java
@@ -35,8 +35,9 @@ import org.sleuthkit.autopsy.coreutils.PlatformUtil;
/**
* Settings for the sqlite implementation of the Central Repository database
- *
- * NOTE: This is public scope because the options panel calls it directly to set/get
+ *
+ * NOTE: This is public scope because the options panel calls it directly to
+ * set/get
*/
public final class SqliteEamDbSettings {
@@ -95,7 +96,7 @@ public final class SqliteEamDbSettings {
ModuleSettings.setConfigSetting("CentralRepository", "db.sqlite.dbDirectory", getDbDirectory()); // NON-NLS
ModuleSettings.setConfigSetting("CentralRepository", "db.sqlite.bulkThreshold", Integer.toString(getBulkThreshold())); // NON-NLS
}
-
+
/**
* Verify that the db file exists.
*
@@ -103,11 +104,11 @@ public final class SqliteEamDbSettings {
*/
public boolean dbFileExists() {
File dbFile = new File(getFileNameWithPath());
- if(! dbFile.exists()){
+ if (!dbFile.exists()) {
return false;
}
// It's unlikely, but make sure the file isn't actually a directory
- return ( ! dbFile.isDirectory());
+ return (!dbFile.isDirectory());
}
/**
@@ -148,10 +149,11 @@ public final class SqliteEamDbSettings {
return true;
}
-
+
/**
* Delete the database
- * @return
+ *
+ * @return
*/
public boolean deleteDatabase() {
File dbFile = new File(this.getFileNameWithPath());
@@ -333,27 +335,14 @@ public final class SqliteEamDbSettings {
createCorrelationTypesTable.append("CONSTRAINT correlation_types_names UNIQUE (display_name, db_table_name)");
createCorrelationTypesTable.append(")");
- // Each "%s" will be replaced with the relevant TYPE_instances table name.
- StringBuilder createArtifactInstancesTableTemplate = new StringBuilder();
- createArtifactInstancesTableTemplate.append("CREATE TABLE IF NOT EXISTS %s (");
- createArtifactInstancesTableTemplate.append("id integer primary key autoincrement NOT NULL,");
- createArtifactInstancesTableTemplate.append("case_id integer NOT NULL,");
- createArtifactInstancesTableTemplate.append("data_source_id integer NOT NULL,");
- createArtifactInstancesTableTemplate.append("value text NOT NULL,");
- createArtifactInstancesTableTemplate.append("file_path text NOT NULL,");
- createArtifactInstancesTableTemplate.append("known_status integer NOT NULL,");
- createArtifactInstancesTableTemplate.append("comment text,");
- createArtifactInstancesTableTemplate.append("CONSTRAINT %s_multi_unique UNIQUE(data_source_id, value, file_path) ON CONFLICT IGNORE,");
- createArtifactInstancesTableTemplate.append("foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL,");
- createArtifactInstancesTableTemplate.append("foreign key (data_source_id) references data_sources(id) ON UPDATE SET NULL ON DELETE SET NULL");
- createArtifactInstancesTableTemplate.append(")");
-
- // Each "%s" will be replaced with the relevant TYPE_instances table name.
- String instancesIdx1 = "CREATE INDEX IF NOT EXISTS %s_case_id ON %s (case_id)";
- String instancesIdx2 = "CREATE INDEX IF NOT EXISTS %s_data_source_id ON %s (data_source_id)";
- String instancesIdx3 = "CREATE INDEX IF NOT EXISTS %s_value ON %s (value)";
- String instancesIdx4 = "CREATE INDEX IF NOT EXISTS %s_value_known_status ON %s (value, known_status)";
+ String createArtifactInstancesTableTemplate = getCreateArtifactInstancesTableTemplate();
+ String instancesCaseIdIdx = getAddCaseIdIndexTemplate();
+ String instancesDatasourceIdIdx = getAddDataSourceIdIndexTemplate();
+ String instancesValueIdx = getAddValueIndexTemplate();
+ String instancesKnownStatusIdx = getAddKnownStatusIndexTemplate();
+ String instancesObjectIdIdx = getAddObjectIdIndexTemplate();
+
StringBuilder createDbInfoTable = new StringBuilder();
createDbInfoTable.append("CREATE TABLE IF NOT EXISTS db_info (");
createDbInfoTable.append("id integer primary key NOT NULL,");
@@ -402,11 +391,12 @@ public final class SqliteEamDbSettings {
reference_type_dbname = EamDbUtil.correlationTypeToReferenceTableName(type);
instance_type_dbname = EamDbUtil.correlationTypeToInstanceTableName(type);
- stmt.execute(String.format(createArtifactInstancesTableTemplate.toString(), instance_type_dbname, instance_type_dbname));
- stmt.execute(String.format(instancesIdx1, instance_type_dbname, instance_type_dbname));
- stmt.execute(String.format(instancesIdx2, instance_type_dbname, instance_type_dbname));
- stmt.execute(String.format(instancesIdx3, instance_type_dbname, instance_type_dbname));
- stmt.execute(String.format(instancesIdx4, instance_type_dbname, instance_type_dbname));
+ stmt.execute(String.format(createArtifactInstancesTableTemplate, instance_type_dbname, instance_type_dbname));
+ stmt.execute(String.format(instancesCaseIdIdx, instance_type_dbname, instance_type_dbname));
+ stmt.execute(String.format(instancesDatasourceIdIdx, instance_type_dbname, instance_type_dbname));
+ stmt.execute(String.format(instancesValueIdx, instance_type_dbname, instance_type_dbname));
+ stmt.execute(String.format(instancesKnownStatusIdx, instance_type_dbname, instance_type_dbname));
+ stmt.execute(String.format(instancesObjectIdIdx, instance_type_dbname, instance_type_dbname));
// FUTURE: allow more than the FILES type
if (type.getId() == CorrelationAttributeInstance.FILES_TYPE_ID) {
@@ -426,6 +416,97 @@ public final class SqliteEamDbSettings {
}
return true;
}
+
+ /**
+ * Get the template String for creating a new _instances table in a Sqlite
+ * central repository. %s will exist in the template where the name of the
+ * new table will be addedd.
+ *
+ * @return a String which is a template for cretating a new _instances table
+ */
+ static String getCreateArtifactInstancesTableTemplate() {
+ // Each "%s" will be replaced with the relevant TYPE_instances table name.
+ StringBuilder createArtifactInstancesTableTemplate = new StringBuilder();
+ createArtifactInstancesTableTemplate.append("CREATE TABLE IF NOT EXISTS %s (");
+ createArtifactInstancesTableTemplate.append("id integer primary key autoincrement NOT NULL,");
+ createArtifactInstancesTableTemplate.append("case_id integer NOT NULL,");
+ createArtifactInstancesTableTemplate.append("data_source_id integer NOT NULL,");
+ createArtifactInstancesTableTemplate.append("value text NOT NULL,");
+ createArtifactInstancesTableTemplate.append("file_path text NOT NULL,");
+ createArtifactInstancesTableTemplate.append("known_status integer NOT NULL,");
+ createArtifactInstancesTableTemplate.append("comment text,");
+ createArtifactInstancesTableTemplate.append("file_obj_id integer,");
+ createArtifactInstancesTableTemplate.append("CONSTRAINT %s_multi_unique UNIQUE(data_source_id, value, file_path) ON CONFLICT IGNORE,");
+ createArtifactInstancesTableTemplate.append("foreign key (case_id) references cases(id) ON UPDATE SET NULL ON DELETE SET NULL,");
+ createArtifactInstancesTableTemplate.append("foreign key (data_source_id) references data_sources(id) ON UPDATE SET NULL ON DELETE SET NULL");
+ createArtifactInstancesTableTemplate.append(")");
+ return createArtifactInstancesTableTemplate.toString();
+ }
+
+ /**
+ * Get the template for creating an index on the case_id column of an
+ * instance table. %s will exist in the template where the name of the new
+ * table will be addedd.
+ *
+ * @return a String which is a template for adding an index to the case_id
+ * column of a _instances table
+ */
+ static String getAddCaseIdIndexTemplate() {
+ // Each "%s" will be replaced with the relevant TYPE_instances table name.
+ return "CREATE INDEX IF NOT EXISTS %s_case_id ON %s (case_id)";
+ }
+
+ /**
+ * Get the template for creating an index on the data_source_id column of an
+ * instance table. %s will exist in the template where the name of the new
+ * table will be addedd.
+ *
+ * @return a String which is a template for adding an index to the
+ * data_source_id column of a _instances table
+ */
+ static String getAddDataSourceIdIndexTemplate() {
+ // Each "%s" will be replaced with the relevant TYPE_instances table name.
+ return "CREATE INDEX IF NOT EXISTS %s_data_source_id ON %s (data_source_id)";
+ }
+
+ /**
+ * Get the template for creating an index on the value column of an instance
+ * table. %s will exist in the template where the name of the new table will
+ * be addedd.
+ *
+ * @return a String which is a template for adding an index to the value
+ * column of a _instances table
+ */
+ static String getAddValueIndexTemplate() {
+ // Each "%s" will be replaced with the relevant TYPE_instances table name.
+ return "CREATE INDEX IF NOT EXISTS %s_value ON %s (value)";
+ }
+
+ /**
+ * Get the template for creating an index on the known_status column of an
+ * instance table. %s will exist in the template where the name of the new
+ * table will be addedd.
+ *
+ * @return a String which is a template for adding an index to the
+ * known_status column of a _instances table
+ */
+ static String getAddKnownStatusIndexTemplate() {
+ // Each "%s" will be replaced with the relevant TYPE_instances table name.
+ return "CREATE INDEX IF NOT EXISTS %s_value_known_status ON %s (value, known_status)";
+ }
+
+ /**
+ * Get the template for creating an index on the file_obj_id column of an
+ * instance table. %s will exist in the template where the name of the new
+ * table will be addedd.
+ *
+ * @return a String which is a template for adding an index to the file_obj_id
+ * column of a _instances table
+ */
+ static String getAddObjectIdIndexTemplate() {
+ // Each "%s" will be replaced with the relevant TYPE_instances table name.
+ return "CREATE INDEX IF NOT EXISTS %s_file_obj_id ON %s (file_obj_id)";
+ }
public boolean insertDefaultDatabaseContent() {
Connection conn = getEphemeralConnection();
@@ -490,8 +571,6 @@ public final class SqliteEamDbSettings {
}
}
-
-
/**
* @return the dbDirectory
*/
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java
index cdfc282b7e..34436380e2 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java
@@ -183,7 +183,10 @@ public class IngestEventsListener {
@Override
public void propertyChange(PropertyChangeEvent evt) {
- if (getCeModuleInstanceCount() > 0) {
+ //if ingest is running we want there to check if there is a Correlation Engine module running
+ //sometimes artifacts are generated by DSPs or other sources while ingest is not running
+ //in these cases we still want to create correlation attributes for those artifacts when appropriate
+ if (!IngestManager.getInstance().isIngestRunning() || getCeModuleInstanceCount() > 0) {
EamDb dbManager;
try {
dbManager = EamDb.getInstance();
@@ -193,7 +196,9 @@ public class IngestEventsListener {
}
switch (IngestManager.IngestModuleEvent.valueOf(evt.getPropertyName())) {
case DATA_ADDED: {
- jobProcessingExecutor.submit(new DataAddedTask(dbManager, evt, isFlagNotableItems()));
+ //if ingest isn't running create the interesting items otherwise use the ingest module setting to determine if we create interesting items
+ boolean flagNotable = !IngestManager.getInstance().isIngestRunning() || isFlagNotableItems();
+ jobProcessingExecutor.submit(new DataAddedTask(dbManager, evt, flagNotable));
break;
}
}
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java
index 05fb3e4c8c..e7894c7916 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java
@@ -70,7 +70,6 @@ final class IngestModule implements FileIngestModule {
private CorrelationDataSource eamDataSource;
private Blackboard blackboard;
private CorrelationAttributeInstance.Type filesType;
-
private final boolean flagTaggedNotableItems;
/**
@@ -152,14 +151,14 @@ final class IngestModule implements FileIngestModule {
// insert this file into the central repository
try {
CorrelationAttributeInstance cefi = new CorrelationAttributeInstance(
+ filesType,
md5,
- filesType,
eamCase,
eamDataSource,
abstractFile.getParentPath() + abstractFile.getName(),
null,
TskData.FileKnown.UNKNOWN // NOTE: Known status in the CR is based on tagging, not hashes like the Case Database.
- );
+, abstractFile.getId());
dbManager.addAttributeInstanceBulk(cefi);
} catch (EamDbException ex) {
logger.log(Level.SEVERE, "Error adding artifact to bulk artifacts.", ex); // NON-NLS
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties
index b45b6f7579..aae9fa321d 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties
@@ -34,7 +34,7 @@ AddNewOrganizationDialog.bnOK.text=OK
AddNewOrganizationDialog.tfName.tooltip=POC Name
ManageTagsDialog.okButton.text=OK
ManageTagsDialog.cancelButton.text=Cancel
-ManageArtifactTypesDialog.taInstructionsMsg.text=Enable one or more correlation properties to use for correlation during ingest. Note, these properties are global and impact all users of the central repository.
+ManageArtifactTypesDialog.taInstructionsMsg.text=Enable one or more correlation properties to use for correlation during ingest. Note, these properties are global and impact all users of the Central Repository.
EamSqliteSettingsDialog.bnOk.text=OK
EamPostgresSettingsDialog.bnSave.text=Save
EamDbSettingsDialog.bnDatabasePathFileOpen.text=Browse...
@@ -58,15 +58,14 @@ ManageCorrelationPropertiesDialog.okButton.text=OK
GlobalSettingsPanel.bnManageProperties.text=Manage Correlation Properties
EamDbSettingsDialog.lbDatabaseDesc.text=Database File:
EamDbSettingsDialog.lbFullDbPath.text=
-GlobalSettingsPanel.cbUseCentralRepo.text=Use a central repository
-GlobalSettingsPanel.correlationPropertiesTextArea.text=Choose which file and result properties to store in the central repository for later correlation.\n
-GlobalSettingsPanel.organizationTextArea.text=Organization information can be tracked in the central repository.
+GlobalSettingsPanel.cbUseCentralRepo.text=Use a Central Repository
+GlobalSettingsPanel.organizationTextArea.text=Organization information can be tracked in the Central Repository.
GlobalSettingsPanel.manageOrganizationButton.text=Manage Organizations
-GlobalSettingsPanel.lbCentralRepository.text=A central repository allows you to correlate files and results between cases.
+GlobalSettingsPanel.lbCentralRepository.text=A Central Repository allows you to correlate files and results between cases.
GlobalSettingsPanel.pnCorrelationProperties.border.title=Correlation Properties
GlobalSettingsPanel.organizationPanel.border.title=Organizations
GlobalSettingsPanel.casesPanel.border.title=Case Details
-GlobalSettingsPanel.showCasesButton.text=Show Cases
+GlobalSettingsPanel.showCasesButton.text=Manage Cases
ShowCasesDialog.closeButton.AccessibleContext.accessibleName=Close
ShowCasesDialog.closeButton.actionCommand=Close
ShowCasesDialog.closeButton.text=Close
@@ -74,5 +73,15 @@ ShowCasesDialog.caseDetailsTable.toolTipText=Click column name to sort. Right-cl
ShowCasesDialog.title=Case Details
GlobalSettingsPanel.Case\ Details.AccessibleContext.accessibleName=Cases Details
ShowCasesDialog.caseDetailsTable.AccessibleContext.accessibleDescription=Click column name to sort.
-GlobalSettingsPanel.casesTextArea.text=Display table that lists central repository case details.
-GlobalSettingsPanel.ingestRunningWarningLabel.text=Cannot make changes to central repository settings when ingest is running!
+GlobalSettingsPanel.casesTextArea.text=Display table that lists Central Repository case details.
+GlobalSettingsPanel.ingestRunningWarningLabel.text=Cannot make changes to Central Repository settings when ingest is running!
+GlobalSettingsPanel.correlationPropertiesTextArea.text=Choose which file and result properties to store in the Central Repository for later correlation.\n
+ManageCasesDialog.examinerPhoneLabel.text=Examiner Phone:
+ManageCasesDialog.examinerNameLabel.text=Examiner Name:
+ManageCasesDialog.examinerEmailLabel.text=Examiner Email:
+ManageCasesDialog.caseNumberLabel.text=Case Number:
+ManageCasesDialog.orgLabel.text=Organization:
+ManageCasesDialog.closeButton.text=Close
+ManageCasesDialog.notesLabel.text=Notes:
+ManageCasesDialog.dataSourcesLabel.text=Data Sources:
+ManageCasesDialog.caseInfoLabel.text=Case Info:
\ No newline at end of file
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/CaseDataSourcesWrapper.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/CaseDataSourcesWrapper.java
new file mode 100644
index 0000000000..34695fc354
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/CaseDataSourcesWrapper.java
@@ -0,0 +1,131 @@
+/*
+ * Central Repository
+ *
+ * Copyright 2018 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.centralrepository.optionspanel;
+
+import java.util.Collections;
+import java.util.List;
+import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
+import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource;
+import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization;
+
+/**
+ * An object to contain both a CorrelationCase and the list of
+ * CorrelationDataSources which are associated with that case.
+ */
+class CaseDataSourcesWrapper {
+
+ private final CorrelationCase eamCase;
+ private final List dataSources;
+
+ /**
+ * Create a new CaseDataSourcesWrapper object.
+ *
+ * @param correlationCase - the CorrelationCase which is being represented
+ * @param dataSourceList - the list of CorrelationDataSource objects which
+ * are associated with the CorrelationCase
+ */
+ CaseDataSourcesWrapper(CorrelationCase correlationCase, List dataSourceList) {
+ eamCase = correlationCase;
+ dataSources = dataSourceList;
+ }
+
+ /**
+ * Get the display name of the CorrelationCase.
+ *
+ * @return the display name of the CorrelationCase.
+ */
+ String getDisplayName() {
+ return eamCase.getDisplayName();
+ }
+
+ /**
+ * Get the list of CorrelationDataSources associated with the
+ * CorrelationCase.
+ *
+ * @return the list of CorrelationDataSources associated with the
+ * CorrelationCase.
+ */
+ List getDataSources() {
+ return Collections.unmodifiableList(dataSources);
+ }
+
+ /**
+ * Get the creation date of the CorrelationCase.
+ *
+ * @return the creation date of the CorrelationCase.
+ */
+ String getCreationDate() {
+ return eamCase.getCreationDate();
+ }
+
+ /**
+ * Get the organization name of the CorrelationCase.
+ *
+ * @return the organization name of the CorrelationCase.
+ */
+ String getOrganizationName() {
+ EamOrganization org = eamCase.getOrg();
+ return org == null ? "" : org.getName();
+ }
+
+ /**
+ * Get the case number of the CorrelationCase.
+ *
+ * @return the case number of the CorrelationCase.
+ */
+ String getCaseNumber() {
+ return eamCase.getCaseNumber();
+ }
+
+ /**
+ * Get the examiner name of the CorrelationCase.
+ *
+ * @return the examiner name of the CorrelationCase.
+ */
+ String getExaminerName() {
+ return eamCase.getExaminerName();
+ }
+
+ /**
+ * Get the examiner email of the CorrelationCase.
+ *
+ * @return the examiner email of the CorrelationCase.
+ */
+ String getExaminerEmail() {
+ return eamCase.getExaminerEmail();
+ }
+
+ /**
+ * Get the notes of the CorrelationCase.
+ *
+ * @return the notes of the CorrelationCase.
+ */
+ String getNotes() {
+ return eamCase.getNotes();
+ }
+
+ /**
+ * Get the examiner phone number of the CorrelationCase.
+ *
+ * @return the examiner phone number of the CorrelationCase.
+ */
+ String getExaminerPhone() {
+ return eamCase.getExaminerPhone();
+ }
+}
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/CasesTableModel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/CasesTableModel.java
new file mode 100644
index 0000000000..5421caef70
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/CasesTableModel.java
@@ -0,0 +1,156 @@
+/*
+ * Central Repository
+ *
+ * Copyright 2018 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.centralrepository.optionspanel;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.swing.table.AbstractTableModel;
+import org.openide.util.NbBundle.Messages;
+import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
+import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource;
+
+/**
+ * Model for cells to display correlation case information
+ */
+class CasesTableModel extends AbstractTableModel {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * list of Eam Cases from central repository.
+ */
+ private final List eamCases;
+
+ /**
+ * Model for cells to display correlation case information
+ */
+ CasesTableModel() {
+ eamCases = new ArrayList<>();
+ }
+
+ @Override
+ public int getColumnCount() {
+ return CaseTableColumns.values().length;
+ }
+
+ @Override
+ public int getRowCount() {
+ return eamCases.size();
+ }
+
+ @Override
+ public String getColumnName(int colIdx) {
+ return CaseTableColumns.values()[colIdx].columnName();
+ }
+
+ @Override
+ public Object getValueAt(int rowIdx, int colIdx) {
+ if (eamCases.isEmpty()) {
+ return Bundle.CasesTableModel_noData();
+ }
+
+ return mapValueById(rowIdx, CaseTableColumns.values()[colIdx]);
+ }
+
+ /**
+ * Map a rowIdx and colId to the value in that cell.
+ *
+ * @param rowIdx Index of row to search
+ * @param colId ID of column to search
+ *
+ * @return value in the cell
+ */
+ @Messages({"CasesTableModel.noData=No Cases"})
+ private Object mapValueById(int rowIdx, CaseTableColumns colId) {
+ CaseDataSourcesWrapper eamCase = eamCases.get(rowIdx);
+ String value = Bundle.CasesTableModel_noData();
+
+ switch (colId) {
+ case CASE_NAME:
+ value = eamCase.getDisplayName();
+ break;
+ case CREATION_DATE:
+ value = eamCase.getCreationDate();
+ break;
+ default:
+ break;
+ }
+ return value;
+ }
+
+ @Override
+ public Class getColumnClass(int colIdx) {
+ return String.class;
+ }
+
+ /**
+ * Add one local central repository case to the table.
+ *
+ * @param eamCase central repository case to add to the table
+ */
+ void addEamCase(CorrelationCase eamCase, List dataSourceList) {
+ eamCases.add(new CaseDataSourcesWrapper(eamCase, dataSourceList));
+ fireTableDataChanged();
+ }
+
+ /**
+ * Get the CaseDataSourcesWrapper for the specified index in the table.
+ *
+ * @param listIndex the idex of the object to get
+ *
+ * @return A caseDataSourcesWrapper containing the CorrelationCase and the
+ * CorrelationDataSources associated with it for the specified
+ * index.
+ */
+ CaseDataSourcesWrapper getEamCase(int listIndex) {
+ return eamCases.get(listIndex);
+ }
+
+ /**
+ * Enum which lists columns of interest from CorrelationCase.
+ */
+ @Messages({"CasesTableModel.case=Case Name",
+ "CasesTableModel.creationDate=Creation Date"})
+ private enum CaseTableColumns {
+ // Ordering here determines displayed column order in Content Viewer.
+ // If order is changed, update the CellRenderer to ensure correct row coloring.
+ CASE_NAME(Bundle.CasesTableModel_case()),
+ CREATION_DATE(Bundle.CasesTableModel_creationDate());
+
+ private final String columnName;
+
+ /**
+ * Make a DataSourceTableColumns enum item.
+ *
+ * @param columnName the name of the column.s
+ */
+ CaseTableColumns(String columnName) {
+ this.columnName = columnName;
+ }
+
+ /**
+ * The name displayed in the column header.
+ *
+ * @return the name of the column.
+ */
+ String columnName() {
+ return columnName;
+ }
+ }
+}
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/DataSourcesTableModel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/DataSourcesTableModel.java
new file mode 100644
index 0000000000..53d917fadf
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/DataSourcesTableModel.java
@@ -0,0 +1,152 @@
+/*
+ * Central Repository
+ *
+ * Copyright 2018 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.centralrepository.optionspanel;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.swing.table.AbstractTableModel;
+import org.openide.util.NbBundle.Messages;
+import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource;
+
+/**
+ * Model for cells to display correlation data source information
+ */
+class DataSourcesTableModel extends AbstractTableModel {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * A list of correlation data sources from central repository.
+ */
+ private final List dataSources;
+
+ /**
+ * Create a new DataSourcesTableModel, with an initially empty list of data
+ * sources.
+ */
+ DataSourcesTableModel() {
+ dataSources = new ArrayList<>();
+ }
+
+ @Override
+ public int getColumnCount() {
+ return DataSourcesTableColumns.values().length;
+ }
+
+ @Override
+ public int getRowCount() {
+ return dataSources.size();
+ }
+
+ @Override
+ public String getColumnName(int colIdx) {
+ return DataSourcesTableColumns.values()[colIdx].columnName();
+ }
+
+ @Override
+ public Object getValueAt(int rowIdx, int colIdx) {
+ if (dataSources.isEmpty()) {
+ return Bundle.DataSourcesTableModel_noData();
+ }
+
+ return mapValueById(rowIdx, DataSourcesTableColumns.values()[colIdx]);
+ }
+
+ /**
+ * Map a rowIdx and colId to the value in that cell.
+ *
+ * @param rowIdx Index of row to search
+ * @param colId ID of column to search
+ *
+ * @return value in the cell
+ */
+ @Messages({"DataSourcesTableModel.noData=No Data Sources"})
+ private Object mapValueById(int rowIdx, DataSourcesTableColumns colId) {
+ CorrelationDataSource dataSource = dataSources.get(rowIdx);
+ String value = Bundle.DataSourcesTableModel_noData();
+
+ switch (colId) {
+ case DATA_SOURCE:
+ value = dataSource.getName();
+ break;
+ case DEVICE_ID:
+ value = dataSource.getDeviceID();
+ break;
+ default:
+ break;
+ }
+ return value;
+ }
+
+ @Override
+ public Class getColumnClass(int colIdx) {
+ return String.class;
+ }
+
+ /**
+ * Add a list of datasources to the table.
+ *
+ * @param dataSourceList the list of datasources to add to the table
+ */
+ void addDataSources(List dataSourceList) {
+ dataSources.addAll(dataSourceList);
+ fireTableDataChanged();
+ }
+
+ /**
+ * Clear the data sources currently included in the model.
+ */
+ void clearTable() {
+ dataSources.clear();
+ fireTableDataChanged();
+ }
+
+ @Messages({"DataSourcesTableModel.dataSource=Data Source Name",
+ "DataSourcesTableModel.deviceId=Device ID"})
+ /**
+ * Enum which lists columns of interest from CorrelationDataSource.
+ */
+ private enum DataSourcesTableColumns {
+ // Ordering here determines displayed column order in Content Viewer.
+ // If order is changed, update the CellRenderer to ensure correct row coloring.
+ DATA_SOURCE(Bundle.DataSourcesTableModel_dataSource()),
+ DEVICE_ID(Bundle.DataSourcesTableModel_deviceId());
+
+ private final String columnName;
+
+ /**
+ * Make a CasesTableColumns enum item.
+ *
+ * @param columnName the name of the column.
+ */
+ DataSourcesTableColumns(String columnName) {
+ this.columnName = columnName;
+ }
+
+ /**
+ * The name displayed in the column header.
+ *
+ * @return the name of the column.
+ */
+ String columnName() {
+ return columnName;
+ }
+ }
+
+}
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java
index c504f666e4..826e66ecbc 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/EamDbSettingsDialog.java
@@ -102,7 +102,7 @@ public class EamDbSettingsDialog extends JDialog {
@Override
public String getDescription() {
- return "Directories and central repository databases";
+ return "Directories and Central Repository databases";
}
});
cbDatabaseType.setSelectedItem(selectedPlatform);
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form
index c3a8f678d6..0a8c7dcc64 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form
@@ -57,7 +57,7 @@
-
+
@@ -67,7 +67,7 @@
-
+
@@ -89,13 +89,13 @@
-
+
-
+
-
+
-
+
@@ -242,14 +242,14 @@
-
-
+
+
-
-
+
+
@@ -258,8 +258,7 @@
-
-
+
@@ -301,7 +300,7 @@
-
+
@@ -334,7 +333,7 @@
-
+
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java
index b8c42eb66d..a4d6ef5cc0 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java
@@ -222,7 +222,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
correlationPropertiesTextArea.setColumns(20);
correlationPropertiesTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N
correlationPropertiesTextArea.setLineWrap(true);
- correlationPropertiesTextArea.setRows(2);
+ correlationPropertiesTextArea.setRows(1);
correlationPropertiesTextArea.setText(org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.correlationPropertiesTextArea.text")); // NOI18N
correlationPropertiesTextArea.setToolTipText("");
correlationPropertiesTextArea.setWrapStyleWord(true);
@@ -236,17 +236,16 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
.addGroup(pnCorrelationPropertiesLayout.createSequentialGroup()
.addContainerGap()
.addGroup(pnCorrelationPropertiesLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(correlationPropertiesScrollPane)
.addGroup(pnCorrelationPropertiesLayout.createSequentialGroup()
.addComponent(bnManageTypes)
- .addGap(0, 0, Short.MAX_VALUE)))
+ .addGap(0, 0, Short.MAX_VALUE))
+ .addComponent(correlationPropertiesScrollPane))
.addContainerGap())
);
pnCorrelationPropertiesLayout.setVerticalGroup(
pnCorrelationPropertiesLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, pnCorrelationPropertiesLayout.createSequentialGroup()
- .addGap(7, 7, 7)
- .addComponent(correlationPropertiesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(correlationPropertiesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 32, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(bnManageTypes)
.addGap(8, 8, 8))
@@ -281,7 +280,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
.addGroup(organizationPanelLayout.createSequentialGroup()
.addContainerGap()
.addGroup(organizationPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(organizationScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 992, Short.MAX_VALUE)
+ .addComponent(organizationScrollPane)
.addGroup(organizationPanelLayout.createSequentialGroup()
.addComponent(manageOrganizationButton)
.addGap(0, 0, Short.MAX_VALUE)))
@@ -356,7 +355,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(lbCentralRepository, javax.swing.GroupLayout.DEFAULT_SIZE, 1022, Short.MAX_VALUE)
+ .addComponent(lbCentralRepository, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addGroup(jPanel1Layout.createSequentialGroup()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
@@ -366,7 +365,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
.addGroup(jPanel1Layout.createSequentialGroup()
.addComponent(cbUseCentralRepo, javax.swing.GroupLayout.PREFERRED_SIZE, 162, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
- .addComponent(ingestRunningWarningLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ .addComponent(ingestRunningWarningLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 844, Short.MAX_VALUE))
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, 974, javax.swing.GroupLayout.PREFERRED_SIZE)))
@@ -382,13 +381,13 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
.addComponent(ingestRunningWarningLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addGap(0, 0, 0)
.addComponent(pnCorrelationProperties, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addGap(0, 0, 0)
.addComponent(organizationPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addGap(0, 0, 0)
.addComponent(casesPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addGap(0, 0, 0)
.addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap())
);
@@ -441,7 +440,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i
private void showCasesButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showCasesButtonActionPerformed
store();
- ShowCasesDialog showCasesDialog = new ShowCasesDialog();
+ ManageCasesDialog.displayManageCasesDialog();
}//GEN-LAST:event_showCasesButtonActionPerformed
@Override
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageCasesDialog.form b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageCasesDialog.form
new file mode 100644
index 0000000000..9d1b82d31a
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageCasesDialog.form
@@ -0,0 +1,358 @@
+
+
+
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageCasesDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageCasesDialog.java
new file mode 100644
index 0000000000..f782af67c5
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageCasesDialog.java
@@ -0,0 +1,353 @@
+/*
+ * Central Repository
+ *
+ * Copyright 2018 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.centralrepository.optionspanel;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import org.openide.windows.WindowManager;
+import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
+import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationDataSource;
+import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
+import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
+import org.sleuthkit.autopsy.coreutils.Logger;
+import org.openide.util.NbBundle.Messages;
+
+/**
+ * A dialog which displays cases existing in the central repository and the
+ * central repo information associated with them.
+ *
+ */
+final class ManageCasesDialog extends javax.swing.JDialog {
+
+ private static final long serialVersionUID = 1L;
+ private final CasesTableModel casesTableModel = new CasesTableModel();
+ private final DataSourcesTableModel dataSourcesTableModel = new DataSourcesTableModel();
+ private final static Logger logger = Logger.getLogger(ManageCasesDialog.class.getName());
+
+ /**
+ * Creates new form ManageCasesDialog
+ */
+ @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
+ @Messages({"ManageCasesDialog.title.text=Manage Cases"})
+ private ManageCasesDialog() {
+ super(WindowManager.getDefault().getMainWindow(), Bundle.ManageCasesDialog_title_text(),
+ true);
+ initComponents();
+ try {
+ EamDb dbManager = EamDb.getInstance();
+ Map> dataSourcesByCaseId = new HashMap<>();
+ for (CorrelationDataSource dataSource : dbManager.getDataSources()) {
+ int caseID = dataSource.getCaseID();
+ List dataSourceNames = dataSourcesByCaseId.getOrDefault(caseID, new ArrayList<>());
+ dataSourceNames.add(dataSource);
+ dataSourcesByCaseId.put(caseID, dataSourceNames);
+ }
+ for (CorrelationCase eamCase : dbManager.getCases()) {
+ casesTableModel.addEamCase(eamCase, dataSourcesByCaseId.getOrDefault(eamCase.getID(), new ArrayList<>()));
+ }
+ } catch (EamDbException ex) {
+ logger.log(Level.SEVERE, "Error getting list of cases from database.", ex); // NON-NLS
+ }
+
+ casesTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
+ @Override
+ public void valueChanged(ListSelectionEvent e) {
+ if (!e.getValueIsAdjusting()) {
+ updateSelection();
+ }
+ }
+ });
+ //sort on first column by default
+ casesTable.getRowSorter().toggleSortOrder(0);
+ }
+
+ /**
+ * Create and display the Manage Cases dialog for the currently enabled
+ * central repository.
+ */
+ static void displayManageCasesDialog() {
+ ManageCasesDialog caseInfoDialog = new ManageCasesDialog();
+ caseInfoDialog.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
+ caseInfoDialog.setVisible(true);
+ }
+
+ /**
+ * 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
+ * regenerated by the Form Editor.
+ */
+ @SuppressWarnings("unchecked")
+ // //GEN-BEGIN:initComponents
+ private void initComponents() {
+
+ casesSplitPane = new javax.swing.JSplitPane();
+ caseInfoPanel = new javax.swing.JPanel();
+ dataSourcesScrollPane = new javax.swing.JScrollPane();
+ dataSourcesTable = new javax.swing.JTable();
+ notesScrollPane = new javax.swing.JScrollPane();
+ notesTextArea = new javax.swing.JTextArea();
+ caseInfoLabel = new javax.swing.JLabel();
+ dataSourcesLabel = new javax.swing.JLabel();
+ notesLabel = new javax.swing.JLabel();
+ orgLabel = new javax.swing.JLabel();
+ caseNumberLabel = new javax.swing.JLabel();
+ examinerEmailLabel = new javax.swing.JLabel();
+ examinerNameLabel = new javax.swing.JLabel();
+ examinerPhoneLabel = new javax.swing.JLabel();
+ orgValueLabel = new javax.swing.JLabel();
+ caseNumberValueLabel = new javax.swing.JLabel();
+ examinerNameValueLabel = new javax.swing.JLabel();
+ examinerEmailValueLabel = new javax.swing.JLabel();
+ examinerPhoneValueLabel = new javax.swing.JLabel();
+ closeButton = new javax.swing.JButton();
+ casesPanel = new javax.swing.JPanel();
+ casesScrollPane = new javax.swing.JScrollPane();
+ casesTable = new javax.swing.JTable();
+
+ setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
+ setMinimumSize(new java.awt.Dimension(400, 400));
+
+ casesSplitPane.setDividerLocation(380);
+
+ dataSourcesTable.setAutoCreateRowSorter(true);
+ dataSourcesTable.setModel(dataSourcesTableModel);
+ dataSourcesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
+ dataSourcesScrollPane.setViewportView(dataSourcesTable);
+
+ notesScrollPane.setBorder(null);
+
+ notesTextArea.setEditable(false);
+ notesTextArea.setBackground(new java.awt.Color(240, 240, 240));
+ notesTextArea.setColumns(20);
+ notesTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N
+ notesTextArea.setLineWrap(true);
+ notesTextArea.setRows(3);
+ notesTextArea.setWrapStyleWord(true);
+ notesTextArea.setBorder(null);
+ notesScrollPane.setViewportView(notesTextArea);
+
+ org.openide.awt.Mnemonics.setLocalizedText(caseInfoLabel, org.openide.util.NbBundle.getMessage(ManageCasesDialog.class, "ManageCasesDialog.caseInfoLabel.text")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(dataSourcesLabel, org.openide.util.NbBundle.getMessage(ManageCasesDialog.class, "ManageCasesDialog.dataSourcesLabel.text")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(notesLabel, org.openide.util.NbBundle.getMessage(ManageCasesDialog.class, "ManageCasesDialog.notesLabel.text")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(orgLabel, org.openide.util.NbBundle.getMessage(ManageCasesDialog.class, "ManageCasesDialog.orgLabel.text")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(caseNumberLabel, org.openide.util.NbBundle.getMessage(ManageCasesDialog.class, "ManageCasesDialog.caseNumberLabel.text")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(examinerEmailLabel, org.openide.util.NbBundle.getMessage(ManageCasesDialog.class, "ManageCasesDialog.examinerEmailLabel.text")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(examinerNameLabel, org.openide.util.NbBundle.getMessage(ManageCasesDialog.class, "ManageCasesDialog.examinerNameLabel.text")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(examinerPhoneLabel, org.openide.util.NbBundle.getMessage(ManageCasesDialog.class, "ManageCasesDialog.examinerPhoneLabel.text")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(closeButton, org.openide.util.NbBundle.getMessage(ManageCasesDialog.class, "ManageCasesDialog.closeButton.text")); // NOI18N
+ closeButton.setMaximumSize(new java.awt.Dimension(65, 23));
+ closeButton.setMinimumSize(new java.awt.Dimension(65, 23));
+ closeButton.setPreferredSize(new java.awt.Dimension(65, 23));
+ closeButton.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ closeButtonActionPerformed(evt);
+ }
+ });
+
+ javax.swing.GroupLayout caseInfoPanelLayout = new javax.swing.GroupLayout(caseInfoPanel);
+ caseInfoPanel.setLayout(caseInfoPanelLayout);
+ caseInfoPanelLayout.setHorizontalGroup(
+ caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(caseInfoPanelLayout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(caseInfoPanelLayout.createSequentialGroup()
+ .addGap(10, 10, 10)
+ .addComponent(dataSourcesScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))
+ .addGroup(caseInfoPanelLayout.createSequentialGroup()
+ .addGap(6, 6, 6)
+ .addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(caseInfoPanelLayout.createSequentialGroup()
+ .addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+ .addComponent(orgLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(caseNumberLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(examinerNameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(examinerEmailLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(examinerPhoneLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 88, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(caseInfoPanelLayout.createSequentialGroup()
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(caseNumberValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(orgValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
+ .addGroup(caseInfoPanelLayout.createSequentialGroup()
+ .addGap(6, 6, 6)
+ .addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(examinerNameValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(examinerEmailValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(examinerPhoneValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))))
+ .addComponent(notesLabel)
+ .addGroup(caseInfoPanelLayout.createSequentialGroup()
+ .addGap(10, 10, 10)
+ .addComponent(notesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 428, Short.MAX_VALUE))))
+ .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, caseInfoPanelLayout.createSequentialGroup()
+ .addGap(0, 0, Short.MAX_VALUE)
+ .addComponent(closeButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addGroup(caseInfoPanelLayout.createSequentialGroup()
+ .addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(caseInfoLabel)
+ .addComponent(dataSourcesLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 77, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addGap(0, 0, Short.MAX_VALUE)))
+ .addContainerGap())
+ );
+ caseInfoPanelLayout.setVerticalGroup(
+ caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, caseInfoPanelLayout.createSequentialGroup()
+ .addContainerGap()
+ .addComponent(caseInfoLabel)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+ .addGroup(caseInfoPanelLayout.createSequentialGroup()
+ .addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(caseInfoPanelLayout.createSequentialGroup()
+ .addComponent(orgLabel)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
+ .addComponent(caseNumberLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(caseNumberValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
+ .addComponent(examinerNameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(examinerNameValueLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
+ .addComponent(orgValueLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(examinerEmailLabel))
+ .addComponent(examinerEmailValueLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addGroup(caseInfoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(examinerPhoneLabel)
+ .addComponent(examinerPhoneValueLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(notesLabel)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(notesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 55, Short.MAX_VALUE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(dataSourcesLabel)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(dataSourcesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 129, Short.MAX_VALUE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(closeButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addContainerGap())
+ );
+
+ casesSplitPane.setRightComponent(caseInfoPanel);
+
+ casesTable.setAutoCreateRowSorter(true);
+ casesTable.setModel(casesTableModel);
+ casesTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
+ casesScrollPane.setViewportView(casesTable);
+
+ javax.swing.GroupLayout casesPanelLayout = new javax.swing.GroupLayout(casesPanel);
+ casesPanel.setLayout(casesPanelLayout);
+ casesPanelLayout.setHorizontalGroup(
+ casesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(casesPanelLayout.createSequentialGroup()
+ .addComponent(casesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 379, Short.MAX_VALUE)
+ .addGap(0, 0, 0))
+ );
+ casesPanelLayout.setVerticalGroup(
+ casesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(casesPanelLayout.createSequentialGroup()
+ .addComponent(casesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 361, Short.MAX_VALUE)
+ .addGap(40, 40, 40))
+ );
+
+ casesSplitPane.setLeftComponent(casesPanel);
+
+ javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
+ getContentPane().setLayout(layout);
+ layout.setHorizontalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(casesSplitPane, javax.swing.GroupLayout.Alignment.TRAILING)
+ );
+ layout.setVerticalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(casesSplitPane)
+ );
+
+ pack();
+ }// //GEN-END:initComponents
+
+ private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed
+ this.dispose();
+ }//GEN-LAST:event_closeButtonActionPerformed
+
+ /**
+ * Update the information displayed to reflect the currently selected case.
+ */
+ private void updateSelection() {
+ dataSourcesTableModel.clearTable();
+ if (casesTable.getSelectedRow() >= 0 && casesTable.getSelectedRow() < casesTable.getRowCount()) {
+ CaseDataSourcesWrapper caseWrapper = casesTableModel.getEamCase(casesTable.convertRowIndexToModel(casesTable.getSelectedRow()));
+ orgValueLabel.setText(caseWrapper.getOrganizationName());
+ caseNumberValueLabel.setText(caseWrapper.getCaseNumber());
+ examinerNameValueLabel.setText(caseWrapper.getExaminerName());
+ examinerPhoneValueLabel.setText(caseWrapper.getExaminerPhone());
+ examinerEmailValueLabel.setText(caseWrapper.getExaminerEmail());
+ notesTextArea.setText(caseWrapper.getNotes());
+ dataSourcesTableModel.addDataSources(caseWrapper.getDataSources());
+ } else {
+ orgValueLabel.setText("");
+ caseNumberValueLabel.setText("");
+ examinerNameValueLabel.setText("");
+ examinerPhoneValueLabel.setText("");
+ examinerEmailValueLabel.setText("");
+ notesTextArea.setText("");
+ }
+ }
+
+ // Variables declaration - do not modify//GEN-BEGIN:variables
+ private javax.swing.JLabel caseInfoLabel;
+ private javax.swing.JPanel caseInfoPanel;
+ private javax.swing.JLabel caseNumberLabel;
+ private javax.swing.JLabel caseNumberValueLabel;
+ private javax.swing.JPanel casesPanel;
+ private javax.swing.JScrollPane casesScrollPane;
+ private javax.swing.JSplitPane casesSplitPane;
+ private javax.swing.JTable casesTable;
+ private javax.swing.JButton closeButton;
+ private javax.swing.JLabel dataSourcesLabel;
+ private javax.swing.JScrollPane dataSourcesScrollPane;
+ private javax.swing.JTable dataSourcesTable;
+ private javax.swing.JLabel examinerEmailLabel;
+ private javax.swing.JLabel examinerEmailValueLabel;
+ private javax.swing.JLabel examinerNameLabel;
+ private javax.swing.JLabel examinerNameValueLabel;
+ private javax.swing.JLabel examinerPhoneLabel;
+ private javax.swing.JLabel examinerPhoneValueLabel;
+ private javax.swing.JLabel notesLabel;
+ private javax.swing.JScrollPane notesScrollPane;
+ private javax.swing.JTextArea notesTextArea;
+ private javax.swing.JLabel orgLabel;
+ private javax.swing.JLabel orgValueLabel;
+ // End of variables declaration//GEN-END:variables
+}
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ShowCasesDialog.form b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ShowCasesDialog.form
deleted file mode 100644
index c6a18ff739..0000000000
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ShowCasesDialog.form
+++ /dev/null
@@ -1,169 +0,0 @@
-
-
-
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ShowCasesDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ShowCasesDialog.java
deleted file mode 100644
index 6432c5376f..0000000000
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ShowCasesDialog.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Central Repository
- *
- * Copyright 2015-2018 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.centralrepository.optionspanel;
-
-import java.util.List;
-import java.util.logging.Level;
-import javax.swing.JDialog;
-import javax.swing.JFrame;
-import org.openide.util.NbBundle.Messages;
-import org.openide.windows.WindowManager;
-import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
-import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
-import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
-import org.sleuthkit.autopsy.coreutils.Logger;
-
-/**
- * Dialog to display table of CorrelationCase information from the CR tab of options.
- */
-@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives
-final class ShowCasesDialog extends JDialog {
-
- private static final long serialVersionUID = 1L;
-
- private final static Logger logger = Logger.getLogger(ShowCasesDialog.class.getName());
-
- private final ShowCasesTableModel tableModel;
- @Messages({"ShowCasesDialog.title_text=All Cases Details"})
- /**
- * Creates new form ShowCases Panel
- */
- ShowCasesDialog() {
- super((JFrame) WindowManager.getDefault().getMainWindow(),
- Bundle.ShowCasesDialog_title_text(),
- true);
- tableModel = new ShowCasesTableModel();
- initComponents();
- try {
- EamDb dbManager = EamDb.getInstance();
- List eamCases = dbManager.getCases();
- for(CorrelationCase eamCase : eamCases) {
- tableModel.addEamCase(eamCase);
- }
- } catch (EamDbException ex) {
- logger.log(Level.SEVERE, "Error getting list of cases from database.", ex); // NON-NLS
- }
- display();
- }
-
- private void display() {
- this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
- setVisible(true);
- }
-
-
-
- /**
- * 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
- * regenerated by the Form Editor.
- */
- @SuppressWarnings("unchecked")
- // //GEN-BEGIN:initComponents
- private void initComponents() {
-
- showCasesPanel = new javax.swing.JPanel();
- showCasesScrollPane = new javax.swing.JScrollPane();
- outCasesPane = new javax.swing.JPanel();
- innerCaseScrollPane = new javax.swing.JScrollPane();
- caseDetailsTable = new javax.swing.JTable();
- closeButton = new javax.swing.JButton();
-
- setTitle(org.openide.util.NbBundle.getMessage(ShowCasesDialog.class, "ShowCasesDialog.title")); // NOI18N
- setMinimumSize(new java.awt.Dimension(545, 415));
-
- showCasesPanel.setPreferredSize(new java.awt.Dimension(527, 407));
-
- showCasesScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
- showCasesScrollPane.setPreferredSize(new java.awt.Dimension(535, 415));
-
- innerCaseScrollPane.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
-
- caseDetailsTable.setAutoCreateRowSorter(true);
- caseDetailsTable.setModel(tableModel);
- caseDetailsTable.setToolTipText(org.openide.util.NbBundle.getMessage(ShowCasesDialog.class, "ShowCasesDialog.caseDetailsTable.toolTipText")); // NOI18N
- caseDetailsTable.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_INTERVAL_SELECTION);
- caseDetailsTable.getTableHeader().setReorderingAllowed(false);
- innerCaseScrollPane.setViewportView(caseDetailsTable);
- caseDetailsTable.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(ShowCasesDialog.class, "ShowCasesDialog.caseDetailsTable.AccessibleContext.accessibleDescription")); // NOI18N
-
- javax.swing.GroupLayout outCasesPaneLayout = new javax.swing.GroupLayout(outCasesPane);
- outCasesPane.setLayout(outCasesPaneLayout);
- outCasesPaneLayout.setHorizontalGroup(
- outCasesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGap(0, 1423, Short.MAX_VALUE)
- .addGroup(outCasesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(innerCaseScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 1423, Short.MAX_VALUE))
- );
- outCasesPaneLayout.setVerticalGroup(
- outCasesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGap(0, 500, Short.MAX_VALUE)
- .addGroup(outCasesPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(innerCaseScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 500, Short.MAX_VALUE))
- );
-
- showCasesScrollPane.setViewportView(outCasesPane);
-
- javax.swing.GroupLayout showCasesPanelLayout = new javax.swing.GroupLayout(showCasesPanel);
- showCasesPanel.setLayout(showCasesPanelLayout);
- showCasesPanelLayout.setHorizontalGroup(
- showCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGap(0, 1188, Short.MAX_VALUE)
- .addGroup(showCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(showCasesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 527, Short.MAX_VALUE))
- );
- showCasesPanelLayout.setVerticalGroup(
- showCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGap(0, 473, Short.MAX_VALUE)
- .addGroup(showCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(showCasesScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 407, Short.MAX_VALUE))
- );
-
- org.openide.awt.Mnemonics.setLocalizedText(closeButton, org.openide.util.NbBundle.getMessage(ShowCasesDialog.class, "ShowCasesDialog.closeButton.text")); // NOI18N
- closeButton.setActionCommand(org.openide.util.NbBundle.getMessage(ShowCasesDialog.class, "ShowCasesDialog.closeButton.actionCommand")); // NOI18N
- closeButton.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- closeButtonActionPerformed(evt);
- }
- });
-
- javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
- getContentPane().setLayout(layout);
- layout.setHorizontalGroup(
- layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(layout.createSequentialGroup()
- .addGap(6, 6, 6)
- .addComponent(showCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 1188, Short.MAX_VALUE)
- .addGap(6, 6, 6))
- .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
- .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
- .addComponent(closeButton)
- .addContainerGap())
- );
- layout.setVerticalGroup(
- layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(layout.createSequentialGroup()
- .addGap(6, 6, 6)
- .addComponent(showCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 473, Short.MAX_VALUE)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(closeButton)
- .addContainerGap())
- );
-
- closeButton.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(ShowCasesDialog.class, "ShowCasesDialog.closeButton.AccessibleContext.accessibleName")); // NOI18N
-
- pack();
- }// //GEN-END:initComponents
-
- private void closeButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_closeButtonActionPerformed
- dispose();
- }//GEN-LAST:event_closeButtonActionPerformed
-
-
- // Variables declaration - do not modify//GEN-BEGIN:variables
- private javax.swing.JTable caseDetailsTable;
- private javax.swing.JButton closeButton;
- private javax.swing.JScrollPane innerCaseScrollPane;
- private javax.swing.JPanel outCasesPane;
- private javax.swing.JPanel showCasesPanel;
- private javax.swing.JScrollPane showCasesScrollPane;
- // End of variables declaration//GEN-END:variables
-
-
-
-}
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ShowCasesTableModel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ShowCasesTableModel.java
deleted file mode 100644
index def6cb15b6..0000000000
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ShowCasesTableModel.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Central Repository
- *
- * Copyright 2018 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.centralrepository.optionspanel;
-
-import java.util.ArrayList;
-import java.util.List;
-import javax.swing.table.AbstractTableModel;
-import org.openide.util.NbBundle.Messages;
-import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationCase;
-
-/**
- * Model for cells to display correlation case information
- */
-class ShowCasesTableModel extends AbstractTableModel {
-
- private static final long serialVersionUID = 1L;
-
- @Messages({"ShowCasesTableModel.case=Case Name",
- "ShowCasesTableModel.creationDate=Creation Date",
- "ShowCasesTableModel.caseNumber=Case Number",
- "ShowCasesTableModel.examinerName=Examiner Name",
- "ShowCasesTableModel.examinerEmail=Examiner Email",
- "ShowCasesTableModel.examinerPhone=Examiner Phone",
- "ShowCasesTableModel.notes=Notes",
- "ShowCasesTableModel.noData=No Cases"})
- /**
- * Enum which lists columns of interest from CorrelationCase.
- */
- enum TableColumns {
- // Ordering here determines displayed column order in Content Viewer.
- // If order is changed, update the CellRenderer to ensure correct row coloring.
- CASE_NAME(Bundle.ShowCasesTableModel_case(), 200),
- CREATION_DATE(Bundle.ShowCasesTableModel_creationDate(), 150),
- CASE_NUMBER(Bundle.ShowCasesTableModel_caseNumber(), 100),
- EXAMINER_NAME(Bundle.ShowCasesTableModel_examinerName(), 200),
- EXAMINER_EMAIL(Bundle.ShowCasesTableModel_examinerEmail(), 100),
- EXAMINER_PHONE(Bundle.ShowCasesTableModel_examinerPhone(), 100),
- NOTES(Bundle.ShowCasesTableModel_notes(), 450);
-
- private final String columnName;
- private final int columnWidth;
-
- TableColumns(String columnName, int columnWidth) {
- this.columnName = columnName;
- this.columnWidth = columnWidth;
- }
-
- String columnName() {
- return columnName;
- }
-
- int columnWidth() {
- return columnWidth;
- }
- };
-
- /**
- * list of Eam Cases from central repository.
- */
- private List eamCases;
-
- ShowCasesTableModel() {
- eamCases = new ArrayList<>();
- }
-
- @Override
- public int getColumnCount() {
- return TableColumns.values().length;
- }
-
- /**
- * Get the preferred width that has been configured for this column.
- *
- * A value of 0 means that no preferred width has been defined for this
- * column.
- *
- * @param colIdx Column index
- *
- * @return preferred column width >= 0
- */
- int getColumnPreferredWidth(int colIdx) {
- return TableColumns.values()[colIdx].columnWidth();
- }
-
- @Override
- public int getRowCount() {
- return eamCases.size();
- }
-
- @Override
- public String getColumnName(int colIdx) {
- return TableColumns.values()[colIdx].columnName();
- }
-
- @Override
- public Object getValueAt(int rowIdx, int colIdx) {
- if (eamCases.isEmpty()) {
- return Bundle.ShowCasesTableModel_noData();
- }
-
- return mapValueById(rowIdx, TableColumns.values()[colIdx]);
- }
-
- Object getRow(int rowIdx) {
- return eamCases.get(rowIdx);
- }
-
- /**
- * Map a rowIdx and colId to the value in that cell.
- *
- * @param rowIdx Index of row to search
- * @param colId ID of column to search
- *
- * @return value in the cell
- */
- private Object mapValueById(int rowIdx, TableColumns colId) {
- CorrelationCase eamCase = eamCases.get(rowIdx);
- String value = Bundle.ShowCasesTableModel_noData();
-
- switch (colId) {
- case CASE_NAME:
- value = eamCase.getDisplayName();
- break;
- case CREATION_DATE:
- value = eamCase.getCreationDate();
- break;
- case CASE_NUMBER:
- value = eamCase.getCaseNumber();
- break;
- case EXAMINER_NAME:
- value = eamCase.getExaminerName();
- break;
- case EXAMINER_EMAIL:
- value = eamCase.getExaminerEmail();
- break;
- case EXAMINER_PHONE:
- value = eamCase.getExaminerPhone();
- break;
- case NOTES:
- value = eamCase.getNotes();
- break;
- default:
- break;
- }
- return value;
- }
-
- @Override
- public Class getColumnClass(int colIdx) {
- return String.class;
- }
-
- /**
- * Add one local central repository case to the table.
- *
- * @param eamCase central repository case to add to the
- * table
- */
- void addEamCase(CorrelationCase eamCase) {
- eamCases.add(eamCase);
- fireTableDataChanged();
- }
-
- void clearTable() {
- eamCases.clear();
- fireTableDataChanged();
- }
-
-
-
-}
diff --git a/Core/src/org/sleuthkit/autopsy/commonfilesearch/CaseDBCommonAttributeInstanceNode.java b/Core/src/org/sleuthkit/autopsy/commonfilesearch/CaseDBCommonAttributeInstanceNode.java
index b4f8ee525e..504aa45b97 100644
--- a/Core/src/org/sleuthkit/autopsy/commonfilesearch/CaseDBCommonAttributeInstanceNode.java
+++ b/Core/src/org/sleuthkit/autopsy/commonfilesearch/CaseDBCommonAttributeInstanceNode.java
@@ -18,17 +18,16 @@
*/
package org.sleuthkit.autopsy.commonfilesearch;
-import java.util.List;
-import org.apache.commons.lang3.StringUtils;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
import org.openide.nodes.Sheet;
-import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance;
-import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
-import org.sleuthkit.autopsy.core.UserPreferences;
+import org.openide.util.NbBundle;
+import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
import org.sleuthkit.autopsy.datamodel.FileNode;
import org.sleuthkit.autopsy.datamodel.NodeProperty;
import org.sleuthkit.datamodel.AbstractFile;
-import org.sleuthkit.datamodel.ContentTag;
/**
* Node that wraps CaseDBCommonAttributeInstance to represent a file instance
@@ -75,33 +74,25 @@ public class CaseDBCommonAttributeInstanceNode extends FileNode {
@Override
protected Sheet createSheet() {
- Sheet sheet = new Sheet();
+ Sheet sheet = super.createSheet();
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
- if (sheetSet == null) {
- sheetSet = Sheet.createPropertiesSet();
- sheet.put(sheetSet);
+ Set keepProps = new HashSet<>(Arrays.asList(
+ NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.nameColLbl"),
+ NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.score.name"),
+ NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.comment.name"),
+ NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.count.name"),
+ NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.mimeType")));
+
+ for(Property> p : sheetSet.getProperties()) {
+ if(!keepProps.contains(p.getName())){
+ sheetSet.remove(p.getName());
+ }
}
- List tags = getContentTagsFromDatabase();
-
final String NO_DESCR = Bundle.CommonFilesSearchResultsViewerTable_noDescText();
-
- sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), Bundle.CommonFilesSearchResultsViewerTable_filesColLbl(), NO_DESCR, this.getContent().getName()));
- addScoreProperty(sheetSet, tags);
-
- CorrelationAttributeInstance correlationAttribute = null;
- if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) {
- correlationAttribute = getCorrelationAttributeInstance();
- }
- addCommentProperty(sheetSet, tags, correlationAttribute);
-
- if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) {
- addCountProperty(sheetSet, correlationAttribute);
- }
- sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), Bundle.CommonFilesSearchResultsViewerTable_pathColLbl(), NO_DESCR, this.getContent().getParentPath()));
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), Bundle.CommonFilesSearchResultsViewerTable_dataSourceColLbl(), NO_DESCR, this.getDataSource()));
- sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), Bundle.CommonFilesSearchResultsViewerTable_mimeTypeColLbl(), NO_DESCR, StringUtils.defaultString(this.getContent().getMIMEType())));
sheetSet.put(new NodeProperty<>(Bundle.CommonFilesSearchResultsViewerTable_caseColLbl1(), Bundle.CommonFilesSearchResultsViewerTable_caseColLbl1(), NO_DESCR, caseName));
+
return sheet;
}
}
\ No newline at end of file
diff --git a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form
index c19b57ea69..38a3e7adbf 100644
--- a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form
+++ b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.form
@@ -303,23 +303,25 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java
index 81ffcb4805..587bf47260 100644
--- a/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java
+++ b/Core/src/org/sleuthkit/autopsy/communications/FiltersPanel.java
@@ -124,7 +124,8 @@ final public class FiltersPanel extends JPanel {
updateFilters(true);
UserPreferences.addChangeListener(preferenceChangeEvent -> {
- if (preferenceChangeEvent.getKey().equals(UserPreferences.DISPLAY_TIMES_IN_LOCAL_TIME)) {
+ if (preferenceChangeEvent.getKey().equals(UserPreferences.DISPLAY_TIMES_IN_LOCAL_TIME) ||
+ preferenceChangeEvent.getKey().equals(UserPreferences.TIME_ZONE_FOR_DISPLAYS)) {
updateTimeZone();
}
});
@@ -175,7 +176,7 @@ final public class FiltersPanel extends JPanel {
}
private void updateTimeZone() {
- dateRangeLabel.setText("Date Range ( " + Utils.getUserPreferredZoneId().toString() + "):");
+ dateRangeLabel.setText("Date Range (" + Utils.getUserPreferredZoneId().toString() + "):");
}
/**
diff --git a/Core/src/org/sleuthkit/autopsy/communications/Utils.java b/Core/src/org/sleuthkit/autopsy/communications/Utils.java
index b155e3b4b4..c4a62209c7 100644
--- a/Core/src/org/sleuthkit/autopsy/communications/Utils.java
+++ b/Core/src/org/sleuthkit/autopsy/communications/Utils.java
@@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.communications;
import java.time.ZoneId;
import java.time.ZoneOffset;
+import java.util.TimeZone;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.datamodel.accounts.Accounts;
import org.sleuthkit.datamodel.Account;
@@ -33,7 +34,8 @@ class Utils {
}
static ZoneId getUserPreferredZoneId() {
- ZoneId zone = UserPreferences.displayTimesInLocalTime() ? ZoneOffset.systemDefault() : ZoneOffset.UTC;
+ ZoneId zone = UserPreferences.displayTimesInLocalTime() ?
+ ZoneOffset.systemDefault() : TimeZone.getTimeZone(UserPreferences.getTimeZoneForDisplays()).toZoneId();
return zone;
}
diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java
index d88b5ac2fb..72343ec616 100755
--- a/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java
+++ b/Core/src/org/sleuthkit/autopsy/contentviewers/AnnotationsContentViewer.java
@@ -67,19 +67,19 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
initComponents();
Utilities.configureTextPaneAsHtml(jTextPane1);
}
-
+
@Override
public void setNode(Node node) {
if ((node == null) || (!isSupported(node))) {
resetComponent();
return;
}
-
+
StringBuilder html = new StringBuilder();
-
+
BlackboardArtifact artifact = node.getLookup().lookup(BlackboardArtifact.class);
Content sourceFile = null;
-
+
try {
if (artifact != null) {
/*
@@ -100,32 +100,32 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
"Exception while trying to retrieve a Content instance from the BlackboardArtifact '%s' (id=%d).",
artifact.getDisplayName(), artifact.getArtifactID()), ex);
}
-
+
if (artifact != null) {
populateTagData(html, artifact, sourceFile);
} else {
populateTagData(html, sourceFile);
}
-
+
if (sourceFile instanceof AbstractFile) {
populateCentralRepositoryData(html, artifact, (AbstractFile) sourceFile);
}
-
+
setText(html.toString());
jTextPane1.setCaretPosition(0);
}
-
+
/**
* Populate the "Selected Item" sections with tag data for the supplied
* content.
- *
+ *
* @param html The HTML text to update.
* @param content Selected content.
*/
private void populateTagData(StringBuilder html, Content content) {
try {
SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase();
-
+
startSection(html, "Selected Item");
List fileTagsList = tskCase.getContentTagsByContent(content);
if (fileTagsList.isEmpty()) {
@@ -142,11 +142,11 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
logger.log(Level.SEVERE, "Exception while getting tags from the case database.", ex); //NON-NLS
}
}
-
+
/**
* Populate the "Selected Item" and "Source File" sections with tag data for
* a supplied artifact.
- *
+ *
* @param html The HTML text to update.
* @param artifact A selected artifact.
* @param sourceFile The source content of the selected artifact.
@@ -154,7 +154,7 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
private void populateTagData(StringBuilder html, BlackboardArtifact artifact, Content sourceFile) {
try {
SleuthkitCase tskCase = Case.getCurrentCaseThrows().getSleuthkitCase();
-
+
startSection(html, "Selected Item");
List artifactTagsList = tskCase.getBlackboardArtifactTagsByArtifact(artifact);
if (artifactTagsList.isEmpty()) {
@@ -165,7 +165,7 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
}
}
endSection(html);
-
+
if (sourceFile != null) {
startSection(html, "Source File");
List fileTagsList = tskCase.getContentTagsByContent(sourceFile);
@@ -184,10 +184,10 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
logger.log(Level.SEVERE, "Exception while getting tags from the case database.", ex); //NON-NLS
}
}
-
+
/**
* Populate the "Central Repository Comments" section with data.
- *
+ *
* @param html The HTML text to update.
* @param artifact A selected artifact (can be null).
* @param sourceFile A selected file, or a source file of the selected
@@ -208,23 +208,24 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
if (attributeType.getId() == CorrelationAttributeInstance.FILES_TYPE_ID) {
CorrelationCase correlationCase = EamDb.getInstance().getCase(Case.getCurrentCase());
instancesList.add(new CorrelationAttributeInstance(
- md5,
attributeType,
+ md5,
correlationCase,
CorrelationDataSource.fromTSKDataSource(correlationCase, sourceFile.getDataSource()),
sourceFile.getParentPath() + sourceFile.getName(),
"",
- sourceFile.getKnown()));
+ sourceFile.getKnown(),
+ sourceFile.getId()));
break;
}
}
}
boolean commentDataFound = false;
-
+
for (CorrelationAttributeInstance instance : instancesList) {
- List correlatedInstancesList =
- EamDb.getInstance().getArtifactInstancesByTypeValue(instance.getCorrelationType(), instance.getCorrelationValue());
+ List correlatedInstancesList
+ = EamDb.getInstance().getArtifactInstancesByTypeValue(instance.getCorrelationType(), instance.getCorrelationValue());
for (CorrelationAttributeInstance correlatedInstance : correlatedInstancesList) {
if (correlatedInstance.getComment() != null && correlatedInstance.getComment().isEmpty() == false) {
commentDataFound = true;
@@ -232,7 +233,7 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
}
}
}
-
+
if (commentDataFound == false) {
addMessage(html, "There is no comment data for the selected content in the Central Repository.");
}
@@ -247,16 +248,16 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
/**
* Set the text of the text panel.
- *
+ *
* @param text The text to set to the text panel.
*/
private void setText(String text) {
jTextPane1.setText("" + text + ""); //NON-NLS
}
-
+
/**
* Start a new data section.
- *
+ *
* @param html The HTML text to add the section to.
* @param sectionName The name of the section.
*/
@@ -265,10 +266,10 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
.append(sectionName)
.append("
"); //NON-NLS
}
-
+
/**
* Add a message.
- *
+ *
* @param html The HTML text to add the message to.
* @param message The message text.
*/
@@ -277,10 +278,10 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
.append(message)
.append(" "); //NON-NLS
}
-
+
/**
* Add a data table containing information about a tag.
- *
+ *
* @param html The HTML text to add the table to.
* @param tag The tag whose information will be used to populate the table.
*/
@@ -296,11 +297,11 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
addRow(html, Bundle.AnnotationsContentViewer_tagEntryDataLabel_comment(), formatHtmlString(tag.getComment()));
endTable(html);
}
-
+
/**
* Add a data table containing information about a correlation attribute
* instance in the Central Repository.
- *
+ *
* @param html The HTML text to add the table to.
* @param attributeInstance The attribute instance whose information will be
* used to populate the table.
@@ -319,10 +320,10 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
addRow(html, Bundle.AnnotationsContentViewer_centralRepositoryEntryDataLabel_path(), attributeInstance.getFilePath());
endTable(html);
}
-
+
/**
* Start a data table.
- *
+ *
* @param html The HTML text to add the table to.
*/
private void startTable(StringBuilder html) {
@@ -331,7 +332,7 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
/**
* Add a data row to a table.
- *
+ *
* @param html The HTML text to add the row to.
* @param key The key for the left column of the data row.
* @param value The value for the right column of the data row.
@@ -343,10 +344,10 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
html.append(value);
html.append(""); //NON-NLS
}
-
+
/**
* End a data table.
- *
+ *
* @param html The HTML text on which to end a table.
*/
private void endTable(StringBuilder html) {
@@ -355,18 +356,19 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
/**
* End a data section.
- *
+ *
* @param html The HTML text on which to end a section.
*/
private void endSection(StringBuilder html) {
html.append(" "); //NON-NLS
}
-
+
/**
* Apply escape sequence to special characters. Line feed and carriage
* return character combinations will be converted to HTML line breaks.
- *
+ *
* @param text The text to format.
+ *
* @return The formatted text.
*/
private String formatHtmlString(String text) {
@@ -428,7 +430,7 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
@Override
public boolean isSupported(Node node) {
BlackboardArtifact artifact = node.getLookup().lookup(BlackboardArtifact.class);
-
+
try {
if (artifact != null) {
if (artifact.getSleuthkitCase().getAbstractFileById(artifact.getObjectID()) != null) {
@@ -444,7 +446,7 @@ public class AnnotationsContentViewer extends javax.swing.JPanel implements Data
"Exception while trying to retrieve a Content instance from the BlackboardArtifact '%s' (id=%d).",
artifact.getDisplayName(), artifact.getArtifactID()), ex);
}
-
+
return false;
}
diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java
index e1565c3b89..bf319bde0c 100644
--- a/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java
+++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java
@@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.contentviewers;
import java.awt.Component;
import java.util.Arrays;
+import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
@@ -43,6 +44,7 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
import org.sleuthkit.autopsy.corecomponents.DataResultPanel;
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
import org.sleuthkit.autopsy.coreutils.Logger;
+import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode;
import org.sleuthkit.autopsy.datamodel.FileNode;
import org.sleuthkit.autopsy.datamodel.NodeProperty;
import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
@@ -721,31 +723,23 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
@Override
protected Sheet createSheet() {
- Sheet sheet = new Sheet();
+ Sheet sheet = super.createSheet();
+ Set keepProps = new HashSet<>(Arrays.asList(
+ NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.nameColLbl"),
+ NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.score.name"),
+ NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.comment.name"),
+ NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.count.name"),
+ NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.sizeColLbl"),
+ NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.mimeType"),
+ NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.knownColLbl")));
+
+ //Remove all other props except for the ones above
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
- if (sheetSet == null) {
- sheetSet = Sheet.createPropertiesSet();
- sheet.put(sheetSet);
+ for(Property> p : sheetSet.getProperties()) {
+ if(!keepProps.contains(p.getName())){
+ sheetSet.remove(p.getName());
+ }
}
- List tags = getContentTagsFromDatabase();
-
- AbstractFile file = getContent();
- sheetSet.put(new NodeProperty<>("Name", "Name", "Name", file.getName()));
-
- addScoreProperty(sheetSet, tags);
-
- CorrelationAttributeInstance correlationAttribute = null;
- if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) {
- correlationAttribute = getCorrelationAttributeInstance();
- }
- addCommentProperty(sheetSet, tags, correlationAttribute);
-
- if (EamDbUtil.useCentralRepo() && UserPreferences.hideCentralRepoCommentsAndOccurrences()== false) {
- addCountProperty(sheetSet, correlationAttribute);
- }
- sheetSet.put(new NodeProperty<>("Size", "Size", "Size", file.getSize()));
- sheetSet.put(new NodeProperty<>("Mime Type", "Mime Type", "Mime Type", StringUtils.defaultString(file.getMIMEType())));
- sheetSet.put(new NodeProperty<>("Known", "Known", "Known", file.getKnown().getName()));
return sheet;
}
diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java
index 506084f0c3..dd73b6f6ca 100644
--- a/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java
+++ b/Core/src/org/sleuthkit/autopsy/contentviewers/PListViewer.java
@@ -74,7 +74,7 @@ class PListViewer extends javax.swing.JPanel implements FileTypeViewer, Explorer
private final Outline outline;
private ExplorerManager explorerManager;
- private NSDictionary rootDict;
+ private NSObject rootDict;
/**
* Creates new form PListViewer
@@ -415,22 +415,35 @@ class PListViewer extends javax.swing.JPanel implements FileTypeViewer, Explorer
}
/**
- * Parses given binary stream and extracts Plist key/value
+ * Parses given binary stream and extracts Plist key/value.
*
- * @param plistbytes
+ * @param plistbytes The byte array containing the Plist data.
*
* @return list of PropKeyValue
*/
private List parsePList(final byte[] plistbytes) throws IOException, PropertyListFormatException, ParseException, ParserConfigurationException, SAXException {
final List plist = new ArrayList<>();
- rootDict = (NSDictionary) PropertyListParser.parse(plistbytes);
+ rootDict = PropertyListParser.parse(plistbytes);
- final String[] keys = rootDict.allKeys();
- for (final String key : keys) {
- final PropKeyValue pkv = parseProperty(key, rootDict.objectForKey(key));
- if (null != pkv) {
- plist.add(pkv);
+ /*
+ * Parse the data if the root is an NSArray or NSDictionary. Anything
+ * else is unexpected and will be ignored.
+ */
+ if (rootDict instanceof NSArray) {
+ for (int i=0; i < ((NSArray)rootDict).count(); i++) {
+ final PropKeyValue pkv = parseProperty("", ((NSArray)rootDict).objectAtIndex(i));
+ if (null != pkv) {
+ plist.add(pkv);
+ }
+ }
+ } else if (rootDict instanceof NSDictionary) {
+ final String[] keys = ((NSDictionary)rootDict).allKeys();
+ for (final String key : keys) {
+ final PropKeyValue pkv = parseProperty(key, ((NSDictionary)rootDict).objectForKey(key));
+ if (null != pkv) {
+ plist.add(pkv);
+ }
}
}
diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java
index 9c09ca01ca..f2db7c2532 100755
--- a/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java
+++ b/Core/src/org/sleuthkit/autopsy/contentviewers/SQLiteViewer.java
@@ -24,21 +24,15 @@ import java.awt.Cursor;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.sql.Connection;
-import java.sql.DriverManager;
-import java.sql.ResultSet;
-import java.sql.ResultSetMetaData;
-import java.sql.SQLException;
-import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.function.Consumer;
import java.util.logging.Level;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
@@ -48,11 +42,11 @@ import org.apache.commons.io.FilenameUtils;
import org.openide.util.NbBundle;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.casemodule.Case;
-import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
+import org.sleuthkit.autopsy.coreutils.SQLiteTableReaderException;
import org.sleuthkit.autopsy.coreutils.Logger;
-import org.sleuthkit.datamodel.AbstractFile;
-import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
+import org.sleuthkit.datamodel.AbstractFile;
+import org.sleuthkit.autopsy.coreutils.SQLiteTableReader;
/**
* A file content viewer for SQLite database files.
@@ -66,8 +60,14 @@ class SQLiteViewer extends javax.swing.JPanel implements FileTypeViewer {
private static final Logger logger = Logger.getLogger(FileViewer.class.getName());
private final SQLiteTableView selectedTableView = new SQLiteTableView();
private AbstractFile sqliteDbFile;
- private File tmpDbFile;
- private Connection connection;
+
+ private SQLiteTableReader viewReader;
+
+ private Map row = new LinkedHashMap<>();
+ private List