From c9e804cd790fd2c7cab2ed013acccbf1f80d744f Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 27 Sep 2018 11:29:22 -0400 Subject: [PATCH 01/42] 4242 fix comparisons in CentralRepoDatamodelTest.testArtifacts --- .../datamodel/CentralRepoDatamodelTest.java | 1310 +++++++++-------- 1 file changed, 658 insertions(+), 652 deletions(-) diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDatamodelTest.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDatamodelTest.java index da5bb330fa..944dd7272e 100755 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDatamodelTest.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDatamodelTest.java @@ -88,109 +88,109 @@ public class CentralRepoDatamodelTest extends TestCase { @Override public void setUp() { -// dbSettingsSqlite = new SqliteEamDbSettings(); -// -// // Delete the test directory, if it exists -// if (testDirectory.toFile().exists()) { -// try { -// FileUtils.deleteDirectory(testDirectory.toFile()); -// } catch (IOException ex) { -// Assert.fail(ex.getMessage()); -// } -// } -// assertFalse("Unable to delete existing test directory", testDirectory.toFile().exists()); -// -// // Create the test directory -// testDirectory.toFile().mkdirs(); -// assertTrue("Unable to create test directory", testDirectory.toFile().exists()); -// -// // Save the current central repo settings -// propertiesMap = ModuleSettings.getConfigSettings(PROPERTIES_FILE); -// -// try { -// dbSettingsSqlite.setDbName(CR_DB_NAME); -// dbSettingsSqlite.setDbDirectory(testDirectory.toString()); -// if (!dbSettingsSqlite.dbDirectoryExists()) { -// dbSettingsSqlite.createDbDirectory(); -// } -// -// assertTrue("Failed to created central repo directory " + dbSettingsSqlite.getDbDirectory(), dbSettingsSqlite.dbDirectoryExists()); -// -// boolean result = dbSettingsSqlite.initializeDatabaseSchema() -// && dbSettingsSqlite.insertDefaultDatabaseContent(); -// -// assertTrue("Failed to initialize central repo database", result); -// -// dbSettingsSqlite.saveSettings(); -// EamDbUtil.setUseCentralRepo(true); -// EamDbPlatformEnum.setSelectedPlatform(EamDbPlatformEnum.SQLITE.name()); -// EamDbPlatformEnum.saveSelectedPlatform(); -// } catch (EamDbException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail(ex.getMessage()); -// } -// -// Path crDbFilePath = Paths.get(testDirectory.toString(), CR_DB_NAME); -// assertTrue("Failed to create central repo database at " + crDbFilePath, crDbFilePath.toFile().exists()); -// -// // Set up some default objects to be used by the tests -// try { -// case1 = new CorrelationCase("case1_uuid", "case1"); -// case1 = EamDb.getInstance().newCase(case1); -// assertTrue("Failed to create test object case1", case1 != null); -// -// case2 = new CorrelationCase("case2_uuid", "case2"); -// case2 = EamDb.getInstance().newCase(case2); -// assertTrue("Failed to create test object case2", case2 != null); -// -// dataSource1fromCase1 = new CorrelationDataSource(case1, "dataSource1_deviceID", "dataSource1"); -// EamDb.getInstance().newDataSource(dataSource1fromCase1); -// dataSource1fromCase1 = EamDb.getInstance().getDataSource(case1, dataSource1fromCase1.getDeviceID()); -// assertTrue("Failed to create test object dataSource1fromCase1", dataSource1fromCase1 != null); -// -// dataSource2fromCase1 = new CorrelationDataSource(case1, "dataSource2_deviceID", "dataSource2"); -// EamDb.getInstance().newDataSource(dataSource2fromCase1); -// dataSource2fromCase1 = EamDb.getInstance().getDataSource(case1, dataSource2fromCase1.getDeviceID()); -// assertTrue("Failed to create test object dataSource2fromCase1", dataSource2fromCase1 != null); -// -// dataSource1fromCase2 = new CorrelationDataSource(case2, "dataSource3_deviceID", "dataSource3"); -// EamDb.getInstance().newDataSource(dataSource1fromCase2); -// dataSource1fromCase2 = EamDb.getInstance().getDataSource(case2, dataSource1fromCase2.getDeviceID()); -// assertTrue("Failed to create test object dataSource1fromCase2", dataSource1fromCase2 != null); -// -// org1 = new EamOrganization("org1"); -// org1 = EamDb.getInstance().newOrganization(org1); -// -// org2 = new EamOrganization("org2"); -// org2 = EamDb.getInstance().newOrganization(org2); -// -// // Store the file type object for later use -// fileType = EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID); -// assertTrue("getCorrelationTypeById(FILES_TYPE_ID) returned null", fileType != null); -// usbDeviceType = EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.USBID_TYPE_ID); -// assertTrue("getCorrelationTypeById(USBID_TYPE_ID) returned null", usbDeviceType != null); -// -// } catch (EamDbException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail(ex.getMessage()); -// } + dbSettingsSqlite = new SqliteEamDbSettings(); + + // Delete the test directory, if it exists + if (testDirectory.toFile().exists()) { + try { + FileUtils.deleteDirectory(testDirectory.toFile()); + } catch (IOException ex) { + Assert.fail(ex.getMessage()); + } + } + assertFalse("Unable to delete existing test directory", testDirectory.toFile().exists()); + + // Create the test directory + testDirectory.toFile().mkdirs(); + assertTrue("Unable to create test directory", testDirectory.toFile().exists()); + + // Save the current central repo settings + propertiesMap = ModuleSettings.getConfigSettings(PROPERTIES_FILE); + + try { + dbSettingsSqlite.setDbName(CR_DB_NAME); + dbSettingsSqlite.setDbDirectory(testDirectory.toString()); + if (!dbSettingsSqlite.dbDirectoryExists()) { + dbSettingsSqlite.createDbDirectory(); + } + + assertTrue("Failed to created central repo directory " + dbSettingsSqlite.getDbDirectory(), dbSettingsSqlite.dbDirectoryExists()); + + boolean result = dbSettingsSqlite.initializeDatabaseSchema() + && dbSettingsSqlite.insertDefaultDatabaseContent(); + + assertTrue("Failed to initialize central repo database", result); + + dbSettingsSqlite.saveSettings(); + EamDbUtil.setUseCentralRepo(true); + EamDbPlatformEnum.setSelectedPlatform(EamDbPlatformEnum.SQLITE.name()); + EamDbPlatformEnum.saveSelectedPlatform(); + } catch (EamDbException ex) { + Exceptions.printStackTrace(ex); + Assert.fail(ex.getMessage()); + } + + Path crDbFilePath = Paths.get(testDirectory.toString(), CR_DB_NAME); + assertTrue("Failed to create central repo database at " + crDbFilePath, crDbFilePath.toFile().exists()); + + // Set up some default objects to be used by the tests + try { + case1 = new CorrelationCase("case1_uuid", "case1"); + case1 = EamDb.getInstance().newCase(case1); + assertTrue("Failed to create test object case1", case1 != null); + + case2 = new CorrelationCase("case2_uuid", "case2"); + case2 = EamDb.getInstance().newCase(case2); + assertTrue("Failed to create test object case2", case2 != null); + + dataSource1fromCase1 = new CorrelationDataSource(case1, "dataSource1_deviceID", "dataSource1"); + EamDb.getInstance().newDataSource(dataSource1fromCase1); + dataSource1fromCase1 = EamDb.getInstance().getDataSource(case1, dataSource1fromCase1.getDeviceID()); + assertTrue("Failed to create test object dataSource1fromCase1", dataSource1fromCase1 != null); + + dataSource2fromCase1 = new CorrelationDataSource(case1, "dataSource2_deviceID", "dataSource2"); + EamDb.getInstance().newDataSource(dataSource2fromCase1); + dataSource2fromCase1 = EamDb.getInstance().getDataSource(case1, dataSource2fromCase1.getDeviceID()); + assertTrue("Failed to create test object dataSource2fromCase1", dataSource2fromCase1 != null); + + dataSource1fromCase2 = new CorrelationDataSource(case2, "dataSource3_deviceID", "dataSource3"); + EamDb.getInstance().newDataSource(dataSource1fromCase2); + dataSource1fromCase2 = EamDb.getInstance().getDataSource(case2, dataSource1fromCase2.getDeviceID()); + assertTrue("Failed to create test object dataSource1fromCase2", dataSource1fromCase2 != null); + + org1 = new EamOrganization("org1"); + org1 = EamDb.getInstance().newOrganization(org1); + + org2 = new EamOrganization("org2"); + org2 = EamDb.getInstance().newOrganization(org2); + + // Store the file type object for later use + fileType = EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID); + assertTrue("getCorrelationTypeById(FILES_TYPE_ID) returned null", fileType != null); + usbDeviceType = EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.USBID_TYPE_ID); + assertTrue("getCorrelationTypeById(USBID_TYPE_ID) returned null", usbDeviceType != null); + + } catch (EamDbException ex) { + Exceptions.printStackTrace(ex); + Assert.fail(ex.getMessage()); + } } @Override public void tearDown() { -// -// // Restore the original properties -// ModuleSettings.setConfigSettings(PROPERTIES_FILE, propertiesMap); -// -// // Close and delete the test case and central repo db -// try { -// EamDb.getInstance().shutdownConnections(); -// FileUtils.deleteDirectory(testDirectory.toFile()); -// } catch (EamDbException | IOException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail(ex.getMessage()); -// } -// assertFalse("Error deleting test directory " + testDirectory.toString(), testDirectory.toFile().exists()); + + // Restore the original properties + ModuleSettings.setConfigSettings(PROPERTIES_FILE, propertiesMap); + + // Close and delete the test case and central repo db + try { + EamDb.getInstance().shutdownConnections(); + FileUtils.deleteDirectory(testDirectory.toFile()); + } catch (EamDbException | IOException ex) { + Exceptions.printStackTrace(ex); + Assert.fail(ex.getMessage()); + } + assertFalse("Error deleting test directory " + testDirectory.toString(), testDirectory.toFile().exists()); } /** @@ -659,559 +659,565 @@ public class CentralRepoDatamodelTest extends TestCase { * with null type - Test with null value */ public void testArtifacts() { -// -// //the hash value of all 0s has not been inserted -// final String unusedHashValue = "00000000000000000000000000000000"; -// -// String inAllDataSourcesHash = "6cddb0e31787b79cfdcc0676b98a71ce"; -// String inAllDataSourcesPath = "C:\\files\\path0.txt"; -// String inDataSource1twiceHash = "b2f5ff47436671b6e533d8dc3614845d"; -// String inDataSource1twicePath1 = "C:\\files\\path1.txt"; -// String inDataSource1twicePath2 = "C:\\files\\path2.txt"; -// String onlyInDataSource3Hash = "2af54305f183778d87de0c70c591fae4"; -// String onlyInDataSource3Path = "C:\\files\\path3.txt"; -// String callbackTestFilePath1 = "C:\\files\\processinstancecallback\\path1.txt"; -// String callbackTestFilePath2 = "C:\\files\\processinstancecallback\\path2.txt"; -// String callbackTestFileHash = "fb9dd8f04dacd3e82f4917f1a002223c"; -// -// // These will all go in dataSource1fromCase1 -// String emailValue = "test@gmail.com"; -// String emailPath = "C:\\files\\emailPath.txt"; -// String phoneValue = "202-555-1234"; -// String phonePath = "C:\\files\\phonePath.txt"; -// String domainValue = "www.mozilla.com"; -// String domainPath = "C:\\files\\domainPath.txt"; -// String devIdValue = "94B21234"; -// String devIdPath = "C:\\files\\devIdPath.txt"; -// -// // Store the email type -// CorrelationAttributeInstance.Type emailType; //used again for other portions of this test -// try { -// emailType = EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.EMAIL_TYPE_ID); -// assertEquals("Unexpected Correlation Type retrieved for Email type id", CorrelationAttributeInstance.EMAIL_TYPE_ID, emailType.getId()); -// } catch (EamDbException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail("Error thrown while attempting to get email attribute " + ex.getMessage()); -// return; -// } -// -// // Test adding attribute with one instance -// try { -// CorrelationAttributeInstance attr = new CorrelationAttributeInstance(onlyInDataSource3Hash, fileType, case2, dataSource1fromCase2, onlyInDataSource3Path); -// EamDb.getInstance().addArtifactInstance(attr); -// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail("Error thrown while attempting to add file attribute from single datasource the first time " + ex.getMessage()); -// } -// -// // Test adding attribute with an instance in each data source -// try { -// CorrelationAttributeInstance attr1 = new CorrelationAttributeInstance(inAllDataSourcesHash, fileType, case1, dataSource1fromCase1, inAllDataSourcesPath); -// EamDb.getInstance().addArtifactInstance(attr1); -// CorrelationAttributeInstance attr2 = new CorrelationAttributeInstance(inAllDataSourcesHash, fileType, case1, dataSource2fromCase1, inAllDataSourcesPath); -// EamDb.getInstance().addArtifactInstance(attr2); -// CorrelationAttributeInstance attr3 = new CorrelationAttributeInstance(inAllDataSourcesHash, fileType, case2, dataSource1fromCase2, inAllDataSourcesPath); -// EamDb.getInstance().addArtifactInstance(attr3); -// -// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail("Error thrown while attempting to add file attribute from all 3 datasources " + ex.getMessage()); -// } -// -// // Test adding attribute with two instances in one data source -// try { -// CorrelationAttributeInstance attr1 = new CorrelationAttributeInstance(inDataSource1twiceHash, fileType, case1, dataSource1fromCase1, inDataSource1twicePath1); -// EamDb.getInstance().addArtifactInstance(attr1); -// CorrelationAttributeInstance attr2 = new CorrelationAttributeInstance(inDataSource1twiceHash, fileType, case1, dataSource1fromCase1, inDataSource1twicePath2); -// EamDb.getInstance().addArtifactInstance(attr2); -// -// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail("Error thrown while attempting to add file attribute from single datasource the second time " + ex.getMessage()); -// } -// -// // Test adding the other types -// // Test adding an email artifact -// try { -// CorrelationAttributeInstance attr = new CorrelationAttributeInstance(emailValue, emailType, case1, dataSource1fromCase1, emailPath); -// EamDb.getInstance().addArtifactInstance(attr); -// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail("Error thrown while attempting to add email attribute from single datasource " + ex.getMessage()); -// } -// -// // Test adding a phone artifact -// try { -// CorrelationAttributeInstance attr = new CorrelationAttributeInstance( -// phoneValue, -// EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.PHONE_TYPE_ID), -// case1, dataSource1fromCase1, phonePath); -// -// EamDb.getInstance().addArtifactInstance(attr); -// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail("Error thrown while attempting to add phone attribute from single datasource " + ex.getMessage()); -// } -// -// // Test adding a domain artifact -// try { -// CorrelationAttributeInstance.Type type = EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.DOMAIN_TYPE_ID); -// assertEquals("Unexpected Correlation Type retrieved for Domain type id", CorrelationAttributeInstance.DOMAIN_TYPE_ID, type.getId()); -// CorrelationAttributeInstance attr = new CorrelationAttributeInstance( -// domainValue, -// type, -// case1, dataSource1fromCase1, domainPath); -// EamDb.getInstance().addArtifactInstance(attr); -// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail("Error thrown while attempting to add domain attribute from single datasource " + ex.getMessage()); -// } -// -// // Test adding a device ID artifact -// try { -// CorrelationAttributeInstance attr = new CorrelationAttributeInstance( -// devIdValue, -// EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.USBID_TYPE_ID), -// case1, dataSource1fromCase1, devIdPath); -// -// EamDb.getInstance().addArtifactInstance(attr); -// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail("Error thrown while attempting to add device ID attribute from single datasource " + ex.getMessage()); -// } -// -// // Test CorrelationAttributeInstance creation -// try { -// new CorrelationAttributeInstance(fileType, randomHash()); -// } catch (CorrelationAttributeNormalizationException | EamDbException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail("Error Creating correlation attribute instance " + ex.getMessage()); -// } -// -// // Test adding instance with null case -// try { -// CorrelationAttributeInstance failAttrInst = new CorrelationAttributeInstance("badInstances", fileType, null, dataSource1fromCase2, BAD_PATH); -// EamDb.getInstance().addArtifactInstance(failAttrInst); -// fail("Error CorrelationAttributeNormalizationException was expected to be thrown making and adding a CorrelationAttributeInstance with null case and was not"); -// } catch (EamDbException ex) { -// fail("Error CorrelationAttributeNormalizationException was expected to be thrown making and adding a CorrelationAttributeInstance with null case, EamDbException was thrown instead " + ex.getMessage()); -// } catch (CorrelationAttributeNormalizationException ex) { -// // This is the expected behavior -// } -// -// // Test adding instance with invalid case ID -// try { -// CorrelationCase badCase = new CorrelationCase("badCaseUuid", "badCaseName"); -// CorrelationAttributeInstance failAttrInst2 = new CorrelationAttributeInstance(randomHash(), fileType, badCase, dataSource1fromCase2, BAD_PATH); -// EamDb.getInstance().addArtifactInstance(failAttrInst2); -// fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with invalid case ID and was not"); -// } catch (EamDbException ex) { -// // This is the expected behavior -// } catch (CorrelationAttributeNormalizationException ex) { -// fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with invalid case ID, CorrelationAttributeNormalizationException was thrown instead " + ex.getMessage()); -// } -// -// // Test adding instance with null data source -// try { -// CorrelationAttributeInstance failAttrInst3 = new CorrelationAttributeInstance(randomHash(), fileType, case1, null, BAD_PATH); -// EamDb.getInstance().addArtifactInstance(failAttrInst3); -// fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with null data source and was not"); -// } catch (EamDbException ex) { -// // This is the expected behavior -// } catch (CorrelationAttributeNormalizationException ex) { -// fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with null data source, CorrelationAttributeNormalizationException was thrown instead " + ex.getMessage()); -// } -// -// // Test adding instance with invalid data source ID -// try { -// CorrelationDataSource badDS = new CorrelationDataSource(case1, "badDSUuid", "badDSName"); -// CorrelationAttributeInstance failAttrInst4 = new CorrelationAttributeInstance(randomHash(), fileType, case1, badDS, BAD_PATH); -// EamDb.getInstance().addArtifactInstance(failAttrInst4); -// fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with invalid data source ID and was not"); -// } catch (EamDbException ex) { -// // This is the expected behavior -// } catch (CorrelationAttributeNormalizationException ex) { -// fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with invalid data source ID, CorrelationAttributeNormalizationException was thrown instead " + ex.getMessage()); -// } -// -// // Test adding instance with null path -// // This will fail in the CorrelationAttributeInstance constructor -// try { -// new CorrelationAttributeInstance(randomHash(), fileType, case1, dataSource1fromCase1, null); -// fail("Error EamDbException was expected to be thrown making a CorrelationAttributeInstance with null path and was not"); -// } catch (EamDbException ex) { -// // This is the expected behavior -// } catch (CorrelationAttributeNormalizationException ex) { -// fail("Error EamDbException was expected to be thrown making a CorrelationAttributeInstance with null path, CorrelationAttributeNormalizationException was thrown instead " + ex.getMessage()); -// } -// -// // Test adding instance with null known status -// try { -// CorrelationAttributeInstance failAttrInst5 = new CorrelationAttributeInstance("badInstances", fileType, case1, dataSource1fromCase1, null, "comment", null); -// EamDb.getInstance().addArtifactInstance(failAttrInst5); -// fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with null known status and was not"); -// } catch (EamDbException ex) { -// // This is the expected behavior -// } catch (CorrelationAttributeNormalizationException ex) { -// fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with null known status, CorrelationAttributeNormalizationException was thrown instead " + ex.getMessage()); -// } -// -// // Test CorrelationAttribute failure cases -// // Test null type -// try { -// CorrelationAttributeInstance attr = new CorrelationAttributeInstance(null, randomHash()); -// EamDb.getInstance().addArtifactInstance(attr); -// fail("Error CorrelationAttributeNormalizationException was expected to be thrown making and adding a CorrelationAttributeInstance with null type and was not"); -// } catch (EamDbException ex) { -// Exceptions.printStackTrace(ex); -// fail("Error CorrelationAttributeNormalizationException was expected to be thrown making and adding a CorrelationAttributeInstance with null type, EamDbException was thrown instead " + ex.getMessage()); -// } catch (CorrelationAttributeNormalizationException ex) { -// // This is the expected behavior -// } -// -// // Test null value -// // This will fail in the CorrelationAttribute constructor -// try { -// new CorrelationAttributeInstance(fileType, null); -// fail("Error CorrelationAttributeNormalizationException was expected to be thrown making a CorrelationAttributeInstance with null type and was not"); -// } catch (CorrelationAttributeNormalizationException ex) { -// // This is the expected behavior -// } catch (EamDbException ex) { -// fail("Error CorrelationAttributeNormalizationException was expected to be thrown making a CorrelationAttributeInstance with null type, EamDbException was thrown instead " + ex.getMessage()); -// } -// -// // Test getting instances with expected results -// try { -// List instances = EamDb.getInstance().getArtifactInstancesByTypeValue(fileType, inAllDataSourcesHash); -// assertEquals("Unexpected number of fileType instances gotten by type value for hash that should be in all 3 data sources", 3, instances.size()); -// -// // This test works because all the instances of this hash were set to the same path -// for (CorrelationAttributeInstance inst : instances) { -// assertTrue("getArtifactInstancesByTypeValue returned file instance with unexpected path " + inst.getFilePath() + " expected " + inAllDataSourcesPath, -// inAllDataSourcesPath.equalsIgnoreCase(inst.getFilePath())); -// } -// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail("Error exception thrown while getting attributes by type value " + ex.getMessage()); -// } -// -// // Test getting instances with mismatched data / data-type and expect an exception -// try { -// EamDb.getInstance().getArtifactInstancesByTypeValue(emailType, inAllDataSourcesHash); -// fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get email type attributes with a hash value"); -// } catch (EamDbException ex) { -// Exceptions.printStackTrace(ex); -// fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get email type attributes with a hash value, EamDbException was thrown instead " + ex.getMessage()); -// } catch (CorrelationAttributeNormalizationException ex) { -// //this is expected -// } -// -// // Test getting instances with null type -// try { -// EamDb.getInstance().getArtifactInstancesByTypeValue(null, inAllDataSourcesHash); -// fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get null type attributes with a hash value"); -// } catch (EamDbException ex) { -// Exceptions.printStackTrace(ex); -// fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get null type attributes with a hash value, EamDbException was thrown instead " + ex.getMessage()); -// } catch (CorrelationAttributeNormalizationException ex) { -// // This is the expected behavior -// } -// -// // Test getting instances with null value -// try { -// EamDb.getInstance().getArtifactInstancesByTypeValue(fileType, null); -// fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get file type attributes with a null value"); -// } catch (EamDbException ex) { -// Exceptions.printStackTrace(ex); -// fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get file type attributes with a null value, EamDbException was thrown instead " + ex.getMessage()); -// } catch (CorrelationAttributeNormalizationException ex) { -// //this is expected -// } -// -// // Test getting instances with path that should produce results -// try { -// List instances = EamDb.getInstance().getArtifactInstancesByPath(fileType, inAllDataSourcesPath); -// assertEquals("Unexpected number of fileType instances retrieved when getting file type attributes by path that should be in all 3 data sources", 3, instances.size()); -// } catch (EamDbException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail("Error EamDbException thrown while getting attributes when getting file type attributes by path" + ex.getMessage()); -// } -// -// // Test getting instances with path that should not produce results -// try { -// List instances = EamDb.getInstance().getArtifactInstancesByPath(fileType, "xyz"); -// assertEquals("Unexpected number of fileType instances retrieved when getting file type attributes by path that should not be in any data sources", 0, instances.size()); -// } catch (EamDbException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail("Error EamDbException thrown while getting attributes when getting file type attributes by path for path that should not exist" + ex.getMessage()); -// } -// -// // Test getting instances with null type -// try { -// EamDb.getInstance().getArtifactInstancesByPath(null, inAllDataSourcesPath); -// fail("Error EamDbException was expected to be thrown when getting null type attributes by path"); -// } catch (EamDbException ex) { -// // This is the expected behavior -// } -// -// // Test getting instances with null path -// try { -// EamDb.getInstance().getArtifactInstancesByPath(fileType, null); -// fail("Error EamDbException was expected to be thrown when getting file type attributes with null path"); -// } catch (EamDbException ex) { -// // This is the expected behavior -// } -// -// // Test getting instance count with path that should produce results -// try { -// long count = EamDb.getInstance().getCountArtifactInstancesByTypeValue(fileType, inAllDataSourcesHash); -// assertEquals("Unexpected number of fileType instances retrieved when getting count of file type value for hash that should be in all 3 data sources", 3, count); -// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail("Error Exception thrown while getting count of file type value for hash that should exist" + ex.getMessage()); -// } -// -// // Test getting instance count with path that should not produce results -// try { -// long count = EamDb.getInstance().getCountArtifactInstancesByTypeValue(fileType, unusedHashValue); -// assertEquals("Unexpected number of fileType instances retrieved when getting count of file type value for hash that should not be in any data sources", 0, count); -// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail("Error Exception thrown while getting count of file type value for hash that should not exist" + ex.getMessage()); -// } -// -// // Test getting instance count with null type -// try { -// EamDb.getInstance().getCountArtifactInstancesByTypeValue(null, inAllDataSourcesHash); -// fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get count of null type attributes with a hash value"); -// } catch (EamDbException ex) { -// Exceptions.printStackTrace(ex); -// fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get count of null type attributes with a hash value, EamDbException was thrown instead " + ex.getMessage()); -// } catch (CorrelationAttributeNormalizationException ex) { -// // This is the expected behavior -// } -// -// // Test getting instance count with null value -// try { -// EamDb.getInstance().getCountArtifactInstancesByTypeValue(fileType, null); -// fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get count of file type attributes with a null hash value"); -// } catch (EamDbException ex) { -// Exceptions.printStackTrace(ex); -// fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get count of null type attributes with a null hash value, EamDbException was thrown instead " + ex.getMessage()); -// } catch (CorrelationAttributeNormalizationException ex) { -// // This is the expected behavior -// } -// -// // Test getting frequency of value that is in all three data sources -// try { -// CorrelationAttributeInstance attr = new CorrelationAttributeInstance(fileType, inAllDataSourcesHash); -// int freq = EamDb.getInstance().getFrequencyPercentage(attr); -// assertEquals("Unexpected frequency value of file type returned for value that should exist in all data sources", 100, freq); -// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail("Error Exception thrown while getting frequency of file type value for hash that should exist in all data sources" + ex.getMessage()); -// } -// -// // Test getting frequency of value that appears twice in a single data source -// try { -// CorrelationAttributeInstance attr = new CorrelationAttributeInstance(fileType, inDataSource1twiceHash); -// int freq = EamDb.getInstance().getFrequencyPercentage(attr); -// assertEquals("Unexpected frequency value of file type returned for value that should exist in one of three data sources", 33, freq); -// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail("Error Exception thrown while getting frequency of file type value for hash that should exist in one of three data sources" + ex.getMessage()); -// } -// -// // Test getting frequency of non-file type -// try { -// CorrelationAttributeInstance attr = new CorrelationAttributeInstance(emailType, emailValue); -// int freq = EamDb.getInstance().getFrequencyPercentage(attr); -// assertEquals("Unexpected frequency value of email type returned for value that should exist in one of three data sources", 33, freq); -// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail("Error Exception thrown while getting frequency of eamil type value for value that should exist in one of three data sources" + ex.getMessage()); -// } -// -// // Test getting frequency of non-existent value -// try { -// CorrelationAttributeInstance attr = new CorrelationAttributeInstance(fileType, unusedHashValue); -// int freq = EamDb.getInstance().getFrequencyPercentage(attr); -// assertEquals("Unexpected frequency value of file type returned for value that should not exist in any data sources", 0, freq); -// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail("Error Exception thrown while getting frequency of eamil type value for value that should not exist in any data sources" + ex.getMessage()); -// } -// -// // Test getting frequency with null type -// try { -// CorrelationAttributeInstance attr = new CorrelationAttributeInstance(null, "randomValue"); -// EamDb.getInstance().getFrequencyPercentage(attr); -// fail("Error Exception was expected to be thrown when getting frequency of null type attribute"); -// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { -// // This is the expected behavior -// } -// -// // Test getting frequency with null attribute -// try { -// EamDb.getInstance().getFrequencyPercentage(null); -// fail("Error EamDbException was expected to be thrown when getting frequency of null attribute"); -// } catch (EamDbException ex) { -// // This is the expected behavior -// } catch (CorrelationAttributeNormalizationException ex) { -// Exceptions.printStackTrace(ex); -// fail("Error EamDbException was expected to be thrown when getting frequency of null attribute, CorrelationAttributeNormalizationException was thrown instead " + ex.getMessage()); -// fail(ex.getMessage()); -// } -// -// // Test updating a correlation attribute instance comment -// try { -// String comment = "new comment"; -// -// CorrelationAttributeInstance correlationAttribute = EamDb.getInstance().getCorrelationAttributeInstance( -// usbDeviceType, case1, dataSource1fromCase1, devIdValue, devIdPath); -// assertNotNull("Correlation Attribute returned was null when it should not have been", correlationAttribute); -// -// correlationAttribute.setComment(comment); -// EamDb.getInstance().updateAttributeInstanceComment(correlationAttribute); -// -// // Get a fresh copy to verify the update. -// correlationAttribute = EamDb.getInstance().getCorrelationAttributeInstance( -// usbDeviceType, case1, dataSource1fromCase1, devIdValue, devIdPath); -// assertEquals("Comment was not successfully set to expected value", -// comment, correlationAttribute.getComment()); -// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail("Error Exception thrown when setting and getting comment for attribute " + ex.getMessage()); -// } -// -// // Test getting count for dataSource1fromCase1 (includes all types) -// try { -// long count = EamDb.getInstance().getCountArtifactInstancesByCaseDataSource(case1.getCaseUUID(), dataSource1fromCase1.getDeviceID()); -// assertEquals("Unexpected count of artifact instances retrieved when getting count for case 1, data source 1", 7, count); -// } catch (EamDbException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail("Error EamDbException thrown when getting count of artifact instances for case 1, data source 1" + ex.getMessage()); -// } -// -// // Test getting count with null case UUID -// try { -// long count = EamDb.getInstance().getCountArtifactInstancesByCaseDataSource(null, dataSource1fromCase1.getDeviceID()); -// assertEquals("Unexpected count of artifact instances retrieved when getting count for null case, data source 1", 0, count); -// } catch (EamDbException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail("Error EamDbException thrown when getting count of artifact instances for null case, data source 1" + ex.getMessage()); -// } -// -// // Test getting count with null device ID -// try { -// long count = EamDb.getInstance().getCountArtifactInstancesByCaseDataSource(case1.getCaseUUID(), null); -// assertEquals("Unexpected count of artifact instances retrieved when getting count for case 1, null data source", 0, count); -// } catch (EamDbException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail("Error EamDbException thrown when getting count of artifact instances for case 1, null data source" + ex.getMessage()); -// } -// -// // Test getting data source count for entry that is in all three -// try { -// long count = EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(fileType, inAllDataSourcesHash); -// assertEquals("Unexpected count of data sources retrieved when getting count for file types with a hash that should exist in all three data sources", 3, count); -// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail("Error Exception thrown when getting count of data sources for file types with a hash that should exist in all three data sources" + ex.getMessage()); -// } -// -// // Test getting data source count for entry that is in one data source twice -// try { -// long count = EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(fileType, inDataSource1twiceHash); -// assertEquals("Unexpected count of data sources retrieved when getting count for file types with a hash that should exist in a single data source twice", 1, count); -// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail("Error Exception thrown when getting count of data sources for file types with a hash that should exist in a single data source twice" + ex.getMessage()); -// } -// -// // Test getting data source count for entry that is not in any data sources -// try { -// long count = EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(fileType, unusedHashValue); -// assertEquals("Unexpected count of data sources retrieved when getting count for file types with a hash that should not exist in any data source", 0, count); -// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail("Error Exception thrown when getting count of data sources for file types with a hash that should not exist in any data source" + ex.getMessage()); -// } -// -// // Test getting data source count for null type -// try { -// EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(null, unusedHashValue); -// fail("Error CorrelationAttributeNormalizationException was expected to be thrown when getting number of datasources containing null type attribute"); -// } catch (EamDbException ex) { -// Exceptions.printStackTrace(ex); -// fail("Error CorrelationAttributeNormalizationException was expected to be thrown when getting number of datasources containing null type attribute, EamDbException was thrown instead " + ex.getMessage()); -// } catch (CorrelationAttributeNormalizationException ex) { -// // This is the expected behavior -// } -// -// // Test getting data source count for null value -// try { -// EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(fileType, null); -// fail("Error CorrelationAttributeNormalizationException was expected to be thrown when getting number of datasources containing file type attribute with null hash"); -// } catch (EamDbException ex) { -// Exceptions.printStackTrace(ex); -// fail("Error CorrelationAttributeNormalizationException was expected to be thrown when getting number of datasources containing file type attribute with null hash, EamDbException was thrown instead " + ex.getMessage()); -// } catch (CorrelationAttributeNormalizationException ex) { -// //this is expected -// } -// -// // Test running processinstance which queries all rows from instances table -// try { -// // Add two instances to the central repository and use the callback query to verify we can see them -// CorrelationAttributeInstance attr1 = new CorrelationAttributeInstance(callbackTestFileHash, fileType, case1, dataSource1fromCase1, callbackTestFilePath1); -// CorrelationAttributeInstance attr2 = new CorrelationAttributeInstance(callbackTestFileHash, fileType, case1, dataSource1fromCase1, callbackTestFilePath2); -// EamDb DbManager = EamDb.getInstance(); -// DbManager.addArtifactInstance(attr1); -// DbManager.addArtifactInstance(attr2); -// AttributeInstanceTableCallback instancetableCallback = new AttributeInstanceTableCallback(); -// DbManager.processInstanceTable(fileType, instancetableCallback); -// int count1 = instancetableCallback.getCounter(); -// int count2 = instancetableCallback.getCounterNamingConvention(); -// assertEquals("Unexpected value for Process Instance count with filepath naming convention", 2, count2); -// assertTrue("Unexpected value for Process Instance count with filepath without naming convention: " + count1 + " - expected greater than 0", count1 > 0); -// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail("Error Exception thrown when calling processInstanceTable " + ex.getMessage()); -// } -// -// try { -// //test null inputs -// EamDb.getInstance().processInstanceTable(null, null); -// fail("Error EamDbException was expected to be thrown when calling processInstanceTable with null inputs"); -// } catch (EamDbException ex) { -// // This is the expected behavior -// } -// -// // Test running processinstance which queries all rows from instances table -// try { -// // Add two instances to the central repository and use the callback query to verify we can see them -// CorrelationAttributeInstance attr1 = new CorrelationAttributeInstance(callbackTestFileHash, fileType, case1, dataSource1fromCase1, callbackTestFilePath1); -// CorrelationAttributeInstance attr2 = new CorrelationAttributeInstance(callbackTestFileHash, fileType, case1, dataSource1fromCase1, callbackTestFilePath2); -// EamDb DbManager = EamDb.getInstance(); -// DbManager.addArtifactInstance(attr1); -// DbManager.addArtifactInstance(attr2); -// AttributeInstanceTableCallback instancetableCallback = new AttributeInstanceTableCallback(); -// DbManager.processInstanceTableWhere(fileType, "value='" + callbackTestFileHash + "'", instancetableCallback); -// int count1 = instancetableCallback.getCounter(); -// int count2 = instancetableCallback.getCounterNamingConvention(); -// assertEquals("Unexpected value for Process Instance Where count with filepath naming convention", 2, count2); -// assertTrue("Unexpected value for Process Instance Where count with filepath without naming convention: " + count1 + " - expected greater than 0", count1 > 0); -// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { -// Exceptions.printStackTrace(ex); -// Assert.fail("Error Exception thrown when calling processInstanceTableWhere " + ex.getMessage()); -// } -// try { -// //test null inputs -// EamDb.getInstance().processInstanceTableWhere(null, null, null); -// fail("Error EamDbException was expected to be thrown when calling processInstanceTableWhere with null inputs"); -// } catch (EamDbException ex) { -// // This is the expected behavior -// } + + //the hash value of all 0s has not been inserted + final String unusedHashValue = "00000000000000000000000000000000"; + + String inAllDataSourcesHash = "6cddb0e31787b79cfdcc0676b98a71ce"; + String inAllDataSourcesPath = "C:\\files\\path0.txt"; + String inDataSource1twiceHash = "b2f5ff47436671b6e533d8dc3614845d"; + String inDataSource1twicePath1 = "C:\\files\\path1.txt"; + String inDataSource1twicePath2 = "C:\\files\\path2.txt"; + String onlyInDataSource3Hash = "2af54305f183778d87de0c70c591fae4"; + String onlyInDataSource3Path = "C:\\files\\path3.txt"; + String callbackTestFilePath1 = "C:\\files\\processinstancecallback\\path1.txt"; + String callbackTestFilePath2 = "C:\\files\\processinstancecallback\\path2.txt"; + String callbackTestFileHash = "fb9dd8f04dacd3e82f4917f1a002223c"; + + // These will all go in dataSource1fromCase1 + String emailValue = "test@gmail.com"; + String emailPath = "C:\\files\\emailPath.txt"; + String phoneValue = "202-555-1234"; + String phonePath = "C:\\files\\phonePath.txt"; + String domainValue = "www.mozilla.com"; + String domainPath = "C:\\files\\domainPath.txt"; + String devIdValue = "94B21234"; + String devIdPath = "C:\\files\\devIdPath.txt"; + + // Store the email type + CorrelationAttributeInstance.Type emailType; //used again for other portions of this test + try { + emailType = EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.EMAIL_TYPE_ID); + assertEquals("Unexpected Correlation Type retrieved for Email type id", CorrelationAttributeInstance.EMAIL_TYPE_ID, emailType.getId()); + } catch (EamDbException ex) { + Exceptions.printStackTrace(ex); + Assert.fail("Error thrown while attempting to get email attribute " + ex.getMessage()); + return; + } + + // Test adding attribute with one instance + try { + CorrelationAttributeInstance attr = new CorrelationAttributeInstance(onlyInDataSource3Hash, fileType, case2, dataSource1fromCase2, onlyInDataSource3Path); + EamDb.getInstance().addArtifactInstance(attr); + } catch (EamDbException | CorrelationAttributeNormalizationException ex) { + Exceptions.printStackTrace(ex); + Assert.fail("Error thrown while attempting to add file attribute from single datasource the first time " + ex.getMessage()); + } + + // Test adding attribute with an instance in each data source + try { + CorrelationAttributeInstance attr1 = new CorrelationAttributeInstance(inAllDataSourcesHash, fileType, case1, dataSource1fromCase1, inAllDataSourcesPath); + EamDb.getInstance().addArtifactInstance(attr1); + CorrelationAttributeInstance attr2 = new CorrelationAttributeInstance(inAllDataSourcesHash, fileType, case1, dataSource2fromCase1, inAllDataSourcesPath); + EamDb.getInstance().addArtifactInstance(attr2); + CorrelationAttributeInstance attr3 = new CorrelationAttributeInstance(inAllDataSourcesHash, fileType, case2, dataSource1fromCase2, inAllDataSourcesPath); + EamDb.getInstance().addArtifactInstance(attr3); + + } catch (EamDbException | CorrelationAttributeNormalizationException ex) { + Exceptions.printStackTrace(ex); + Assert.fail("Error thrown while attempting to add file attribute from all 3 datasources " + ex.getMessage()); + } + + // Test adding attribute with two instances in one data source + try { + CorrelationAttributeInstance attr1 = new CorrelationAttributeInstance(inDataSource1twiceHash, fileType, case1, dataSource1fromCase1, inDataSource1twicePath1); + EamDb.getInstance().addArtifactInstance(attr1); + CorrelationAttributeInstance attr2 = new CorrelationAttributeInstance(inDataSource1twiceHash, fileType, case1, dataSource1fromCase1, inDataSource1twicePath2); + EamDb.getInstance().addArtifactInstance(attr2); + + } catch (EamDbException | CorrelationAttributeNormalizationException ex) { + Exceptions.printStackTrace(ex); + Assert.fail("Error thrown while attempting to add file attribute from single datasource the second time " + ex.getMessage()); + } + + // Test adding the other types + // Test adding an email artifact + try { + CorrelationAttributeInstance attr = new CorrelationAttributeInstance(emailValue, emailType, case1, dataSource1fromCase1, emailPath); + EamDb.getInstance().addArtifactInstance(attr); + } catch (EamDbException | CorrelationAttributeNormalizationException ex) { + Exceptions.printStackTrace(ex); + Assert.fail("Error thrown while attempting to add email attribute from single datasource " + ex.getMessage()); + } + + // Test adding a phone artifact + try { + CorrelationAttributeInstance attr = new CorrelationAttributeInstance( + phoneValue, + EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.PHONE_TYPE_ID), + case1, dataSource1fromCase1, phonePath); + + EamDb.getInstance().addArtifactInstance(attr); + } catch (EamDbException | CorrelationAttributeNormalizationException ex) { + Exceptions.printStackTrace(ex); + Assert.fail("Error thrown while attempting to add phone attribute from single datasource " + ex.getMessage()); + } + + // Test adding a domain artifact + try { + CorrelationAttributeInstance.Type type = EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.DOMAIN_TYPE_ID); + assertEquals("Unexpected Correlation Type retrieved for Domain type id", CorrelationAttributeInstance.DOMAIN_TYPE_ID, type.getId()); + CorrelationAttributeInstance attr = new CorrelationAttributeInstance( + domainValue, + type, + case1, dataSource1fromCase1, domainPath); + EamDb.getInstance().addArtifactInstance(attr); + } catch (EamDbException | CorrelationAttributeNormalizationException ex) { + Exceptions.printStackTrace(ex); + Assert.fail("Error thrown while attempting to add domain attribute from single datasource " + ex.getMessage()); + } + + // Test adding a device ID artifact + try { + CorrelationAttributeInstance attr = new CorrelationAttributeInstance( + devIdValue, + EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.USBID_TYPE_ID), + case1, dataSource1fromCase1, devIdPath); + + EamDb.getInstance().addArtifactInstance(attr); + } catch (EamDbException | CorrelationAttributeNormalizationException ex) { + Exceptions.printStackTrace(ex); + Assert.fail("Error thrown while attempting to add device ID attribute from single datasource " + ex.getMessage()); + } + + // Test CorrelationAttributeInstance creation + try { + new CorrelationAttributeInstance(fileType, randomHash()); + } catch (CorrelationAttributeNormalizationException | EamDbException ex) { + Exceptions.printStackTrace(ex); + Assert.fail("Error Creating correlation attribute instance " + ex.getMessage()); + } + + // Test adding instance with null case + try { + CorrelationAttributeInstance failAttrInst = new CorrelationAttributeInstance("badInstances", fileType, null, dataSource1fromCase2, BAD_PATH); + EamDb.getInstance().addArtifactInstance(failAttrInst); + fail("Error CorrelationAttributeNormalizationException was expected to be thrown making and adding a CorrelationAttributeInstance with null case and was not"); + } catch (EamDbException ex) { + fail("Error CorrelationAttributeNormalizationException was expected to be thrown making and adding a CorrelationAttributeInstance with null case, EamDbException was thrown instead " + ex.getMessage()); + } catch (CorrelationAttributeNormalizationException ex) { + // This is the expected behavior + } + + // Test adding instance with invalid case ID + try { + CorrelationCase badCase = new CorrelationCase("badCaseUuid", "badCaseName"); + CorrelationAttributeInstance failAttrInst2 = new CorrelationAttributeInstance(randomHash(), fileType, badCase, dataSource1fromCase2, BAD_PATH); + EamDb.getInstance().addArtifactInstance(failAttrInst2); + fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with invalid case ID and was not"); + } catch (EamDbException ex) { + // This is the expected behavior + } catch (CorrelationAttributeNormalizationException ex) { + fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with invalid case ID, CorrelationAttributeNormalizationException was thrown instead " + ex.getMessage()); + } + + // Test adding instance with null data source + try { + CorrelationAttributeInstance failAttrInst3 = new CorrelationAttributeInstance(randomHash(), fileType, case1, null, BAD_PATH); + EamDb.getInstance().addArtifactInstance(failAttrInst3); + fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with null data source and was not"); + } catch (EamDbException ex) { + // This is the expected behavior + } catch (CorrelationAttributeNormalizationException ex) { + fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with null data source, CorrelationAttributeNormalizationException was thrown instead " + ex.getMessage()); + } + + // Test adding instance with invalid data source ID + try { + CorrelationDataSource badDS = new CorrelationDataSource(case1, "badDSUuid", "badDSName"); + CorrelationAttributeInstance failAttrInst4 = new CorrelationAttributeInstance(randomHash(), fileType, case1, badDS, BAD_PATH); + EamDb.getInstance().addArtifactInstance(failAttrInst4); + fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with invalid data source ID and was not"); + } catch (EamDbException ex) { + // This is the expected behavior + } catch (CorrelationAttributeNormalizationException ex) { + fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with invalid data source ID, CorrelationAttributeNormalizationException was thrown instead " + ex.getMessage()); + } + + // Test adding instance with null path + // This will fail in the CorrelationAttributeInstance constructor + try { + new CorrelationAttributeInstance(randomHash(), fileType, case1, dataSource1fromCase1, null); + fail("Error EamDbException was expected to be thrown making a CorrelationAttributeInstance with null path and was not"); + } catch (EamDbException ex) { + // This is the expected behavior + } catch (CorrelationAttributeNormalizationException ex) { + fail("Error EamDbException was expected to be thrown making a CorrelationAttributeInstance with null path, CorrelationAttributeNormalizationException was thrown instead " + ex.getMessage()); + } + + // Test adding instance with null known status + try { + CorrelationAttributeInstance failAttrInst5 = new CorrelationAttributeInstance("badInstances", fileType, case1, dataSource1fromCase1, null, "comment", null); + EamDb.getInstance().addArtifactInstance(failAttrInst5); + fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with null known status and was not"); + } catch (EamDbException ex) { + // This is the expected behavior + } catch (CorrelationAttributeNormalizationException ex) { + fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with null known status, CorrelationAttributeNormalizationException was thrown instead " + ex.getMessage()); + } + + // Test CorrelationAttribute failure cases + // Test null type + try { + CorrelationAttributeInstance attr = new CorrelationAttributeInstance(null, randomHash()); + EamDb.getInstance().addArtifactInstance(attr); + fail("Error CorrelationAttributeNormalizationException was expected to be thrown making and adding a CorrelationAttributeInstance with null type and was not"); + } catch (EamDbException ex) { + Exceptions.printStackTrace(ex); + fail("Error CorrelationAttributeNormalizationException was expected to be thrown making and adding a CorrelationAttributeInstance with null type, EamDbException was thrown instead " + ex.getMessage()); + } catch (CorrelationAttributeNormalizationException ex) { + // This is the expected behavior + } + + // Test null value + // This will fail in the CorrelationAttribute constructor + try { + new CorrelationAttributeInstance(fileType, null); + fail("Error CorrelationAttributeNormalizationException was expected to be thrown making a CorrelationAttributeInstance with null type and was not"); + } catch (CorrelationAttributeNormalizationException ex) { + // This is the expected behavior + } catch (EamDbException ex) { + fail("Error CorrelationAttributeNormalizationException was expected to be thrown making a CorrelationAttributeInstance with null type, EamDbException was thrown instead " + ex.getMessage()); + } + + // Test getting instances with expected results + try { + List instances = EamDb.getInstance().getArtifactInstancesByTypeValue(fileType, inAllDataSourcesHash); + assertEquals("Unexpected number of fileType instances gotten by type value for hash that should be in all 3 data sources", 3, instances.size()); + + // This test works because all the instances of this hash were set to the same path + for (CorrelationAttributeInstance inst : instances) { + assertTrue("getArtifactInstancesByTypeValue returned file instance with unexpected path " + inst.getFilePath() + " expected " + inAllDataSourcesPath, + inAllDataSourcesPath.equalsIgnoreCase(inst.getFilePath())); + } + } catch (EamDbException | CorrelationAttributeNormalizationException ex) { + Exceptions.printStackTrace(ex); + Assert.fail("Error exception thrown while getting attributes by type value " + ex.getMessage()); + } + + // Test getting instances with mismatched data / data-type and expect an exception + try { + EamDb.getInstance().getArtifactInstancesByTypeValue(emailType, inAllDataSourcesHash); + fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get email type attributes with a hash value"); + } catch (EamDbException ex) { + Exceptions.printStackTrace(ex); + fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get email type attributes with a hash value, EamDbException was thrown instead " + ex.getMessage()); + } catch (CorrelationAttributeNormalizationException ex) { + //this is expected + } + + // Test getting instances with null type + try { + EamDb.getInstance().getArtifactInstancesByTypeValue(null, inAllDataSourcesHash); + fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get null type attributes with a hash value"); + } catch (EamDbException ex) { + Exceptions.printStackTrace(ex); + fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get null type attributes with a hash value, EamDbException was thrown instead " + ex.getMessage()); + } catch (CorrelationAttributeNormalizationException ex) { + // This is the expected behavior + } + + // Test getting instances with null value + try { + EamDb.getInstance().getArtifactInstancesByTypeValue(fileType, null); + fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get file type attributes with a null value"); + } catch (EamDbException ex) { + Exceptions.printStackTrace(ex); + fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get file type attributes with a null value, EamDbException was thrown instead " + ex.getMessage()); + } catch (CorrelationAttributeNormalizationException ex) { + //this is expected + } + + // Test getting instances with path that should produce results + try { + List instances = EamDb.getInstance().getArtifactInstancesByPath(fileType, inAllDataSourcesPath); + assertEquals("Unexpected number of fileType instances retrieved when getting file type attributes by path that should be in all 3 data sources", 3, instances.size()); + } catch (EamDbException ex) { + Exceptions.printStackTrace(ex); + Assert.fail("Error EamDbException thrown while getting attributes when getting file type attributes by path" + ex.getMessage()); + } + + // Test getting instances with path that should not produce results + try { + List instances = EamDb.getInstance().getArtifactInstancesByPath(fileType, "xyz"); + assertEquals("Unexpected number of fileType instances retrieved when getting file type attributes by path that should not be in any data sources", 0, instances.size()); + } catch (EamDbException ex) { + Exceptions.printStackTrace(ex); + Assert.fail("Error EamDbException thrown while getting attributes when getting file type attributes by path for path that should not exist" + ex.getMessage()); + } + + // Test getting instances with null type + try { + EamDb.getInstance().getArtifactInstancesByPath(null, inAllDataSourcesPath); + fail("Error EamDbException was expected to be thrown when getting null type attributes by path"); + } catch (EamDbException ex) { + // This is the expected behavior + } + + // Test getting instances with null path + try { + EamDb.getInstance().getArtifactInstancesByPath(fileType, null); + fail("Error EamDbException was expected to be thrown when getting file type attributes with null path"); + } catch (EamDbException ex) { + // This is the expected behavior + } + + // Test getting instance count with path that should produce results + try { + long count = EamDb.getInstance().getCountArtifactInstancesByTypeValue(fileType, inAllDataSourcesHash); + assertEquals("Unexpected number of fileType instances retrieved when getting count of file type value for hash that should be in all 3 data sources", 3, count); + } catch (EamDbException | CorrelationAttributeNormalizationException ex) { + Exceptions.printStackTrace(ex); + Assert.fail("Error Exception thrown while getting count of file type value for hash that should exist" + ex.getMessage()); + } + + // Test getting instance count with path that should not produce results + try { + long count = EamDb.getInstance().getCountArtifactInstancesByTypeValue(fileType, unusedHashValue); + assertEquals("Unexpected number of fileType instances retrieved when getting count of file type value for hash that should not be in any data sources", 0, count); + } catch (EamDbException | CorrelationAttributeNormalizationException ex) { + Exceptions.printStackTrace(ex); + Assert.fail("Error Exception thrown while getting count of file type value for hash that should not exist" + ex.getMessage()); + } + + // Test getting instance count with null type + try { + EamDb.getInstance().getCountArtifactInstancesByTypeValue(null, inAllDataSourcesHash); + fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get count of null type attributes with a hash value"); + } catch (EamDbException ex) { + Exceptions.printStackTrace(ex); + fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get count of null type attributes with a hash value, EamDbException was thrown instead " + ex.getMessage()); + } catch (CorrelationAttributeNormalizationException ex) { + // This is the expected behavior + } + + // Test getting instance count with null value + try { + EamDb.getInstance().getCountArtifactInstancesByTypeValue(fileType, null); + fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get count of file type attributes with a null hash value"); + } catch (EamDbException ex) { + Exceptions.printStackTrace(ex); + fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get count of null type attributes with a null hash value, EamDbException was thrown instead " + ex.getMessage()); + } catch (CorrelationAttributeNormalizationException ex) { + // This is the expected behavior + } + + // Test getting frequency of value that is in all three data sources + try { + CorrelationAttributeInstance attr = new CorrelationAttributeInstance(fileType, inAllDataSourcesHash); + int freq = EamDb.getInstance().getFrequencyPercentage(attr); + assertEquals("Unexpected frequency value of file type returned for value that should exist in all data sources", 100, freq); + } catch (EamDbException | CorrelationAttributeNormalizationException ex) { + Exceptions.printStackTrace(ex); + Assert.fail("Error Exception thrown while getting frequency of file type value for hash that should exist in all data sources" + ex.getMessage()); + } + + // Test getting frequency of value that appears twice in a single data source + try { + CorrelationAttributeInstance attr = new CorrelationAttributeInstance(fileType, inDataSource1twiceHash); + int freq = EamDb.getInstance().getFrequencyPercentage(attr); + assertEquals("Unexpected frequency value of file type returned for value that should exist in one of three data sources", 33, freq); + } catch (EamDbException | CorrelationAttributeNormalizationException ex) { + Exceptions.printStackTrace(ex); + Assert.fail("Error Exception thrown while getting frequency of file type value for hash that should exist in one of three data sources" + ex.getMessage()); + } + + // Test getting frequency of non-file type + try { + CorrelationAttributeInstance attr = new CorrelationAttributeInstance(emailType, emailValue); + int freq = EamDb.getInstance().getFrequencyPercentage(attr); + assertEquals("Unexpected frequency value of email type returned for value that should exist in one of three data sources", 33, freq); + } catch (EamDbException | CorrelationAttributeNormalizationException ex) { + Exceptions.printStackTrace(ex); + Assert.fail("Error Exception thrown while getting frequency of eamil type value for value that should exist in one of three data sources" + ex.getMessage()); + } + + // Test getting frequency of non-existent value + try { + CorrelationAttributeInstance attr = new CorrelationAttributeInstance(fileType, unusedHashValue); + int freq = EamDb.getInstance().getFrequencyPercentage(attr); + assertEquals("Unexpected frequency value of file type returned for value that should not exist in any data sources", 0, freq); + } catch (EamDbException | CorrelationAttributeNormalizationException ex) { + Exceptions.printStackTrace(ex); + Assert.fail("Error Exception thrown while getting frequency of eamil type value for value that should not exist in any data sources" + ex.getMessage()); + } + + // Test getting frequency with null type + try { + CorrelationAttributeInstance attr = new CorrelationAttributeInstance(null, "randomValue"); + EamDb.getInstance().getFrequencyPercentage(attr); + fail("Error Exception was expected to be thrown when getting frequency of null type attribute"); + } catch (EamDbException | CorrelationAttributeNormalizationException ex) { + // This is the expected behavior + } + + // Test getting frequency with null attribute + try { + EamDb.getInstance().getFrequencyPercentage(null); + fail("Error EamDbException was expected to be thrown when getting frequency of null attribute"); + } catch (EamDbException ex) { + // This is the expected behavior + } catch (CorrelationAttributeNormalizationException ex) { + Exceptions.printStackTrace(ex); + fail("Error EamDbException was expected to be thrown when getting frequency of null attribute, CorrelationAttributeNormalizationException was thrown instead " + ex.getMessage()); + fail(ex.getMessage()); + } + + // Test updating a correlation attribute instance comment + try { + String comment = "new comment"; + + CorrelationAttributeInstance correlationAttribute = EamDb.getInstance().getCorrelationAttributeInstance( + usbDeviceType, case1, dataSource1fromCase1, devIdValue, devIdPath); + assertNotNull("Correlation Attribute returned was null when it should not have been", correlationAttribute); + + correlationAttribute.setComment(comment); + EamDb.getInstance().updateAttributeInstanceComment(correlationAttribute); + + // Get a fresh copy to verify the update. + correlationAttribute = EamDb.getInstance().getCorrelationAttributeInstance( + usbDeviceType, case1, dataSource1fromCase1, devIdValue, devIdPath); + assertEquals("Comment was not successfully set to expected value", + comment, correlationAttribute.getComment()); + } catch (EamDbException | CorrelationAttributeNormalizationException ex) { + Exceptions.printStackTrace(ex); + Assert.fail("Error Exception thrown when setting and getting comment for attribute " + ex.getMessage()); + } + + // Test getting count for dataSource1fromCase1 (includes all types) + try { + long count = EamDb.getInstance().getCountArtifactInstancesByCaseDataSource(case1.getCaseUUID(), dataSource1fromCase1.getDeviceID()); + assertEquals("Unexpected count of artifact instances retrieved when getting count for case 1, data source 1", 7, count); + } catch (EamDbException ex) { + Exceptions.printStackTrace(ex); + Assert.fail("Error EamDbException thrown when getting count of artifact instances for case 1, data source 1" + ex.getMessage()); + } + + // Test getting count with null case UUID + try { + long count = EamDb.getInstance().getCountArtifactInstancesByCaseDataSource(null, dataSource1fromCase1.getDeviceID()); + assertEquals("Unexpected count of artifact instances retrieved when getting count for null case, data source 1", 0, count); + } catch (EamDbException ex) { + Exceptions.printStackTrace(ex); + Assert.fail("Error EamDbException thrown when getting count of artifact instances for null case, data source 1" + ex.getMessage()); + } + + // Test getting count with null device ID + try { + long count = EamDb.getInstance().getCountArtifactInstancesByCaseDataSource(case1.getCaseUUID(), null); + assertEquals("Unexpected count of artifact instances retrieved when getting count for case 1, null data source", 0, count); + } catch (EamDbException ex) { + Exceptions.printStackTrace(ex); + Assert.fail("Error EamDbException thrown when getting count of artifact instances for case 1, null data source" + ex.getMessage()); + } + + // Test getting data source count for entry that is in all three + try { + long count = EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(fileType, inAllDataSourcesHash); + assertEquals("Unexpected count of data sources retrieved when getting count for file types with a hash that should exist in all three data sources", 3, count); + } catch (EamDbException | CorrelationAttributeNormalizationException ex) { + Exceptions.printStackTrace(ex); + Assert.fail("Error Exception thrown when getting count of data sources for file types with a hash that should exist in all three data sources" + ex.getMessage()); + } + + // Test getting data source count for entry that is in one data source twice + try { + long count = EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(fileType, inDataSource1twiceHash); + assertEquals("Unexpected count of data sources retrieved when getting count for file types with a hash that should exist in a single data source twice", 1, count); + } catch (EamDbException | CorrelationAttributeNormalizationException ex) { + Exceptions.printStackTrace(ex); + Assert.fail("Error Exception thrown when getting count of data sources for file types with a hash that should exist in a single data source twice" + ex.getMessage()); + } + + // Test getting data source count for entry that is not in any data sources + try { + long count = EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(fileType, unusedHashValue); + assertEquals("Unexpected count of data sources retrieved when getting count for file types with a hash that should not exist in any data source", 0, count); + } catch (EamDbException | CorrelationAttributeNormalizationException ex) { + Exceptions.printStackTrace(ex); + Assert.fail("Error Exception thrown when getting count of data sources for file types with a hash that should not exist in any data source" + ex.getMessage()); + } + + // Test getting data source count for null type + try { + EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(null, unusedHashValue); + fail("Error CorrelationAttributeNormalizationException was expected to be thrown when getting number of datasources containing null type attribute"); + } catch (EamDbException ex) { + Exceptions.printStackTrace(ex); + fail("Error CorrelationAttributeNormalizationException was expected to be thrown when getting number of datasources containing null type attribute, EamDbException was thrown instead " + ex.getMessage()); + } catch (CorrelationAttributeNormalizationException ex) { + // This is the expected behavior + } + + // Test getting data source count for null value + try { + EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(fileType, null); + fail("Error CorrelationAttributeNormalizationException was expected to be thrown when getting number of datasources containing file type attribute with null hash"); + } catch (EamDbException ex) { + Exceptions.printStackTrace(ex); + fail("Error CorrelationAttributeNormalizationException was expected to be thrown when getting number of datasources containing file type attribute with null hash, EamDbException was thrown instead " + ex.getMessage()); + } catch (CorrelationAttributeNormalizationException ex) { + //this is expected + } + + // Test running processinstance which queries all rows from instances table + try { + // Add two instances to the central repository and use the callback query to verify we can see them + CorrelationAttributeInstance attr1 = new CorrelationAttributeInstance(callbackTestFileHash, fileType, case1, dataSource1fromCase1, callbackTestFilePath1); + CorrelationAttributeInstance attr2 = new CorrelationAttributeInstance(callbackTestFileHash, fileType, case1, dataSource1fromCase1, callbackTestFilePath2); + EamDb DbManager = EamDb.getInstance(); + DbManager.addArtifactInstance(attr1); + DbManager.addArtifactInstance(attr2); + AttributeInstanceTableCallback instancetableCallback = new AttributeInstanceTableCallback(); + DbManager.processInstanceTable(fileType, instancetableCallback); + int count1 = instancetableCallback.getCounter(); + int count2 = instancetableCallback.getCounterNamingConvention(); + //expects 2 rows to match the naming convention to of been processed, expects at least one row not matching the naming convention to be processed + //if the test code is changed to add additional Correlation Attributes which also have "processinstancecallback" in their path the first of these comparisons will need to change + assertEquals("Counter for items matching naming convention from AttributeInstaceTableCallback indicates an unexepected number of results when processed with DbManager.processInstanceTable", 2, count2); + assertTrue("Counter for items which do not match naming convention from AttributeInstaceTableCallback indicates an unexepected number of results when processed with DbManager.processInstanceTable. Count indicated: " + count1 + " - expected a number greater than 0", count1 > 0); + } catch (EamDbException | CorrelationAttributeNormalizationException ex) { + Exceptions.printStackTrace(ex); + Assert.fail("Error Exception thrown when calling processInstanceTable " + ex.getMessage()); + } + + try { + //test null inputs + EamDb.getInstance().processInstanceTable(null, null); + fail("Error EamDbException was expected to be thrown when calling processInstanceTable with null inputs"); + } catch (EamDbException ex) { + // This is the expected behavior + } + + // Test running processinstance which queries all rows from instances table + try { + // Add two instances to the central repository and use the callback query to verify we can see them + CorrelationAttributeInstance attr1 = new CorrelationAttributeInstance(callbackTestFileHash, fileType, case1, dataSource1fromCase1, callbackTestFilePath1); + CorrelationAttributeInstance attr2 = new CorrelationAttributeInstance(callbackTestFileHash, fileType, case1, dataSource1fromCase1, callbackTestFilePath2); + EamDb DbManager = EamDb.getInstance(); + //these redundant addArtifactInstance calls allow code to be rearranged if necessary + DbManager.addArtifactInstance(attr1); + DbManager.addArtifactInstance(attr2); + AttributeInstanceTableCallback instancetableCallback = new AttributeInstanceTableCallback(); + DbManager.processInstanceTableWhere(fileType, "value='" + callbackTestFileHash + "'", instancetableCallback); + int count1 = instancetableCallback.getCounter(); + //naming convention counts + int count2 = instancetableCallback.getCounterNamingConvention(); + //this has only processed the rows where the value is equal to the specified value, which should only be the two rows with the naming convention checked for + //if the test code is changed to add additional Correlation Attributes with the same callbackTestFileHash value that is used here these comparisons will need to change + assertEquals("Counter for items matching naming convention from AttributeInstaceTableCallback indicates an unexepected number of results when processed with DbManager.processInstanceTableWhere", 2, count2); + assertEquals("Counter for items which do not match naming convention from AttributeInstaceTableCallback indicates an unexepected number of results when processed with DbManager.processInstanceTableWhere", 0, count1); + } catch (EamDbException | CorrelationAttributeNormalizationException ex) { + Exceptions.printStackTrace(ex); + Assert.fail("Error Exception thrown when calling processInstanceTableWhere " + ex.getMessage()); + } + try { + //test null inputs + EamDb.getInstance().processInstanceTableWhere(null, null, null); + fail("Error EamDbException was expected to be thrown when calling processInstanceTableWhere with null inputs"); + } catch (EamDbException ex) { + // This is the expected behavior + } } /** From f44031d344980691e68c2f243d22a427bbb4c885 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 27 Sep 2018 11:31:43 -0400 Subject: [PATCH 02/42] 4242 return now fixed test to commented out state awaiting 4241 changes --- .../datamodel/CentralRepoDatamodelTest.java | 1316 ++++++++--------- 1 file changed, 658 insertions(+), 658 deletions(-) diff --git a/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDatamodelTest.java b/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDatamodelTest.java index 944dd7272e..2a7f76b5e2 100755 --- a/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDatamodelTest.java +++ b/Core/test/qa-functional/src/org/sleuthkit/autopsy/centralrepository/datamodel/CentralRepoDatamodelTest.java @@ -88,109 +88,109 @@ public class CentralRepoDatamodelTest extends TestCase { @Override public void setUp() { - dbSettingsSqlite = new SqliteEamDbSettings(); - - // Delete the test directory, if it exists - if (testDirectory.toFile().exists()) { - try { - FileUtils.deleteDirectory(testDirectory.toFile()); - } catch (IOException ex) { - Assert.fail(ex.getMessage()); - } - } - assertFalse("Unable to delete existing test directory", testDirectory.toFile().exists()); - - // Create the test directory - testDirectory.toFile().mkdirs(); - assertTrue("Unable to create test directory", testDirectory.toFile().exists()); - - // Save the current central repo settings - propertiesMap = ModuleSettings.getConfigSettings(PROPERTIES_FILE); - - try { - dbSettingsSqlite.setDbName(CR_DB_NAME); - dbSettingsSqlite.setDbDirectory(testDirectory.toString()); - if (!dbSettingsSqlite.dbDirectoryExists()) { - dbSettingsSqlite.createDbDirectory(); - } - - assertTrue("Failed to created central repo directory " + dbSettingsSqlite.getDbDirectory(), dbSettingsSqlite.dbDirectoryExists()); - - boolean result = dbSettingsSqlite.initializeDatabaseSchema() - && dbSettingsSqlite.insertDefaultDatabaseContent(); - - assertTrue("Failed to initialize central repo database", result); - - dbSettingsSqlite.saveSettings(); - EamDbUtil.setUseCentralRepo(true); - EamDbPlatformEnum.setSelectedPlatform(EamDbPlatformEnum.SQLITE.name()); - EamDbPlatformEnum.saveSelectedPlatform(); - } catch (EamDbException ex) { - Exceptions.printStackTrace(ex); - Assert.fail(ex.getMessage()); - } - - Path crDbFilePath = Paths.get(testDirectory.toString(), CR_DB_NAME); - assertTrue("Failed to create central repo database at " + crDbFilePath, crDbFilePath.toFile().exists()); - - // Set up some default objects to be used by the tests - try { - case1 = new CorrelationCase("case1_uuid", "case1"); - case1 = EamDb.getInstance().newCase(case1); - assertTrue("Failed to create test object case1", case1 != null); - - case2 = new CorrelationCase("case2_uuid", "case2"); - case2 = EamDb.getInstance().newCase(case2); - assertTrue("Failed to create test object case2", case2 != null); - - dataSource1fromCase1 = new CorrelationDataSource(case1, "dataSource1_deviceID", "dataSource1"); - EamDb.getInstance().newDataSource(dataSource1fromCase1); - dataSource1fromCase1 = EamDb.getInstance().getDataSource(case1, dataSource1fromCase1.getDeviceID()); - assertTrue("Failed to create test object dataSource1fromCase1", dataSource1fromCase1 != null); - - dataSource2fromCase1 = new CorrelationDataSource(case1, "dataSource2_deviceID", "dataSource2"); - EamDb.getInstance().newDataSource(dataSource2fromCase1); - dataSource2fromCase1 = EamDb.getInstance().getDataSource(case1, dataSource2fromCase1.getDeviceID()); - assertTrue("Failed to create test object dataSource2fromCase1", dataSource2fromCase1 != null); - - dataSource1fromCase2 = new CorrelationDataSource(case2, "dataSource3_deviceID", "dataSource3"); - EamDb.getInstance().newDataSource(dataSource1fromCase2); - dataSource1fromCase2 = EamDb.getInstance().getDataSource(case2, dataSource1fromCase2.getDeviceID()); - assertTrue("Failed to create test object dataSource1fromCase2", dataSource1fromCase2 != null); - - org1 = new EamOrganization("org1"); - org1 = EamDb.getInstance().newOrganization(org1); - - org2 = new EamOrganization("org2"); - org2 = EamDb.getInstance().newOrganization(org2); - - // Store the file type object for later use - fileType = EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID); - assertTrue("getCorrelationTypeById(FILES_TYPE_ID) returned null", fileType != null); - usbDeviceType = EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.USBID_TYPE_ID); - assertTrue("getCorrelationTypeById(USBID_TYPE_ID) returned null", usbDeviceType != null); - - } catch (EamDbException ex) { - Exceptions.printStackTrace(ex); - Assert.fail(ex.getMessage()); - } +// dbSettingsSqlite = new SqliteEamDbSettings(); +// +// // Delete the test directory, if it exists +// if (testDirectory.toFile().exists()) { +// try { +// FileUtils.deleteDirectory(testDirectory.toFile()); +// } catch (IOException ex) { +// Assert.fail(ex.getMessage()); +// } +// } +// assertFalse("Unable to delete existing test directory", testDirectory.toFile().exists()); +// +// // Create the test directory +// testDirectory.toFile().mkdirs(); +// assertTrue("Unable to create test directory", testDirectory.toFile().exists()); +// +// // Save the current central repo settings +// propertiesMap = ModuleSettings.getConfigSettings(PROPERTIES_FILE); +// +// try { +// dbSettingsSqlite.setDbName(CR_DB_NAME); +// dbSettingsSqlite.setDbDirectory(testDirectory.toString()); +// if (!dbSettingsSqlite.dbDirectoryExists()) { +// dbSettingsSqlite.createDbDirectory(); +// } +// +// assertTrue("Failed to created central repo directory " + dbSettingsSqlite.getDbDirectory(), dbSettingsSqlite.dbDirectoryExists()); +// +// boolean result = dbSettingsSqlite.initializeDatabaseSchema() +// && dbSettingsSqlite.insertDefaultDatabaseContent(); +// +// assertTrue("Failed to initialize central repo database", result); +// +// dbSettingsSqlite.saveSettings(); +// EamDbUtil.setUseCentralRepo(true); +// EamDbPlatformEnum.setSelectedPlatform(EamDbPlatformEnum.SQLITE.name()); +// EamDbPlatformEnum.saveSelectedPlatform(); +// } catch (EamDbException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail(ex.getMessage()); +// } +// +// Path crDbFilePath = Paths.get(testDirectory.toString(), CR_DB_NAME); +// assertTrue("Failed to create central repo database at " + crDbFilePath, crDbFilePath.toFile().exists()); +// +// // Set up some default objects to be used by the tests +// try { +// case1 = new CorrelationCase("case1_uuid", "case1"); +// case1 = EamDb.getInstance().newCase(case1); +// assertTrue("Failed to create test object case1", case1 != null); +// +// case2 = new CorrelationCase("case2_uuid", "case2"); +// case2 = EamDb.getInstance().newCase(case2); +// assertTrue("Failed to create test object case2", case2 != null); +// +// dataSource1fromCase1 = new CorrelationDataSource(case1, "dataSource1_deviceID", "dataSource1"); +// EamDb.getInstance().newDataSource(dataSource1fromCase1); +// dataSource1fromCase1 = EamDb.getInstance().getDataSource(case1, dataSource1fromCase1.getDeviceID()); +// assertTrue("Failed to create test object dataSource1fromCase1", dataSource1fromCase1 != null); +// +// dataSource2fromCase1 = new CorrelationDataSource(case1, "dataSource2_deviceID", "dataSource2"); +// EamDb.getInstance().newDataSource(dataSource2fromCase1); +// dataSource2fromCase1 = EamDb.getInstance().getDataSource(case1, dataSource2fromCase1.getDeviceID()); +// assertTrue("Failed to create test object dataSource2fromCase1", dataSource2fromCase1 != null); +// +// dataSource1fromCase2 = new CorrelationDataSource(case2, "dataSource3_deviceID", "dataSource3"); +// EamDb.getInstance().newDataSource(dataSource1fromCase2); +// dataSource1fromCase2 = EamDb.getInstance().getDataSource(case2, dataSource1fromCase2.getDeviceID()); +// assertTrue("Failed to create test object dataSource1fromCase2", dataSource1fromCase2 != null); +// +// org1 = new EamOrganization("org1"); +// org1 = EamDb.getInstance().newOrganization(org1); +// +// org2 = new EamOrganization("org2"); +// org2 = EamDb.getInstance().newOrganization(org2); +// +// // Store the file type object for later use +// fileType = EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.FILES_TYPE_ID); +// assertTrue("getCorrelationTypeById(FILES_TYPE_ID) returned null", fileType != null); +// usbDeviceType = EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.USBID_TYPE_ID); +// assertTrue("getCorrelationTypeById(USBID_TYPE_ID) returned null", usbDeviceType != null); +// +// } catch (EamDbException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail(ex.getMessage()); +// } } @Override public void tearDown() { - - // Restore the original properties - ModuleSettings.setConfigSettings(PROPERTIES_FILE, propertiesMap); - - // Close and delete the test case and central repo db - try { - EamDb.getInstance().shutdownConnections(); - FileUtils.deleteDirectory(testDirectory.toFile()); - } catch (EamDbException | IOException ex) { - Exceptions.printStackTrace(ex); - Assert.fail(ex.getMessage()); - } - assertFalse("Error deleting test directory " + testDirectory.toString(), testDirectory.toFile().exists()); +// +// // Restore the original properties +// ModuleSettings.setConfigSettings(PROPERTIES_FILE, propertiesMap); +// +// // Close and delete the test case and central repo db +// try { +// EamDb.getInstance().shutdownConnections(); +// FileUtils.deleteDirectory(testDirectory.toFile()); +// } catch (EamDbException | IOException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail(ex.getMessage()); +// } +// assertFalse("Error deleting test directory " + testDirectory.toString(), testDirectory.toFile().exists()); } /** @@ -659,565 +659,565 @@ public class CentralRepoDatamodelTest extends TestCase { * with null type - Test with null value */ public void testArtifacts() { - - //the hash value of all 0s has not been inserted - final String unusedHashValue = "00000000000000000000000000000000"; - - String inAllDataSourcesHash = "6cddb0e31787b79cfdcc0676b98a71ce"; - String inAllDataSourcesPath = "C:\\files\\path0.txt"; - String inDataSource1twiceHash = "b2f5ff47436671b6e533d8dc3614845d"; - String inDataSource1twicePath1 = "C:\\files\\path1.txt"; - String inDataSource1twicePath2 = "C:\\files\\path2.txt"; - String onlyInDataSource3Hash = "2af54305f183778d87de0c70c591fae4"; - String onlyInDataSource3Path = "C:\\files\\path3.txt"; - String callbackTestFilePath1 = "C:\\files\\processinstancecallback\\path1.txt"; - String callbackTestFilePath2 = "C:\\files\\processinstancecallback\\path2.txt"; - String callbackTestFileHash = "fb9dd8f04dacd3e82f4917f1a002223c"; - - // These will all go in dataSource1fromCase1 - String emailValue = "test@gmail.com"; - String emailPath = "C:\\files\\emailPath.txt"; - String phoneValue = "202-555-1234"; - String phonePath = "C:\\files\\phonePath.txt"; - String domainValue = "www.mozilla.com"; - String domainPath = "C:\\files\\domainPath.txt"; - String devIdValue = "94B21234"; - String devIdPath = "C:\\files\\devIdPath.txt"; - - // Store the email type - CorrelationAttributeInstance.Type emailType; //used again for other portions of this test - try { - emailType = EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.EMAIL_TYPE_ID); - assertEquals("Unexpected Correlation Type retrieved for Email type id", CorrelationAttributeInstance.EMAIL_TYPE_ID, emailType.getId()); - } catch (EamDbException ex) { - Exceptions.printStackTrace(ex); - Assert.fail("Error thrown while attempting to get email attribute " + ex.getMessage()); - return; - } - - // Test adding attribute with one instance - try { - CorrelationAttributeInstance attr = new CorrelationAttributeInstance(onlyInDataSource3Hash, fileType, case2, dataSource1fromCase2, onlyInDataSource3Path); - EamDb.getInstance().addArtifactInstance(attr); - } catch (EamDbException | CorrelationAttributeNormalizationException ex) { - Exceptions.printStackTrace(ex); - Assert.fail("Error thrown while attempting to add file attribute from single datasource the first time " + ex.getMessage()); - } - - // Test adding attribute with an instance in each data source - try { - CorrelationAttributeInstance attr1 = new CorrelationAttributeInstance(inAllDataSourcesHash, fileType, case1, dataSource1fromCase1, inAllDataSourcesPath); - EamDb.getInstance().addArtifactInstance(attr1); - CorrelationAttributeInstance attr2 = new CorrelationAttributeInstance(inAllDataSourcesHash, fileType, case1, dataSource2fromCase1, inAllDataSourcesPath); - EamDb.getInstance().addArtifactInstance(attr2); - CorrelationAttributeInstance attr3 = new CorrelationAttributeInstance(inAllDataSourcesHash, fileType, case2, dataSource1fromCase2, inAllDataSourcesPath); - EamDb.getInstance().addArtifactInstance(attr3); - - } catch (EamDbException | CorrelationAttributeNormalizationException ex) { - Exceptions.printStackTrace(ex); - Assert.fail("Error thrown while attempting to add file attribute from all 3 datasources " + ex.getMessage()); - } - - // Test adding attribute with two instances in one data source - try { - CorrelationAttributeInstance attr1 = new CorrelationAttributeInstance(inDataSource1twiceHash, fileType, case1, dataSource1fromCase1, inDataSource1twicePath1); - EamDb.getInstance().addArtifactInstance(attr1); - CorrelationAttributeInstance attr2 = new CorrelationAttributeInstance(inDataSource1twiceHash, fileType, case1, dataSource1fromCase1, inDataSource1twicePath2); - EamDb.getInstance().addArtifactInstance(attr2); - - } catch (EamDbException | CorrelationAttributeNormalizationException ex) { - Exceptions.printStackTrace(ex); - Assert.fail("Error thrown while attempting to add file attribute from single datasource the second time " + ex.getMessage()); - } - - // Test adding the other types - // Test adding an email artifact - try { - CorrelationAttributeInstance attr = new CorrelationAttributeInstance(emailValue, emailType, case1, dataSource1fromCase1, emailPath); - EamDb.getInstance().addArtifactInstance(attr); - } catch (EamDbException | CorrelationAttributeNormalizationException ex) { - Exceptions.printStackTrace(ex); - Assert.fail("Error thrown while attempting to add email attribute from single datasource " + ex.getMessage()); - } - - // Test adding a phone artifact - try { - CorrelationAttributeInstance attr = new CorrelationAttributeInstance( - phoneValue, - EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.PHONE_TYPE_ID), - case1, dataSource1fromCase1, phonePath); - - EamDb.getInstance().addArtifactInstance(attr); - } catch (EamDbException | CorrelationAttributeNormalizationException ex) { - Exceptions.printStackTrace(ex); - Assert.fail("Error thrown while attempting to add phone attribute from single datasource " + ex.getMessage()); - } - - // Test adding a domain artifact - try { - CorrelationAttributeInstance.Type type = EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.DOMAIN_TYPE_ID); - assertEquals("Unexpected Correlation Type retrieved for Domain type id", CorrelationAttributeInstance.DOMAIN_TYPE_ID, type.getId()); - CorrelationAttributeInstance attr = new CorrelationAttributeInstance( - domainValue, - type, - case1, dataSource1fromCase1, domainPath); - EamDb.getInstance().addArtifactInstance(attr); - } catch (EamDbException | CorrelationAttributeNormalizationException ex) { - Exceptions.printStackTrace(ex); - Assert.fail("Error thrown while attempting to add domain attribute from single datasource " + ex.getMessage()); - } - - // Test adding a device ID artifact - try { - CorrelationAttributeInstance attr = new CorrelationAttributeInstance( - devIdValue, - EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.USBID_TYPE_ID), - case1, dataSource1fromCase1, devIdPath); - - EamDb.getInstance().addArtifactInstance(attr); - } catch (EamDbException | CorrelationAttributeNormalizationException ex) { - Exceptions.printStackTrace(ex); - Assert.fail("Error thrown while attempting to add device ID attribute from single datasource " + ex.getMessage()); - } - - // Test CorrelationAttributeInstance creation - try { - new CorrelationAttributeInstance(fileType, randomHash()); - } catch (CorrelationAttributeNormalizationException | EamDbException ex) { - Exceptions.printStackTrace(ex); - Assert.fail("Error Creating correlation attribute instance " + ex.getMessage()); - } - - // Test adding instance with null case - try { - CorrelationAttributeInstance failAttrInst = new CorrelationAttributeInstance("badInstances", fileType, null, dataSource1fromCase2, BAD_PATH); - EamDb.getInstance().addArtifactInstance(failAttrInst); - fail("Error CorrelationAttributeNormalizationException was expected to be thrown making and adding a CorrelationAttributeInstance with null case and was not"); - } catch (EamDbException ex) { - fail("Error CorrelationAttributeNormalizationException was expected to be thrown making and adding a CorrelationAttributeInstance with null case, EamDbException was thrown instead " + ex.getMessage()); - } catch (CorrelationAttributeNormalizationException ex) { - // This is the expected behavior - } - - // Test adding instance with invalid case ID - try { - CorrelationCase badCase = new CorrelationCase("badCaseUuid", "badCaseName"); - CorrelationAttributeInstance failAttrInst2 = new CorrelationAttributeInstance(randomHash(), fileType, badCase, dataSource1fromCase2, BAD_PATH); - EamDb.getInstance().addArtifactInstance(failAttrInst2); - fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with invalid case ID and was not"); - } catch (EamDbException ex) { - // This is the expected behavior - } catch (CorrelationAttributeNormalizationException ex) { - fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with invalid case ID, CorrelationAttributeNormalizationException was thrown instead " + ex.getMessage()); - } - - // Test adding instance with null data source - try { - CorrelationAttributeInstance failAttrInst3 = new CorrelationAttributeInstance(randomHash(), fileType, case1, null, BAD_PATH); - EamDb.getInstance().addArtifactInstance(failAttrInst3); - fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with null data source and was not"); - } catch (EamDbException ex) { - // This is the expected behavior - } catch (CorrelationAttributeNormalizationException ex) { - fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with null data source, CorrelationAttributeNormalizationException was thrown instead " + ex.getMessage()); - } - - // Test adding instance with invalid data source ID - try { - CorrelationDataSource badDS = new CorrelationDataSource(case1, "badDSUuid", "badDSName"); - CorrelationAttributeInstance failAttrInst4 = new CorrelationAttributeInstance(randomHash(), fileType, case1, badDS, BAD_PATH); - EamDb.getInstance().addArtifactInstance(failAttrInst4); - fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with invalid data source ID and was not"); - } catch (EamDbException ex) { - // This is the expected behavior - } catch (CorrelationAttributeNormalizationException ex) { - fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with invalid data source ID, CorrelationAttributeNormalizationException was thrown instead " + ex.getMessage()); - } - - // Test adding instance with null path - // This will fail in the CorrelationAttributeInstance constructor - try { - new CorrelationAttributeInstance(randomHash(), fileType, case1, dataSource1fromCase1, null); - fail("Error EamDbException was expected to be thrown making a CorrelationAttributeInstance with null path and was not"); - } catch (EamDbException ex) { - // This is the expected behavior - } catch (CorrelationAttributeNormalizationException ex) { - fail("Error EamDbException was expected to be thrown making a CorrelationAttributeInstance with null path, CorrelationAttributeNormalizationException was thrown instead " + ex.getMessage()); - } - - // Test adding instance with null known status - try { - CorrelationAttributeInstance failAttrInst5 = new CorrelationAttributeInstance("badInstances", fileType, case1, dataSource1fromCase1, null, "comment", null); - EamDb.getInstance().addArtifactInstance(failAttrInst5); - fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with null known status and was not"); - } catch (EamDbException ex) { - // This is the expected behavior - } catch (CorrelationAttributeNormalizationException ex) { - fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with null known status, CorrelationAttributeNormalizationException was thrown instead " + ex.getMessage()); - } - - // Test CorrelationAttribute failure cases - // Test null type - try { - CorrelationAttributeInstance attr = new CorrelationAttributeInstance(null, randomHash()); - EamDb.getInstance().addArtifactInstance(attr); - fail("Error CorrelationAttributeNormalizationException was expected to be thrown making and adding a CorrelationAttributeInstance with null type and was not"); - } catch (EamDbException ex) { - Exceptions.printStackTrace(ex); - fail("Error CorrelationAttributeNormalizationException was expected to be thrown making and adding a CorrelationAttributeInstance with null type, EamDbException was thrown instead " + ex.getMessage()); - } catch (CorrelationAttributeNormalizationException ex) { - // This is the expected behavior - } - - // Test null value - // This will fail in the CorrelationAttribute constructor - try { - new CorrelationAttributeInstance(fileType, null); - fail("Error CorrelationAttributeNormalizationException was expected to be thrown making a CorrelationAttributeInstance with null type and was not"); - } catch (CorrelationAttributeNormalizationException ex) { - // This is the expected behavior - } catch (EamDbException ex) { - fail("Error CorrelationAttributeNormalizationException was expected to be thrown making a CorrelationAttributeInstance with null type, EamDbException was thrown instead " + ex.getMessage()); - } - - // Test getting instances with expected results - try { - List instances = EamDb.getInstance().getArtifactInstancesByTypeValue(fileType, inAllDataSourcesHash); - assertEquals("Unexpected number of fileType instances gotten by type value for hash that should be in all 3 data sources", 3, instances.size()); - - // This test works because all the instances of this hash were set to the same path - for (CorrelationAttributeInstance inst : instances) { - assertTrue("getArtifactInstancesByTypeValue returned file instance with unexpected path " + inst.getFilePath() + " expected " + inAllDataSourcesPath, - inAllDataSourcesPath.equalsIgnoreCase(inst.getFilePath())); - } - } catch (EamDbException | CorrelationAttributeNormalizationException ex) { - Exceptions.printStackTrace(ex); - Assert.fail("Error exception thrown while getting attributes by type value " + ex.getMessage()); - } - - // Test getting instances with mismatched data / data-type and expect an exception - try { - EamDb.getInstance().getArtifactInstancesByTypeValue(emailType, inAllDataSourcesHash); - fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get email type attributes with a hash value"); - } catch (EamDbException ex) { - Exceptions.printStackTrace(ex); - fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get email type attributes with a hash value, EamDbException was thrown instead " + ex.getMessage()); - } catch (CorrelationAttributeNormalizationException ex) { - //this is expected - } - - // Test getting instances with null type - try { - EamDb.getInstance().getArtifactInstancesByTypeValue(null, inAllDataSourcesHash); - fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get null type attributes with a hash value"); - } catch (EamDbException ex) { - Exceptions.printStackTrace(ex); - fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get null type attributes with a hash value, EamDbException was thrown instead " + ex.getMessage()); - } catch (CorrelationAttributeNormalizationException ex) { - // This is the expected behavior - } - - // Test getting instances with null value - try { - EamDb.getInstance().getArtifactInstancesByTypeValue(fileType, null); - fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get file type attributes with a null value"); - } catch (EamDbException ex) { - Exceptions.printStackTrace(ex); - fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get file type attributes with a null value, EamDbException was thrown instead " + ex.getMessage()); - } catch (CorrelationAttributeNormalizationException ex) { - //this is expected - } - - // Test getting instances with path that should produce results - try { - List instances = EamDb.getInstance().getArtifactInstancesByPath(fileType, inAllDataSourcesPath); - assertEquals("Unexpected number of fileType instances retrieved when getting file type attributes by path that should be in all 3 data sources", 3, instances.size()); - } catch (EamDbException ex) { - Exceptions.printStackTrace(ex); - Assert.fail("Error EamDbException thrown while getting attributes when getting file type attributes by path" + ex.getMessage()); - } - - // Test getting instances with path that should not produce results - try { - List instances = EamDb.getInstance().getArtifactInstancesByPath(fileType, "xyz"); - assertEquals("Unexpected number of fileType instances retrieved when getting file type attributes by path that should not be in any data sources", 0, instances.size()); - } catch (EamDbException ex) { - Exceptions.printStackTrace(ex); - Assert.fail("Error EamDbException thrown while getting attributes when getting file type attributes by path for path that should not exist" + ex.getMessage()); - } - - // Test getting instances with null type - try { - EamDb.getInstance().getArtifactInstancesByPath(null, inAllDataSourcesPath); - fail("Error EamDbException was expected to be thrown when getting null type attributes by path"); - } catch (EamDbException ex) { - // This is the expected behavior - } - - // Test getting instances with null path - try { - EamDb.getInstance().getArtifactInstancesByPath(fileType, null); - fail("Error EamDbException was expected to be thrown when getting file type attributes with null path"); - } catch (EamDbException ex) { - // This is the expected behavior - } - - // Test getting instance count with path that should produce results - try { - long count = EamDb.getInstance().getCountArtifactInstancesByTypeValue(fileType, inAllDataSourcesHash); - assertEquals("Unexpected number of fileType instances retrieved when getting count of file type value for hash that should be in all 3 data sources", 3, count); - } catch (EamDbException | CorrelationAttributeNormalizationException ex) { - Exceptions.printStackTrace(ex); - Assert.fail("Error Exception thrown while getting count of file type value for hash that should exist" + ex.getMessage()); - } - - // Test getting instance count with path that should not produce results - try { - long count = EamDb.getInstance().getCountArtifactInstancesByTypeValue(fileType, unusedHashValue); - assertEquals("Unexpected number of fileType instances retrieved when getting count of file type value for hash that should not be in any data sources", 0, count); - } catch (EamDbException | CorrelationAttributeNormalizationException ex) { - Exceptions.printStackTrace(ex); - Assert.fail("Error Exception thrown while getting count of file type value for hash that should not exist" + ex.getMessage()); - } - - // Test getting instance count with null type - try { - EamDb.getInstance().getCountArtifactInstancesByTypeValue(null, inAllDataSourcesHash); - fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get count of null type attributes with a hash value"); - } catch (EamDbException ex) { - Exceptions.printStackTrace(ex); - fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get count of null type attributes with a hash value, EamDbException was thrown instead " + ex.getMessage()); - } catch (CorrelationAttributeNormalizationException ex) { - // This is the expected behavior - } - - // Test getting instance count with null value - try { - EamDb.getInstance().getCountArtifactInstancesByTypeValue(fileType, null); - fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get count of file type attributes with a null hash value"); - } catch (EamDbException ex) { - Exceptions.printStackTrace(ex); - fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get count of null type attributes with a null hash value, EamDbException was thrown instead " + ex.getMessage()); - } catch (CorrelationAttributeNormalizationException ex) { - // This is the expected behavior - } - - // Test getting frequency of value that is in all three data sources - try { - CorrelationAttributeInstance attr = new CorrelationAttributeInstance(fileType, inAllDataSourcesHash); - int freq = EamDb.getInstance().getFrequencyPercentage(attr); - assertEquals("Unexpected frequency value of file type returned for value that should exist in all data sources", 100, freq); - } catch (EamDbException | CorrelationAttributeNormalizationException ex) { - Exceptions.printStackTrace(ex); - Assert.fail("Error Exception thrown while getting frequency of file type value for hash that should exist in all data sources" + ex.getMessage()); - } - - // Test getting frequency of value that appears twice in a single data source - try { - CorrelationAttributeInstance attr = new CorrelationAttributeInstance(fileType, inDataSource1twiceHash); - int freq = EamDb.getInstance().getFrequencyPercentage(attr); - assertEquals("Unexpected frequency value of file type returned for value that should exist in one of three data sources", 33, freq); - } catch (EamDbException | CorrelationAttributeNormalizationException ex) { - Exceptions.printStackTrace(ex); - Assert.fail("Error Exception thrown while getting frequency of file type value for hash that should exist in one of three data sources" + ex.getMessage()); - } - - // Test getting frequency of non-file type - try { - CorrelationAttributeInstance attr = new CorrelationAttributeInstance(emailType, emailValue); - int freq = EamDb.getInstance().getFrequencyPercentage(attr); - assertEquals("Unexpected frequency value of email type returned for value that should exist in one of three data sources", 33, freq); - } catch (EamDbException | CorrelationAttributeNormalizationException ex) { - Exceptions.printStackTrace(ex); - Assert.fail("Error Exception thrown while getting frequency of eamil type value for value that should exist in one of three data sources" + ex.getMessage()); - } - - // Test getting frequency of non-existent value - try { - CorrelationAttributeInstance attr = new CorrelationAttributeInstance(fileType, unusedHashValue); - int freq = EamDb.getInstance().getFrequencyPercentage(attr); - assertEquals("Unexpected frequency value of file type returned for value that should not exist in any data sources", 0, freq); - } catch (EamDbException | CorrelationAttributeNormalizationException ex) { - Exceptions.printStackTrace(ex); - Assert.fail("Error Exception thrown while getting frequency of eamil type value for value that should not exist in any data sources" + ex.getMessage()); - } - - // Test getting frequency with null type - try { - CorrelationAttributeInstance attr = new CorrelationAttributeInstance(null, "randomValue"); - EamDb.getInstance().getFrequencyPercentage(attr); - fail("Error Exception was expected to be thrown when getting frequency of null type attribute"); - } catch (EamDbException | CorrelationAttributeNormalizationException ex) { - // This is the expected behavior - } - - // Test getting frequency with null attribute - try { - EamDb.getInstance().getFrequencyPercentage(null); - fail("Error EamDbException was expected to be thrown when getting frequency of null attribute"); - } catch (EamDbException ex) { - // This is the expected behavior - } catch (CorrelationAttributeNormalizationException ex) { - Exceptions.printStackTrace(ex); - fail("Error EamDbException was expected to be thrown when getting frequency of null attribute, CorrelationAttributeNormalizationException was thrown instead " + ex.getMessage()); - fail(ex.getMessage()); - } - - // Test updating a correlation attribute instance comment - try { - String comment = "new comment"; - - CorrelationAttributeInstance correlationAttribute = EamDb.getInstance().getCorrelationAttributeInstance( - usbDeviceType, case1, dataSource1fromCase1, devIdValue, devIdPath); - assertNotNull("Correlation Attribute returned was null when it should not have been", correlationAttribute); - - correlationAttribute.setComment(comment); - EamDb.getInstance().updateAttributeInstanceComment(correlationAttribute); - - // Get a fresh copy to verify the update. - correlationAttribute = EamDb.getInstance().getCorrelationAttributeInstance( - usbDeviceType, case1, dataSource1fromCase1, devIdValue, devIdPath); - assertEquals("Comment was not successfully set to expected value", - comment, correlationAttribute.getComment()); - } catch (EamDbException | CorrelationAttributeNormalizationException ex) { - Exceptions.printStackTrace(ex); - Assert.fail("Error Exception thrown when setting and getting comment for attribute " + ex.getMessage()); - } - - // Test getting count for dataSource1fromCase1 (includes all types) - try { - long count = EamDb.getInstance().getCountArtifactInstancesByCaseDataSource(case1.getCaseUUID(), dataSource1fromCase1.getDeviceID()); - assertEquals("Unexpected count of artifact instances retrieved when getting count for case 1, data source 1", 7, count); - } catch (EamDbException ex) { - Exceptions.printStackTrace(ex); - Assert.fail("Error EamDbException thrown when getting count of artifact instances for case 1, data source 1" + ex.getMessage()); - } - - // Test getting count with null case UUID - try { - long count = EamDb.getInstance().getCountArtifactInstancesByCaseDataSource(null, dataSource1fromCase1.getDeviceID()); - assertEquals("Unexpected count of artifact instances retrieved when getting count for null case, data source 1", 0, count); - } catch (EamDbException ex) { - Exceptions.printStackTrace(ex); - Assert.fail("Error EamDbException thrown when getting count of artifact instances for null case, data source 1" + ex.getMessage()); - } - - // Test getting count with null device ID - try { - long count = EamDb.getInstance().getCountArtifactInstancesByCaseDataSource(case1.getCaseUUID(), null); - assertEquals("Unexpected count of artifact instances retrieved when getting count for case 1, null data source", 0, count); - } catch (EamDbException ex) { - Exceptions.printStackTrace(ex); - Assert.fail("Error EamDbException thrown when getting count of artifact instances for case 1, null data source" + ex.getMessage()); - } - - // Test getting data source count for entry that is in all three - try { - long count = EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(fileType, inAllDataSourcesHash); - assertEquals("Unexpected count of data sources retrieved when getting count for file types with a hash that should exist in all three data sources", 3, count); - } catch (EamDbException | CorrelationAttributeNormalizationException ex) { - Exceptions.printStackTrace(ex); - Assert.fail("Error Exception thrown when getting count of data sources for file types with a hash that should exist in all three data sources" + ex.getMessage()); - } - - // Test getting data source count for entry that is in one data source twice - try { - long count = EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(fileType, inDataSource1twiceHash); - assertEquals("Unexpected count of data sources retrieved when getting count for file types with a hash that should exist in a single data source twice", 1, count); - } catch (EamDbException | CorrelationAttributeNormalizationException ex) { - Exceptions.printStackTrace(ex); - Assert.fail("Error Exception thrown when getting count of data sources for file types with a hash that should exist in a single data source twice" + ex.getMessage()); - } - - // Test getting data source count for entry that is not in any data sources - try { - long count = EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(fileType, unusedHashValue); - assertEquals("Unexpected count of data sources retrieved when getting count for file types with a hash that should not exist in any data source", 0, count); - } catch (EamDbException | CorrelationAttributeNormalizationException ex) { - Exceptions.printStackTrace(ex); - Assert.fail("Error Exception thrown when getting count of data sources for file types with a hash that should not exist in any data source" + ex.getMessage()); - } - - // Test getting data source count for null type - try { - EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(null, unusedHashValue); - fail("Error CorrelationAttributeNormalizationException was expected to be thrown when getting number of datasources containing null type attribute"); - } catch (EamDbException ex) { - Exceptions.printStackTrace(ex); - fail("Error CorrelationAttributeNormalizationException was expected to be thrown when getting number of datasources containing null type attribute, EamDbException was thrown instead " + ex.getMessage()); - } catch (CorrelationAttributeNormalizationException ex) { - // This is the expected behavior - } - - // Test getting data source count for null value - try { - EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(fileType, null); - fail("Error CorrelationAttributeNormalizationException was expected to be thrown when getting number of datasources containing file type attribute with null hash"); - } catch (EamDbException ex) { - Exceptions.printStackTrace(ex); - fail("Error CorrelationAttributeNormalizationException was expected to be thrown when getting number of datasources containing file type attribute with null hash, EamDbException was thrown instead " + ex.getMessage()); - } catch (CorrelationAttributeNormalizationException ex) { - //this is expected - } - - // Test running processinstance which queries all rows from instances table - try { - // Add two instances to the central repository and use the callback query to verify we can see them - CorrelationAttributeInstance attr1 = new CorrelationAttributeInstance(callbackTestFileHash, fileType, case1, dataSource1fromCase1, callbackTestFilePath1); - CorrelationAttributeInstance attr2 = new CorrelationAttributeInstance(callbackTestFileHash, fileType, case1, dataSource1fromCase1, callbackTestFilePath2); - EamDb DbManager = EamDb.getInstance(); - DbManager.addArtifactInstance(attr1); - DbManager.addArtifactInstance(attr2); - AttributeInstanceTableCallback instancetableCallback = new AttributeInstanceTableCallback(); - DbManager.processInstanceTable(fileType, instancetableCallback); - int count1 = instancetableCallback.getCounter(); - int count2 = instancetableCallback.getCounterNamingConvention(); - //expects 2 rows to match the naming convention to of been processed, expects at least one row not matching the naming convention to be processed - //if the test code is changed to add additional Correlation Attributes which also have "processinstancecallback" in their path the first of these comparisons will need to change - assertEquals("Counter for items matching naming convention from AttributeInstaceTableCallback indicates an unexepected number of results when processed with DbManager.processInstanceTable", 2, count2); - assertTrue("Counter for items which do not match naming convention from AttributeInstaceTableCallback indicates an unexepected number of results when processed with DbManager.processInstanceTable. Count indicated: " + count1 + " - expected a number greater than 0", count1 > 0); - } catch (EamDbException | CorrelationAttributeNormalizationException ex) { - Exceptions.printStackTrace(ex); - Assert.fail("Error Exception thrown when calling processInstanceTable " + ex.getMessage()); - } - - try { - //test null inputs - EamDb.getInstance().processInstanceTable(null, null); - fail("Error EamDbException was expected to be thrown when calling processInstanceTable with null inputs"); - } catch (EamDbException ex) { - // This is the expected behavior - } - - // Test running processinstance which queries all rows from instances table - try { - // Add two instances to the central repository and use the callback query to verify we can see them - CorrelationAttributeInstance attr1 = new CorrelationAttributeInstance(callbackTestFileHash, fileType, case1, dataSource1fromCase1, callbackTestFilePath1); - CorrelationAttributeInstance attr2 = new CorrelationAttributeInstance(callbackTestFileHash, fileType, case1, dataSource1fromCase1, callbackTestFilePath2); - EamDb DbManager = EamDb.getInstance(); - //these redundant addArtifactInstance calls allow code to be rearranged if necessary - DbManager.addArtifactInstance(attr1); - DbManager.addArtifactInstance(attr2); - AttributeInstanceTableCallback instancetableCallback = new AttributeInstanceTableCallback(); - DbManager.processInstanceTableWhere(fileType, "value='" + callbackTestFileHash + "'", instancetableCallback); - int count1 = instancetableCallback.getCounter(); - //naming convention counts - int count2 = instancetableCallback.getCounterNamingConvention(); - //this has only processed the rows where the value is equal to the specified value, which should only be the two rows with the naming convention checked for - //if the test code is changed to add additional Correlation Attributes with the same callbackTestFileHash value that is used here these comparisons will need to change - assertEquals("Counter for items matching naming convention from AttributeInstaceTableCallback indicates an unexepected number of results when processed with DbManager.processInstanceTableWhere", 2, count2); - assertEquals("Counter for items which do not match naming convention from AttributeInstaceTableCallback indicates an unexepected number of results when processed with DbManager.processInstanceTableWhere", 0, count1); - } catch (EamDbException | CorrelationAttributeNormalizationException ex) { - Exceptions.printStackTrace(ex); - Assert.fail("Error Exception thrown when calling processInstanceTableWhere " + ex.getMessage()); - } - try { - //test null inputs - EamDb.getInstance().processInstanceTableWhere(null, null, null); - fail("Error EamDbException was expected to be thrown when calling processInstanceTableWhere with null inputs"); - } catch (EamDbException ex) { - // This is the expected behavior - } +// +// //the hash value of all 0s has not been inserted +// final String unusedHashValue = "00000000000000000000000000000000"; +// +// String inAllDataSourcesHash = "6cddb0e31787b79cfdcc0676b98a71ce"; +// String inAllDataSourcesPath = "C:\\files\\path0.txt"; +// String inDataSource1twiceHash = "b2f5ff47436671b6e533d8dc3614845d"; +// String inDataSource1twicePath1 = "C:\\files\\path1.txt"; +// String inDataSource1twicePath2 = "C:\\files\\path2.txt"; +// String onlyInDataSource3Hash = "2af54305f183778d87de0c70c591fae4"; +// String onlyInDataSource3Path = "C:\\files\\path3.txt"; +// String callbackTestFilePath1 = "C:\\files\\processinstancecallback\\path1.txt"; +// String callbackTestFilePath2 = "C:\\files\\processinstancecallback\\path2.txt"; +// String callbackTestFileHash = "fb9dd8f04dacd3e82f4917f1a002223c"; +// +// // These will all go in dataSource1fromCase1 +// String emailValue = "test@gmail.com"; +// String emailPath = "C:\\files\\emailPath.txt"; +// String phoneValue = "202-555-1234"; +// String phonePath = "C:\\files\\phonePath.txt"; +// String domainValue = "www.mozilla.com"; +// String domainPath = "C:\\files\\domainPath.txt"; +// String devIdValue = "94B21234"; +// String devIdPath = "C:\\files\\devIdPath.txt"; +// +// // Store the email type +// CorrelationAttributeInstance.Type emailType; //used again for other portions of this test +// try { +// emailType = EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.EMAIL_TYPE_ID); +// assertEquals("Unexpected Correlation Type retrieved for Email type id", CorrelationAttributeInstance.EMAIL_TYPE_ID, emailType.getId()); +// } catch (EamDbException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail("Error thrown while attempting to get email attribute " + ex.getMessage()); +// return; +// } +// +// // Test adding attribute with one instance +// try { +// CorrelationAttributeInstance attr = new CorrelationAttributeInstance(onlyInDataSource3Hash, fileType, case2, dataSource1fromCase2, onlyInDataSource3Path); +// EamDb.getInstance().addArtifactInstance(attr); +// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail("Error thrown while attempting to add file attribute from single datasource the first time " + ex.getMessage()); +// } +// +// // Test adding attribute with an instance in each data source +// try { +// CorrelationAttributeInstance attr1 = new CorrelationAttributeInstance(inAllDataSourcesHash, fileType, case1, dataSource1fromCase1, inAllDataSourcesPath); +// EamDb.getInstance().addArtifactInstance(attr1); +// CorrelationAttributeInstance attr2 = new CorrelationAttributeInstance(inAllDataSourcesHash, fileType, case1, dataSource2fromCase1, inAllDataSourcesPath); +// EamDb.getInstance().addArtifactInstance(attr2); +// CorrelationAttributeInstance attr3 = new CorrelationAttributeInstance(inAllDataSourcesHash, fileType, case2, dataSource1fromCase2, inAllDataSourcesPath); +// EamDb.getInstance().addArtifactInstance(attr3); +// +// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail("Error thrown while attempting to add file attribute from all 3 datasources " + ex.getMessage()); +// } +// +// // Test adding attribute with two instances in one data source +// try { +// CorrelationAttributeInstance attr1 = new CorrelationAttributeInstance(inDataSource1twiceHash, fileType, case1, dataSource1fromCase1, inDataSource1twicePath1); +// EamDb.getInstance().addArtifactInstance(attr1); +// CorrelationAttributeInstance attr2 = new CorrelationAttributeInstance(inDataSource1twiceHash, fileType, case1, dataSource1fromCase1, inDataSource1twicePath2); +// EamDb.getInstance().addArtifactInstance(attr2); +// +// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail("Error thrown while attempting to add file attribute from single datasource the second time " + ex.getMessage()); +// } +// +// // Test adding the other types +// // Test adding an email artifact +// try { +// CorrelationAttributeInstance attr = new CorrelationAttributeInstance(emailValue, emailType, case1, dataSource1fromCase1, emailPath); +// EamDb.getInstance().addArtifactInstance(attr); +// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail("Error thrown while attempting to add email attribute from single datasource " + ex.getMessage()); +// } +// +// // Test adding a phone artifact +// try { +// CorrelationAttributeInstance attr = new CorrelationAttributeInstance( +// phoneValue, +// EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.PHONE_TYPE_ID), +// case1, dataSource1fromCase1, phonePath); +// +// EamDb.getInstance().addArtifactInstance(attr); +// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail("Error thrown while attempting to add phone attribute from single datasource " + ex.getMessage()); +// } +// +// // Test adding a domain artifact +// try { +// CorrelationAttributeInstance.Type type = EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.DOMAIN_TYPE_ID); +// assertEquals("Unexpected Correlation Type retrieved for Domain type id", CorrelationAttributeInstance.DOMAIN_TYPE_ID, type.getId()); +// CorrelationAttributeInstance attr = new CorrelationAttributeInstance( +// domainValue, +// type, +// case1, dataSource1fromCase1, domainPath); +// EamDb.getInstance().addArtifactInstance(attr); +// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail("Error thrown while attempting to add domain attribute from single datasource " + ex.getMessage()); +// } +// +// // Test adding a device ID artifact +// try { +// CorrelationAttributeInstance attr = new CorrelationAttributeInstance( +// devIdValue, +// EamDb.getInstance().getCorrelationTypeById(CorrelationAttributeInstance.USBID_TYPE_ID), +// case1, dataSource1fromCase1, devIdPath); +// +// EamDb.getInstance().addArtifactInstance(attr); +// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail("Error thrown while attempting to add device ID attribute from single datasource " + ex.getMessage()); +// } +// +// // Test CorrelationAttributeInstance creation +// try { +// new CorrelationAttributeInstance(fileType, randomHash()); +// } catch (CorrelationAttributeNormalizationException | EamDbException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail("Error Creating correlation attribute instance " + ex.getMessage()); +// } +// +// // Test adding instance with null case +// try { +// CorrelationAttributeInstance failAttrInst = new CorrelationAttributeInstance("badInstances", fileType, null, dataSource1fromCase2, BAD_PATH); +// EamDb.getInstance().addArtifactInstance(failAttrInst); +// fail("Error CorrelationAttributeNormalizationException was expected to be thrown making and adding a CorrelationAttributeInstance with null case and was not"); +// } catch (EamDbException ex) { +// fail("Error CorrelationAttributeNormalizationException was expected to be thrown making and adding a CorrelationAttributeInstance with null case, EamDbException was thrown instead " + ex.getMessage()); +// } catch (CorrelationAttributeNormalizationException ex) { +// // This is the expected behavior +// } +// +// // Test adding instance with invalid case ID +// try { +// CorrelationCase badCase = new CorrelationCase("badCaseUuid", "badCaseName"); +// CorrelationAttributeInstance failAttrInst2 = new CorrelationAttributeInstance(randomHash(), fileType, badCase, dataSource1fromCase2, BAD_PATH); +// EamDb.getInstance().addArtifactInstance(failAttrInst2); +// fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with invalid case ID and was not"); +// } catch (EamDbException ex) { +// // This is the expected behavior +// } catch (CorrelationAttributeNormalizationException ex) { +// fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with invalid case ID, CorrelationAttributeNormalizationException was thrown instead " + ex.getMessage()); +// } +// +// // Test adding instance with null data source +// try { +// CorrelationAttributeInstance failAttrInst3 = new CorrelationAttributeInstance(randomHash(), fileType, case1, null, BAD_PATH); +// EamDb.getInstance().addArtifactInstance(failAttrInst3); +// fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with null data source and was not"); +// } catch (EamDbException ex) { +// // This is the expected behavior +// } catch (CorrelationAttributeNormalizationException ex) { +// fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with null data source, CorrelationAttributeNormalizationException was thrown instead " + ex.getMessage()); +// } +// +// // Test adding instance with invalid data source ID +// try { +// CorrelationDataSource badDS = new CorrelationDataSource(case1, "badDSUuid", "badDSName"); +// CorrelationAttributeInstance failAttrInst4 = new CorrelationAttributeInstance(randomHash(), fileType, case1, badDS, BAD_PATH); +// EamDb.getInstance().addArtifactInstance(failAttrInst4); +// fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with invalid data source ID and was not"); +// } catch (EamDbException ex) { +// // This is the expected behavior +// } catch (CorrelationAttributeNormalizationException ex) { +// fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with invalid data source ID, CorrelationAttributeNormalizationException was thrown instead " + ex.getMessage()); +// } +// +// // Test adding instance with null path +// // This will fail in the CorrelationAttributeInstance constructor +// try { +// new CorrelationAttributeInstance(randomHash(), fileType, case1, dataSource1fromCase1, null); +// fail("Error EamDbException was expected to be thrown making a CorrelationAttributeInstance with null path and was not"); +// } catch (EamDbException ex) { +// // This is the expected behavior +// } catch (CorrelationAttributeNormalizationException ex) { +// fail("Error EamDbException was expected to be thrown making a CorrelationAttributeInstance with null path, CorrelationAttributeNormalizationException was thrown instead " + ex.getMessage()); +// } +// +// // Test adding instance with null known status +// try { +// CorrelationAttributeInstance failAttrInst5 = new CorrelationAttributeInstance("badInstances", fileType, case1, dataSource1fromCase1, null, "comment", null); +// EamDb.getInstance().addArtifactInstance(failAttrInst5); +// fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with null known status and was not"); +// } catch (EamDbException ex) { +// // This is the expected behavior +// } catch (CorrelationAttributeNormalizationException ex) { +// fail("Error EamDbException was expected to be thrown making and adding a CorrelationAttributeInstance with null known status, CorrelationAttributeNormalizationException was thrown instead " + ex.getMessage()); +// } +// +// // Test CorrelationAttribute failure cases +// // Test null type +// try { +// CorrelationAttributeInstance attr = new CorrelationAttributeInstance(null, randomHash()); +// EamDb.getInstance().addArtifactInstance(attr); +// fail("Error CorrelationAttributeNormalizationException was expected to be thrown making and adding a CorrelationAttributeInstance with null type and was not"); +// } catch (EamDbException ex) { +// Exceptions.printStackTrace(ex); +// fail("Error CorrelationAttributeNormalizationException was expected to be thrown making and adding a CorrelationAttributeInstance with null type, EamDbException was thrown instead " + ex.getMessage()); +// } catch (CorrelationAttributeNormalizationException ex) { +// // This is the expected behavior +// } +// +// // Test null value +// // This will fail in the CorrelationAttribute constructor +// try { +// new CorrelationAttributeInstance(fileType, null); +// fail("Error CorrelationAttributeNormalizationException was expected to be thrown making a CorrelationAttributeInstance with null type and was not"); +// } catch (CorrelationAttributeNormalizationException ex) { +// // This is the expected behavior +// } catch (EamDbException ex) { +// fail("Error CorrelationAttributeNormalizationException was expected to be thrown making a CorrelationAttributeInstance with null type, EamDbException was thrown instead " + ex.getMessage()); +// } +// +// // Test getting instances with expected results +// try { +// List instances = EamDb.getInstance().getArtifactInstancesByTypeValue(fileType, inAllDataSourcesHash); +// assertEquals("Unexpected number of fileType instances gotten by type value for hash that should be in all 3 data sources", 3, instances.size()); +// +// // This test works because all the instances of this hash were set to the same path +// for (CorrelationAttributeInstance inst : instances) { +// assertTrue("getArtifactInstancesByTypeValue returned file instance with unexpected path " + inst.getFilePath() + " expected " + inAllDataSourcesPath, +// inAllDataSourcesPath.equalsIgnoreCase(inst.getFilePath())); +// } +// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail("Error exception thrown while getting attributes by type value " + ex.getMessage()); +// } +// +// // Test getting instances with mismatched data / data-type and expect an exception +// try { +// EamDb.getInstance().getArtifactInstancesByTypeValue(emailType, inAllDataSourcesHash); +// fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get email type attributes with a hash value"); +// } catch (EamDbException ex) { +// Exceptions.printStackTrace(ex); +// fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get email type attributes with a hash value, EamDbException was thrown instead " + ex.getMessage()); +// } catch (CorrelationAttributeNormalizationException ex) { +// //this is expected +// } +// +// // Test getting instances with null type +// try { +// EamDb.getInstance().getArtifactInstancesByTypeValue(null, inAllDataSourcesHash); +// fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get null type attributes with a hash value"); +// } catch (EamDbException ex) { +// Exceptions.printStackTrace(ex); +// fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get null type attributes with a hash value, EamDbException was thrown instead " + ex.getMessage()); +// } catch (CorrelationAttributeNormalizationException ex) { +// // This is the expected behavior +// } +// +// // Test getting instances with null value +// try { +// EamDb.getInstance().getArtifactInstancesByTypeValue(fileType, null); +// fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get file type attributes with a null value"); +// } catch (EamDbException ex) { +// Exceptions.printStackTrace(ex); +// fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get file type attributes with a null value, EamDbException was thrown instead " + ex.getMessage()); +// } catch (CorrelationAttributeNormalizationException ex) { +// //this is expected +// } +// +// // Test getting instances with path that should produce results +// try { +// List instances = EamDb.getInstance().getArtifactInstancesByPath(fileType, inAllDataSourcesPath); +// assertEquals("Unexpected number of fileType instances retrieved when getting file type attributes by path that should be in all 3 data sources", 3, instances.size()); +// } catch (EamDbException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail("Error EamDbException thrown while getting attributes when getting file type attributes by path" + ex.getMessage()); +// } +// +// // Test getting instances with path that should not produce results +// try { +// List instances = EamDb.getInstance().getArtifactInstancesByPath(fileType, "xyz"); +// assertEquals("Unexpected number of fileType instances retrieved when getting file type attributes by path that should not be in any data sources", 0, instances.size()); +// } catch (EamDbException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail("Error EamDbException thrown while getting attributes when getting file type attributes by path for path that should not exist" + ex.getMessage()); +// } +// +// // Test getting instances with null type +// try { +// EamDb.getInstance().getArtifactInstancesByPath(null, inAllDataSourcesPath); +// fail("Error EamDbException was expected to be thrown when getting null type attributes by path"); +// } catch (EamDbException ex) { +// // This is the expected behavior +// } +// +// // Test getting instances with null path +// try { +// EamDb.getInstance().getArtifactInstancesByPath(fileType, null); +// fail("Error EamDbException was expected to be thrown when getting file type attributes with null path"); +// } catch (EamDbException ex) { +// // This is the expected behavior +// } +// +// // Test getting instance count with path that should produce results +// try { +// long count = EamDb.getInstance().getCountArtifactInstancesByTypeValue(fileType, inAllDataSourcesHash); +// assertEquals("Unexpected number of fileType instances retrieved when getting count of file type value for hash that should be in all 3 data sources", 3, count); +// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail("Error Exception thrown while getting count of file type value for hash that should exist" + ex.getMessage()); +// } +// +// // Test getting instance count with path that should not produce results +// try { +// long count = EamDb.getInstance().getCountArtifactInstancesByTypeValue(fileType, unusedHashValue); +// assertEquals("Unexpected number of fileType instances retrieved when getting count of file type value for hash that should not be in any data sources", 0, count); +// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail("Error Exception thrown while getting count of file type value for hash that should not exist" + ex.getMessage()); +// } +// +// // Test getting instance count with null type +// try { +// EamDb.getInstance().getCountArtifactInstancesByTypeValue(null, inAllDataSourcesHash); +// fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get count of null type attributes with a hash value"); +// } catch (EamDbException ex) { +// Exceptions.printStackTrace(ex); +// fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get count of null type attributes with a hash value, EamDbException was thrown instead " + ex.getMessage()); +// } catch (CorrelationAttributeNormalizationException ex) { +// // This is the expected behavior +// } +// +// // Test getting instance count with null value +// try { +// EamDb.getInstance().getCountArtifactInstancesByTypeValue(fileType, null); +// fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get count of file type attributes with a null hash value"); +// } catch (EamDbException ex) { +// Exceptions.printStackTrace(ex); +// fail("Error CorrelationAttributeNormalizationException was expected to be thrown attempting to get count of null type attributes with a null hash value, EamDbException was thrown instead " + ex.getMessage()); +// } catch (CorrelationAttributeNormalizationException ex) { +// // This is the expected behavior +// } +// +// // Test getting frequency of value that is in all three data sources +// try { +// CorrelationAttributeInstance attr = new CorrelationAttributeInstance(fileType, inAllDataSourcesHash); +// int freq = EamDb.getInstance().getFrequencyPercentage(attr); +// assertEquals("Unexpected frequency value of file type returned for value that should exist in all data sources", 100, freq); +// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail("Error Exception thrown while getting frequency of file type value for hash that should exist in all data sources" + ex.getMessage()); +// } +// +// // Test getting frequency of value that appears twice in a single data source +// try { +// CorrelationAttributeInstance attr = new CorrelationAttributeInstance(fileType, inDataSource1twiceHash); +// int freq = EamDb.getInstance().getFrequencyPercentage(attr); +// assertEquals("Unexpected frequency value of file type returned for value that should exist in one of three data sources", 33, freq); +// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail("Error Exception thrown while getting frequency of file type value for hash that should exist in one of three data sources" + ex.getMessage()); +// } +// +// // Test getting frequency of non-file type +// try { +// CorrelationAttributeInstance attr = new CorrelationAttributeInstance(emailType, emailValue); +// int freq = EamDb.getInstance().getFrequencyPercentage(attr); +// assertEquals("Unexpected frequency value of email type returned for value that should exist in one of three data sources", 33, freq); +// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail("Error Exception thrown while getting frequency of eamil type value for value that should exist in one of three data sources" + ex.getMessage()); +// } +// +// // Test getting frequency of non-existent value +// try { +// CorrelationAttributeInstance attr = new CorrelationAttributeInstance(fileType, unusedHashValue); +// int freq = EamDb.getInstance().getFrequencyPercentage(attr); +// assertEquals("Unexpected frequency value of file type returned for value that should not exist in any data sources", 0, freq); +// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail("Error Exception thrown while getting frequency of eamil type value for value that should not exist in any data sources" + ex.getMessage()); +// } +// +// // Test getting frequency with null type +// try { +// CorrelationAttributeInstance attr = new CorrelationAttributeInstance(null, "randomValue"); +// EamDb.getInstance().getFrequencyPercentage(attr); +// fail("Error Exception was expected to be thrown when getting frequency of null type attribute"); +// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { +// // This is the expected behavior +// } +// +// // Test getting frequency with null attribute +// try { +// EamDb.getInstance().getFrequencyPercentage(null); +// fail("Error EamDbException was expected to be thrown when getting frequency of null attribute"); +// } catch (EamDbException ex) { +// // This is the expected behavior +// } catch (CorrelationAttributeNormalizationException ex) { +// Exceptions.printStackTrace(ex); +// fail("Error EamDbException was expected to be thrown when getting frequency of null attribute, CorrelationAttributeNormalizationException was thrown instead " + ex.getMessage()); +// fail(ex.getMessage()); +// } +// +// // Test updating a correlation attribute instance comment +// try { +// String comment = "new comment"; +// +// CorrelationAttributeInstance correlationAttribute = EamDb.getInstance().getCorrelationAttributeInstance( +// usbDeviceType, case1, dataSource1fromCase1, devIdValue, devIdPath); +// assertNotNull("Correlation Attribute returned was null when it should not have been", correlationAttribute); +// +// correlationAttribute.setComment(comment); +// EamDb.getInstance().updateAttributeInstanceComment(correlationAttribute); +// +// // Get a fresh copy to verify the update. +// correlationAttribute = EamDb.getInstance().getCorrelationAttributeInstance( +// usbDeviceType, case1, dataSource1fromCase1, devIdValue, devIdPath); +// assertEquals("Comment was not successfully set to expected value", +// comment, correlationAttribute.getComment()); +// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail("Error Exception thrown when setting and getting comment for attribute " + ex.getMessage()); +// } +// +// // Test getting count for dataSource1fromCase1 (includes all types) +// try { +// long count = EamDb.getInstance().getCountArtifactInstancesByCaseDataSource(case1.getCaseUUID(), dataSource1fromCase1.getDeviceID()); +// assertEquals("Unexpected count of artifact instances retrieved when getting count for case 1, data source 1", 7, count); +// } catch (EamDbException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail("Error EamDbException thrown when getting count of artifact instances for case 1, data source 1" + ex.getMessage()); +// } +// +// // Test getting count with null case UUID +// try { +// long count = EamDb.getInstance().getCountArtifactInstancesByCaseDataSource(null, dataSource1fromCase1.getDeviceID()); +// assertEquals("Unexpected count of artifact instances retrieved when getting count for null case, data source 1", 0, count); +// } catch (EamDbException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail("Error EamDbException thrown when getting count of artifact instances for null case, data source 1" + ex.getMessage()); +// } +// +// // Test getting count with null device ID +// try { +// long count = EamDb.getInstance().getCountArtifactInstancesByCaseDataSource(case1.getCaseUUID(), null); +// assertEquals("Unexpected count of artifact instances retrieved when getting count for case 1, null data source", 0, count); +// } catch (EamDbException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail("Error EamDbException thrown when getting count of artifact instances for case 1, null data source" + ex.getMessage()); +// } +// +// // Test getting data source count for entry that is in all three +// try { +// long count = EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(fileType, inAllDataSourcesHash); +// assertEquals("Unexpected count of data sources retrieved when getting count for file types with a hash that should exist in all three data sources", 3, count); +// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail("Error Exception thrown when getting count of data sources for file types with a hash that should exist in all three data sources" + ex.getMessage()); +// } +// +// // Test getting data source count for entry that is in one data source twice +// try { +// long count = EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(fileType, inDataSource1twiceHash); +// assertEquals("Unexpected count of data sources retrieved when getting count for file types with a hash that should exist in a single data source twice", 1, count); +// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail("Error Exception thrown when getting count of data sources for file types with a hash that should exist in a single data source twice" + ex.getMessage()); +// } +// +// // Test getting data source count for entry that is not in any data sources +// try { +// long count = EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(fileType, unusedHashValue); +// assertEquals("Unexpected count of data sources retrieved when getting count for file types with a hash that should not exist in any data source", 0, count); +// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail("Error Exception thrown when getting count of data sources for file types with a hash that should not exist in any data source" + ex.getMessage()); +// } +// +// // Test getting data source count for null type +// try { +// EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(null, unusedHashValue); +// fail("Error CorrelationAttributeNormalizationException was expected to be thrown when getting number of datasources containing null type attribute"); +// } catch (EamDbException ex) { +// Exceptions.printStackTrace(ex); +// fail("Error CorrelationAttributeNormalizationException was expected to be thrown when getting number of datasources containing null type attribute, EamDbException was thrown instead " + ex.getMessage()); +// } catch (CorrelationAttributeNormalizationException ex) { +// // This is the expected behavior +// } +// +// // Test getting data source count for null value +// try { +// EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(fileType, null); +// fail("Error CorrelationAttributeNormalizationException was expected to be thrown when getting number of datasources containing file type attribute with null hash"); +// } catch (EamDbException ex) { +// Exceptions.printStackTrace(ex); +// fail("Error CorrelationAttributeNormalizationException was expected to be thrown when getting number of datasources containing file type attribute with null hash, EamDbException was thrown instead " + ex.getMessage()); +// } catch (CorrelationAttributeNormalizationException ex) { +// //this is expected +// } +// +// // Test running processinstance which queries all rows from instances table +// try { +// // Add two instances to the central repository and use the callback query to verify we can see them +// CorrelationAttributeInstance attr1 = new CorrelationAttributeInstance(callbackTestFileHash, fileType, case1, dataSource1fromCase1, callbackTestFilePath1); +// CorrelationAttributeInstance attr2 = new CorrelationAttributeInstance(callbackTestFileHash, fileType, case1, dataSource1fromCase1, callbackTestFilePath2); +// EamDb DbManager = EamDb.getInstance(); +// DbManager.addArtifactInstance(attr1); +// DbManager.addArtifactInstance(attr2); +// AttributeInstanceTableCallback instancetableCallback = new AttributeInstanceTableCallback(); +// DbManager.processInstanceTable(fileType, instancetableCallback); +// int count1 = instancetableCallback.getCounter(); +// int count2 = instancetableCallback.getCounterNamingConvention(); +// //expects 2 rows to match the naming convention to of been processed, expects at least one row not matching the naming convention to be processed +// //if the test code is changed to add additional Correlation Attributes which also have "processinstancecallback" in their path the first of these comparisons will need to change +// assertEquals("Counter for items matching naming convention from AttributeInstaceTableCallback indicates an unexepected number of results when processed with DbManager.processInstanceTable", 2, count2); +// assertTrue("Counter for items which do not match naming convention from AttributeInstaceTableCallback indicates an unexepected number of results when processed with DbManager.processInstanceTable. Count indicated: " + count1 + " - expected a number greater than 0", count1 > 0); +// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail("Error Exception thrown when calling processInstanceTable " + ex.getMessage()); +// } +// +// try { +// //test null inputs +// EamDb.getInstance().processInstanceTable(null, null); +// fail("Error EamDbException was expected to be thrown when calling processInstanceTable with null inputs"); +// } catch (EamDbException ex) { +// // This is the expected behavior +// } +// +// // Test running processinstance which queries all rows from instances table +// try { +// // Add two instances to the central repository and use the callback query to verify we can see them +// CorrelationAttributeInstance attr1 = new CorrelationAttributeInstance(callbackTestFileHash, fileType, case1, dataSource1fromCase1, callbackTestFilePath1); +// CorrelationAttributeInstance attr2 = new CorrelationAttributeInstance(callbackTestFileHash, fileType, case1, dataSource1fromCase1, callbackTestFilePath2); +// EamDb DbManager = EamDb.getInstance(); +// //these redundant addArtifactInstance calls allow code to be rearranged if necessary +// DbManager.addArtifactInstance(attr1); +// DbManager.addArtifactInstance(attr2); +// AttributeInstanceTableCallback instancetableCallback = new AttributeInstanceTableCallback(); +// DbManager.processInstanceTableWhere(fileType, "value='" + callbackTestFileHash + "'", instancetableCallback); +// int count1 = instancetableCallback.getCounter(); +// //naming convention counts +// int count2 = instancetableCallback.getCounterNamingConvention(); +// //this has only processed the rows where the value is equal to the specified value, which should only be the two rows with the naming convention checked for +// //if the test code is changed to add additional Correlation Attributes with the same callbackTestFileHash value that is used here these comparisons will need to change +// assertEquals("Counter for items matching naming convention from AttributeInstaceTableCallback indicates an unexepected number of results when processed with DbManager.processInstanceTableWhere", 2, count2); +// assertEquals("Counter for items which do not match naming convention from AttributeInstaceTableCallback indicates an unexepected number of results when processed with DbManager.processInstanceTableWhere", 0, count1); +// } catch (EamDbException | CorrelationAttributeNormalizationException ex) { +// Exceptions.printStackTrace(ex); +// Assert.fail("Error Exception thrown when calling processInstanceTableWhere " + ex.getMessage()); +// } +// try { +// //test null inputs +// EamDb.getInstance().processInstanceTableWhere(null, null, null); +// fail("Error EamDbException was expected to be thrown when calling processInstanceTableWhere with null inputs"); +// } catch (EamDbException ex) { +// // This is the expected behavior +// } } /** From 03e00edc8e172f8e27067be676e4068d8415f2b2 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 16 Nov 2018 22:35:33 -0500 Subject: [PATCH 03/42] Implemented feature. --- .../modules/stix/STIXReportModule.java | 2 +- .../autopsy/report/Bundle.properties | 6 +- .../autopsy/report/Bundle_ja.properties | 2 +- .../autopsy/report/FileReportModule.java | 12 +- .../autopsy/report/FileReportText.java | 2 +- .../autopsy/report/GeneralReportModule.java | 17 +-- .../report/GeneralReportModuleAdapter.java | 2 +- .../autopsy/report/ReportBodyFile.java | 2 +- .../sleuthkit/autopsy/report/ReportExcel.java | 2 +- .../sleuthkit/autopsy/report/ReportHTML.java | 66 +++++++++- .../report/ReportHTMLConfigurationPanel.form | 89 +++++++++++++ .../report/ReportHTMLConfigurationPanel.java | 120 ++++++++++++++++++ .../sleuthkit/autopsy/report/ReportKML.java | 2 +- .../autopsy/report/ReportModule.java | 23 +++- .../autopsy/report/ReportVisualPanel1.java | 12 +- .../autopsy/report/TableReportGenerator.java | 8 ++ .../autopsy/report/TableReportModule.java | 26 ++-- .../taggedhashes/AddTaggedHashesToHashDb.java | 2 +- 18 files changed, 338 insertions(+), 57 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/report/ReportHTMLConfigurationPanel.form create mode 100755 Core/src/org/sleuthkit/autopsy/report/ReportHTMLConfigurationPanel.java diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java b/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java index 5daf23c217..85cb198b25 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java @@ -64,7 +64,7 @@ import org.sleuthkit.datamodel.TskCoreException; /** * */ -public class STIXReportModule implements GeneralReportModule { +public class STIXReportModule extends GeneralReportModule { private static final Logger logger = Logger.getLogger(STIXReportModule.class.getName()); private STIXReportModuleConfigPanel configPanel; diff --git a/Core/src/org/sleuthkit/autopsy/report/Bundle.properties b/Core/src/org/sleuthkit/autopsy/report/Bundle.properties index 8efbfd9178..92ac26cba2 100644 --- a/Core/src/org/sleuthkit/autopsy/report/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/report/Bundle.properties @@ -253,4 +253,8 @@ ReportGenerator.errList.coreExceptionWhileGenRptRow=Core exception while generat ReportKML.latLongStartPoint={0};{1};;{2} (Start)\n ReportKML.latLongEndPoint={0};{1};;{2} (End)\n ReportGenerationPanel.cancelButton.actionCommand=Cancel -ReportGenerationPanel.cancelButton.text=Cancel \ No newline at end of file +ReportGenerationPanel.cancelButton.text=Cancel +ReportHTMLConfigurationPanel.headerTextField.text= +ReportHTMLConfigurationPanel.footerTextField.text= +ReportHTMLConfigurationPanel.headerLabel.text=Header: +ReportHTMLConfigurationPanel.footerLabel.text=Footer: diff --git a/Core/src/org/sleuthkit/autopsy/report/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/report/Bundle_ja.properties index a877c52899..b4c2844989 100644 --- a/Core/src/org/sleuthkit/autopsy/report/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/report/Bundle_ja.properties @@ -243,4 +243,4 @@ ReportVisualPanel1.invalidModuleWarning=\u7121\u52b9\u306a\u30ec\u30dd\u30fc\u30 ReportGenerationPanel.confDlg.cancelReport.msg=\u672c\u5f53\u306b\u30ec\u30dd\u30fc\u30c8\u3092\u30ad\u30e3\u30f3\u30bb\u30eb\u3057\u307e\u3059\u304b\uff1f ReportProgressPanel.complete.processLb2.text=\u5b8c\u4e86\u3057\u307e\u3057\u305f\u304c\u3001\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f ReportGenerationPanel.cancelButton.actionCommand=\u30ad\u30e3\u30f3\u30bb\u30eb -ReportGenerationPanel.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb \ No newline at end of file +ReportGenerationPanel.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb diff --git a/Core/src/org/sleuthkit/autopsy/report/FileReportModule.java b/Core/src/org/sleuthkit/autopsy/report/FileReportModule.java index cff2ab6a4f..a3d0f679f2 100644 --- a/Core/src/org/sleuthkit/autopsy/report/FileReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/report/FileReportModule.java @@ -26,7 +26,7 @@ import org.sleuthkit.datamodel.AbstractFile; * * @author jwallace */ -interface FileReportModule extends ReportModule { +abstract class FileReportModule extends ReportModule { /** * Initialize the report which will be stored at the given path. @@ -35,19 +35,19 @@ interface FileReportModule extends ReportModule { * should go into baseReportDir + * getRelativeFilePath(). */ - public void startReport(String baseReportDir); + public abstract void startReport(String baseReportDir); /** * End the report. Will be called after the entire report has been written. */ - public void endReport(); + public abstract void endReport(); /** * Start the file list table. * * @param headers The columns that should be included in the table. */ - public void startTable(List headers); + public abstract void startTable(List headers); /** * Add the given AbstractFile as a row in the table. Guaranteed to be called @@ -56,10 +56,10 @@ interface FileReportModule extends ReportModule { * @param toAdd the AbstractFile to be added. * @param columns the columns that should be included */ - public void addRow(AbstractFile toAdd, List columns); + public abstract void addRow(AbstractFile toAdd, List columns); /** * Close the table. */ - public void endTable(); + public abstract void endTable(); } diff --git a/Core/src/org/sleuthkit/autopsy/report/FileReportText.java b/Core/src/org/sleuthkit/autopsy/report/FileReportText.java index f96bad446b..5c47f16ecc 100644 --- a/Core/src/org/sleuthkit/autopsy/report/FileReportText.java +++ b/Core/src/org/sleuthkit/autopsy/report/FileReportText.java @@ -40,7 +40,7 @@ import org.sleuthkit.datamodel.TskCoreException; * * @author jwallace */ -class FileReportText implements FileReportModule { +class FileReportText extends FileReportModule { private static final Logger logger = Logger.getLogger(FileReportText.class.getName()); private String reportPath; diff --git a/Core/src/org/sleuthkit/autopsy/report/GeneralReportModule.java b/Core/src/org/sleuthkit/autopsy/report/GeneralReportModule.java index 1048750b9d..ce866cfcee 100644 --- a/Core/src/org/sleuthkit/autopsy/report/GeneralReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/report/GeneralReportModule.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2012 Basis Technology Corp. + * Copyright 2012-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,9 +18,7 @@ */ package org.sleuthkit.autopsy.report; -import javax.swing.JPanel; - -public interface GeneralReportModule extends ReportModule { +public abstract class GeneralReportModule extends ReportModule { /** * Called to generate the report. Method is responsible for saving the file @@ -31,15 +29,6 @@ public interface GeneralReportModule extends ReportModule { * getRelativeFilePath(). * @param progressPanel panel to update the report's progress with */ - public void generateReport(String baseReportDir, ReportProgressPanel progressPanel); - - /** - * Returns the configuration panel for the report, which is displayed in the - * report configuration step of the report wizard. - * - * @return Configuration panel or null if the module does not need - * configuration. - */ - public JPanel getConfigurationPanel(); + public abstract void generateReport(String baseReportDir, ReportProgressPanel progressPanel); } diff --git a/Core/src/org/sleuthkit/autopsy/report/GeneralReportModuleAdapter.java b/Core/src/org/sleuthkit/autopsy/report/GeneralReportModuleAdapter.java index f66b1c69a2..a2e7c28b70 100644 --- a/Core/src/org/sleuthkit/autopsy/report/GeneralReportModuleAdapter.java +++ b/Core/src/org/sleuthkit/autopsy/report/GeneralReportModuleAdapter.java @@ -24,7 +24,7 @@ import javax.swing.JPanel; * An adapter that provides no-op implementations of various GeneralReportModule * methods. */ -public abstract class GeneralReportModuleAdapter implements GeneralReportModule { +public abstract class GeneralReportModuleAdapter extends GeneralReportModule { @Override public abstract String getName(); diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportBodyFile.java b/Core/src/org/sleuthkit/autopsy/report/ReportBodyFile.java index 4695418117..aa61906dd7 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportBodyFile.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportBodyFile.java @@ -42,7 +42,7 @@ import org.sleuthkit.datamodel.*; * Sleuth Kit wiki as * MD5|name|inode|mode_as_string|UID|GID|size|atime|mtime|ctime|crtime. */ -class ReportBodyFile implements GeneralReportModule { +class ReportBodyFile extends GeneralReportModule { private static final Logger logger = Logger.getLogger(ReportBodyFile.class.getName()); private static ReportBodyFile instance = null; diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java b/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java index 3dcc416ef3..24cfa655e7 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java @@ -31,7 +31,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.TskCoreException; -class ReportExcel implements TableReportModule { +class ReportExcel extends TableReportModule { private static final Logger logger = Logger.getLogger(ReportExcel.class.getName()); private static ReportExcel instance; diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index 13a5078658..d01bbbacb9 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -47,6 +47,8 @@ import java.util.Set; import java.util.TreeMap; import java.util.logging.Level; import javax.imageio.ImageIO; +import javax.swing.JPanel; +import org.apache.commons.lang3.StringEscapeUtils; import org.openide.filesystems.FileUtil; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; @@ -56,6 +58,7 @@ import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.EscapeUtil; import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.Version; import org.sleuthkit.autopsy.datamodel.ContentUtils.ExtractFscContentVisitor; import org.sleuthkit.autopsy.ingest.IngestManager; @@ -72,7 +75,7 @@ import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM; -class ReportHTML implements TableReportModule { +class ReportHTML extends TableReportModule { private static final Logger logger = Logger.getLogger(ReportHTML.class.getName()); private static final String THUMBS_REL_PATH = "thumbs" + File.separator; //NON-NLS @@ -89,6 +92,8 @@ class ReportHTML implements TableReportModule { private String currentDataType; // name of current data type private Integer rowCount; // number of rows (aka artifacts or tags) for the current data type private Writer out; + + private ReportHTMLConfigurationPanel configPanel; private final ReportBranding reportBranding; @@ -104,6 +109,14 @@ class ReportHTML implements TableReportModule { private ReportHTML() { reportBranding = new ReportBranding(); } + + @Override + public JPanel getConfigurationPanel() { + if (configPanel == null) { + configPanel = new ReportHTMLConfigurationPanel(); + } + return configPanel; + } // Refesh the member variables private void refresh() throws NoCurrentCaseException { @@ -332,6 +345,10 @@ class ReportHTML implements TableReportModule { */ @Override public void startReport(String baseReportDir) { + // Save settings + ModuleSettings.setConfigSetting("HTMLReport", "header", configPanel.getHeader()); //NON-NLS + ModuleSettings.setConfigSetting("HTMLReport", "footer", configPanel.getFooter()); //NON-NLS + // Refresh the HTML report try { refresh(); @@ -392,8 +409,10 @@ class ReportHTML implements TableReportModule { try { StringBuilder page = new StringBuilder(); - page.append("\n\n\t").append(name).append("\n\t\n\n\n\n"); //NON-NLS - page.append("
").append(name).append("
\n
\n"); //NON-NLS + page.append("\n\n\t").append(name).append("\n\t\n\n\n\n") //NON-NLS + .append(writePageHeader()) + .append("
").append(name).append("
\n") + .append("
\n"); //NON-NLS if (!description.isEmpty()) { page.append("

"); //NON-NLS page.append(description); @@ -415,7 +434,10 @@ class ReportHTML implements TableReportModule { public void endDataType() { dataTypes.put(currentDataType, rowCount); try { - out.write("

\n\n\n"); //NON-NLS + StringBuilder builder = new StringBuilder(); + builder.append(writePageFooter()); + builder.append("
\n\n\n"); //NON-NLS + out.write(builder.toString()); } catch (IOException ex) { logger.log(Level.SEVERE, "Failed to write end of HTML report.", ex); //NON-NLS } finally { @@ -430,6 +452,40 @@ class ReportHTML implements TableReportModule { } } } + + /** + * Write HTML-formatted page header text based on the text provided in the + * configuration panel. + * + * @return The HTML-formatted text. + */ + private String writePageHeader() { + StringBuilder output = new StringBuilder(); + String pageHeader = configPanel.getHeader(); + if (pageHeader.isEmpty() == false) { + output.append("

") + .append(StringEscapeUtils.escapeHtml4(pageHeader)) + .append("

\n"); //NON-NLS + } + return output.toString(); + } + + /** + * Write HTML-formatted page footer text based on the text provided in the + * configuration panel. + * + * @return The HTML-formatted text. + */ + private String writePageFooter() { + StringBuilder output = new StringBuilder(); + String pageFooter = configPanel.getFooter(); + if (pageFooter.isEmpty() == false) { + output.append("

") + .append(StringEscapeUtils.escapeHtml4(pageFooter)) + .append("

\n"); //NON-NLS + } + return output.toString(); + } /** * Start a new set under the current data type. @@ -1109,6 +1165,7 @@ class ReportHTML implements TableReportModule { final boolean generatorLogoSet = reportBranding.getGeneratorLogoPath() != null && !reportBranding.getGeneratorLogoPath().isEmpty(); summary.append("
\n"); //NON-NLS + summary.append(writePageHeader()); summary.append("

").append(reportTitle) //NON-NLS .append(running ? NbBundle.getMessage(this.getClass(), "ReportHTML.writeSum.warningMsg") : "") .append("

\n"); //NON-NLS @@ -1129,6 +1186,7 @@ class ReportHTML implements TableReportModule { summary.append("

").append(reportFooter).append("

\n"); //NON-NLS } summary.append("
\n"); //NON-NLS + summary.append(writePageFooter()); summary.append(""); //NON-NLS output.write(summary.toString()); } catch (FileNotFoundException ex) { diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTMLConfigurationPanel.form b/Core/src/org/sleuthkit/autopsy/report/ReportHTMLConfigurationPanel.form new file mode 100755 index 0000000000..33a7eb0b43 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTMLConfigurationPanel.form @@ -0,0 +1,89 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTMLConfigurationPanel.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTMLConfigurationPanel.java new file mode 100755 index 0000000000..348a55cb70 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTMLConfigurationPanel.java @@ -0,0 +1,120 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2012-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.report; + +import org.sleuthkit.autopsy.coreutils.ModuleSettings; + +/** + * The panel shown for all TableReportModules when configuring report modules. + */ +@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives +public class ReportHTMLConfigurationPanel extends javax.swing.JPanel { + + /** + * Creates new form DefaultReportConfigurationPanel + */ + public ReportHTMLConfigurationPanel() { + initComponents(); + + // Load settings + String header = ModuleSettings.getConfigSetting("HTMLReport", "header"); //NON-NLS + String footer = ModuleSettings.getConfigSetting("HTMLReport", "footer"); //NON-NLS + + headerTextField.setText(header != null ? header : ""); + footerTextField.setText(footer != null ? footer : ""); + } + + /** + * Get the header text. + * + * @return The header text. + */ + String getHeader() { + return headerTextField.getText(); + } + + /** + * Get the footer text. + * + * @return The footer text. + */ + String getFooter() { + return footerTextField.getText(); + } + + /** + * 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() { + + headerLabel = new javax.swing.JLabel(); + footerLabel = new javax.swing.JLabel(); + headerTextField = new javax.swing.JTextField(); + footerTextField = new javax.swing.JTextField(); + + setFont(getFont().deriveFont(getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + + org.openide.awt.Mnemonics.setLocalizedText(headerLabel, org.openide.util.NbBundle.getMessage(ReportHTMLConfigurationPanel.class, "ReportHTMLConfigurationPanel.headerLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(footerLabel, org.openide.util.NbBundle.getMessage(ReportHTMLConfigurationPanel.class, "ReportHTMLConfigurationPanel.footerLabel.text")); // NOI18N + + headerTextField.setText(org.openide.util.NbBundle.getMessage(ReportHTMLConfigurationPanel.class, "ReportHTMLConfigurationPanel.headerTextField.text")); // NOI18N + + footerTextField.setText(org.openide.util.NbBundle.getMessage(ReportHTMLConfigurationPanel.class, "ReportHTMLConfigurationPanel.footerTextField.text")); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(headerLabel) + .addComponent(footerLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(headerTextField) + .addComponent(footerTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 371, Short.MAX_VALUE)) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(headerLabel) + .addComponent(headerTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(footerTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(footerLabel)) + .addContainerGap(188, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel footerLabel; + private javax.swing.JTextField footerTextField; + private javax.swing.JLabel headerLabel; + private javax.swing.JTextField headerTextField; + // End of variables declaration//GEN-END:variables +} diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportKML.java b/Core/src/org/sleuthkit/autopsy/report/ReportKML.java index 3a092efc83..3be68b610a 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportKML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportKML.java @@ -49,7 +49,7 @@ import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamExce /** * Generates a KML file based on geospatial information from the BlackBoard. */ -class ReportKML implements GeneralReportModule { +class ReportKML extends GeneralReportModule { private static final Logger logger = Logger.getLogger(ReportKML.class.getName()); private static final String KML_STYLE_FILE = "style.kml"; diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportModule.java b/Core/src/org/sleuthkit/autopsy/report/ReportModule.java index a27caa9442..f3af8b0c74 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportModule.java @@ -2,7 +2,7 @@ * * Autopsy Forensic Browser * - * Copyright 2012 Basis Technology Corp. + * Copyright 2012-2018 Basis Technology Corp. * * Copyright 2012 42six Solutions. * Contact: aebadirad 42six com @@ -22,21 +22,23 @@ */ package org.sleuthkit.autopsy.report; +import javax.swing.JPanel; + /** * Interface for report modules that plug in to the reporting infrastructure. */ -interface ReportModule { +abstract class ReportModule { /** * Get the name of the report this module generates. */ - public String getName(); + public abstract String getName(); /** * Gets a one-line, user friendly description of the type of report this * module generates. */ - public String getDescription(); + public abstract String getDescription(); /** * Gets the relative path of the report file, if any, generated by this @@ -46,5 +48,16 @@ interface ReportModule { * @return Relative path to where report will be stored. May be null if the * module does not produce a report file. */ - public String getRelativeFilePath(); + public abstract String getRelativeFilePath(); + + /** + * Returns the configuration panel for the report, which is displayed in the + * report configuration step of the report wizard. + * + * @return Configuration panel or null if the module does not need + * configuration. + */ + public JPanel getConfigurationPanel() { + return new DefaultReportConfigurationPanel(); + } } diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel1.java b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel1.java index a032f44381..c992baf9a7 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel1.java @@ -294,18 +294,18 @@ final class ReportVisualPanel1 extends JPanel implements ListSelectionListener { // single selection, so max selection index is the only one selected. selectedIndex = m.getMaxSelectionIndex(); - JPanel panel = new DefaultReportConfigurationPanel(); ReportModule module = modules.get(selectedIndex); - boolean generalModuleSelected = false; - if (module instanceof GeneralReportModule) { - JPanel generalPanel = ((GeneralReportModule) module).getConfigurationPanel(); - panel = (generalPanel == null) ? new JPanel() : generalPanel; - generalModuleSelected = true; + JPanel panel = module.getConfigurationPanel(); + if (panel == null) { + panel = new JPanel(); } descriptionTextPane.setText(module.getDescription()); configurationPanel.add(panel, BorderLayout.CENTER); configurationPanel.revalidate(); + configurationPanel.repaint(); + + boolean generalModuleSelected = (module instanceof GeneralReportModule); wizPanel.setNext(!generalModuleSelected); wizPanel.setFinish(generalModuleSelected); diff --git a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java index 722af5494a..fd1084dfc7 100644 --- a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java @@ -756,9 +756,12 @@ class TableReportGenerator { BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName(), currentList)); } if (!keyword.equals(currentKeyword)) { + // End the previous table if one exists. if (!currentKeyword.equals("")) { tableModule.endTable(); } + + // Prepare for a new table. currentKeyword = keyword; tableModule.addSetElement(currentKeyword); List columnHeaderNames = new ArrayList<>(); @@ -770,6 +773,11 @@ class TableReportGenerator { tableModule.addRow(Arrays.asList(new String[]{preview, uniquePath, tagsList})); } + + // End the previous table if one exists. + if (!currentKeyword.isEmpty()) { + tableModule.endTable(); + } // Finish the current data type progressPanel.increment(); diff --git a/Core/src/org/sleuthkit/autopsy/report/TableReportModule.java b/Core/src/org/sleuthkit/autopsy/report/TableReportModule.java index 3e9a39a46d..8b982b7bb8 100644 --- a/Core/src/org/sleuthkit/autopsy/report/TableReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/report/TableReportModule.java @@ -29,7 +29,7 @@ import java.util.List; * The data sent consists of user-chosen fields such as Blackboard Artifacts and * File/Result Tags. */ -interface TableReportModule extends ReportModule { +abstract class TableReportModule extends ReportModule { /** * Start the report. Open any output streams, initialize member variables, @@ -40,13 +40,13 @@ interface TableReportModule extends ReportModule { * should go into baseReportDir + * getRelativeFilePath(). */ - public void startReport(String baseReportDir); + public abstract void startReport(String baseReportDir); /** * End the report. Close all output streams and write any end-of-report * files. */ - public void endReport(); + public abstract void endReport(); /** * Start a new data type for the report. This is how the report will @@ -57,26 +57,26 @@ interface TableReportModule extends ReportModule { * @param title String name of the data type * @param description Description of the data type */ - public void startDataType(String title, String description); + public abstract void startDataType(String title, String description); /** * End the current data type and prepare for either the end of the report or * the start of a new data type. */ - public void endDataType(); + public abstract void endDataType(); /** * Start a new set, or sub-category, for the current data type. * * @param setName String name of the set */ - public void startSet(String setName); + public abstract void startSet(String setName); /** * End the current set and prepare for either the end of the current data * type or the start of a new set. */ - public void endSet(); + public abstract void endSet(); /** * Add an index of all the sets to the report's current data type. This @@ -85,7 +85,7 @@ interface TableReportModule extends ReportModule { * * @param sets List of all the String set names */ - public void addSetIndex(List sets); + public abstract void addSetIndex(List sets); /** * Add an element to the current set. An element is considered the 'title' @@ -93,26 +93,26 @@ interface TableReportModule extends ReportModule { * * @param elementName String name of element */ - public void addSetElement(String elementName); + public abstract void addSetElement(String elementName); /** * Create a table with the column names given. * * @param titles List of String column names */ - public void startTable(List titles); + public abstract void startTable(List titles); /** * End the current table. */ - public void endTable(); + public abstract void endTable(); /** * Add a row with the cell values given to the current table. * * @param row List of String cell values */ - public void addRow(List row); + public abstract void addRow(List row); /** * Returns a String date, created by the module. All date values will query @@ -123,6 +123,6 @@ interface TableReportModule extends ReportModule { * * @return String date as String */ - public String dateToString(long date); + public abstract String dateToString(long date); } diff --git a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java index eb8b8a289f..7513949455 100644 --- a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java +++ b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java @@ -43,7 +43,7 @@ import org.sleuthkit.datamodel.TskCoreException; * convenient way to add content hashes to hash set databases. */ @ServiceProvider(service = GeneralReportModule.class) -public class AddTaggedHashesToHashDb implements GeneralReportModule { +public class AddTaggedHashesToHashDb extends GeneralReportModule { private AddTaggedHashesToHashDbConfigPanel configPanel; From 61f08ad9149deae902a9a2b68ed1ef4b1a9e282f Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 16 Nov 2018 22:42:30 -0500 Subject: [PATCH 04/42] Fixed copyright. --- .../sleuthkit/autopsy/report/ReportHTMLConfigurationPanel.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTMLConfigurationPanel.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTMLConfigurationPanel.java index 348a55cb70..cd9f3a11e8 100755 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTMLConfigurationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTMLConfigurationPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2012-2018 Basis Technology Corp. + * Copyright 2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); From 963e528a6903e0a5dd4f2871a5b4f2d6e65cea8d Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Mon, 19 Nov 2018 11:34:34 -0500 Subject: [PATCH 05/42] Fixed backwards compatibility. --- .../modules/stix/STIXReportModule.java | 2 +- .../autopsy/report/FileReportModule.java | 12 ++++----- .../autopsy/report/FileReportText.java | 2 +- .../autopsy/report/GeneralReportModule.java | 4 +-- .../report/GeneralReportModuleAdapter.java | 2 +- .../autopsy/report/ReportBodyFile.java | 2 +- .../sleuthkit/autopsy/report/ReportExcel.java | 2 +- .../sleuthkit/autopsy/report/ReportHTML.java | 4 +-- .../sleuthkit/autopsy/report/ReportKML.java | 2 +- .../autopsy/report/ReportModule.java | 10 +++---- .../autopsy/report/TableReportModule.java | 26 +++++++++---------- .../taggedhashes/AddTaggedHashesToHashDb.java | 2 +- 12 files changed, 35 insertions(+), 35 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java b/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java index 85cb198b25..5daf23c217 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/STIXReportModule.java @@ -64,7 +64,7 @@ import org.sleuthkit.datamodel.TskCoreException; /** * */ -public class STIXReportModule extends GeneralReportModule { +public class STIXReportModule implements GeneralReportModule { private static final Logger logger = Logger.getLogger(STIXReportModule.class.getName()); private STIXReportModuleConfigPanel configPanel; diff --git a/Core/src/org/sleuthkit/autopsy/report/FileReportModule.java b/Core/src/org/sleuthkit/autopsy/report/FileReportModule.java index a3d0f679f2..cff2ab6a4f 100644 --- a/Core/src/org/sleuthkit/autopsy/report/FileReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/report/FileReportModule.java @@ -26,7 +26,7 @@ import org.sleuthkit.datamodel.AbstractFile; * * @author jwallace */ -abstract class FileReportModule extends ReportModule { +interface FileReportModule extends ReportModule { /** * Initialize the report which will be stored at the given path. @@ -35,19 +35,19 @@ abstract class FileReportModule extends ReportModule { * should go into baseReportDir + * getRelativeFilePath(). */ - public abstract void startReport(String baseReportDir); + public void startReport(String baseReportDir); /** * End the report. Will be called after the entire report has been written. */ - public abstract void endReport(); + public void endReport(); /** * Start the file list table. * * @param headers The columns that should be included in the table. */ - public abstract void startTable(List headers); + public void startTable(List headers); /** * Add the given AbstractFile as a row in the table. Guaranteed to be called @@ -56,10 +56,10 @@ abstract class FileReportModule extends ReportModule { * @param toAdd the AbstractFile to be added. * @param columns the columns that should be included */ - public abstract void addRow(AbstractFile toAdd, List columns); + public void addRow(AbstractFile toAdd, List columns); /** * Close the table. */ - public abstract void endTable(); + public void endTable(); } diff --git a/Core/src/org/sleuthkit/autopsy/report/FileReportText.java b/Core/src/org/sleuthkit/autopsy/report/FileReportText.java index 5c47f16ecc..f96bad446b 100644 --- a/Core/src/org/sleuthkit/autopsy/report/FileReportText.java +++ b/Core/src/org/sleuthkit/autopsy/report/FileReportText.java @@ -40,7 +40,7 @@ import org.sleuthkit.datamodel.TskCoreException; * * @author jwallace */ -class FileReportText extends FileReportModule { +class FileReportText implements FileReportModule { private static final Logger logger = Logger.getLogger(FileReportText.class.getName()); private String reportPath; diff --git a/Core/src/org/sleuthkit/autopsy/report/GeneralReportModule.java b/Core/src/org/sleuthkit/autopsy/report/GeneralReportModule.java index ce866cfcee..da0541b48a 100644 --- a/Core/src/org/sleuthkit/autopsy/report/GeneralReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/report/GeneralReportModule.java @@ -18,7 +18,7 @@ */ package org.sleuthkit.autopsy.report; -public abstract class GeneralReportModule extends ReportModule { +public interface GeneralReportModule extends ReportModule { /** * Called to generate the report. Method is responsible for saving the file @@ -29,6 +29,6 @@ public abstract class GeneralReportModule extends ReportModule { * getRelativeFilePath(). * @param progressPanel panel to update the report's progress with */ - public abstract void generateReport(String baseReportDir, ReportProgressPanel progressPanel); + public void generateReport(String baseReportDir, ReportProgressPanel progressPanel); } diff --git a/Core/src/org/sleuthkit/autopsy/report/GeneralReportModuleAdapter.java b/Core/src/org/sleuthkit/autopsy/report/GeneralReportModuleAdapter.java index a2e7c28b70..f66b1c69a2 100644 --- a/Core/src/org/sleuthkit/autopsy/report/GeneralReportModuleAdapter.java +++ b/Core/src/org/sleuthkit/autopsy/report/GeneralReportModuleAdapter.java @@ -24,7 +24,7 @@ import javax.swing.JPanel; * An adapter that provides no-op implementations of various GeneralReportModule * methods. */ -public abstract class GeneralReportModuleAdapter extends GeneralReportModule { +public abstract class GeneralReportModuleAdapter implements GeneralReportModule { @Override public abstract String getName(); diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportBodyFile.java b/Core/src/org/sleuthkit/autopsy/report/ReportBodyFile.java index aa61906dd7..4695418117 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportBodyFile.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportBodyFile.java @@ -42,7 +42,7 @@ import org.sleuthkit.datamodel.*; * Sleuth Kit wiki as * MD5|name|inode|mode_as_string|UID|GID|size|atime|mtime|ctime|crtime. */ -class ReportBodyFile extends GeneralReportModule { +class ReportBodyFile implements GeneralReportModule { private static final Logger logger = Logger.getLogger(ReportBodyFile.class.getName()); private static ReportBodyFile instance = null; diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java b/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java index 24cfa655e7..3dcc416ef3 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java @@ -31,7 +31,7 @@ import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.TskCoreException; -class ReportExcel extends TableReportModule { +class ReportExcel implements TableReportModule { private static final Logger logger = Logger.getLogger(ReportExcel.class.getName()); private static ReportExcel instance; diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index d01bbbacb9..207035239d 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -75,7 +75,7 @@ import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM; -class ReportHTML extends TableReportModule { +class ReportHTML implements TableReportModule { private static final Logger logger = Logger.getLogger(ReportHTML.class.getName()); private static final String THUMBS_REL_PATH = "thumbs" + File.separator; //NON-NLS @@ -416,7 +416,7 @@ class ReportHTML extends TableReportModule { if (!description.isEmpty()) { page.append("

"); //NON-NLS page.append(description); - page.append("

\n"); //NON-NLS + page.append("

\n"); //NON-NLS } out.write(page.toString()); currentDataType = name; diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportKML.java b/Core/src/org/sleuthkit/autopsy/report/ReportKML.java index 3be68b610a..3a092efc83 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportKML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportKML.java @@ -49,7 +49,7 @@ import org.sleuthkit.datamodel.ReadContentInputStream.ReadContentInputStreamExce /** * Generates a KML file based on geospatial information from the BlackBoard. */ -class ReportKML extends GeneralReportModule { +class ReportKML implements GeneralReportModule { private static final Logger logger = Logger.getLogger(ReportKML.class.getName()); private static final String KML_STYLE_FILE = "style.kml"; diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportModule.java b/Core/src/org/sleuthkit/autopsy/report/ReportModule.java index f3af8b0c74..2109d8a526 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportModule.java @@ -27,18 +27,18 @@ import javax.swing.JPanel; /** * Interface for report modules that plug in to the reporting infrastructure. */ -abstract class ReportModule { +interface ReportModule { /** * Get the name of the report this module generates. */ - public abstract String getName(); + public String getName(); /** * Gets a one-line, user friendly description of the type of report this * module generates. */ - public abstract String getDescription(); + public String getDescription(); /** * Gets the relative path of the report file, if any, generated by this @@ -48,7 +48,7 @@ abstract class ReportModule { * @return Relative path to where report will be stored. May be null if the * module does not produce a report file. */ - public abstract String getRelativeFilePath(); + public String getRelativeFilePath(); /** * Returns the configuration panel for the report, which is displayed in the @@ -57,7 +57,7 @@ abstract class ReportModule { * @return Configuration panel or null if the module does not need * configuration. */ - public JPanel getConfigurationPanel() { + public default JPanel getConfigurationPanel() { return new DefaultReportConfigurationPanel(); } } diff --git a/Core/src/org/sleuthkit/autopsy/report/TableReportModule.java b/Core/src/org/sleuthkit/autopsy/report/TableReportModule.java index 8b982b7bb8..3e9a39a46d 100644 --- a/Core/src/org/sleuthkit/autopsy/report/TableReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/report/TableReportModule.java @@ -29,7 +29,7 @@ import java.util.List; * The data sent consists of user-chosen fields such as Blackboard Artifacts and * File/Result Tags. */ -abstract class TableReportModule extends ReportModule { +interface TableReportModule extends ReportModule { /** * Start the report. Open any output streams, initialize member variables, @@ -40,13 +40,13 @@ abstract class TableReportModule extends ReportModule { * should go into baseReportDir + * getRelativeFilePath(). */ - public abstract void startReport(String baseReportDir); + public void startReport(String baseReportDir); /** * End the report. Close all output streams and write any end-of-report * files. */ - public abstract void endReport(); + public void endReport(); /** * Start a new data type for the report. This is how the report will @@ -57,26 +57,26 @@ abstract class TableReportModule extends ReportModule { * @param title String name of the data type * @param description Description of the data type */ - public abstract void startDataType(String title, String description); + public void startDataType(String title, String description); /** * End the current data type and prepare for either the end of the report or * the start of a new data type. */ - public abstract void endDataType(); + public void endDataType(); /** * Start a new set, or sub-category, for the current data type. * * @param setName String name of the set */ - public abstract void startSet(String setName); + public void startSet(String setName); /** * End the current set and prepare for either the end of the current data * type or the start of a new set. */ - public abstract void endSet(); + public void endSet(); /** * Add an index of all the sets to the report's current data type. This @@ -85,7 +85,7 @@ abstract class TableReportModule extends ReportModule { * * @param sets List of all the String set names */ - public abstract void addSetIndex(List sets); + public void addSetIndex(List sets); /** * Add an element to the current set. An element is considered the 'title' @@ -93,26 +93,26 @@ abstract class TableReportModule extends ReportModule { * * @param elementName String name of element */ - public abstract void addSetElement(String elementName); + public void addSetElement(String elementName); /** * Create a table with the column names given. * * @param titles List of String column names */ - public abstract void startTable(List titles); + public void startTable(List titles); /** * End the current table. */ - public abstract void endTable(); + public void endTable(); /** * Add a row with the cell values given to the current table. * * @param row List of String cell values */ - public abstract void addRow(List row); + public void addRow(List row); /** * Returns a String date, created by the module. All date values will query @@ -123,6 +123,6 @@ abstract class TableReportModule extends ReportModule { * * @return String date as String */ - public abstract String dateToString(long date); + public String dateToString(long date); } diff --git a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java index 7513949455..eb8b8a289f 100644 --- a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java +++ b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDb.java @@ -43,7 +43,7 @@ import org.sleuthkit.datamodel.TskCoreException; * convenient way to add content hashes to hash set databases. */ @ServiceProvider(service = GeneralReportModule.class) -public class AddTaggedHashesToHashDb extends GeneralReportModule { +public class AddTaggedHashesToHashDb implements GeneralReportModule { private AddTaggedHashesToHashDbConfigPanel configPanel; From 3602ad11996dd9fa41597bcbf255ab766f7377a1 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 20 Nov 2018 16:46:27 -0500 Subject: [PATCH 06/42] 4402 Add code to create device previously existed interesting items --- .../eventlisteners/IngestEventsListener.java | 60 ++++++++++++++++++- 1 file changed, 58 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java index 2f2a35ab2a..93b9fcaf6a 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java @@ -179,6 +179,43 @@ public class IngestEventsListener { } } + @NbBundle.Messages({"IngestEventsListener.prevExists.text=Previously Seen Devices (Central Repository)", + "# {0} - typeName", + "# {1} - count", + "IngestEventsListener.prevCount.text=Number of previous {0}: {1}"}) + static private void postCorrelatedPreviousArtifactToBlackboard(BlackboardArtifact bbArtifact, long count, String displayName) { + + try { + AbstractFile af = bbArtifact.getSleuthkitCase().getAbstractFileById(bbArtifact.getObjectID()); + Collection attributes = new ArrayList<>(); + String MODULE_NAME = Bundle.IngestEventsListener_ingestmodule_name(); + BlackboardArtifact tifArtifact = af.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT); + BlackboardAttribute att = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, + Bundle.IngestEventsListener_prevExists_text()); + BlackboardAttribute att2 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, MODULE_NAME, + Bundle.IngestEventsListener_prevCount_text(displayName, count)); + attributes.add(att); + attributes.add(att2); + attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, bbArtifact.getArtifactID())); + + tifArtifact.addAttributes(attributes); + try { + // index the artifact for keyword search + Blackboard blackboard = Case.getCurrentCaseThrows().getServices().getBlackboard(); + blackboard.indexArtifact(tifArtifact); + } catch (Blackboard.BlackboardException | NoCurrentCaseException ex) { + LOGGER.log(Level.SEVERE, "Unable to index blackboard artifact " + tifArtifact.getArtifactID(), ex); //NON-NLS + } + + // fire event to notify UI of this new artifact + IngestServices.getInstance().fireModuleDataEvent(new ModuleDataEvent(MODULE_NAME, BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT)); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Failed to create BlackboardArtifact.", ex); // NON-NLS + } catch (IllegalStateException ex) { + LOGGER.log(Level.SEVERE, "Failed to create BlackboardAttribute.", ex); // NON-NLS + } + } + private class IngestModuleEventListener implements PropertyChangeListener { @Override @@ -198,7 +235,8 @@ public class IngestEventsListener { case DATA_ADDED: { //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)); + boolean flagPrevious = !IngestManager.getInstance().isIngestRunning() || true; //WJS-TODO change this to use a setting instead of true + jobProcessingExecutor.submit(new DataAddedTask(dbManager, evt, flagNotable, flagPrevious)); break; } } @@ -237,11 +275,13 @@ public class IngestEventsListener { private final EamDb dbManager; private final PropertyChangeEvent event; private final boolean flagNotableItemsEnabled; + private final boolean flagPreviousItemsEnabled; - private DataAddedTask(EamDb db, PropertyChangeEvent evt, boolean flagNotableItemsEnabled) { + private DataAddedTask(EamDb db, PropertyChangeEvent evt, boolean flagNotableItemsEnabled, boolean flagPreviousItemsEnabled) { dbManager = db; event = evt; this.flagNotableItemsEnabled = flagNotableItemsEnabled; + this.flagPreviousItemsEnabled = flagPreviousItemsEnabled; } @Override @@ -279,6 +319,22 @@ public class IngestEventsListener { LOGGER.log(Level.INFO, String.format("Unable to flag notable item: %s.", eamArtifact.toString()), ex); } } + if (flagPreviousItemsEnabled && + (eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.USBID_TYPE_ID || + eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.ICCID_TYPE_ID || + eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.IMEI_TYPE_ID || + eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.IMSI_TYPE_ID || + eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.MAC_TYPE_ID)) { + try { + Long countPreviousOccurences = dbManager.getCountArtifactInstancesByTypeValue(eamArtifact.getCorrelationType(), eamArtifact.getCorrelationValue()); + if (countPreviousOccurences > 0) { + postCorrelatedPreviousArtifactToBlackboard(bbArtifact, + countPreviousOccurences, eamArtifact.getCorrelationType().getDisplayName()); + } + } catch (CorrelationAttributeNormalizationException ex) { + LOGGER.log(Level.INFO, String.format("Unable to flag notable item: %s.", eamArtifact.toString()), ex); + } + } eamArtifacts.add(eamArtifact); } } catch (EamDbException ex) { From dc7adb94fb0acf5b0acf015f5b2c1117bb180496 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 20 Nov 2018 17:46:22 -0500 Subject: [PATCH 07/42] 4402 add ingest module setting for flagging previously seen devices --- .../eventlisteners/IngestEventsListener.java | 33 +++++++++++++++---- .../ingestmodule/Bundle.properties | 1 + .../ingestmodule/IngestModule.java | 6 ++++ .../ingestmodule/IngestSettings.java | 14 ++++---- .../ingestmodule/IngestSettingsPanel.form | 22 ++++++++++--- .../ingestmodule/IngestSettingsPanel.java | 17 +++++++--- 6 files changed, 71 insertions(+), 22 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java index 93b9fcaf6a..08e5ab1c1a 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java @@ -60,6 +60,7 @@ public class IngestEventsListener { final Collection recentlyAddedCeArtifacts = new LinkedHashSet<>(); private static int correlationModuleInstanceCount; private static boolean flagNotableItems; + private static boolean flagSeenDevices; private final ExecutorService jobProcessingExecutor; private static final String INGEST_EVENT_THREAD_NAME = "Ingest-Event-Listener-%d"; private final PropertyChangeListener pcl1 = new IngestModuleEventListener(); @@ -134,6 +135,15 @@ public class IngestEventsListener { return flagNotableItems; } + /** + * Are previously seen devices being flagged? + * + * @return True if flagging seen devices; otherwise false. + */ + public synchronized static boolean isFlagSeenDevices() { + return flagSeenDevices; + } + /** * Configure the listener to flag notable items or not. * @@ -143,6 +153,15 @@ public class IngestEventsListener { flagNotableItems = value; } + /** + * Configure the listener to flag previously seen devices or not. + * + * @param value True to flag seen devices; otherwise false. + */ + public synchronized static void setFlagSeenDevices(boolean value) { + flagSeenDevices = value; + } + @NbBundle.Messages({"IngestEventsListener.prevTaggedSet.text=Previously Tagged As Notable (Central Repository)", "IngestEventsListener.prevCaseComment.text=Previous Case: ", "IngestEventsListener.ingestmodule.name=Correlation Engine"}) @@ -235,7 +254,7 @@ public class IngestEventsListener { case DATA_ADDED: { //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(); - boolean flagPrevious = !IngestManager.getInstance().isIngestRunning() || true; //WJS-TODO change this to use a setting instead of true + boolean flagPrevious = !IngestManager.getInstance().isIngestRunning() || isFlagSeenDevices(); jobProcessingExecutor.submit(new DataAddedTask(dbManager, evt, flagNotable, flagPrevious)); break; } @@ -319,12 +338,12 @@ public class IngestEventsListener { LOGGER.log(Level.INFO, String.format("Unable to flag notable item: %s.", eamArtifact.toString()), ex); } } - if (flagPreviousItemsEnabled && - (eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.USBID_TYPE_ID || - eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.ICCID_TYPE_ID || - eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.IMEI_TYPE_ID || - eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.IMSI_TYPE_ID || - eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.MAC_TYPE_ID)) { + if (flagPreviousItemsEnabled + && (eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.USBID_TYPE_ID + || eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.ICCID_TYPE_ID + || eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.IMEI_TYPE_ID + || eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.IMSI_TYPE_ID + || eamArtifact.getCorrelationType().getId() == CorrelationAttributeInstance.MAC_TYPE_ID)) { try { Long countPreviousOccurences = dbManager.getCountArtifactInstancesByTypeValue(eamArtifact.getCorrelationType(), eamArtifact.getCorrelationValue()); if (countPreviousOccurences > 0) { diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties index a525713f7c..f99db1edb6 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/Bundle.properties @@ -1,2 +1,3 @@ IngestSettingsPanel.ingestSettingsLabel.text=Ingest Settings IngestSettingsPanel.flagTaggedNotableItemsCheckbox.text=Flag items previously tagged as notable +IngestSettingsPanel.flagPreviouslySeenDevicesCheckbox.text=Flag previously seen devices diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java index 0eecc533b0..8073f8e8d7 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java @@ -61,6 +61,7 @@ import org.sleuthkit.autopsy.healthmonitor.TimingMetric; final class IngestModule implements FileIngestModule { static final boolean DEFAULT_FLAG_TAGGED_NOTABLE_ITEMS = true; + static final boolean DEFAULT_FLAG_PREVIOUS_DEVICES = true; private final static Logger logger = Logger.getLogger(IngestModule.class.getName()); private final IngestServices services = IngestServices.getInstance(); @@ -72,6 +73,7 @@ final class IngestModule implements FileIngestModule { private Blackboard blackboard; private CorrelationAttributeInstance.Type filesType; private final boolean flagTaggedNotableItems; + private final boolean flagPreviouslySeenDevices; /** * Instantiate the Correlation Engine ingest module. @@ -80,6 +82,7 @@ final class IngestModule implements FileIngestModule { */ IngestModule(IngestSettings settings) { flagTaggedNotableItems = settings.isFlagTaggedNotableItems(); + flagPreviouslySeenDevices = settings.isFlagPreviousDevices(); } @Override @@ -228,6 +231,9 @@ final class IngestModule implements FileIngestModule { if (IngestEventsListener.getCeModuleInstanceCount() == 1 || !IngestEventsListener.isFlagNotableItems()) { IngestEventsListener.setFlagNotableItems(flagTaggedNotableItems); } + if (IngestEventsListener.getCeModuleInstanceCount() == 1 || !IngestEventsListener.isFlagSeenDevices()) { + IngestEventsListener.setFlagSeenDevices(flagPreviouslySeenDevices); + } if (EamDb.isEnabled() == false) { /* diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettings.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettings.java index 32ab9e9f2d..30039a9f86 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettings.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettings.java @@ -28,12 +28,14 @@ final class IngestSettings implements IngestModuleIngestJobSettings { private static final long serialVersionUID = 1L; private boolean flagTaggedNotableItems; + private boolean flagPreviousDevices; /** * Instantiate the ingest job settings with default values. */ IngestSettings() { this.flagTaggedNotableItems = IngestModule.DEFAULT_FLAG_TAGGED_NOTABLE_ITEMS; + this.flagTaggedNotableItems = IngestModule.DEFAULT_FLAG_PREVIOUS_DEVICES; } /** @@ -41,8 +43,9 @@ final class IngestSettings implements IngestModuleIngestJobSettings { * * @param flagTaggedNotableItems Flag previously tagged notable items. */ - IngestSettings(boolean flagTaggedNotableItems) { + IngestSettings(boolean flagTaggedNotableItems, boolean flagPreviousDevices) { this.flagTaggedNotableItems = flagTaggedNotableItems; + this.flagPreviousDevices = flagPreviousDevices; } @Override @@ -60,12 +63,11 @@ final class IngestSettings implements IngestModuleIngestJobSettings { } /** - * Flag or ignore previously identified notable items. + * Are previously seen devices to be flagged? * - * @param ignorePreviousNotableItems Are previously tagged notable items to - * be flagged? + * @return True if flagging; otherwise false. */ - void setFlagTaggedNotableItems(boolean flagTaggedNotableItems) { - this.flagTaggedNotableItems = flagTaggedNotableItems; + boolean isFlagPreviousDevices() { + return flagTaggedNotableItems; } } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.form index 564031cb72..3c2fddca0f 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.form @@ -19,11 +19,14 @@ - - - - + + + + + + + @@ -36,7 +39,9 @@ - + + + @@ -59,5 +64,12 @@ + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.java index ed36c71287..159f925355 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettingsPanel.java @@ -42,11 +42,12 @@ final class IngestSettingsPanel extends IngestModuleIngestJobSettingsPanel { */ private void customizeComponents(IngestSettings settings) { flagTaggedNotableItemsCheckbox.setSelected(settings.isFlagTaggedNotableItems()); + flagPreviouslySeenDevicesCheckbox.setSelected(settings.isFlagPreviousDevices()); } @Override public IngestModuleIngestJobSettings getSettings() { - return new IngestSettings(flagTaggedNotableItemsCheckbox.isSelected()); + return new IngestSettings(flagTaggedNotableItemsCheckbox.isSelected(), flagPreviouslySeenDevicesCheckbox.isSelected()); } /** @@ -60,12 +61,15 @@ final class IngestSettingsPanel extends IngestModuleIngestJobSettingsPanel { ingestSettingsLabel = new javax.swing.JLabel(); flagTaggedNotableItemsCheckbox = new javax.swing.JCheckBox(); + flagPreviouslySeenDevicesCheckbox = new javax.swing.JCheckBox(); ingestSettingsLabel.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(ingestSettingsLabel, org.openide.util.NbBundle.getMessage(IngestSettingsPanel.class, "IngestSettingsPanel.ingestSettingsLabel.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(flagTaggedNotableItemsCheckbox, org.openide.util.NbBundle.getMessage(IngestSettingsPanel.class, "IngestSettingsPanel.flagTaggedNotableItemsCheckbox.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(flagPreviouslySeenDevicesCheckbox, org.openide.util.NbBundle.getMessage(IngestSettingsPanel.class, "IngestSettingsPanel.flagPreviouslySeenDevicesCheckbox.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -73,10 +77,12 @@ final class IngestSettingsPanel extends IngestModuleIngestJobSettingsPanel { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(ingestSettingsLabel) .addGroup(layout.createSequentialGroup() .addGap(10, 10, 10) - .addComponent(flagTaggedNotableItemsCheckbox)) - .addComponent(ingestSettingsLabel)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(flagPreviouslySeenDevicesCheckbox) + .addComponent(flagTaggedNotableItemsCheckbox)))) .addContainerGap(65, Short.MAX_VALUE)) ); layout.setVerticalGroup( @@ -86,11 +92,14 @@ final class IngestSettingsPanel extends IngestModuleIngestJobSettingsPanel { .addComponent(ingestSettingsLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(flagTaggedNotableItemsCheckbox) - .addContainerGap(245, Short.MAX_VALUE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(flagPreviouslySeenDevicesCheckbox) + .addContainerGap(222, Short.MAX_VALUE)) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JCheckBox flagPreviouslySeenDevicesCheckbox; private javax.swing.JCheckBox flagTaggedNotableItemsCheckbox; private javax.swing.JLabel ingestSettingsLabel; // End of variables declaration//GEN-END:variables From 1f21552a226d26874b4d6e590b82c9b2cee81cb6 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 21 Nov 2018 16:49:15 -0500 Subject: [PATCH 08/42] 4402 remove comment attr from interesting item for previous devices --- .../eventlisteners/IngestEventsListener.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java index 08e5ab1c1a..1e8d7003b3 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java @@ -202,7 +202,7 @@ public class IngestEventsListener { "# {0} - typeName", "# {1} - count", "IngestEventsListener.prevCount.text=Number of previous {0}: {1}"}) - static private void postCorrelatedPreviousArtifactToBlackboard(BlackboardArtifact bbArtifact, long count, String displayName) { + static private void postCorrelatedPreviousArtifactToBlackboard(BlackboardArtifact bbArtifact) { try { AbstractFile af = bbArtifact.getSleuthkitCase().getAbstractFileById(bbArtifact.getObjectID()); @@ -211,10 +211,7 @@ public class IngestEventsListener { BlackboardArtifact tifArtifact = af.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT); BlackboardAttribute att = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, Bundle.IngestEventsListener_prevExists_text()); - BlackboardAttribute att2 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, MODULE_NAME, - Bundle.IngestEventsListener_prevCount_text(displayName, count)); attributes.add(att); - attributes.add(att2); attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, bbArtifact.getArtifactID())); tifArtifact.addAttributes(attributes); @@ -347,8 +344,7 @@ public class IngestEventsListener { try { Long countPreviousOccurences = dbManager.getCountArtifactInstancesByTypeValue(eamArtifact.getCorrelationType(), eamArtifact.getCorrelationValue()); if (countPreviousOccurences > 0) { - postCorrelatedPreviousArtifactToBlackboard(bbArtifact, - countPreviousOccurences, eamArtifact.getCorrelationType().getDisplayName()); + postCorrelatedPreviousArtifactToBlackboard(bbArtifact); } } catch (CorrelationAttributeNormalizationException ex) { LOGGER.log(Level.INFO, String.format("Unable to flag notable item: %s.", eamArtifact.toString()), ex); From cae6485ba435477ff8860b6773bf186e88f403a6 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Wed, 21 Nov 2018 16:57:54 -0500 Subject: [PATCH 09/42] 4402 add comment to new method for adding interesting item --- .../eventlisteners/IngestEventsListener.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java index 1e8d7003b3..549695432a 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java @@ -198,6 +198,12 @@ public class IngestEventsListener { } } + /** + * Create an Interesting Aritfact hit for a device which was previously seen + * in the central repository. + * + * @param bbArtifact the artifact to create the interesting item for + */ @NbBundle.Messages({"IngestEventsListener.prevExists.text=Previously Seen Devices (Central Repository)", "# {0} - typeName", "# {1} - count", From 1b3b8ee094f23d0f2380e83a43aa19dc4661b1b3 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 21 Nov 2018 17:42:14 -0500 Subject: [PATCH 10/42] Other correlation types supported. --- .../OtherCasesSearchDialog.java | 155 ++++++++++++------ 1 file changed, 106 insertions(+), 49 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.java b/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.java index 51e21631d2..d0d82534ff 100755 --- a/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.java +++ b/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.java @@ -26,19 +26,17 @@ import java.util.Collection; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.logging.Level; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import javax.swing.JFrame; import javax.swing.SwingWorker; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import org.openide.nodes.Node; -import org.openide.util.Exceptions; import org.openide.util.NbBundle.Messages; import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizationException; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeNormalizer; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; import org.sleuthkit.autopsy.corecomponentinterfaces.DataResultViewer; @@ -55,6 +53,10 @@ import org.sleuthkit.autopsy.datamodel.EmptyNode; "OtherCasesSearchDialog.resultsDescription.text=Other Cases Search", "OtherCasesSearchDialog.emptyNode.text=No results found.", "OtherCasesSearchDialog.validation.invalidHash=The supplied value is not a valid MD5 hash.", + "OtherCasesSearchDialog.validation.invalidEmail=The supplied value is not a valid e-mail address.", + "OtherCasesSearchDialog.validation.invalidDomain=The supplied value is not a valid domain.", + "OtherCasesSearchDialog.validation.invalidPhone=The supplied value is not a valid phone number.", + "OtherCasesSearchDialog.validation.genericMessage=The supplied value is not valid.", "# {0} - number of cases", "OtherCasesSearchDialog.caseLabel.text=The current Central Repository contains {0} case(s)." }) @@ -67,9 +69,8 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog { private static final Logger logger = Logger.getLogger(OtherCasesSearchDialog.class.getName()); private static final long serialVersionUID = 1L; - private static final String FILES_CORRELATION_TYPE = "Files"; - private final List correlationTypes; + private CorrelationAttributeInstance.Type selectedCorrelationType; private TextPrompt correlationValueTextFieldPrompt; /** @@ -84,23 +85,19 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog { /** * Perform the other cases search. + * + * @param type The correlation type. + * @param value The value to be matched. */ - private void search() { + private void search(CorrelationAttributeInstance.Type type, String value) { new SwingWorker, Void>() { @Override protected List doInBackground() { - List correlationTypes; List correlationInstances = new ArrayList<>(); try { - correlationTypes = EamDb.getInstance().getDefinedCorrelationTypes(); - for (CorrelationAttributeInstance.Type type : correlationTypes) { - if (type.getDisplayName().equals((String) correlationTypeComboBox.getSelectedItem())) { - correlationInstances = EamDb.getInstance().getArtifactInstancesByTypeValue(type, correlationValueTextField.getText()); - break; - } - } + correlationInstances = EamDb.getInstance().getArtifactInstancesByTypeValue(type, value); } catch (EamDbException ex) { logger.log(Level.SEVERE, "Unable to connect to the Central Repository database.", ex); } catch (CorrelationAttributeNormalizationException ex) { @@ -123,9 +120,7 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog { TableFilterNode tableFilterNode = new TableFilterNode(searchNode, true, searchNode.getName()); String resultsText = String.format("%s (%s; \"%s\")", - Bundle.OtherCasesSearchDialog_resultsTitle_text(), - (String) correlationTypeComboBox.getSelectedItem(), - correlationValueTextField.getText()); + Bundle.OtherCasesSearchDialog_resultsTitle_text(), type.getDisplayName(), value); final TopComponent searchResultWin; if (correlationInstances.isEmpty()) { Node emptyNode = new TableFilterNode( @@ -240,23 +235,57 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog { }// //GEN-END:initComponents private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchButtonActionPerformed - if (validateInputs()) { - /* - * Just in case, we'll lock down the type and value components to - * avoid the possibly of a race condition. - */ - correlationTypeComboBox.setEnabled(false); - correlationValueTextField.setEnabled(false); - - search(); + CorrelationAttributeInstance.Type correlationType = selectedCorrelationType; + String correlationValue = correlationValueTextField.getText(); + + if (validateInputs(correlationType, correlationValue)) { + search(correlationType, correlationValue); dispose(); } else { + String validationMessage; + switch (correlationType.getId()) { + case CorrelationAttributeInstance.FILES_TYPE_ID: + validationMessage = Bundle.OtherCasesSearchDialog_validation_invalidHash(); + break; + case CorrelationAttributeInstance.DOMAIN_TYPE_ID: + validationMessage = Bundle.OtherCasesSearchDialog_validation_invalidDomain(); + break; + case CorrelationAttributeInstance.EMAIL_TYPE_ID: + validationMessage = Bundle.OtherCasesSearchDialog_validation_invalidEmail(); + break; + case CorrelationAttributeInstance.PHONE_TYPE_ID: + validationMessage = Bundle.OtherCasesSearchDialog_validation_invalidPhone(); + break; + default: + validationMessage = Bundle.OtherCasesSearchDialog_validation_genericMessage(); + break; + + } + errorLabel.setText(validationMessage); searchButton.setEnabled(false); - errorLabel.setText(Bundle.OtherCasesSearchDialog_validation_invalidHash()); correlationValueTextField.grabFocus(); } }//GEN-LAST:event_searchButtonActionPerformed - + + /** + * Validate the supplied input. + * + * @param type The correlation type. + * @param value The value to be validated. + * + * @return True if the input is valid for the given type; otherwise false. + */ + private boolean validateInputs(CorrelationAttributeInstance.Type type, String value) { + try { + CorrelationAttributeNormalizer.normalize(type, correlationValueTextField.getText().trim()); + } catch (CorrelationAttributeNormalizationException ex) { + // No need to log this. + return false; + } + + return true; + } + /** * Further customize the components beyond the standard initialization. */ @@ -277,20 +306,21 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog { } for (CorrelationAttributeInstance.Type type : correlationTypes) { - // We only support the "Files" type for now. - if (type.getDisplayName().equals(FILES_CORRELATION_TYPE)) { - correlationTypeComboBox.addItem(type.getDisplayName()); - } + correlationTypeComboBox.addItem(type.getDisplayName()); } correlationTypeComboBox.setSelectedIndex(0); correlationTypeComboBox.addItemListener(new ItemListener() { @Override public void itemStateChanged(ItemEvent e) { + updateSelectedType(); + updateCorrelationValueTextFieldPrompt(); updateSearchButton(); } }); + updateSelectedType(); + /* * Create listener for text input. */ @@ -315,7 +345,12 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog { } @Messages({ - "OtherCasesSearchDialog.correlationValueTextField.filesExample=Example: \"f0e1d2c3b4a5968778695a4b3c2d1e0f\"" + "OtherCasesSearchDialog.correlationValueTextField.filesExample=Example: \"f0e1d2c3b4a5968778695a4b3c2d1e0f\"", + "OtherCasesSearchDialog.correlationValueTextField.domainExample=Example: \"domain.com\"", + "OtherCasesSearchDialog.correlationValueTextField.emailExample=Example: \"user@host.com\"", + "OtherCasesSearchDialog.correlationValueTextField.phoneExample=Example: \"(800)123-4567\"", + "OtherCasesSearchDialog.correlationValueTextField.usbExample=Example: \"4&1234567&0\"", + "OtherCasesSearchDialog.correlationValueTextField.ssidExample=Example: \"WirelessNetwork-5G\"" }) /** * Update the text prompt of the name text field based on the input type @@ -325,7 +360,30 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog { /** * Add text prompt to the text field. */ - String text = Bundle.OtherCasesSearchDialog_correlationValueTextField_filesExample(); + String text; + switch(selectedCorrelationType.getId()) { + case CorrelationAttributeInstance.FILES_TYPE_ID: + text = Bundle.OtherCasesSearchDialog_correlationValueTextField_filesExample(); + break; + case CorrelationAttributeInstance.DOMAIN_TYPE_ID: + text = Bundle.OtherCasesSearchDialog_correlationValueTextField_domainExample(); + break; + case CorrelationAttributeInstance.EMAIL_TYPE_ID: + text = Bundle.OtherCasesSearchDialog_correlationValueTextField_emailExample(); + break; + case CorrelationAttributeInstance.PHONE_TYPE_ID: + text = Bundle.OtherCasesSearchDialog_correlationValueTextField_phoneExample(); + break; + case CorrelationAttributeInstance.USBID_TYPE_ID: + text = Bundle.OtherCasesSearchDialog_correlationValueTextField_usbExample(); + break; + case CorrelationAttributeInstance.SSID_TYPE_ID: + text = Bundle.OtherCasesSearchDialog_correlationValueTextField_ssidExample(); + break; + default: + text = ""; + break; + } correlationValueTextFieldPrompt = new TextPrompt(text, correlationValueTextField); /** @@ -338,6 +396,19 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog { repaint(); } + /** + * Update the 'selectedCorrelationType' value to match the selected type + * from the combo-box. + */ + private void updateSelectedType() { + for (CorrelationAttributeInstance.Type type : correlationTypes) { + if (type.getDisplayName().equals((String) correlationTypeComboBox.getSelectedItem())) { + selectedCorrelationType = type; + break; + } + } + } + /** * Enable or disable the Search button depending on whether or not text has * been provided for the correlation property value. @@ -345,20 +416,6 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog { private void updateSearchButton() { searchButton.setEnabled(correlationValueTextField.getText().isEmpty() == false); } - - /** - * Validate the value input. - * - * @return True if the input is valid for the selected type; otherwise false. - */ - private boolean validateInputs() { - Pattern md5Pattern = Pattern.compile("^[a-fA-F0-9]{32}$"); // NON-NLS - Matcher matcher = md5Pattern.matcher(correlationValueTextField.getText().trim()); - if (matcher.find()) { - return true; - } - return false; - } /** * Display the Search Other Cases dialog. @@ -378,4 +435,4 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog { private javax.swing.JLabel errorLabel; private javax.swing.JButton searchButton; // End of variables declaration//GEN-END:variables -} +} \ No newline at end of file From a051a0ba2b0cfe5834ff3637df18d321032e72e0 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Mon, 26 Nov 2018 12:21:24 -0500 Subject: [PATCH 11/42] Reapplied trimming to correlation search. --- .../autopsy/othercasessearch/OtherCasesSearchDialog.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.java b/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.java index d0d82534ff..5fe417621c 100755 --- a/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.java +++ b/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.java @@ -236,7 +236,7 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog { private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchButtonActionPerformed CorrelationAttributeInstance.Type correlationType = selectedCorrelationType; - String correlationValue = correlationValueTextField.getText(); + String correlationValue = correlationValueTextField.getText().trim(); if (validateInputs(correlationType, correlationValue)) { search(correlationType, correlationValue); @@ -277,7 +277,7 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog { */ private boolean validateInputs(CorrelationAttributeInstance.Type type, String value) { try { - CorrelationAttributeNormalizer.normalize(type, correlationValueTextField.getText().trim()); + CorrelationAttributeNormalizer.normalize(type, value); } catch (CorrelationAttributeNormalizationException ex) { // No need to log this. return false; From 903084a5f303125913fa0f80f486c8b5c04a2804 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 26 Nov 2018 16:37:09 -0500 Subject: [PATCH 12/42] 4381 remove Artifact from the end of Artifact type column entries --- .../sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java index 7269a09e2c..8e950720b0 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java @@ -326,7 +326,6 @@ public class BlackboardArtifactNode extends AbstractContentNode(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactType.name"), NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactType.displayName"), NO_DESCR, - associatedArtifact.getDisplayName() + " " + NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.artifact.displayName"))); + associatedArtifact.getDisplayName())); sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactDetails.name"), NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactDetails.displayName"), NO_DESCR, From 6727c8a10b85e3ff177549a2837c71d5c847138f Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Mon, 26 Nov 2018 16:37:46 -0500 Subject: [PATCH 13/42] 4381 rename Artifact Type column to Result Type --- .../autopsy/datamodel/BlackboardArtifactNode.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java index 8e950720b0..5604f328d6 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java @@ -322,10 +322,10 @@ public class BlackboardArtifactNode extends AbstractContentNode Date: Tue, 27 Nov 2018 11:43:18 -0500 Subject: [PATCH 14/42] Revised signature. --- .../autopsy/report/ReportHTMLConfigurationPanel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTMLConfigurationPanel.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTMLConfigurationPanel.java index cd9f3a11e8..fbaa9d3a1a 100755 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTMLConfigurationPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTMLConfigurationPanel.java @@ -24,12 +24,12 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings; * The panel shown for all TableReportModules when configuring report modules. */ @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives -public class ReportHTMLConfigurationPanel extends javax.swing.JPanel { +final class ReportHTMLConfigurationPanel extends javax.swing.JPanel { /** * Creates new form DefaultReportConfigurationPanel */ - public ReportHTMLConfigurationPanel() { + ReportHTMLConfigurationPanel() { initComponents(); // Load settings From a95b734f17bfef8bb9595acceccd36478176baad Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 27 Nov 2018 21:50:36 -0500 Subject: [PATCH 15/42] Added note to UI; trimming in normalizer. --- .../CorrelationAttributeNormalizer.java | 16 ++++---- .../othercasessearch/Bundle.properties | 3 +- .../OtherCasesSearchDialog.form | 38 ++++++++++++------- .../OtherCasesSearchDialog.java | 34 ++++++++++------- 4 files changed, 57 insertions(+), 34 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeNormalizer.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeNormalizer.java index 4ce04769c8..d16a53a3a5 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeNormalizer.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeNormalizer.java @@ -52,19 +52,21 @@ final public class CorrelationAttributeNormalizer { throw new CorrelationAttributeNormalizationException("Data was null."); } + String trimmedData = data.trim(); + switch(attributeType.getId()){ case CorrelationAttributeInstance.FILES_TYPE_ID: - return normalizeMd5(data); + return normalizeMd5(trimmedData); case CorrelationAttributeInstance.DOMAIN_TYPE_ID: - return normalizeDomain(data); + return normalizeDomain(trimmedData); case CorrelationAttributeInstance.EMAIL_TYPE_ID: - return normalizeEmail(data); + return normalizeEmail(trimmedData); case CorrelationAttributeInstance.PHONE_TYPE_ID: - return normalizePhone(data); + return normalizePhone(trimmedData); case CorrelationAttributeInstance.USBID_TYPE_ID: - return normalizeUsbId(data); + return normalizeUsbId(trimmedData); case CorrelationAttributeInstance.SSID_TYPE_ID: - return data; + return trimmedData; default: final String errorMessage = String.format( "Validator function not found for attribute type: %s", @@ -89,7 +91,7 @@ final public class CorrelationAttributeNormalizer { if(typeOption.isPresent()){ CorrelationAttributeInstance.Type type = typeOption.get(); - return CorrelationAttributeNormalizer.normalize(type, data); + return CorrelationAttributeNormalizer.normalize(type, data.trim()); } else { throw new CorrelationAttributeNormalizationException(String.format("Given attributeTypeId did not correspond to any known Attribute: %s", attributeTypeId)); } diff --git a/Core/src/org/sleuthkit/autopsy/othercasessearch/Bundle.properties b/Core/src/org/sleuthkit/autopsy/othercasessearch/Bundle.properties index 17ea13ee0b..01ff2b1a1b 100755 --- a/Core/src/org/sleuthkit/autopsy/othercasessearch/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/othercasessearch/Bundle.properties @@ -4,7 +4,8 @@ OtherCasesSearchDialog.searchButton.AccessibleContext.accessibleName=Search OtherCasesSearchDialog.searchButton.text=Search OtherCasesSearchDialog.correlationValueTextField.text= OtherCasesSearchDialog.correlationValueLabel.text=Correlation Property Value: -OtherCasesSearchDialog.descriptionLabel.text=Search data in the Central Repository from other cases. +OtherCasesSearchDialog.descriptionLabel.text=Perform an exact-match (case insensitive) search for data in the Central Repository. OtherCasesSearchDialog.errorLabel.text=\ OtherCasesSearchDialog.correlationTypeLabel.text=Correlation Property Type: OtherCasesSearchDialog.casesLabel.text=\ +OtherCasesSearchDialog.noteLabel.text=Note: The search is case-insensitive, but will otherwise be an exact match. diff --git a/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.form b/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.form index 00eb862b4a..1e314b2a0f 100755 --- a/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.form +++ b/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.form @@ -27,15 +27,6 @@ - - - - - - - - - @@ -48,6 +39,18 @@ + + + + + + + + + + + + @@ -58,24 +61,26 @@ + + - + - + - + - + @@ -155,5 +160,12 @@ + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.java b/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.java index 5fe417621c..2a0237e5a0 100755 --- a/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.java +++ b/Core/src/org/sleuthkit/autopsy/othercasessearch/OtherCasesSearchDialog.java @@ -156,6 +156,7 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog { errorLabel = new javax.swing.JLabel(); descriptionLabel = new javax.swing.JLabel(); casesLabel = new javax.swing.JLabel(); + noteLabel = new javax.swing.JLabel(); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); setResizable(false); @@ -181,6 +182,8 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog { casesLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER); org.openide.awt.Mnemonics.setLocalizedText(casesLabel, org.openide.util.NbBundle.getMessage(OtherCasesSearchDialog.class, "OtherCasesSearchDialog.casesLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(noteLabel, org.openide.util.NbBundle.getMessage(OtherCasesSearchDialog.class, "OtherCasesSearchDialog.noteLabel.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( @@ -188,13 +191,6 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(casesLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGap(18, 18, 18) - .addComponent(searchButton)) - .addGroup(layout.createSequentialGroup() - .addComponent(descriptionLabel) - .addGap(0, 0, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(correlationValueLabel) @@ -203,7 +199,16 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog { .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(correlationTypeComboBox, 0, 289, Short.MAX_VALUE) .addComponent(correlationValueTextField) - .addComponent(errorLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) + .addComponent(errorLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addComponent(casesLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGap(18, 18, 18) + .addComponent(searchButton)) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(descriptionLabel) + .addComponent(noteLabel)) + .addGap(0, 0, Short.MAX_VALUE))) .addContainerGap()) ); layout.setVerticalGroup( @@ -211,21 +216,23 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog { .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addContainerGap() .addComponent(descriptionLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(noteLabel) .addGap(18, 18, 18) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(correlationTypeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(correlationTypeLabel)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGap(15, 15, 15) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(correlationValueLabel) - .addComponent(correlationValueTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(correlationValueTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(correlationValueLabel)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(errorLabel) - .addGap(11, 11, 11) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(searchButton) .addComponent(casesLabel)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) ); searchButton.getAccessibleContext().setAccessibleName(org.openide.util.NbBundle.getMessage(OtherCasesSearchDialog.class, "OtherCasesSearchDialog.searchButton.AccessibleContext.accessibleName")); // NOI18N @@ -433,6 +440,7 @@ final class OtherCasesSearchDialog extends javax.swing.JDialog { private javax.swing.JTextField correlationValueTextField; private javax.swing.JLabel descriptionLabel; private javax.swing.JLabel errorLabel; + private javax.swing.JLabel noteLabel; private javax.swing.JButton searchButton; // End of variables declaration//GEN-END:variables } \ No newline at end of file From ef404aa6ccf7fe943df743ac39875bf0078ce1bc Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 27 Nov 2018 21:53:51 -0500 Subject: [PATCH 16/42] Fixed typo. --- .../org/sleuthkit/autopsy/othercasessearch/Bundle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/othercasessearch/Bundle.properties b/Core/src/org/sleuthkit/autopsy/othercasessearch/Bundle.properties index 01ff2b1a1b..1634a47bfb 100755 --- a/Core/src/org/sleuthkit/autopsy/othercasessearch/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/othercasessearch/Bundle.properties @@ -4,7 +4,7 @@ OtherCasesSearchDialog.searchButton.AccessibleContext.accessibleName=Search OtherCasesSearchDialog.searchButton.text=Search OtherCasesSearchDialog.correlationValueTextField.text= OtherCasesSearchDialog.correlationValueLabel.text=Correlation Property Value: -OtherCasesSearchDialog.descriptionLabel.text=Perform an exact-match (case insensitive) search for data in the Central Repository. +OtherCasesSearchDialog.descriptionLabel.text=Search for data in Central Repository cases. OtherCasesSearchDialog.errorLabel.text=\ OtherCasesSearchDialog.correlationTypeLabel.text=Correlation Property Type: OtherCasesSearchDialog.casesLabel.text=\ From 93b1e81df23da4d9ae3345b3a9767a87f66c2099 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 29 Nov 2018 09:07:04 -0500 Subject: [PATCH 17/42] Initial ImageGalleryTopComponent improvements with TODOs --- .../imagegallery/ImageGalleryController.java | 13 +- .../imagegallery/ImageGalleryModule.java | 421 +++++++------- .../ImageGalleryOptionsPanel.java | 2 +- .../ImageGalleryTopComponent.java | 518 ++++++++++-------- .../imagegallery/actions/OpenAction.java | 55 +- .../datamodel/grouping/DrawableGroup.java | 14 +- .../datamodel/grouping/GroupManager.java | 2 +- .../gui/drawableviews/GroupPane.java | 8 +- 8 files changed, 545 insertions(+), 488 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index abe89abf40..4c192f2da5 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2018 Basis Technology Corp. + * Copyright 2013-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -183,7 +183,9 @@ public final class ImageGalleryController { } ImageGalleryController(@Nonnull Case newCase) throws TskCoreException { - + + + this.autopsyCase = Objects.requireNonNull(newCase); this.sleuthKitCase = newCase.getSleuthkitCase(); @@ -318,17 +320,14 @@ public final class ImageGalleryController { /** * reset the state of the controller (eg if the case is closed) */ - public synchronized void reset() { - logger.info("Closing ImageGalleryControler for case."); //NON-NLS - + public synchronized void shutDown() { selectionModel.clearSelection(); thumbnailCache.clearCache(); historyManager.clear(); groupManager.reset(); - shutDownDBExecutor(); drawableDB.close(); - dbExecutor = getNewDBExecutor(); + //dbExecutor = getNewDBExecutor(); RJCTODO } /** diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryModule.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryModule.java index 530e3eb7d6..f2be11ddae 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryModule.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryModule.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-18 Basis Technology Corp. + * Copyright 2013-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,12 +22,14 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.EnumSet; +import java.util.Set; import java.util.logging.Level; import javafx.application.Platform; +import javax.annotation.concurrent.GuardedBy; import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import static org.apache.commons.lang3.StringUtils.isNotBlank; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; @@ -35,11 +37,9 @@ import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.events.AutopsyEvent; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; import org.sleuthkit.autopsy.ingest.IngestManager; -import org.sleuthkit.autopsy.ingest.IngestManager.IngestJobEvent; import static org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent.DATA_ADDED; import static org.sleuthkit.autopsy.ingest.IngestManager.IngestModuleEvent.FILE_DONE; import org.sleuthkit.autopsy.ingest.ModuleDataEvent; @@ -53,71 +53,100 @@ import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; -/** static definitions, utilities, and listeners for the ImageGallery module */ +/** + * This class is reponsible for handling selected application events for the + * image gallery module, managing the image gallery module's per case MVC + * controller and keeping track of the following state: the module name, the + * module output directory and whether or not the ingest gallery module is + * enabled for the current case. + */ @NbBundle.Messages({"ImageGalleryModule.moduleName=Image Gallery"}) public class ImageGalleryModule { private static final Logger logger = Logger.getLogger(ImageGalleryModule.class.getName()); - private static final String MODULE_NAME = Bundle.ImageGalleryModule_moduleName(); - + private static final Set CASE_EVENTS_OF_INTEREST = EnumSet.of( + Case.Events.CURRENT_CASE, + Case.Events.DATA_SOURCE_ADDED, + Case.Events.CONTENT_TAG_ADDED, + Case.Events.CONTENT_TAG_DELETED + ); private static final Object controllerLock = new Object(); + @GuardedBy("controllerLock") private static ImageGalleryController controller; - public static ImageGalleryController getController() throws TskCoreException, NoCurrentCaseException { + /** + * Gets the per case image gallery controller for the current case. The + * controller is changed in the case event listener. + * + * @return The image gallery controller for the current case. + * + * @throws TskCoreException If there is a problem creating the controller. + */ + public static ImageGalleryController getController() throws TskCoreException { synchronized (controllerLock) { if (controller == null) { - controller = new ImageGalleryController(Case.getCurrentCaseThrows()); + try { + Case currentCase = Case.getCurrentCaseThrows(); + controller = new ImageGalleryController(currentCase); + } catch (NoCurrentCaseException ex) { + throw new TskCoreException("no current case", ex); + } } return controller; } } /** - * - * - * This method is invoked by virtue of the OnStart annotation on the OnStart - * class class + * Sets the implicit exit property attribute of the JavaFX Runtime to false + * and sets up listeners for application events. It is invoked at + * application start up by virtue of the OnStart annotation on the OnStart + * class in this package. */ static void onStart() { Platform.setImplicitExit(false); - logger.info("Setting up ImageGallery listeners"); //NON-NLS - IngestManager.getInstance().addIngestJobEventListener(new IngestJobEventListener()); IngestManager.getInstance().addIngestModuleEventListener(new IngestModuleEventListener()); - Case.addPropertyChangeListener(new CaseEventListener()); + Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, new CaseEventListener()); } + /** + * Gets the image gallery module name. + * + * @return The module name, + */ static String getModuleName() { return MODULE_NAME; } /** - * get the Path to the Case's ImageGallery ModuleOutput subfolder; ie - * ".../[CaseName]/ModuleOutput/Image Gallery/" + * Gets the path to the image gallery module output folder for a given case. * - * @param theCase the case to get the ImageGallery ModuleOutput subfolder - * for + * @param theCase The case. * - * @return the Path to the ModuleOuput subfolder for Image Gallery + * @return The path to the image gallery module output folder for the case. */ public static Path getModuleOutputDir(Case theCase) { return Paths.get(theCase.getModuleDirectory(), getModuleName()); } - /** provides static utilities, can not be instantiated */ + /** + * Prevents instantiation. + */ private ImageGalleryModule() { } - /** is listening enabled for the given case + /** + * Indicates whether or not the image gallery module is enabled for a given + * case. * - * @param c + * @param theCase The case. * - * @return true if listening is enabled for the given case, false otherwise + * @return True or false. */ - static boolean isEnabledforCase(Case c) { - if (c != null) { - String enabledforCaseProp = new PerCaseProperties(c).getConfigSetting(ImageGalleryModule.MODULE_NAME, PerCaseProperties.ENABLED); + static boolean isEnabledforCase(Case theCase) { + if (theCase != null) { + String enabledforCaseProp = new PerCaseProperties(theCase).getConfigSetting(ImageGalleryModule.MODULE_NAME, PerCaseProperties.ENABLED); return isNotBlank(enabledforCaseProp) ? Boolean.valueOf(enabledforCaseProp) : ImageGalleryPreferences.isEnabledByDefault(); } else { return false; @@ -125,197 +154,184 @@ public class ImageGalleryModule { } /** - * Is the given file 'supported' and not 'known'(nsrl hash hit). If so we - * should include it in {@link DrawableDB} and UI + * Indicates whether or not a given file is of interest to the image gallery + * module (is "drawable") and is not marked as a "known" file (e.g., is not + * a file in the NSRL hash set). * - * @param abstractFile + * @param file The file. * - * @return true if the given {@link AbstractFile} is "drawable" and not - * 'known', else false + * @return True if the file is "drawable" and not "known", false otherwise. * - * @throws - * org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector.FileTypeDetectorInitException + * @throws FileTypeDetectorInitException If there is an error determining + * the type of the file. */ - public static boolean isDrawableAndNotKnown(AbstractFile abstractFile) throws FileTypeDetector.FileTypeDetectorInitException { + private static boolean isDrawableAndNotKnown(AbstractFile abstractFile) throws FileTypeDetector.FileTypeDetectorInitException { return (abstractFile.getKnown() != TskData.FileKnown.KNOWN) && FileTypeUtils.isDrawable(abstractFile); } /** - * Listener for IngestModuleEvents + * A listener for ingest module application events. */ static private class IngestModuleEventListener implements PropertyChangeListener { @Override - public void propertyChange(PropertyChangeEvent evt) { + public void propertyChange(PropertyChangeEvent event) { + /* + * If running in "headless" mode, there is no need to process any + * ingest module events during the current session. + * + * Note that this check cannot be done earlier on start up because + * the "headless" property may not have been set yet. + */ if (RuntimeProperties.runningWithGUI() == false) { - /* - * Running in "headless" mode, no need to process any events. - * This cannot be done earlier because the switch to core - * components inactive may not have been made at start up. - */ IngestManager.getInstance().removeIngestModuleEventListener(this); return; } - /* only process individual files in realtime on the node that is - * running the ingest. on a remote node, image files are processed - * enblock when ingest is complete */ - if (((AutopsyEvent) evt).getSourceType() != AutopsyEvent.SourceType.LOCAL) { + /* + * Only process individual files and artifacts in "real time" on the + * node that is running the ingest job. On a remote node, image + * files are processed as a group when the ingest job is complete. + */ + if (((AutopsyEvent) event).getSourceType() != AutopsyEvent.SourceType.LOCAL) { return; } - // Bail out if the case is closed + ImageGalleryController currentController; try { - if (controller == null || Case.getCurrentCaseThrows() == null) { - return; - } - } catch (NoCurrentCaseException ex) { + currentController = getController(); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Failed to handle %s event", event.getPropertyName()), ex); //NON-NLS return; } - if (IngestManager.IngestModuleEvent.valueOf(evt.getPropertyName()) == FILE_DONE) { - - // getOldValue has fileID getNewValue has Abstractfile - AbstractFile file = (AbstractFile) evt.getNewValue(); - if (false == file.isFile()) { - return; - } - - try { - ImageGalleryController con = getController(); - if (con.isListeningEnabled()) { + String eventType = event.getPropertyName(); + switch (IngestManager.IngestModuleEvent.valueOf(eventType)) { + case FILE_DONE: + AbstractFile file = (AbstractFile) event.getNewValue(); + if (!file.isFile()) { + return; + } + if (currentController.isListeningEnabled()) { try { - // Update the entry if it is a picture and not in NSRL if (isDrawableAndNotKnown(file)) { - con.queueDBTask(new ImageGalleryController.UpdateFileTask(file, controller.getDatabase())); - } - // Remove it from the DB if it is no longer relevant, but had the correct extension - else if (FileTypeUtils.getAllSupportedExtensions().contains(file.getNameExtension())) { - /* Doing this check results in fewer tasks queued - * up, and faster completion of db update. This file - * would have gotten scooped up in initial grab, but - * actually we don't need it */ - con.queueDBTask(new ImageGalleryController.RemoveFileTask(file, controller.getDatabase())); + currentController.queueDBTask(new ImageGalleryController.UpdateFileTask(file, currentController.getDatabase())); } } catch (FileTypeDetector.FileTypeDetectorInitException ex) { - logger.log(Level.SEVERE, "Unable to determine if file is drawable and not known. Not making any changes to DB", ex); //NON-NLS - MessageNotifyUtil.Notify.error("Image Gallery Error", - "Unable to determine if file is drawable and not known. Not making any changes to DB. See the logs for details."); + logger.log(Level.SEVERE, String.format("Failed to determine if file is of interest to the image gallery module, ignoring file (obj_id=%d)", file.getId()), ex); //NON-NLS } } - } catch (NoCurrentCaseException ex) { - logger.log(Level.SEVERE, "Attempted to access ImageGallery with no case open.", ex); //NON-NLS - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error getting ImageGalleryController.", ex); //NON-NLS - } - } - else if (IngestManager.IngestModuleEvent.valueOf(evt.getPropertyName()) == DATA_ADDED) { - ModuleDataEvent mde = (ModuleDataEvent) evt.getOldValue(); - - if (mde.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID()) { - DrawableDB drawableDB = controller.getDatabase(); - if (mde.getArtifacts() != null) { - for (BlackboardArtifact art : mde.getArtifacts()) { - drawableDB.addExifCache(art.getObjectID()); + break; + case DATA_ADDED: + ModuleDataEvent artifactAddedEvent = (ModuleDataEvent) event.getOldValue(); + if (artifactAddedEvent.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID()) { + DrawableDB drawableDB = currentController.getDatabase(); + if (artifactAddedEvent.getArtifacts() != null) { + for (BlackboardArtifact art : artifactAddedEvent.getArtifacts()) { + drawableDB.addExifCache(art.getObjectID()); + } + } + } else if (artifactAddedEvent.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) { + DrawableDB drawableDB = currentController.getDatabase(); + if (artifactAddedEvent.getArtifacts() != null) { + for (BlackboardArtifact art : artifactAddedEvent.getArtifacts()) { + drawableDB.addHashSetCache(art.getObjectID()); + } } } - } - else if (mde.getBlackboardArtifactType().getTypeID() == ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) { - DrawableDB drawableDB = controller.getDatabase(); - if (mde.getArtifacts() != null) { - for (BlackboardArtifact art : mde.getArtifacts()) { - drawableDB.addHashSetCache(art.getObjectID()); - } - } - } + break; + default: + break; } } } /** - * Listener for case events. + * A listener for case application events. */ static private class CaseEventListener implements PropertyChangeListener { @Override - public void propertyChange(PropertyChangeEvent evt) { + public void propertyChange(PropertyChangeEvent event) { + /* + * If running in "headless" mode, there is no need to process any + * case events during the current session. Note that this check + * cannot be done earlier in onStart because the "headless" property + * may not have been set yet. + */ if (RuntimeProperties.runningWithGUI() == false) { - /* - * Running in "headless" mode, no need to process any events. - * This cannot be done earlier because the switch to core - * components inactive may not have been made at start up. - */ Case.removePropertyChangeListener(this); return; } - ImageGalleryController con; - try { - con = getController(); - } catch (NoCurrentCaseException ex) { - logger.log(Level.SEVERE, "Attempted to access ImageGallery with no case open.", ex); //NON-NLS - return; - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error getting ImageGalleryController.", ex); //NON-NLS - return; - } - switch (Case.Events.valueOf(evt.getPropertyName())) { - case CURRENT_CASE: - synchronized (controllerLock) { - // case has changes: close window, reset everything - SwingUtilities.invokeLater(ImageGalleryTopComponent::closeTopComponent); - if (controller != null) { - controller.reset(); - } - controller = null; - Case newCase = (Case) evt.getNewValue(); - if (newCase != null) { - // a new case has been opened: connect db, groupmanager, start worker thread - try { - controller = new ImageGalleryController(newCase); - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error changing case in ImageGallery.", ex); + Case.Events eventType = Case.Events.valueOf(event.getPropertyName()); + if (eventType == Case.Events.CURRENT_CASE) { + synchronized (controllerLock) { + if (event.getNewValue() != null && event.getNewValue() instanceof Case) { + /* + * CURRENT_CASE(_OPENED) event. Construct a new Image + * Gallery controller. + */ + Case newCase = (Case) event.getNewValue(); + try { + controller = new ImageGalleryController(newCase); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Failed to construct controller for new case", ex); + } + } else if (event.getOldValue() != null && event.getOldValue() instanceof Case) { + /* + * CURRENT_CASE(_CLOSED) event. Shut down the controller + * for the case and close the top component, if it is + * open. + */ + SwingUtilities.invokeLater(ImageGalleryTopComponent::closeTopComponent); + controller.shutDown(); + controller = null; + } + } + } else { + ImageGalleryController currentController; + try { + currentController = getController(); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Failed to handle %s event", event.getPropertyName()), ex); //NON-NLS + return; + } + + switch (eventType) { + case DATA_SOURCE_ADDED: + if (((AutopsyEvent) event).getSourceType() == AutopsyEvent.SourceType.LOCAL) { + Content newDataSource = (Content) event.getNewValue(); + if (currentController.isListeningEnabled()) { + currentController.getDatabase().insertOrUpdateDataSource(newDataSource.getId(), DrawableDB.DrawableDbBuildStatusEnum.DEFAULT); } } - } - break; - case DATA_SOURCE_ADDED: - //For a data source added on the local node, prepopulate all file data to drawable database - if (((AutopsyEvent) evt).getSourceType() == AutopsyEvent.SourceType.LOCAL) { - Content newDataSource = (Content) evt.getNewValue(); - if (con.isListeningEnabled()) { - controller.getDatabase().insertOrUpdateDataSource(newDataSource.getId(), DrawableDB.DrawableDbBuildStatusEnum.DEFAULT); + break; + case CONTENT_TAG_ADDED: + final ContentTagAddedEvent tagAddedEvent = (ContentTagAddedEvent) event; + long objId = tagAddedEvent.getAddedTag().getContent().getId(); + DrawableDB drawableDB = currentController.getDatabase(); + drawableDB.addTagCache(objId); + if (drawableDB.isInDB(objId)) { // RJCTODO: Put in cache before in DB check? + currentController.getTagsManager().fireTagAddedEvent(tagAddedEvent); } - } - break; - case CONTENT_TAG_ADDED: - final ContentTagAddedEvent tagAddedEvent = (ContentTagAddedEvent) evt; - - long objId = tagAddedEvent.getAddedTag().getContent().getId(); - - // update the cache - DrawableDB drawableDB = controller.getDatabase(); - drawableDB.addTagCache(objId); - - if (con.getDatabase().isInDB(objId)) { - con.getTagsManager().fireTagAddedEvent(tagAddedEvent); - } - break; - case CONTENT_TAG_DELETED: - final ContentTagDeletedEvent tagDeletedEvent = (ContentTagDeletedEvent) evt; - if (con.getDatabase().isInDB(tagDeletedEvent.getDeletedTagInfo().getContentID())) { - con.getTagsManager().fireTagDeletedEvent(tagDeletedEvent); - } - break; - default: - //we don't need to do anything for other events. - break; + break; + case CONTENT_TAG_DELETED: + final ContentTagDeletedEvent tagDeletedEvent = (ContentTagDeletedEvent) event; + if (currentController.getDatabase().isInDB(tagDeletedEvent.getDeletedTagInfo().getContentID())) { + currentController.getTagsManager().fireTagDeletedEvent(tagDeletedEvent); + } + break; + default: + logger.log(Level.SEVERE, String.format("Received %s event with no subscription", event.getPropertyName())); //NON-NLS + break; + } } } } /** - * Listener for Ingest Job events. + * A listener for ingest job application events. */ static private class IngestJobEventListener implements PropertyChangeListener { @@ -326,42 +342,54 @@ public class ImageGalleryModule { "ImageGalleryController.dataSourceAnalyzed.confDlg.title=Image Gallery" }) @Override - public void propertyChange(PropertyChangeEvent evt) { - IngestJobEvent eventType = IngestJobEvent.valueOf(evt.getPropertyName()); - + public void propertyChange(PropertyChangeEvent event) { + ImageGalleryController controller; try { - ImageGalleryController controller = getController(); - - if (eventType == IngestJobEvent.DATA_SOURCE_ANALYSIS_STARTED) { - - if (((AutopsyEvent) evt).getSourceType() == AutopsyEvent.SourceType.LOCAL) { + controller = getController(); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Failed to handle %s event", event.getPropertyName()), ex); //NON-NLS + return; + } + + String eventType = event.getPropertyName(); + switch (IngestManager.IngestJobEvent.valueOf(eventType)) { + case DATA_SOURCE_ANALYSIS_STARTED: + if (((AutopsyEvent) event).getSourceType() == AutopsyEvent.SourceType.LOCAL) { if (controller.isListeningEnabled()) { - DataSourceAnalysisStartedEvent dataSourceAnalysisStartedEvent = (DataSourceAnalysisStartedEvent) evt; + DataSourceAnalysisStartedEvent dataSourceAnalysisStartedEvent = (DataSourceAnalysisStartedEvent) event; Content dataSource = dataSourceAnalysisStartedEvent.getDataSource(); - - controller.getDatabase().insertOrUpdateDataSource(dataSource.getId(), DrawableDB.DrawableDbBuildStatusEnum.IN_PROGRESS); + + controller.getDatabase().insertOrUpdateDataSource(dataSource.getId(), DrawableDB.DrawableDbBuildStatusEnum.IN_PROGRESS); } } - } else if (eventType == IngestJobEvent.DATA_SOURCE_ANALYSIS_COMPLETED) { - - if (((AutopsyEvent) evt).getSourceType() == AutopsyEvent.SourceType.LOCAL) { + break; + case DATA_SOURCE_ANALYSIS_COMPLETED: + if (((AutopsyEvent) event).getSourceType() == AutopsyEvent.SourceType.LOCAL) { + /* + * This node just completed analysis of a data source. + * Set the state of the local drawables database. + */ if (controller.isListeningEnabled()) { - DataSourceAnalysisCompletedEvent dataSourceAnalysisCompletedEvent = (DataSourceAnalysisCompletedEvent) evt; + DataSourceAnalysisCompletedEvent dataSourceAnalysisCompletedEvent = (DataSourceAnalysisCompletedEvent) event; Content dataSource = dataSourceAnalysisCompletedEvent.getDataSource(); - - DrawableDB.DrawableDbBuildStatusEnum datasourceDrawableDBStatus = - controller.hasFilesWithNoMimetype(dataSource) ? - DrawableDB.DrawableDbBuildStatusEnum.DEFAULT : - DrawableDB.DrawableDbBuildStatusEnum.COMPLETE; - + try { + DrawableDB.DrawableDbBuildStatusEnum datasourceDrawableDBStatus + = controller.hasFilesWithNoMimetype(dataSource) + ? DrawableDB.DrawableDbBuildStatusEnum.DEFAULT + : DrawableDB.DrawableDbBuildStatusEnum.COMPLETE; controller.getDatabase().insertOrUpdateDataSource(dataSource.getId(), datasourceDrawableDBStatus); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Failed to query case database to determine drawables database state", ex); + } } - return; - } - - if (((AutopsyEvent) evt).getSourceType() == AutopsyEvent.SourceType.REMOTE) { - // A remote node added a new data source and just finished ingest on it. - //drawable db is stale, and if ImageGallery is open, ask user what to do + } else { + /* + * A remote node just completed analysis of a data + * source. The local drawables database is therefore + * stale. If the image gallery top component is open, + * give the user an opportunity to update the drawables + * database now. + */ controller.setStale(true); if (controller.isListeningEnabled()) { SwingUtilities.invokeLater(() -> { @@ -384,12 +412,9 @@ public class ImageGalleryModule { }); } } - } - } - catch (NoCurrentCaseException ex) { - logger.log(Level.SEVERE, "Attempted to access ImageGallery with no case open.", ex); //NON-NLS - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error getting ImageGalleryController.", ex); //NON-NLS + break; + default: + break; } } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryOptionsPanel.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryOptionsPanel.java index df0dacd3fe..92e65e2f4d 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryOptionsPanel.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryOptionsPanel.java @@ -212,7 +212,7 @@ final class ImageGalleryOptionsPanel extends javax.swing.JPanel { } catch (NoCurrentCaseException ex) { // It's not an error if there's no case open } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error getting ImageGalleryController.", ex); //NON-NLS + logger.log(Level.SEVERE, "Failed to get image gallery controller", ex); //NON-NLS } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java index 927dc6b70e..2a5f7c12d4 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2018 Basis Technology Corp. + * Copyright 2015-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -49,6 +49,7 @@ import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.stage.Modality; +import javax.annotation.concurrent.GuardedBy; import javax.swing.SwingUtilities; import static org.apache.commons.collections4.CollectionUtils.isNotEmpty; import static org.apache.commons.lang3.ObjectUtils.notEqual; @@ -61,7 +62,6 @@ import org.openide.windows.Mode; import org.openide.windows.RetainLocation; import org.openide.windows.TopComponent; import org.openide.windows.WindowManager; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; @@ -81,16 +81,11 @@ import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.TskCoreException; /** - * Top component which displays ImageGallery interface. - * - * Although ImageGallery doesn't currently use the explorer manager, this - * TopComponent provides one through the getExplorerManager method. However, - * this does not seem to function correctly unless a Netbeans provided explorer - * view is present in the TopComponenet, even if it is invisible/ zero sized + * The singleton Image Gallery top component. */ @TopComponent.Description( preferredID = "ImageGalleryTopComponent", - //iconBase = "org/sleuthkit/autopsy/imagegallery/images/lightbulb.png" use this to put icon in window title area, + //iconBase = "org/sleuthkit/autopsy/imagegallery/images/lightbulb.png", /*use this to put icon in window title area*/ persistenceType = TopComponent.PERSISTENCE_NEVER) @RetainLocation("ImageGallery") @TopComponent.Registration(mode = "ImageGallery", openAtStartup = false) @@ -101,13 +96,15 @@ import org.sleuthkit.datamodel.TskCoreException; @SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives public final class ImageGalleryTopComponent extends TopComponent implements ExplorerManager.Provider, Lookup.Provider { - public final static String PREFERRED_ID = "ImageGalleryTopComponent"; // NON-NLS + private static final long serialVersionUID = 1L; + public final static String PREFERRED_ID = "ImageGalleryTopComponent"; // NON-NLS // RJCTODO: This should not be public, clients should call getTopComponent instead private static final Logger logger = Logger.getLogger(ImageGalleryTopComponent.class.getName()); - private static volatile boolean topComponentInitialized = false; private final ExplorerManager em = new ExplorerManager(); private final Lookup lookup = (ExplorerUtils.createLookup(em, getActionMap())); + private final Object controllerLock = new Object(); + @GuardedBy("controllerLock") private ImageGalleryController controller; private SplitPane splitPane; @@ -125,148 +122,86 @@ public final class ImageGalleryTopComponent extends TopComponent implements Expl private final Region infoOverLayBackground = new TranslucentRegion(); /** - * Returns whether the ImageGallery window is open or not. + * Queries whether the singleton Image Gallery top component's window is + * open. Note that calling this method will cause the top component to be + * constructed if it does not already exist. * - * @return true, if Image gallery is opened, false otherwise + * @return True or false. */ public static boolean isImageGalleryOpen() { - - final TopComponent topComponent = WindowManager.getDefault().findTopComponent(PREFERRED_ID); - if (topComponent != null) { - return topComponent.isOpened(); - } - return false; + return getTopComponent().isOpened(); } /** - * Returns the top component window. + * Gets the singleton Image Gallery top component. Note that calling this + * method will cause the top component to be constructed if it does not + * already exist. * - * @return Image gallery top component window, null if it's not open + * @return The top component. */ - public static TopComponent getTopComponent() { - return WindowManager.getDefault().findTopComponent(PREFERRED_ID); + public static ImageGalleryTopComponent getTopComponent() { + return (ImageGalleryTopComponent) WindowManager.getDefault().findTopComponent(PREFERRED_ID); } /** - * Open the ImageGalleryTopComponent. + * Creates the Image Gallery top component if it does not already exist and + * opens its window. * - * @throws NoCurrentCaseException If there is no case open. - * @throws TskCoreException If there is a problem accessing the case - * db. + * @throws TskCoreException If there is a problem opening the top component. */ @ThreadConfined(type = ThreadConfined.ThreadType.AWT) - @Messages({ - "ImageGalleryTopComponent.chooseDataSourceDialog.headerText=Choose a data source to view.", - "ImageGalleryTopComponent.chooseDataSourceDialog.contentText=Data source:", - "ImageGalleryTopComponent.chooseDataSourceDialog.all=All", - "ImageGalleryTopComponent.chooseDataSourceDialog.titleText=Image Gallery",}) - public static void openTopComponent() throws NoCurrentCaseException, TskCoreException { - - // This creates the top component and adds the UI widgets (via the constructor) if it has not yet been opened - final TopComponent topComponent = WindowManager.getDefault().findTopComponent(PREFERRED_ID); - if (topComponent == null) { - return; - } - + public static void openTopComponent() throws TskCoreException { + final ImageGalleryTopComponent topComponent = getTopComponent(); if (topComponent.isOpened()) { - showTopComponent(topComponent); - return; + showTopComponent(); + } else { + topComponent.getCurrentControllerAndOpen(); } - - // Wait until the FX UI has been created. This way, we can always - // show the gray progress screen - // TODO: do this in a more elegant way. - while (topComponentInitialized == false) { - } - - ImageGalleryController controller = ImageGalleryModule.getController(); - ImageGalleryTopComponent igTopComponent = (ImageGalleryTopComponent) topComponent; - igTopComponent.setController(controller); - - //gather information about datasources and the groupmanager in a bg thread. - new Thread(new Task() { - @Override - protected Void call() throws Exception { - Map dataSourcesTooManyFiles = new HashMap<>(); - List dataSources = controller.getSleuthKitCase().getDataSources(); - - /* - * If there is only one datasource or the grouping is already - * set to something other than path , don't bother to ask for - * datasource. - */ - if (dataSources.size() <= 1 - || controller.getGroupManager().getGroupBy() != DrawableAttribute.PATH) { - // null represents all datasources, which is only one in this case. - dataSourcesTooManyFiles.put(null, controller.hasTooManyFiles(null)); - igTopComponent.showDataSource(null, dataSourcesTooManyFiles); - return null; - } - - /* - * Else there is more than one data source and the grouping is - * PATH (the default): open a dialog prompting the user to pick - * a datasource. - */ - dataSources.add(0, null); //null represents all datasources - //first, while still on background thread, gather viewability info for the datasources. - for (DataSource dataSource : dataSources) { - dataSourcesTooManyFiles.put(dataSource, controller.hasTooManyFiles(dataSource)); - } - - Platform.runLater(() -> { - //configure the dialog - List> dataSourceOptionals = dataSources.stream().map(Optional::ofNullable).collect(Collectors.toList()); - ChoiceDialog> datasourceDialog = new ChoiceDialog<>(null, dataSourceOptionals); - datasourceDialog.setTitle(Bundle.ImageGalleryTopComponent_chooseDataSourceDialog_titleText()); - datasourceDialog.setHeaderText(Bundle.ImageGalleryTopComponent_chooseDataSourceDialog_headerText()); - datasourceDialog.setContentText(Bundle.ImageGalleryTopComponent_chooseDataSourceDialog_contentText()); - datasourceDialog.initModality(Modality.APPLICATION_MODAL); - GuiUtils.setDialogIcons(datasourceDialog); - //get the combobox by its css class... this is hacky but should be safe. - @SuppressWarnings(value = "unchecked") - ComboBox> comboBox = (ComboBox>) datasourceDialog.getDialogPane().lookup(".combo-box"); - //set custom cell renderer - comboBox.setCellFactory((ListView> param) -> new DataSourceCell(dataSourcesTooManyFiles, controller.getAllDataSourcesDrawableDBStatus())); - comboBox.setButtonCell(new DataSourceCell(dataSourcesTooManyFiles, controller.getAllDataSourcesDrawableDBStatus())); - - DataSource dataSource = datasourceDialog.showAndWait().orElse(Optional.empty()).orElse(null); - try { - - igTopComponent.showDataSource(dataSource, dataSourcesTooManyFiles); - } catch (TskCoreException ex) { - if (dataSource != null) { - logger.log(Level.SEVERE, "Error showing data source " + dataSource.getName() + ":" + dataSource.getId() + " in Image Gallery", ex); - } else { - logger.log(Level.SEVERE, "Error showing all data sources in Image Gallery.", ex); - } - } - }); - - return null; - } - }).start(); } - synchronized private void showDataSource(DataSource datasource, Map dataSourcesTooManyFiles) throws TskCoreException { - if (dataSourcesTooManyFiles.get(datasource)) { + /** + * Configures the groups manager for the selected data source(s) and opens + * this top component's window. + * + * @param selectedDataSource The data source selected, null if all data + * sources are selected. + * @param dataSourcesTooManyFiles A map of data sources to flags indicating + * whether or not the data source has to many + * files to actually be displayed. + */ + private void openWithSelectedDataSources(DataSource selectedDataSource, Map dataSourcesTooManyFiles) { + if (dataSourcesTooManyFiles.get(selectedDataSource)) { Platform.runLater(ImageGalleryTopComponent::showTooManyFiles); - return; - } - // Display the UI so that they can see the progress screen - SwingUtilities.invokeLater(() -> showTopComponent(this)); - GroupManager groupManager = controller.getGroupManager(); - synchronized (groupManager) { - groupManager.regroup(datasource, groupManager.getGroupBy(), groupManager.getSortBy(), groupManager.getSortOrder(), true); + } else { + /* + * Open the top component's window before configuring the groups + * manager so that the wait cursor animation over the empty, gray + * window will be displayed if the operations takes awhile. + */ + SwingUtilities.invokeLater(() -> showTopComponent()); + synchronized (controllerLock) { + GroupManager groupManager = controller.getGroupManager(); + // RJCTODO: Why are there potentially hazardous nested synchronized + // blocks here (note: method used ot be synchronized)? Why is + // the groups manager not taking responsibility for its own thread + // safety policy? + synchronized (groupManager) { + groupManager.regroup(selectedDataSource, groupManager.getGroupBy(), groupManager.getSortBy(), groupManager.getSortOrder(), true); + } + } } } + /** + * Displays a dialog box informing the user that the data source(s) selected + * to have their images displayed have too many image files and will not be + * displayed. + */ @NbBundle.Messages({"ImageGallery.dialogTitle=Image Gallery", "ImageGallery.showTooManyFiles.contentText=There are too many files in the selected datasource(s) to ensure reasonable performance.", "ImageGallery.showTooManyFiles.headerText="}) - public static void showTooManyFiles() { - Alert dialog = new Alert(Alert.AlertType.INFORMATION, - Bundle.ImageGallery_showTooManyFiles_contentText(), ButtonType.OK); + private static void showTooManyFiles() { + Alert dialog = new Alert(Alert.AlertType.INFORMATION, Bundle.ImageGallery_showTooManyFiles_contentText(), ButtonType.OK); dialog.initModality(Modality.APPLICATION_MODAL); dialog.setTitle(Bundle.ImageGallery_dialogTitle()); GuiUtils.setDialogIcons(dialog); @@ -274,8 +209,14 @@ public final class ImageGalleryTopComponent extends TopComponent implements Expl dialog.showAndWait(); } + /** + * Opens the singleton top component's window, brings it to the front and + * gives it focus. Note that calling this method will cause the top + * component to be constructed if it does not already exist. + */ @ThreadConfined(type = ThreadConfined.ThreadType.AWT) - public static void showTopComponent(TopComponent topComponent) { + private static void showTopComponent() { + final ImageGalleryTopComponent topComponent = getTopComponent(); if (topComponent.isOpened() == false) { topComponent.open(); } @@ -283,76 +224,170 @@ public final class ImageGalleryTopComponent extends TopComponent implements Expl topComponent.requestActive(); } + /* + * Closes the singleton Image Gallery top component. Note that calling this + * method will cause the top component to be constructed if it does not + * already exist. + */ public static void closeTopComponent() { - if (topComponentInitialized) { - final TopComponent etc = WindowManager.getDefault().findTopComponent(PREFERRED_ID); - if (etc != null) { - try { - etc.close(); - } catch (Exception e) { - logger.log(Level.SEVERE, "failed to close " + PREFERRED_ID, e); // NON-NLS - } - } - } + getTopComponent().close(); } + /** + * Contructs the singleton Image Gallery top component. Called by the + * NetBeans WindowManager. + */ public ImageGalleryTopComponent() { setName(Bundle.CTL_ImageGalleryTopComponent()); initComponents(); - try { - setController(ImageGalleryModule.getController()); - } catch (NoCurrentCaseException ex) { - logger.log(Level.SEVERE, "Attempted to access ImageGallery with no case open.", ex); //NON-NLS - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error getting ImageGalleryController.", ex); //NON-NLS - } } - synchronized private void setController(ImageGalleryController controller) { - if (notEqual(this.controller, controller)) { - if (this.controller != null) { - this.controller.reset(); - } - this.controller = controller; - Platform.runLater(new Runnable() { - @Override - public void run() { - //initialize jfx ui - fullUIStack = new StackPane(); //this is passed into controller - myScene = new Scene(fullUIStack); - jfxPanel.setScene(myScene); - groupPane = new GroupPane(controller); - centralStack = new StackPane(groupPane); //this is passed into controller - fullUIStack.getChildren().add(borderPane); - splitPane = new SplitPane(); - borderPane.setCenter(splitPane); - Toolbar toolbar = new Toolbar(controller); - borderPane.setTop(toolbar); - borderPane.setBottom(new StatusBar(controller)); - metaDataTable = new MetaDataPane(controller); - groupTree = new GroupTree(controller); - hashHitList = new HashHitGroupList(controller); - TabPane tabPane = new TabPane(groupTree, hashHitList); - tabPane.setPrefWidth(TabPane.USE_COMPUTED_SIZE); - tabPane.setMinWidth(TabPane.USE_PREF_SIZE); - VBox.setVgrow(tabPane, Priority.ALWAYS); - leftPane = new VBox(tabPane, new SummaryTablePane(controller)); - SplitPane.setResizableWithParent(leftPane, Boolean.FALSE); - SplitPane.setResizableWithParent(groupPane, Boolean.TRUE); - SplitPane.setResizableWithParent(metaDataTable, Boolean.FALSE); - splitPane.getItems().addAll(leftPane, centralStack, metaDataTable); - splitPane.setDividerPositions(0.1, 1.0); + /** + * Gets the current controller, allows the user to select the data sources + * for which images are to be displayed and opens the top component's + * window. + * + * @throws TskCoreException If there is an error getting the current + * controller. + */ + @Messages({ + "ImageGalleryTopComponent.chooseDataSourceDialog.headerText=Choose a data source to view.", + "ImageGalleryTopComponent.chooseDataSourceDialog.contentText=Data source:", + "ImageGalleryTopComponent.chooseDataSourceDialog.all=All", + "ImageGalleryTopComponent.chooseDataSourceDialog.titleText=Image Gallery",}) + private void getCurrentControllerAndOpen() throws TskCoreException { + ImageGalleryController currentController = ImageGalleryModule.getController(); + /* + * First, dispatch a task to run in the JavaFX thread. This task will + * swap the new controller, if there is one, into this top component and + * its child UI components. It also queues another JavaFX thread task to + * check for analyzed groups, which has the side effect of managing the + * spinner(s) that take the place of a wait cursor. + */ + Platform.runLater(new Runnable() { + @Override + public void run() { + synchronized (controllerLock) { + if (notEqual(controller, currentController)) { + controller = currentController; + /* + * Create or re-create the top component's child UI + * components. This is currently done every time a new + * controller is created (i.e., a new case is opened). + * It could be done by resetting the controller in the + * child UI components instead. + */ + fullUIStack = new StackPane(); + myScene = new Scene(fullUIStack); + jfxPanel.setScene(myScene); + groupPane = new GroupPane(controller); + centralStack = new StackPane(groupPane); + fullUIStack.getChildren().add(borderPane); + splitPane = new SplitPane(); + borderPane.setCenter(splitPane); + Toolbar toolbar = new Toolbar(controller); + borderPane.setTop(toolbar); + borderPane.setBottom(new StatusBar(controller)); + metaDataTable = new MetaDataPane(controller); + groupTree = new GroupTree(controller); + hashHitList = new HashHitGroupList(controller); + TabPane tabPane = new TabPane(groupTree, hashHitList); + tabPane.setPrefWidth(TabPane.USE_COMPUTED_SIZE); + tabPane.setMinWidth(TabPane.USE_PREF_SIZE); + VBox.setVgrow(tabPane, Priority.ALWAYS); + leftPane = new VBox(tabPane, new SummaryTablePane(controller)); + SplitPane.setResizableWithParent(leftPane, Boolean.FALSE); + SplitPane.setResizableWithParent(groupPane, Boolean.TRUE); + SplitPane.setResizableWithParent(metaDataTable, Boolean.FALSE); + splitPane.getItems().addAll(leftPane, centralStack, metaDataTable); + splitPane.setDividerPositions(0.1, 1.0); - controller.regroupDisabledProperty().addListener((Observable observable) -> checkForGroups()); - controller.getGroupManager().getAnalyzedGroups().addListener((Observable observable) -> Platform.runLater(() -> checkForGroups())); + /* + * Set up for a call to checkForGroups to happen + * whenever the controller's regrouping disabled + * property or the group manager's analyzed groups + * property changes. + */ + // RJCTODO: Why was the first lambda not set up to happen on + // the JavaFX thread? I am using that thread confinement and + // a volatile controller reference for simplified thread safety, + // is there a problem with this? It seems like this is a bug, + // since why would we want this code to execute both in the + // JavaFX thread and elsewhere? + controller.regroupDisabledProperty().addListener((Observable unused) -> Platform.runLater(() -> checkForAnalyzedGroups())); + controller.getGroupManager().getAnalyzedGroups().addListener((Observable unused) -> Platform.runLater(() -> checkForAnalyzedGroups())); - topComponentInitialized = true; + /* + * Dispatch a later task to call check for groups. Note + * that this method displays one or more spinner(s) that + * take the place of a wait cursor if there are no + * analyzed groups yet, ingest is running, etc. + */ + // RJCTODO: Is there a race condition here, since this task will be + // executed before the task to actually open the top component window? + // It seems like this might be a sort of a hack and I am wondering + // why this can't be done in openWithSelectedDataSources instead. + Platform.runLater(() -> checkForAnalyzedGroups()); + } - // This will cause the UI to show the progress dialog - Platform.runLater(() -> checkForGroups()); + /* + * Kick off a background task to query the case database for + * data sources. This task may queue another task for the + * JavaFX thread to allow the user to select which data + * sources for which to display images. Ultimately, a task + * will be queued for the AWT EDT that will show the top + * component window. + */ + new Thread(new Task() { + @Override + protected Void call() throws Exception { + synchronized (controllerLock) { + /* + * If there is only one datasource or the + * grouping criterion is already set to + * something other than by path (the default), + * proceed to open this top component. + * Otherwise, do a dialog to allow the user to + * select the data sources for which images are + * to be displayed, then open the top component. + */ + List dataSources = controller.getSleuthKitCase().getDataSources(); + Map dataSourcesWithTooManyFiles = new HashMap<>(); + // RJCTODO: At least some of this designation of "all data sources" with null seems uneccessary; + // in any case, the use of nulls and zeros here is + // very confusing and should be reworked. Why was this done? + if (dataSources.size() <= 1 + || controller.getGroupManager().getGroupBy() != DrawableAttribute.PATH) { + dataSourcesWithTooManyFiles.put(null, controller.hasTooManyFiles(null)); + openWithSelectedDataSources(null, dataSourcesWithTooManyFiles); + } else { + dataSources.add(0, null); + for (DataSource dataSource : dataSources) { + dataSourcesWithTooManyFiles.put(dataSource, controller.hasTooManyFiles(dataSource)); + } + Platform.runLater(() -> { + List> dataSourceOptionals = dataSources.stream().map(Optional::ofNullable).collect(Collectors.toList()); + ChoiceDialog> datasourceDialog = new ChoiceDialog<>(null, dataSourceOptionals); + datasourceDialog.setTitle(Bundle.ImageGalleryTopComponent_chooseDataSourceDialog_titleText()); + datasourceDialog.setHeaderText(Bundle.ImageGalleryTopComponent_chooseDataSourceDialog_headerText()); + datasourceDialog.setContentText(Bundle.ImageGalleryTopComponent_chooseDataSourceDialog_contentText()); + datasourceDialog.initModality(Modality.APPLICATION_MODAL); + GuiUtils.setDialogIcons(datasourceDialog); + @SuppressWarnings(value = "unchecked") + ComboBox> comboBox = (ComboBox>) datasourceDialog.getDialogPane().lookup(".combo-box"); + comboBox.setCellFactory((ListView> param) -> new DataSourceCell(dataSourcesWithTooManyFiles, controller.getAllDataSourcesDrawableDBStatus())); + comboBox.setButtonCell(new DataSourceCell(dataSourcesWithTooManyFiles, controller.getAllDataSourcesDrawableDBStatus())); + DataSource dataSource = datasourceDialog.showAndWait().orElse(Optional.empty()).orElse(null); + openWithSelectedDataSources(dataSource, dataSourcesWithTooManyFiles); + }); + } + return null; + } + } + }).start(); } - }); - } + } + }); } /** @@ -400,6 +435,14 @@ public final class ImageGalleryTopComponent extends TopComponent implements Expl @Override public ExplorerManager getExplorerManager() { + /* + * Although ImageGallery doesn't currently use the explorer manager, + * this TopComponent provides one through the getExplorerManager method. + * However, this does not seem to function correctly unless a Netbeans + * provided explorer view is present in the TopComponenet, even if it is + * invisible/ zero sized + */ + // RJCTODO: Why is this here? return em; } @@ -409,11 +452,10 @@ public final class ImageGalleryTopComponent extends TopComponent implements Expl } /** - * Check if there are any fully analyzed groups available from the - * GroupManager and remove blocking progress spinners if there are. If there - * aren't, add a blocking progress spinner with appropriate message. - * - * This gets called when any group becomes analyzed and when started. + * Checks if there are any fully analyzed groups available from the groups + * manager and removes the blocking progress spinner if there are analyzed + * groups; otherwise adds a blocking progress spinner with an appropriate + * message. */ @ThreadConfined(type = ThreadConfined.ThreadType.JFX) @NbBundle.Messages({ @@ -427,57 +469,59 @@ public final class ImageGalleryTopComponent extends TopComponent implements Expl "ImageGalleryController.noGroupsDlg.msg6=There are no fully analyzed groups to display:" + " the current Group By setting resulted in no groups, " + "or no groups are fully analyzed but ingest is not running."}) - private void checkForGroups() { - GroupManager groupManager = controller.getGroupManager(); + private void checkForAnalyzedGroups() { + synchronized (controllerLock) { + GroupManager groupManager = controller.getGroupManager(); - // if there are groups to display, then display them - // @@@ Need to check timing on this and make sure we have only groups for the selected DS. Seems like rebuild can cause groups to be created for a DS that is not later selected... - if (isNotEmpty(groupManager.getAnalyzedGroups())) { - clearNotification(); - return; - } - - // display a message based on if ingest is running and/or listening - if (IngestManager.getInstance().isIngestRunning()) { - if (controller.isListeningEnabled()) { - replaceNotification(centralStack, - new NoGroupsDialog(Bundle.ImageGalleryController_noGroupsDlg_msg2(), - new ProgressIndicator())); - } else { - replaceNotification(fullUIStack, - new NoGroupsDialog(Bundle.ImageGalleryController_noGroupsDlg_msg1())); + // if there are groups to display, then display them + // @@@ Need to check timing on this and make sure we have only groups for the selected DS. Seems like rebuild can cause groups to be created for a DS that is not later selected... + if (isNotEmpty(groupManager.getAnalyzedGroups())) { + clearNotification(); + return; } - return; - } - // display a message about stuff still being in the queue - if (controller.getDBTasksQueueSizeProperty().get() > 0) { - replaceNotification(fullUIStack, - new NoGroupsDialog(Bundle.ImageGalleryController_noGroupsDlg_msg3(), - new ProgressIndicator())); - return; - } - - // are there are files in the DB? - try { - if (controller.getDatabase().countAllFiles() <= 0) { - // there are no files in db + // display a message based on if ingest is running and/or listening + if (IngestManager.getInstance().isIngestRunning()) { if (controller.isListeningEnabled()) { - replaceNotification(fullUIStack, - new NoGroupsDialog(Bundle.ImageGalleryController_noGroupsDlg_msg5())); + replaceNotification(centralStack, + new NoGroupsDialog(Bundle.ImageGalleryController_noGroupsDlg_msg2(), + new ProgressIndicator())); } else { replaceNotification(fullUIStack, - new NoGroupsDialog(Bundle.ImageGalleryController_noGroupsDlg_msg4())); + new NoGroupsDialog(Bundle.ImageGalleryController_noGroupsDlg_msg1())); } return; } - } catch (TskCoreException tskCoreException) { - logger.log(Level.SEVERE, "Error counting files in the database.", tskCoreException); - } - if (false == groupManager.isRegrouping()) { - replaceNotification(centralStack, - new NoGroupsDialog(Bundle.ImageGalleryController_noGroupsDlg_msg6())); + // display a message about stuff still being in the queue + if (controller.getDBTasksQueueSizeProperty().get() > 0) { + replaceNotification(fullUIStack, + new NoGroupsDialog(Bundle.ImageGalleryController_noGroupsDlg_msg3(), + new ProgressIndicator())); + return; + } + + // are there are files in the DB? + try { + if (controller.getDatabase().countAllFiles() <= 0) { + // there are no files in db + if (controller.isListeningEnabled()) { + replaceNotification(fullUIStack, + new NoGroupsDialog(Bundle.ImageGalleryController_noGroupsDlg_msg5())); + } else { + replaceNotification(fullUIStack, + new NoGroupsDialog(Bundle.ImageGalleryController_noGroupsDlg_msg4())); + } + return; + } + } catch (TskCoreException tskCoreException) { + logger.log(Level.SEVERE, "Error counting files in the database.", tskCoreException); + } + + if (false == groupManager.isRegrouping()) { + replaceNotification(centralStack, + new NoGroupsDialog(Bundle.ImageGalleryController_noGroupsDlg_msg6())); + } } } @@ -491,17 +535,17 @@ public final class ImageGalleryTopComponent extends TopComponent implements Expl } + /** + * Removes the spinner(s). + */ @ThreadConfined(type = ThreadConfined.ThreadType.JFX) private void clearNotification() { - //remove the ingest spinner fullUIStack.getChildren().remove(infoOverlay); - //remove the ingest spinner centralStack.getChildren().remove(infoOverlay); - } /** - * Region with partialy opacity used to block out parts of the UI behind a + * A partially opaque region used to block out parts of the UI behind a * pseudo dialog. */ static final private class TranslucentRegion extends Region { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java index 5a921e6130..429051b931 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/OpenAction.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015-2018 Basis Technology Corp. + * Copyright 2013-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -70,7 +70,7 @@ import org.sleuthkit.datamodel.TskCoreException; + "Do you want to update and listen for further ingest results?\n" + "Choosing 'yes' will update the database and enable listening to future ingests.", "OpenAction.notAnalyzedDlg.msg=No image/video files available to display yet.\n" - + "Please run FileType and EXIF ingest modules.", + + "Please run FileType and EXIF ingest modules.", "OpenAction.stale.confDlg.title=Image Gallery"}) public final class OpenAction extends CallableSystemAction { @@ -147,19 +147,20 @@ public final class OpenAction extends CallableSystemAction { try { currentCase = Case.getCurrentCaseThrows(); } catch (NoCurrentCaseException ex) { - logger.log(Level.SEVERE, "Exception while getting open case.", ex); - return; - } - ImageGalleryController controller; - try { - controller = ImageGalleryModule.getController(); - } catch (TskCoreException | NoCurrentCaseException ex) { - logger.log(Level.SEVERE, "Exception while getting ImageGalleryController for current case.", ex); + logger.log(Level.SEVERE, "No current case", ex); return; } Platform.runLater(() -> { + ImageGalleryController controller; + try { + controller = ImageGalleryModule.getController(); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Failed to get ImageGalleryController", ex); + return; + } + if (currentCase.getCaseType() == Case.CaseType.MULTI_USER_CASE - && ImageGalleryPreferences.isMultiUserCaseInfoDialogDisabled() == false) { + && ImageGalleryPreferences.isMultiUserCaseInfoDialogDisabled() == false) { Alert dialog = new Alert(Alert.AlertType.INFORMATION); dialog.initModality(Modality.APPLICATION_MODAL); dialog.setResizable(true); @@ -185,32 +186,32 @@ public final class OpenAction extends CallableSystemAction { } private void checkDBStale(ImageGalleryController controller) { - - ListenableFuture> dataSourceStatusMapFuture = TaskUtils.getExecutorForClass(OpenAction.class) + + ListenableFuture> dataSourceStatusMapFuture = TaskUtils.getExecutorForClass(OpenAction.class) .submit(controller::getAllDataSourcesDrawableDBStatus); - + addFXCallback(dataSourceStatusMapFuture, dataSourceStatusMap -> { - + boolean dbIsStale = false; for (Map.Entry entry : dataSourceStatusMap.entrySet()) { DrawableDbBuildStatusEnum status = entry.getValue(); if (DrawableDbBuildStatusEnum.COMPLETE != status) { - dbIsStale = true; + dbIsStale = true; } - } - + } + //back on fx thread. if (false == dbIsStale) { //drawable db is not stale, just open it openTopComponent(); } else { - + // If there is only one datasource and it's in DEFAULT State - // ingest modules need to be run on the data source - if (dataSourceStatusMap.size()== 1) { + if (dataSourceStatusMap.size() == 1) { Map.Entry entry = dataSourceStatusMap.entrySet().iterator().next(); - if (entry.getValue() == DrawableDbBuildStatusEnum.DEFAULT ) { + if (entry.getValue() == DrawableDbBuildStatusEnum.DEFAULT) { Alert alert = new Alert(Alert.AlertType.WARNING, Bundle.OpenAction_notAnalyzedDlg_msg(), ButtonType.OK); alert.setTitle(Bundle.OpenAction_stale_confDlg_title()); alert.initModality(Modality.APPLICATION_MODAL); @@ -218,8 +219,8 @@ public final class OpenAction extends CallableSystemAction { alert.showAndWait(); return; } - } - + } + //drawable db is stale, //ask what to do Alert alert = new Alert(Alert.AlertType.WARNING, @@ -235,7 +236,8 @@ public final class OpenAction extends CallableSystemAction { openTopComponent(); } else if (answer == ButtonType.YES) { if (controller.getAutopsyCase().getCaseType() == Case.CaseType.SINGLE_USER_CASE) { - /* For a single-user case, we favor user + /* + * For a single-user case, we favor user * experience, and rebuild the database as soon * as Image Gallery is enabled for the case. * @@ -267,10 +269,9 @@ public final class OpenAction extends CallableSystemAction { SwingUtilities.invokeLater(() -> { try { ImageGalleryTopComponent.openTopComponent(); - } catch (NoCurrentCaseException ex) { - logger.log(Level.SEVERE, "Attempted to access ImageGallery with no case open.", ex);//NON-NLS } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error getting ImageGalleryController.", ex); //NON-NLS} + logger.log(Level.SEVERE, "Failed to open Image Gallery top component", ex); //NON-NLS} + // RJCTODO: Give the user some feedback here } }); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java index 5469afe4d3..98808a4197 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-18 Basis Technology Corp. + * Copyright 2013-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -31,9 +31,7 @@ import javafx.beans.property.ReadOnlyBooleanWrapper; import javafx.beans.property.ReadOnlyLongProperty; import javafx.beans.property.ReadOnlyLongWrapper; import javafx.collections.FXCollections; -import javafx.collections.ListChangeListener; import javafx.collections.ObservableList; -import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.ImageGalleryModule; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; @@ -120,10 +118,8 @@ public class DrawableGroup implements Comparable { .map(ImageGalleryModule.getController().getHashSetManager()::isInAnyHashSet) .filter(Boolean::booleanValue) .count()); - } catch (NoCurrentCaseException ex) { - logger.log(Level.WARNING, "Could not access case during getFilesWithHashSetHitsCount()"); //NON-NLS } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error getting ImageGalleryController.", ex); //NON-NLS + logger.log(Level.SEVERE, "Failed to get image gallery controller", ex); //NON-NLS } } return hashSetHitsCount.get(); @@ -138,12 +134,10 @@ public class DrawableGroup implements Comparable { if (uncatCount.get() < 0) { try { uncatCount.set(ImageGalleryModule.getController().getDatabase().getUncategorizedCount(fileIDs)); - - } catch (TskCoreException | NoCurrentCaseException ex) { - logger.log(Level.WARNING, "Could not access case during getFilesWithHashSetHitsCount()"); //NON-NLS + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Failed to get image gallery controller", ex); //NON-NLS } } - return uncatCount.get(); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index 99069b7790..b35bae7625 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-18 Basis Technology Corp. + * Copyright 2013-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java index 26a7772759..3d20fb7edb 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2013-18 Basis Technology Corp. + * Copyright 2013-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,9 +20,7 @@ package org.sleuthkit.autopsy.imagegallery.gui.drawableviews; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Lists; import static com.google.common.collect.Lists.transform; -import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; import java.util.ArrayList; import java.util.Arrays; @@ -35,7 +33,6 @@ import java.util.Map; import static java.util.Objects.isNull; import static java.util.Objects.nonNull; import java.util.Optional; -import java.util.function.Consumer; import java.util.logging.Level; import java.util.stream.IntStream; import javafx.animation.Interpolator; @@ -135,18 +132,15 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewMode; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState; -import org.sleuthkit.autopsy.imagegallery.gui.GuiUtils; import static org.sleuthkit.autopsy.imagegallery.gui.GuiUtils.createAutoAssigningMenuItem; import org.sleuthkit.autopsy.imagegallery.utils.TaskUtils; import static org.sleuthkit.autopsy.imagegallery.utils.TaskUtils.addFXCallback; -import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; /** * A GroupPane displays the contents of a DrawableGroup. It supports both * GridView and SlideShowView modes by swapping out its internal components. * - * * TODO: Extract the The GridView instance to a separate class analogous to the * SlideShow. * From a74059c6ad86f882d824acb2fe21fb7fd934d7a2 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Thu, 29 Nov 2018 10:44:02 -0500 Subject: [PATCH 18/42] Fixed typo. --- .../datamodel/CorrelationAttributeNormalizer.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeNormalizer.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeNormalizer.java index b194788d6d..a5886bc219 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeNormalizer.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeNormalizer.java @@ -66,15 +66,15 @@ final public class CorrelationAttributeNormalizer { case CorrelationAttributeInstance.USBID_TYPE_ID: return normalizeUsbId(trimmedData); case CorrelationAttributeInstance.SSID_TYPE_ID: - return data; + return trimmedData; case CorrelationAttributeInstance.MAC_TYPE_ID: - return data; + return trimmedData; case CorrelationAttributeInstance.IMEI_TYPE_ID: - return data; + return trimmedData; case CorrelationAttributeInstance.IMSI_TYPE_ID: - return data; + return trimmedData; case CorrelationAttributeInstance.ICCID_TYPE_ID: - return data; + return trimmedData; default: final String errorMessage = String.format( "Validator function not found for attribute type: %s", From 99b1d2d379a834c759517e27e519778ddcf4b869 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Thu, 29 Nov 2018 10:52:54 -0500 Subject: [PATCH 19/42] Cleanup. --- .../datamodel/CorrelationAttributeNormalizer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeNormalizer.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeNormalizer.java index a5886bc219..651c07f74c 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeNormalizer.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationAttributeNormalizer.java @@ -99,7 +99,7 @@ final public class CorrelationAttributeNormalizer { if(typeOption.isPresent()){ CorrelationAttributeInstance.Type type = typeOption.get(); - return CorrelationAttributeNormalizer.normalize(type, data.trim()); + return CorrelationAttributeNormalizer.normalize(type, data); } else { throw new CorrelationAttributeNormalizationException(String.format("Given attributeTypeId did not correspond to any known Attribute: %s", attributeTypeId)); } From 371b00a9dcba1989450482a32f1d533ff8079b04 Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 29 Nov 2018 11:53:07 -0500 Subject: [PATCH 20/42] 1142: fix DrawableFile.getDataSource() --- .../autopsy/imagegallery/datamodel/DrawableFile.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java index 4b777b387d..438ace44d5 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java @@ -158,7 +158,11 @@ public abstract class DrawableFile { } public DataSource getDataSource() throws TskCoreException, TskDataException { - return getSleuthkitCase().getDataSource(file.getDataSource().getId()); + if (file.getDataSource() instanceof DataSource) { + return (DataSource)file.getDataSource(); + } else { + throw new TskCoreException(String.format("Failed to get data source for drawable file (id = %s)", file.getId())); + } } private Pair, Collection> makeAttributeValuePair(DrawableAttribute attribute) { From 612b7f135b6346b307451ce14a7312422746f67a Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 29 Nov 2018 12:30:29 -0500 Subject: [PATCH 21/42] Remove eager init of executor in IG controller shutDown --- .../imagegallery/ImageGalleryController.java | 13 +++++-------- .../org/netbeans/core/startup/Bundle.properties | 2 +- .../netbeans/core/windows/view/ui/Bundle.properties | 2 +- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index 84c4ae0b61..fbba2a8683 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -37,7 +37,6 @@ import javafx.beans.Observable; import javafx.beans.property.DoubleProperty; import javafx.beans.property.ReadOnlyBooleanProperty; import javafx.beans.property.ReadOnlyBooleanWrapper; -import javafx.beans.property.ReadOnlyDoubleProperty; import javafx.beans.property.ReadOnlyIntegerProperty; import javafx.beans.property.ReadOnlyIntegerWrapper; import javafx.beans.property.ReadOnlyObjectProperty; @@ -51,7 +50,6 @@ import javax.annotation.Nonnull; import static org.apache.commons.collections4.CollectionUtils.isNotEmpty; import org.netbeans.api.progress.ProgressHandle; import org.openide.util.Cancellable; -import org.openide.util.Exceptions; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case.CaseType; @@ -71,7 +69,6 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupManager; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewState; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.DataSource; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbTransaction; @@ -192,9 +189,7 @@ public final class ImageGalleryController { } ImageGalleryController(@Nonnull Case newCase) throws TskCoreException { - - - + this.autopsyCase = Objects.requireNonNull(newCase); this.sleuthKitCase = newCase.getSleuthkitCase(); @@ -327,16 +322,17 @@ public final class ImageGalleryController { } /** - * reset the state of the controller (eg if the case is closed) + * Shuts down this per case singleton image gallery controller. */ public synchronized void shutDown() { + logger.log(Level.INFO, String.format("Shutting down image gallery controller for case %s (%s)", autopsyCase.getDisplayName(), autopsyCase.getName())); selectionModel.clearSelection(); thumbnailCache.clearCache(); historyManager.clear(); groupManager.reset(); shutDownDBExecutor(); drawableDB.close(); - //dbExecutor = getNewDBExecutor(); RJCTODO + logger.log(Level.INFO, String.format("Completed shut down of image gallery controller for case %s (%s)", autopsyCase.getDisplayName(), autopsyCase.getName())); } /** @@ -508,6 +504,7 @@ public final class ImageGalleryController { } catch (InterruptedException ex) { logger.log(Level.WARNING, "Image Gallery failed to shutdown DB Task Executor in a timely fashion.", ex); } + dbExecutor = null; } } diff --git a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties index 202947f033..35f63bf19a 100644 --- a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties +++ b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties @@ -1,5 +1,5 @@ #Updated by build script -#Tue, 13 Nov 2018 17:30:09 -0500 +#Thu, 29 Nov 2018 12:23:03 -0500 LBL_splash_window_title=Starting Autopsy SPLASH_HEIGHT=314 SPLASH_WIDTH=538 diff --git a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties index 11be888847..8643234b16 100644 --- a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties +++ b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties @@ -1,4 +1,4 @@ #Updated by build script -#Tue, 13 Nov 2018 17:30:09 -0500 +#Thu, 29 Nov 2018 12:23:03 -0500 CTL_MainWindow_Title=Autopsy 4.9.1 CTL_MainWindow_Title_No_Project=Autopsy 4.9.1 From 1faf12f3e37e1c601660c9f8acd0b328dc21b7f2 Mon Sep 17 00:00:00 2001 From: Raman Date: Thu, 29 Nov 2018 12:40:53 -0500 Subject: [PATCH 22/42] Fixed error message. --- .../sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java index 438ace44d5..9a8c7dca59 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java @@ -161,7 +161,7 @@ public abstract class DrawableFile { if (file.getDataSource() instanceof DataSource) { return (DataSource)file.getDataSource(); } else { - throw new TskCoreException(String.format("Failed to get data source for drawable file (id = %s)", file.getId())); + throw new TskCoreException(String.format("File's data source is not of type DataSource (file id = %s)", file.getId())); } } From 0229a19be1b93046b2ceb284986dac1ea2692c64 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 29 Nov 2018 13:10:08 -0500 Subject: [PATCH 23/42] Fix bug in IGModule event handler and tidy up --- .../imagegallery/ImageGalleryController.java | 3 +- .../imagegallery/ImageGalleryModule.java | 54 +++++-------------- 2 files changed, 13 insertions(+), 44 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index fbba2a8683..49fd742775 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -188,8 +188,7 @@ public final class ImageGalleryController { return isCaseStale.get(); } - ImageGalleryController(@Nonnull Case newCase) throws TskCoreException { - + ImageGalleryController(@Nonnull Case newCase) throws TskCoreException { this.autopsyCase = Objects.requireNonNull(newCase); this.sleuthKitCase = newCase.getSleuthkitCase(); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryModule.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryModule.java index 3a55903daa..5310fc4bb3 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryModule.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryModule.java @@ -89,7 +89,7 @@ public class ImageGalleryModule { Case currentCase = Case.getCurrentCaseThrows(); controller = new ImageGalleryController(currentCase); } catch (NoCurrentCaseException ex) { - throw new TskCoreException("no current case", ex); + throw new TskCoreException("Failed to get ", ex); } } return controller; @@ -97,7 +97,7 @@ public class ImageGalleryModule { } /** - * Sets the implicit exit property attribute of the JavaFX Runtime to false + * Sets the implicit exit property attribute of the JavaFX runtime to false * and sets up listeners for application events. It is invoked at * application start up by virtue of the OnStart annotation on the OnStart * class in this package. @@ -144,12 +144,8 @@ public class ImageGalleryModule { * @return True or false. */ static boolean isEnabledforCase(Case theCase) { - if (theCase != null) { - String enabledforCaseProp = new PerCaseProperties(theCase).getConfigSetting(ImageGalleryModule.MODULE_NAME, PerCaseProperties.ENABLED); - return isNotBlank(enabledforCaseProp) ? Boolean.valueOf(enabledforCaseProp) : ImageGalleryPreferences.isEnabledByDefault(); - } else { - return false; - } + String enabledforCaseProp = new PerCaseProperties(theCase).getConfigSetting(ImageGalleryModule.MODULE_NAME, PerCaseProperties.ENABLED); + return isNotBlank(enabledforCaseProp) ? Boolean.valueOf(enabledforCaseProp) : ImageGalleryPreferences.isEnabledByDefault(); } /** @@ -175,18 +171,6 @@ public class ImageGalleryModule { @Override public void propertyChange(PropertyChangeEvent event) { - /* - * If running in "headless" mode, there is no need to process any - * ingest module events during the current session. - * - * Note that this check cannot be done earlier on start up because - * the "headless" property may not have been set yet. - */ - if (RuntimeProperties.runningWithGUI() == false) { - IngestManager.getInstance().removeIngestModuleEventListener(this); - return; - } - /* * Only process individual files and artifacts in "real time" on the * node that is running the ingest job. On a remote node, image @@ -252,36 +236,22 @@ public class ImageGalleryModule { @Override public void propertyChange(PropertyChangeEvent event) { - /* - * If running in "headless" mode, there is no need to process any - * case events during the current session. Note that this check - * cannot be done earlier in onStart because the "headless" property - * may not have been set yet. - */ - if (RuntimeProperties.runningWithGUI() == false) { - Case.removePropertyChangeListener(this); - return; - } - Case.Events eventType = Case.Events.valueOf(event.getPropertyName()); if (eventType == Case.Events.CURRENT_CASE) { synchronized (controllerLock) { - if (event.getNewValue() != null && event.getNewValue() instanceof Case) { + if (event.getNewValue() != null) { /* - * CURRENT_CASE(_OPENED) event. Construct a new Image - * Gallery controller. + * CURRENT_CASE(_OPENED) event. */ Case newCase = (Case) event.getNewValue(); try { controller = new ImageGalleryController(newCase); } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Failed to construct controller for new case", ex); + logger.log(Level.SEVERE, String.format("Failed to construct controller for new case %s (%s)", newCase.getDisplayName(), newCase.getName()), ex); } - } else if (event.getOldValue() != null && event.getOldValue() instanceof Case) { + } else if (event.getOldValue() != null) { /* - * CURRENT_CASE(_CLOSED) event. Shut down the controller - * for the case and close the top component, if it is - * open. + * CURRENT_CASE(_CLOSED) event. */ SwingUtilities.invokeLater(ImageGalleryTopComponent::closeTopComponent); controller.shutDown(); @@ -310,8 +280,8 @@ public class ImageGalleryModule { final ContentTagAddedEvent tagAddedEvent = (ContentTagAddedEvent) event; long objId = tagAddedEvent.getAddedTag().getContent().getId(); DrawableDB drawableDB = currentController.getDatabase(); - drawableDB.addTagCache(objId); - if (drawableDB.isInDB(objId)) { // RJCTODO: Put in cache before in DB check? + drawableDB.addTagCache(objId); // RJCTODO: Why add the tag to the cache before doing the in DB check? + if (drawableDB.isInDB(objId)) { currentController.getTagsManager().fireTagAddedEvent(tagAddedEvent); } break; @@ -319,7 +289,7 @@ public class ImageGalleryModule { final ContentTagDeletedEvent tagDeletedEvent = (ContentTagDeletedEvent) event; if (currentController.getDatabase().isInDB(tagDeletedEvent.getDeletedTagInfo().getContentID())) { currentController.getTagsManager().fireTagDeletedEvent(tagDeletedEvent); - } + } // RJCTODO: Why not remove the tag from the cache? break; default: logger.log(Level.SEVERE, String.format("Received %s event with no subscription", event.getPropertyName())); //NON-NLS From 78dabdf3fa2554fe1182331473064ae716ae6189 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 29 Nov 2018 13:28:13 -0500 Subject: [PATCH 24/42] Add comments TODOs ImageGalleryModule --- .../imagegallery/ImageGalleryModule.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryModule.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryModule.java index 5310fc4bb3..cf053bf308 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryModule.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryModule.java @@ -183,6 +183,11 @@ public class ImageGalleryModule { ImageGalleryController currentController; try { currentController = getController(); + // RJCTODO: If a closed controller had a method that could be + // queried to determine whether it was shut down, we could + // bail out here. The older code that used to try to check for + // a current case was flawed; there was no guarantee the current + // case was the same case associated with the event. } catch (TskCoreException ex) { logger.log(Level.SEVERE, String.format("Failed to handle %s event", event.getPropertyName()), ex); //NON-NLS return; @@ -232,6 +237,9 @@ public class ImageGalleryModule { /** * A listener for case application events. */ + // RJCTODO: This code would be easier to read if there were two case event + // listeners, one that handled CURRENT_CASE events and one that handled + // the other events. static private class CaseEventListener implements PropertyChangeListener { @Override @@ -255,13 +263,17 @@ public class ImageGalleryModule { */ SwingUtilities.invokeLater(ImageGalleryTopComponent::closeTopComponent); controller.shutDown(); - controller = null; } } } else { ImageGalleryController currentController; try { currentController = getController(); + // RJCTODO: If a closed controller had a method that could be + // queried to determine whether it was shut down, we could + // bail out here. The older code that used to try to check for + // a current case was flawed; there was no guarantee the current + // case was the same case associated with the event. } catch (TskCoreException ex) { logger.log(Level.SEVERE, String.format("Failed to handle %s event", event.getPropertyName()), ex); //NON-NLS return; @@ -322,6 +334,11 @@ public class ImageGalleryModule { ImageGalleryController controller; try { controller = getController(); + // RJCTODO: If a closed controller had a method that could be + // queried to determine whether it was shut down, we could + // bail out here. The older code that used to try to check for + // a current case was flawed; there was no guarantee the current + // case was the same case associated with the event. } catch (TskCoreException ex) { logger.log(Level.SEVERE, String.format("Failed to handle %s event", event.getPropertyName()), ex); //NON-NLS return; From 336b7b4e9210ca0d984c55dc80d632129ee364b7 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 29 Nov 2018 14:04:39 -0500 Subject: [PATCH 25/42] Clarify/add comments in ImageGalleryTopComponent --- .../ImageGalleryTopComponent.java | 47 ++++++++++--------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java index 2a5f7c12d4..58bfd5914a 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015-2018 Basis Technology Corp. + * Copyright 2013-2018 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -175,15 +175,17 @@ public final class ImageGalleryTopComponent extends TopComponent implements Expl } else { /* * Open the top component's window before configuring the groups - * manager so that the wait cursor animation over the empty, gray - * window will be displayed if the operations takes awhile. + * manager so that the spinner(s) that take the place of a wait will + * be displayed if the operations takes awhile. */ + // RJCTODO: Is this really necessary? SwingUtilities.invokeLater(() -> showTopComponent()); synchronized (controllerLock) { GroupManager groupManager = controller.getGroupManager(); // RJCTODO: Why are there potentially hazardous nested synchronized - // blocks here (note: method used ot be synchronized)? Why is - // the groups manager not taking responsibility for its own thread + // blocks here (note: method used to be synchronized, my + // dedicated controllerLock lock just makes the nesting more obvious)? + // Why is the groups manager not taking responsibility for its own thread // safety policy? synchronized (groupManager) { groupManager.regroup(selectedDataSource, groupManager.getGroupBy(), groupManager.getSortBy(), groupManager.getSortOrder(), true); @@ -230,6 +232,8 @@ public final class ImageGalleryTopComponent extends TopComponent implements Expl * already exist. */ public static void closeTopComponent() { + // RJCTODO: Could add the flag that used to be used for the busy wait on + // the initial JavaFX thread task to avoid superfluous construction here. getTopComponent().close(); } @@ -258,12 +262,18 @@ public final class ImageGalleryTopComponent extends TopComponent implements Expl private void getCurrentControllerAndOpen() throws TskCoreException { ImageGalleryController currentController = ImageGalleryModule.getController(); /* - * First, dispatch a task to run in the JavaFX thread. This task will - * swap the new controller, if there is one, into this top component and - * its child UI components. It also queues another JavaFX thread task to - * check for analyzed groups, which has the side effect of managing the - * spinner(s) that take the place of a wait cursor. + * Dispatch a task to run in the JavaFX thread. This task will swap the + * new controller, if there is one, into this top component and its + * child UI components. This task also queues another JavaFX thread task + * to check for analyzed groups, which has the side effect of starting + * the spinner(s) that take the place of a wait cursor. Finally, this + * task starts a background thread to query the case database. This + * background task may dispatch a JavaFX thread task to do a data source + * selection dialog. Ultimately, there is a final task that either opens + * the window in the AWT EDT or displays a "too many files" dialog in + * the JFX thread. */ + // RJCTODO: Verify the side effect remark above. Platform.runLater(new Runnable() { @Override public void run() { @@ -308,12 +318,6 @@ public final class ImageGalleryTopComponent extends TopComponent implements Expl * property or the group manager's analyzed groups * property changes. */ - // RJCTODO: Why was the first lambda not set up to happen on - // the JavaFX thread? I am using that thread confinement and - // a volatile controller reference for simplified thread safety, - // is there a problem with this? It seems like this is a bug, - // since why would we want this code to execute both in the - // JavaFX thread and elsewhere? controller.regroupDisabledProperty().addListener((Observable unused) -> Platform.runLater(() -> checkForAnalyzedGroups())); controller.getGroupManager().getAnalyzedGroups().addListener((Observable unused) -> Platform.runLater(() -> checkForAnalyzedGroups())); @@ -323,7 +327,7 @@ public final class ImageGalleryTopComponent extends TopComponent implements Expl * take the place of a wait cursor if there are no * analyzed groups yet, ingest is running, etc. */ - // RJCTODO: Is there a race condition here, since this task will be + // RJCTODO: Is there a race condition here, since this task could be // executed before the task to actually open the top component window? // It seems like this might be a sort of a hack and I am wondering // why this can't be done in openWithSelectedDataSources instead. @@ -355,7 +359,7 @@ public final class ImageGalleryTopComponent extends TopComponent implements Expl Map dataSourcesWithTooManyFiles = new HashMap<>(); // RJCTODO: At least some of this designation of "all data sources" with null seems uneccessary; // in any case, the use of nulls and zeros here is - // very confusing and should be reworked. Why was this done? + // very confusing and should be reworked. if (dataSources.size() <= 1 || controller.getGroupManager().getGroupBy() != DrawableAttribute.PATH) { dataSourcesWithTooManyFiles.put(null, controller.hasTooManyFiles(null)); @@ -375,7 +379,7 @@ public final class ImageGalleryTopComponent extends TopComponent implements Expl GuiUtils.setDialogIcons(datasourceDialog); @SuppressWarnings(value = "unchecked") ComboBox> comboBox = (ComboBox>) datasourceDialog.getDialogPane().lookup(".combo-box"); - comboBox.setCellFactory((ListView> param) -> new DataSourceCell(dataSourcesWithTooManyFiles, controller.getAllDataSourcesDrawableDBStatus())); + comboBox.setCellFactory((ListView> unused) -> new DataSourceCell(dataSourcesWithTooManyFiles, controller.getAllDataSourcesDrawableDBStatus())); comboBox.setButtonCell(new DataSourceCell(dataSourcesWithTooManyFiles, controller.getAllDataSourcesDrawableDBStatus())); DataSource dataSource = datasourceDialog.showAndWait().orElse(Optional.empty()).orElse(null); openWithSelectedDataSources(dataSource, dataSourcesWithTooManyFiles); @@ -422,7 +426,6 @@ public final class ImageGalleryTopComponent extends TopComponent implements Expl * to indicate this method is effectively deprecated. A break point * placed here was never hit. */ - return modes.stream().filter(mode -> mode.getName().equals("timeline") || mode.getName().equals("ImageGallery")) .collect(Collectors.toList()); } @@ -442,7 +445,8 @@ public final class ImageGalleryTopComponent extends TopComponent implements Expl * provided explorer view is present in the TopComponenet, even if it is * invisible/ zero sized */ - // RJCTODO: Why is this here? + // RJCTODO: Why is this override here? Does the "this" in "this does + // not seem to function correctly" refer to the methdo or the top compnent? return em; } @@ -475,6 +479,7 @@ public final class ImageGalleryTopComponent extends TopComponent implements Expl // if there are groups to display, then display them // @@@ Need to check timing on this and make sure we have only groups for the selected DS. Seems like rebuild can cause groups to be created for a DS that is not later selected... + // RJCTODO: Get Brian's TODO resolved. if (isNotEmpty(groupManager.getAnalyzedGroups())) { clearNotification(); return; From 21a279063b8ff91ea4355e8ab4f0ecfafe07f841 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 29 Nov 2018 14:29:38 -0500 Subject: [PATCH 26/42] Add a TODO to ImageGalleryTopComponent --- .../autopsy/imagegallery/ImageGalleryTopComponent.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java index 58bfd5914a..da7b8a6043 100644 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryTopComponent.java @@ -287,6 +287,11 @@ public final class ImageGalleryTopComponent extends TopComponent implements Expl * It could be done by resetting the controller in the * child UI components instead. */ + // RJCTODO: Construction of these components can perhaps + // be separated from opening the window again so that + // a setController implementation could be called from + // the case opened event handler in the ImageGalleryModule + // object. fullUIStack = new StackPane(); myScene = new Scene(fullUIStack); jfxPanel.setScene(myScene); From 46342f675ea83e72ee69de99362964f9654699ba Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 29 Nov 2018 15:30:18 -0500 Subject: [PATCH 27/42] 4402 fix error with failure to use new setting --- .../centralrepository/ingestmodule/IngestSettings.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettings.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettings.java index 30039a9f86..741de9eedb 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettings.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestSettings.java @@ -35,7 +35,7 @@ final class IngestSettings implements IngestModuleIngestJobSettings { */ IngestSettings() { this.flagTaggedNotableItems = IngestModule.DEFAULT_FLAG_TAGGED_NOTABLE_ITEMS; - this.flagTaggedNotableItems = IngestModule.DEFAULT_FLAG_PREVIOUS_DEVICES; + this.flagPreviousDevices = IngestModule.DEFAULT_FLAG_PREVIOUS_DEVICES; } /** @@ -68,6 +68,6 @@ final class IngestSettings implements IngestModuleIngestJobSettings { * @return True if flagging; otherwise false. */ boolean isFlagPreviousDevices() { - return flagTaggedNotableItems; + return flagPreviousDevices; } } From bffb8cbc71a4137ecba47b255f667abcd555edc7 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Thu, 29 Nov 2018 16:17:08 -0500 Subject: [PATCH 28/42] Increased font size. --- Core/src/org/sleuthkit/autopsy/report/ReportHTML.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index 207035239d..0f4a568ba1 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -463,9 +463,9 @@ class ReportHTML implements TableReportModule { StringBuilder output = new StringBuilder(); String pageHeader = configPanel.getHeader(); if (pageHeader.isEmpty() == false) { - output.append("

") + output.append("

") .append(StringEscapeUtils.escapeHtml4(pageHeader)) - .append("

\n"); //NON-NLS + .append("
\n"); //NON-NLS } return output.toString(); } @@ -480,9 +480,9 @@ class ReportHTML implements TableReportModule { StringBuilder output = new StringBuilder(); String pageFooter = configPanel.getFooter(); if (pageFooter.isEmpty() == false) { - output.append("

") + output.append("

") .append(StringEscapeUtils.escapeHtml4(pageFooter)) - .append("

\n"); //NON-NLS + .append("
"); //NON-NLS } return output.toString(); } @@ -916,6 +916,8 @@ class ReportHTML implements TableReportModule { + //NON-NLS "#header {width:100%; padding: 10px; line-height: 25px; background: #07A; color: #FFF; font-size: 20px;}\n" + //NON-NLS + "#pageHeaderFooter {width: 100%; padding: 10px; line-height: 25px; text-align: center; font-size: 20px;}\n" + + //NON-NLS "h1 {font-size: 20px; font-weight: normal; color: #07A; padding: 0 0 7px 0; margin-top: 25px; border-bottom: 1px solid #D6D6D6;}\n" + //NON-NLS "h2 {font-size: 20px; font-weight: bolder; color: #07A;}\n" @@ -1127,6 +1129,7 @@ class ReportHTML implements TableReportModule { NbBundle.getMessage(this.getClass(), "ReportHTML.writeSum.title")).append("\n"); //NON-NLS head.append("\n"); //NON-NLS head.append("