From bf1f5157d73a39a8a39adbe9e64ec508a83e93e6 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Sat, 2 Feb 2019 15:38:31 -0500 Subject: [PATCH 01/20] aquisition details --- .../autoingest/AddArchiveTask.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index 2cc73c7be8..46facf7bff 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -201,10 +201,16 @@ class AddArchiveTask implements Runnable { success = true; newDataSources.addAll(internalDataSource.getContent()); - // Update the names for all new data sources to be the root archive plus the name of the data source + // update data source info for (Content c:internalDataSource.getContent()) { if (c instanceof DataSource) { DataSource ds = (DataSource) c; + + // Update aquisition details + String details = "Extracted from archive: " + archivePath.toString(); + ds.setAcquisitionDetails(details); + + // Update the names for all new data sources to be the root archive plus the name of the data source String newName = Paths.get(archivePath).getFileName() + "/" + ds.getName(); ds.setDisplayName(newName); currentCase.notifyDataSourceNameChanged(c, newName); @@ -253,8 +259,17 @@ class AddArchiveTask implements Runnable { archiveDspLock.wait(); - // at this point we got the content object(s) from the current DSP + // at this point we got the content object(s) from the current DSP. newDataSources.addAll(internalDataSource.getContent()); + + for (Content c : internalDataSource.getContent()) { + if (c instanceof DataSource) { + DataSource ds = (DataSource) c; + // Update aquisition details + String details = "Extracted from archive: " + archivePath.toString(); + ds.setAcquisitionDetails(details); + } + } } } } catch (Exception ex) { From fd2b8c926ce5f344da88612f5a39019257f1b55c Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Tue, 5 Feb 2019 15:47:46 -0500 Subject: [PATCH 02/20] Reading existing acquisition details and updating them, as opposed to overwriting --- .../experimental/autoingest/AddArchiveTask.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index 46facf7bff..e8e38dc743 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -206,9 +206,14 @@ class AddArchiveTask implements Runnable { if (c instanceof DataSource) { DataSource ds = (DataSource) c; - // Update aquisition details + // Read existing aquisition details and update them String details = "Extracted from archive: " + archivePath.toString(); - ds.setAcquisitionDetails(details); + String existingDetails = ds.getAcquisitionDetails(); + if (existingDetails != null && !existingDetails.isEmpty()) { + ds.setAcquisitionDetails(existingDetails + System.getProperty("line.separator") + details); + } else { + ds.setAcquisitionDetails(details); + } // Update the names for all new data sources to be the root archive plus the name of the data source String newName = Paths.get(archivePath).getFileName() + "/" + ds.getName(); @@ -265,7 +270,7 @@ class AddArchiveTask implements Runnable { for (Content c : internalDataSource.getContent()) { if (c instanceof DataSource) { DataSource ds = (DataSource) c; - // Update aquisition details + // This is a new data source so just write the aquisition details String details = "Extracted from archive: " + archivePath.toString(); ds.setAcquisitionDetails(details); } From 825c7ecb09f592bd8d263c21c51c63e26d01d0ec Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Tue, 19 Feb 2019 14:05:09 -0500 Subject: [PATCH 03/20] 4708 only perform screen shot when test times out first time --- .../autopsy/testing/AutopsyTestCases.java | 493 ++++++++++-------- 1 file changed, 279 insertions(+), 214 deletions(-) diff --git a/Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java b/Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java index 96f7d18fa3..2a140bc84f 100644 --- a/Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java +++ b/Testing/src/org/sleuthkit/autopsy/testing/AutopsyTestCases.java @@ -42,6 +42,7 @@ import org.netbeans.jellytools.NbDialogOperator; import org.netbeans.jellytools.WizardOperator; import org.netbeans.jemmy.JemmyProperties; import org.netbeans.jemmy.Timeout; +import org.netbeans.jemmy.TimeoutExpiredException; import org.netbeans.jemmy.Timeouts; import org.netbeans.jemmy.operators.JButtonOperator; import org.netbeans.jemmy.operators.JCheckBoxOperator; @@ -67,7 +68,7 @@ public class AutopsyTestCases { private static final Logger logger = Logger.getLogger(AutopsyTestCases.class.getName()); private long start; - + /** * Escapes the slashes in a file or directory path. * @@ -96,274 +97,338 @@ public class AutopsyTestCases { } public void testNewCaseWizardOpen(String title) { - logger.info("New Case"); - resetTimeouts("WindowWaiter.WaitWindowTimeout", 240000); - NbDialogOperator nbdo = new NbDialogOperator(title); - JButtonOperator jbo = new JButtonOperator(nbdo, 0); // the "New Case" button - jbo.pushNoBlock(); + try { + logger.info("New Case"); + setTimeout("WindowWaiter.WaitWindowTimeout", 240000); + NbDialogOperator nbdo = new NbDialogOperator(title); + JButtonOperator jbo = new JButtonOperator(nbdo, 0); // the "New Case" button + jbo.pushNoBlock(); + } catch (TimeoutExpiredException ex) { + screenshot("TimeoutScreenshot"); + logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex); + } } public void testNewCaseWizard() { - logger.info("New Case Wizard"); - WizardOperator wo = new WizardOperator("New Case Information"); - JTextFieldOperator jtfo0 = new JTextFieldOperator(wo, 1); - jtfo0.typeText("AutopsyTestCase"); // Name the case "AutopsyTestCase" - JTextFieldOperator jtfo1 = new JTextFieldOperator(wo, 2); - jtfo1.typeText(getEscapedPath(System.getProperty("out_path"))); - wo.btNext().clickMouse(); - JTextFieldOperator jtfo2 = new JTextFieldOperator(wo, 0); - jtfo2.typeText("000"); // Set the case number - JTextFieldOperator jtfo3 = new JTextFieldOperator(wo, 1); - jtfo3.typeText("Examiner 1"); // Set the case examiner - start = System.currentTimeMillis(); - wo.btFinish().clickMouse(); + try { + logger.info("New Case Wizard"); + WizardOperator wo = new WizardOperator("New Case Information"); + JTextFieldOperator jtfo0 = new JTextFieldOperator(wo, 1); + jtfo0.typeText("AutopsyTestCase"); // Name the case "AutopsyTestCase" + JTextFieldOperator jtfo1 = new JTextFieldOperator(wo, 2); + jtfo1.typeText(getEscapedPath(System.getProperty("out_path"))); + wo.btNext().clickMouse(); + JTextFieldOperator jtfo2 = new JTextFieldOperator(wo, 0); + jtfo2.typeText("000"); // Set the case number + JTextFieldOperator jtfo3 = new JTextFieldOperator(wo, 1); + jtfo3.typeText("Examiner 1"); // Set the case examiner + start = System.currentTimeMillis(); + wo.btFinish().clickMouse(); + } catch (TimeoutExpiredException ex) { + screenshot("TimeoutScreenshot"); + logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex); + } } public void testStartAddImageFileDataSource() { - /* - * This time out is to give time for creating case database and opening solr index - */ - new Timeout("pausing", 120000).sleep(); - logger.info("Starting Add Image process"); - resetTimeouts("WindowWaiter.WaitWindowTimeOut", 240000); - WizardOperator wo = new WizardOperator("Add Data Source"); - while(!wo.btNext().isEnabled()){ - new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled + try { + /* + * This time out is to give time for creating case database and + * opening solr index + */ + new Timeout("pausing", 120000).sleep(); + logger.info("Starting Add Image process"); + setTimeout("WindowWaiter.WaitWindowTimeOut", 240000); + WizardOperator wo = new WizardOperator("Add Data Source"); + while (!wo.btNext().isEnabled()) { + new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled + } + //select the toggle button for Disk Image or VM File it will be the first button created and proceed to next panel + JToggleButtonOperator jtbo = new JToggleButtonOperator(wo, 0); + jtbo.clickMouse(); + wo.btNext().clickMouse(); + JTextFieldOperator jtfo0 = new JTextFieldOperator(wo, 0); + String img_path = getEscapedPath(System.getProperty("img_path")); + String imageDir = img_path; + ((JTextComponent) jtfo0.getSource()).setText(imageDir); + JComboBoxOperator comboBoxOperator = new JComboBoxOperator(wo, 0); + comboBoxOperator.setSelectedItem("(GMT-5:00) America/New_York"); + wo.btNext().clickMouse(); + } catch (TimeoutExpiredException ex) { + screenshot("TimeoutScreenshot"); + logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex); } - //select the toggle button for Disk Image or VM File it will be the first button created and proceed to next panel - JToggleButtonOperator jtbo = new JToggleButtonOperator(wo, 0); - jtbo.clickMouse(); - wo.btNext().clickMouse(); - JTextFieldOperator jtfo0 = new JTextFieldOperator(wo, 0); - String img_path = getEscapedPath(System.getProperty("img_path")); - String imageDir = img_path; - ((JTextComponent) jtfo0.getSource()).setText(imageDir); - JComboBoxOperator comboBoxOperator = new JComboBoxOperator(wo, 0); - comboBoxOperator.setSelectedItem("(GMT-5:00) America/New_York"); - wo.btNext().clickMouse(); } public void testStartAddLogicalFilesDataSource() { - /* - * This time out is to give time for creating case database and opening solr index - */ - new Timeout("pausing", 120000).sleep(); - logger.info("Starting Add Logical Files process"); - WizardOperator wo = new WizardOperator("Add Data Source"); - wo.setTimeouts(resetTimeouts("WindowWaiter.WaitWindowTimeOut", 240000)); - while(!wo.btNext().isEnabled()){ - new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled + try { + /* + * This time out is to give time for creating case database and + * opening solr index + */ + new Timeout("pausing", 120000).sleep(); + logger.info("Starting Add Logical Files process"); + WizardOperator wo = new WizardOperator("Add Data Source"); + wo.setTimeouts(setTimeout("WindowWaiter.WaitWindowTimeOut", 240000)); + while (!wo.btNext().isEnabled()) { + new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled + } + //select the toggle button for Logical Files it will be the third button created and proceed to next panel + JToggleButtonOperator jtbo = new JToggleButtonOperator(wo, 2); + jtbo.clickMouse(); + wo.btNext().clickMouse(); + JButtonOperator addButtonOperator = new JButtonOperator(wo, "Add"); + addButtonOperator.pushNoBlock(); + JFileChooserOperator fileChooserOperator = new JFileChooserOperator(); + fileChooserOperator.setCurrentDirectory(new File(getEscapedPath(System.getProperty("img_path")))); + // set the current directory one level above the directory containing logicalFileSet folder. + fileChooserOperator.goUpLevel(); + fileChooserOperator.chooseFile(new File(getEscapedPath(System.getProperty("img_path"))).getName()); + wo.btNext().clickMouse(); + } catch (TimeoutExpiredException ex) { + screenshot("TimeoutScreenshot"); + logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex); } - //select the toggle button for Logical Files it will be the third button created and proceed to next panel - JToggleButtonOperator jtbo = new JToggleButtonOperator(wo, 2); - jtbo.clickMouse(); - wo.btNext().clickMouse(); - JButtonOperator addButtonOperator = new JButtonOperator(wo, "Add"); - addButtonOperator.pushNoBlock(); - JFileChooserOperator fileChooserOperator = new JFileChooserOperator(); - fileChooserOperator.setCurrentDirectory(new File(getEscapedPath(System.getProperty("img_path")))); - // set the current directory one level above the directory containing logicalFileSet folder. - fileChooserOperator.goUpLevel(); - fileChooserOperator.chooseFile(new File(getEscapedPath(System.getProperty("img_path"))).getName()); - wo.btNext().clickMouse(); } public void testAddSourceWizard1() { - WizardOperator wo = new WizardOperator("Add Data Source"); - while (!wo.btFinish().isEnabled()) { - new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process + try { + WizardOperator wo = new WizardOperator("Add Data Source"); + while (!wo.btFinish().isEnabled()) { + new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process + } + logger.log(Level.INFO, "Add image took {0}ms", (System.currentTimeMillis() - start)); + wo.btFinish().clickMouse(); + } catch (TimeoutExpiredException ex) { + screenshot("TimeoutScreenshot"); + logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex); } - logger.log(Level.INFO, "Add image took {0}ms", (System.currentTimeMillis() - start)); - wo.btFinish().clickMouse(); } public void testConfigureIngest1() { - /* - * This timeout is to allow the setup for the ingest job settings panel - * to complete. - */ - new Timeout("pausing", 10000).sleep(); + try { + /* + * This timeout is to allow the setup for the ingest job settings + * panel to complete. + */ + new Timeout("pausing", 10000).sleep(); - logger.info("Looking for hash lookup module in ingest job settings panel"); - WizardOperator wo = new WizardOperator("Add Data Source"); - while(!wo.btNext().isEnabled()){ - new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled + logger.info("Looking for hash lookup module in ingest job settings panel"); + WizardOperator wo = new WizardOperator("Add Data Source"); + while (!wo.btNext().isEnabled()) { + new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled + } + JTableOperator jto = new JTableOperator(wo, 0); + int row = jto.findCellRow("Hash Lookup", 2, 0); + jto.clickOnCell(row, 1); + logger.info("Selected hash lookup module in ingest job settings panel"); + JButtonOperator jbo1 = new JButtonOperator(wo, "Global Settings"); + jbo1.pushNoBlock(); + logger.info("Pushed Global Settings button for hash lookup module in ingest job settings panel"); + } catch (TimeoutExpiredException ex) { + screenshot("TimeoutScreenshot"); + logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex); } - JTableOperator jto = new JTableOperator(wo, 0); - int row = jto.findCellRow("Hash Lookup", 2, 0); - jto.clickOnCell(row, 1); - logger.info("Selected hash lookup module in ingest job settings panel"); - JButtonOperator jbo1 = new JButtonOperator(wo, "Global Settings"); - jbo1.pushNoBlock(); - logger.info("Pushed Global Settings button for hash lookup module in ingest job settings panel"); } public void testConfigureHash() { - logger.info("Hash Configure"); - JDialog hashMainDialog = JDialogOperator.waitJDialog("Global Hash Lookup Settings", false, false); - JDialogOperator hashMainDialogOperator = new JDialogOperator(hashMainDialog); - List databases = new ArrayList<>(); - databases.add(getEscapedPath(System.getProperty("nsrl_path"))); - databases.add(getEscapedPath(System.getProperty("known_bad_path"))); - databases.stream().map((database) -> { - JButtonOperator importButtonOperator = new JButtonOperator(hashMainDialogOperator, "Import"); - importButtonOperator.pushNoBlock(); - JDialog addDatabaseDialog = JDialogOperator.waitJDialog("Import Hash Set", false, false); - JDialogOperator addDatabaseDialogOperator = new JDialogOperator(addDatabaseDialog); - JButtonOperator browseButtonOperator = new JButtonOperator(addDatabaseDialogOperator, "Open...", 0); - browseButtonOperator.pushNoBlock(); - JFileChooserOperator fileChooserOperator = new JFileChooserOperator(); - fileChooserOperator.chooseFile(database); - JButtonOperator okButtonOperator = new JButtonOperator(addDatabaseDialogOperator, "OK", 0); - return okButtonOperator; - }).map((okButtonOperator) -> { - okButtonOperator.pushNoBlock(); - return okButtonOperator; - }).forEach((_item) -> { + try { + logger.info("Hash Configure"); + JDialog hashMainDialog = JDialogOperator.waitJDialog("Global Hash Lookup Settings", false, false); + JDialogOperator hashMainDialogOperator = new JDialogOperator(hashMainDialog); + List databases = new ArrayList<>(); + databases.add(getEscapedPath(System.getProperty("nsrl_path"))); + databases.add(getEscapedPath(System.getProperty("known_bad_path"))); + databases.stream().map((database) -> { + JButtonOperator importButtonOperator = new JButtonOperator(hashMainDialogOperator, "Import"); + importButtonOperator.pushNoBlock(); + JDialog addDatabaseDialog = JDialogOperator.waitJDialog("Import Hash Set", false, false); + JDialogOperator addDatabaseDialogOperator = new JDialogOperator(addDatabaseDialog); + JButtonOperator browseButtonOperator = new JButtonOperator(addDatabaseDialogOperator, "Open...", 0); + browseButtonOperator.pushNoBlock(); + JFileChooserOperator fileChooserOperator = new JFileChooserOperator(); + fileChooserOperator.chooseFile(database); + JButtonOperator okButtonOperator = new JButtonOperator(addDatabaseDialogOperator, "OK", 0); + return okButtonOperator; + }).map((okButtonOperator) -> { + okButtonOperator.pushNoBlock(); + return okButtonOperator; + }).forEach((_item) -> { + new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process + }); + // Used if the database has no index + //JDialog jd3 = JDialogOperator.waitJDialog("No Index Exists", false, false); + //JDialogOperator jdo3 = new JDialogOperator(jd3); + //JButtonOperator jbo3 = new JButtonOperator(jdo3, "Yes", 0); new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process - }); - // Used if the database has no index - //JDialog jd3 = JDialogOperator.waitJDialog("No Index Exists", false, false); - //JDialogOperator jdo3 = new JDialogOperator(jd3); - //JButtonOperator jbo3 = new JButtonOperator(jdo3, "Yes", 0); - new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process - //jbo3.pushNoBlock(); - JButtonOperator jbo4 = new JButtonOperator(hashMainDialogOperator, "OK", 0); - jbo4.pushNoBlock(); + //jbo3.pushNoBlock(); + JButtonOperator jbo4 = new JButtonOperator(hashMainDialogOperator, "OK", 0); + jbo4.pushNoBlock(); + } catch (TimeoutExpiredException ex) { + screenshot("TimeoutScreenshot"); + logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex); + } } public void testConfigureIngest2() { - logger.info("Looking for keyword search module in ingest job settings panel"); - WizardOperator wo = new WizardOperator("Add Data Source"); - while(!wo.btNext().isEnabled()){ - new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled + try { + logger.info("Looking for keyword search module in ingest job settings panel"); + WizardOperator wo = new WizardOperator("Add Data Source"); + while (!wo.btNext().isEnabled()) { + new Timeout("pausing", 1000).sleep(); // give it a second till the Add Data Source dialog enabled + } + JTableOperator jto = new JTableOperator(wo, 0); + int row = jto.findCellRow("Keyword Search", 2, 0); + jto.clickOnCell(row, 1); + logger.info("Selected keyword search module in ingest job settings panel"); + JButtonOperator jbo1 = new JButtonOperator(wo, "Global Settings"); + jbo1.pushNoBlock(); + logger.info("Pushed Global Settings button for keyword search module in ingest job settings panel"); + } catch (TimeoutExpiredException ex) { + screenshot("TimeoutScreenshot"); + logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex); } - JTableOperator jto = new JTableOperator(wo, 0); - int row = jto.findCellRow("Keyword Search", 2, 0); - jto.clickOnCell(row, 1); - logger.info("Selected keyword search module in ingest job settings panel"); - JButtonOperator jbo1 = new JButtonOperator(wo, "Global Settings"); - jbo1.pushNoBlock(); - logger.info("Pushed Global Settings button for keyword search module in ingest job settings panel"); } public void testConfigureSearch() { - logger.info("Search Configure"); - JDialog jd = JDialogOperator.waitJDialog("Global Keyword Search Settings", false, false); - JDialogOperator jdo = new JDialogOperator(jd); - String words = getEscapedPath(System.getProperty("keyword_path")); - JButtonOperator jbo0 = new JButtonOperator(jdo, "Import List", 0); - jbo0.pushNoBlock(); - JFileChooserOperator jfco0 = new JFileChooserOperator(); - jfco0.chooseFile(words); - JTableOperator jto = new JTableOperator(jdo, 0); - jto.clickOnCell(0, 0); - new Timeout("pausing", 1000).sleep(); // give it a second to process - if (Boolean.parseBoolean(System.getProperty("mugen_mode"))) { - JTabbedPaneOperator jtpo = new JTabbedPaneOperator(jdo); - jtpo.selectPage("String Extraction"); - JCheckBoxOperator jcbo0 = new JCheckBoxOperator(jtpo, "Arabic (Arabic)"); - jcbo0.doClick(); - JCheckBoxOperator jcbo1 = new JCheckBoxOperator(jtpo, "Han (Chinese, Japanese, Korean)"); - jcbo1.doClick(); + try { + logger.info("Search Configure"); + JDialog jd = JDialogOperator.waitJDialog("Global Keyword Search Settings", false, false); + JDialogOperator jdo = new JDialogOperator(jd); + String words = getEscapedPath(System.getProperty("keyword_path")); + JButtonOperator jbo0 = new JButtonOperator(jdo, "Import List", 0); + jbo0.pushNoBlock(); + JFileChooserOperator jfco0 = new JFileChooserOperator(); + jfco0.chooseFile(words); + JTableOperator jto = new JTableOperator(jdo, 0); + jto.clickOnCell(0, 0); new Timeout("pausing", 1000).sleep(); // give it a second to process + if (Boolean.parseBoolean(System.getProperty("mugen_mode"))) { + JTabbedPaneOperator jtpo = new JTabbedPaneOperator(jdo); + jtpo.selectPage("String Extraction"); + JCheckBoxOperator jcbo0 = new JCheckBoxOperator(jtpo, "Arabic (Arabic)"); + jcbo0.doClick(); + JCheckBoxOperator jcbo1 = new JCheckBoxOperator(jtpo, "Han (Chinese, Japanese, Korean)"); + jcbo1.doClick(); + new Timeout("pausing", 1000).sleep(); // give it a second to process + } + JButtonOperator jbo2 = new JButtonOperator(jdo, "OK", 0); + jbo2.pushNoBlock(); + WizardOperator wo = new WizardOperator("Add Data Source"); + new Timeout("pausing", 10000).sleep(); // let things catch up + wo.btNext().clickMouse(); + } catch (TimeoutExpiredException ex) { + screenshot("TimeoutScreenshot"); + logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex); } - JButtonOperator jbo2 = new JButtonOperator(jdo, "OK", 0); - jbo2.pushNoBlock(); - WizardOperator wo = new WizardOperator("Add Data Source"); - new Timeout("pausing", 10000).sleep(); // let things catch up - wo.btNext().clickMouse(); } public void testIngest() { - logger.info("Ingest 3"); - new Timeout("pausing", 10000).sleep(); // wait for ingest to actually start - long startIngest = System.currentTimeMillis(); - IngestManager man = IngestManager.getInstance(); - while (man.isIngestRunning()) { - new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process + try { + logger.info("Ingest 3"); + new Timeout("pausing", 10000).sleep(); // wait for ingest to actually start + long startIngest = System.currentTimeMillis(); + IngestManager man = IngestManager.getInstance(); + while (man.isIngestRunning()) { + new Timeout("pausing", 1000).sleep(); // give it a second (or five) to process + } + logger.log(Level.INFO, "Ingest (including enqueue) took {0}ms", (System.currentTimeMillis() - startIngest)); + // allow keyword search to finish saving artifacts, just in case + // but randomize the timing so that we don't always get the same error + // consistently, making it seem like default behavior + Random rand = new Random(); + new Timeout("pausing", 10000 + (rand.nextInt(15000) + 5000)).sleep(); + } catch (TimeoutExpiredException ex) { + screenshot("TimeoutScreenshot"); + logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex); } - logger.log(Level.INFO, "Ingest (including enqueue) took {0}ms", (System.currentTimeMillis() - startIngest)); - // allow keyword search to finish saving artifacts, just in case - // but randomize the timing so that we don't always get the same error - // consistently, making it seem like default behavior - Random rand = new Random(); - new Timeout("pausing", 10000 + (rand.nextInt(15000) + 5000)).sleep(); - screenshot("Finished Ingest"); } public void testExpandDataSourcesTree() { - logger.info("Data Sources Node"); - MainWindowOperator mwo = MainWindowOperator.getDefault(); - JTreeOperator jto = new JTreeOperator(mwo, "Data Sources"); - String [] nodeNames = {"Data Sources"}; - TreePath tp = jto.findPath(nodeNames); - expandNodes(jto, tp); - screenshot("Data Sources Tree"); + try { + logger.info("Data Sources Node"); + MainWindowOperator mwo = MainWindowOperator.getDefault(); + JTreeOperator jto = new JTreeOperator(mwo, "Data Sources"); + String[] nodeNames = {"Data Sources"}; + TreePath tp = jto.findPath(nodeNames); + expandNodes(jto, tp); + } catch (TimeoutExpiredException ex) { + screenshot("TimeoutScreenshot"); + logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex); + } } public void testGenerateReportToolbar() { - logger.info("Generate Report Toolbars"); - MainWindowOperator mwo = MainWindowOperator.getDefault(); - JButtonOperator jbo = new JButtonOperator(mwo, "Generate Report"); - jbo.pushNoBlock(); - new Timeout("pausing", 5000).sleep(); + try { + logger.info("Generate Report Toolbars"); + MainWindowOperator mwo = MainWindowOperator.getDefault(); + JButtonOperator jbo = new JButtonOperator(mwo, "Generate Report"); + jbo.pushNoBlock(); + } catch (TimeoutExpiredException ex) { + screenshot("TimeoutScreenshot"); + logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex); + } } public void testGenerateReportButton() throws IOException { - logger.info("Generate Report Button"); - resetTimeouts("ComponentOperator.WaitComponentTimeout", 240000); - JDialog reportDialog = JDialogOperator.waitJDialog("Generate Report", false, false); - JDialogOperator reportDialogOperator = new JDialogOperator(reportDialog); - JListOperator listOperator = new JListOperator(reportDialogOperator); - JButtonOperator jbo0 = new JButtonOperator(reportDialogOperator, "Next"); - DateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss"); - Date date = new Date(); - String datenotime = dateFormat.format(date); - listOperator.clickOnItem(0, 1); - jbo0.pushNoBlock(); - new Timeout("pausing", 2000).sleep(); - JButtonOperator jbo1 = new JButtonOperator(reportDialogOperator, "Finish"); - jbo1.pushNoBlock(); - JDialog previewDialog = JDialogOperator.waitJDialog("Progress", false, false); - screenshot("Progress"); - JDialogOperator previewDialogOperator = new JDialogOperator(previewDialog); - JLabelOperator.waitJLabel(previewDialog, "Complete", false, false); - JButtonOperator jbo2 = new JButtonOperator(previewDialogOperator, "Close"); - jbo2.pushNoBlock(); - new Timeout("pausing", 10000).sleep(); - System.setProperty("ReportStr", datenotime); - screenshot("Done Testing"); + try { + logger.info("Generate Report Button"); + setTimeout("ComponentOperator.WaitComponentTimeout", 240000); + JDialog reportDialog = JDialogOperator.waitJDialog("Generate Report", false, false); + JDialogOperator reportDialogOperator = new JDialogOperator(reportDialog); + JListOperator listOperator = new JListOperator(reportDialogOperator); + JButtonOperator jbo0 = new JButtonOperator(reportDialogOperator, "Next"); + DateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy-HH-mm-ss"); + Date date = new Date(); + String datenotime = dateFormat.format(date); + listOperator.clickOnItem(0, 1); + jbo0.pushNoBlock(); + new Timeout("pausing", 2000).sleep(); + JButtonOperator jbo1 = new JButtonOperator(reportDialogOperator, "Finish"); + jbo1.pushNoBlock(); + JDialog previewDialog = JDialogOperator.waitJDialog("Progress", false, false); + JDialogOperator previewDialogOperator = new JDialogOperator(previewDialog); + JLabelOperator.waitJLabel(previewDialog, "Complete", false, false); + JButtonOperator jbo2 = new JButtonOperator(previewDialogOperator, "Close"); + jbo2.pushNoBlock(); + new Timeout("pausing", 10000).sleep(); + System.setProperty("ReportStr", datenotime); + } catch (TimeoutExpiredException ex) { + screenshot("TimeoutScreenshot"); + logger.log(Level.SEVERE, "AutopsyTestCases.testNewCaseWizard encountered timed out", ex); + } } public void screenshot(String name) { - logger.info("Taking screenshot."); - try { - Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()); - BufferedImage capture = new Robot().createScreenCapture(screenRect); - String outPath = getEscapedPath(System.getProperty("out_path")); - ImageIO.write(capture, "png", new File(outPath + "\\" + name + ".png")); - new Timeout("pausing", 1000).sleep(); // give it a second to save - } catch (IOException ex) { - logger.log(Level.WARNING, "IOException taking screenshot.", ex); - } catch (AWTException ex) { - logger.log(Level.WARNING, "AWTException taking screenshot.", ex); - + String outPath = getEscapedPath(System.getProperty("out_path")); + File screenShotFile = new File(outPath + "\\" + name + ".png"); + if (!screenShotFile.exists()) { + logger.info("Taking screenshot."); + try { + Rectangle screenRect = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize()); + BufferedImage capture = new Robot().createScreenCapture(screenRect); + ImageIO.write(capture, "png", screenShotFile); + new Timeout("pausing", 1000).sleep(); // give it a second to save + } catch (IOException ex) { + logger.log(Level.WARNING, "IOException taking screenshot.", ex); + } catch (AWTException ex) { + logger.log(Level.WARNING, "AWTException taking screenshot.", ex); + } } } - - /* - * Nightly test failed at WindowWaiter.WaitWindowTimeOut because of TimeoutExpiredException. So we - * use this conveninent method to override the default Jemmy Timeouts value. - */ - private Timeouts resetTimeouts(String name, int value) { + /* + * Nightly test failed at WindowWaiter.WaitWindowTimeOut because of + * TimeoutExpiredException. So we use this conveninent method to override + * the default Jemmy Timeouts value. + */ + private Timeouts setTimeout(String name, int value) { Timeouts timeouts = JemmyProperties.getCurrentTimeouts(); timeouts.setTimeout(name, value); return timeouts; } - + private void setMultiUserPerferences() { UserPreferences.setIsMultiUserModeEnabled(true); //PostgreSQL database settings @@ -393,8 +458,8 @@ public class AutopsyTestCases { logger.log(Level.SEVERE, "Error saving messaging service connection info", ex); //NON-NLS } } - - private void expandNodes (JTreeOperator jto, TreePath tp) { + + private void expandNodes(JTreeOperator jto, TreePath tp) { try { jto.expandPath(tp); for (TreePath t : jto.getChildPaths(tp)) { From e16063cf8eaa028a8008e6521bdb107ecebf41d0 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 26 Feb 2019 01:46:59 -0500 Subject: [PATCH 04/20] New HTML content viewer added. --- .../autopsy/contentviewers/Bundle.properties | 1 + .../autopsy/contentviewers/FileViewer.form | 1 + .../autopsy/contentviewers/FileViewer.java | 5 +- .../autopsy/contentviewers/HtmlPanel.form | 65 +++++++ .../autopsy/contentviewers/HtmlPanel.java | 166 ++++++++++++++++++ .../autopsy/contentviewers/HtmlViewer.form | 40 +++++ .../autopsy/contentviewers/HtmlViewer.java | 130 ++++++++++++++ .../contentviewers/MessageContentViewer.form | 39 +--- .../contentviewers/MessageContentViewer.java | 84 +++------ 9 files changed, 432 insertions(+), 99 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/contentviewers/HtmlPanel.form create mode 100755 Core/src/org/sleuthkit/autopsy/contentviewers/HtmlPanel.java create mode 100755 Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.form create mode 100755 Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.java diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties index e43fc72267..e6b621092f 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/Bundle.properties @@ -83,3 +83,4 @@ MediaViewImagePanel.zoomResetButton.text=Reset MediaViewImagePanel.zoomTextField.text= MediaViewImagePanel.rotationTextField.text= MediaViewImagePanel.rotateLeftButton.toolTipText= +HtmlPanel.showImagesToggleButton.text=Show Images diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.form b/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.form index d07831cafe..b3a7244a10 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.form @@ -11,6 +11,7 @@ + diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java index 84f216e253..ab92f3f543 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/FileViewer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2018 Basis Technology Corp. + * Copyright 2018-2019 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -49,7 +49,8 @@ public class FileViewer extends javax.swing.JPanel implements DataContentViewer private final FileTypeViewer[] KNOWN_VIEWERS = new FileTypeViewer[]{ new SQLiteViewer(), new PListViewer(), - new MediaFileViewer() + new MediaFileViewer(), + new HtmlViewer() }; private FileTypeViewer lastViewer; diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlPanel.form b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlPanel.form new file mode 100755 index 0000000000..ec9f0fc569 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlPanel.form @@ -0,0 +1,65 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlPanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlPanel.java new file mode 100755 index 0000000000..058848d00e --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlPanel.java @@ -0,0 +1,166 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 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.contentviewers; + +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.coreutils.Logger; + +/** + * A file content viewer for HTML files. + */ +@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives +final class HtmlPanel extends javax.swing.JPanel { + + private static final long serialVersionUID = 1L; + private static final Logger logger = Logger.getLogger(HtmlPanel.class.getName()); + + private String htmlText; + + /** + * Creates new form HtmlViewerPanel + */ + HtmlPanel() { + initComponents(); + + Utilities.configureTextPaneAsHtml(htmlbodyTextPane); + } + + /** + * Set the text pane's HTML text and refresh the view to display it. + * + * @param htmlText The HTML text to be applied to the text pane. + */ + void setHtmlText(String htmlText) { + this.htmlText = htmlText; + refresh(); + } + + /** + * Clear the HTML in the text pane and disable the show/hide button. + */ + void reset() { + htmlbodyTextPane.setText(""); + showImagesToggleButton.setEnabled(false); + } + + /** + * Guarantee the HTML text has 'html' and 'body' tags. + * + * @param htmlText The HTML text + * + * @return The HTML text with the 'html' and 'body' tags applied. + */ + private String wrapInHtmlBody(String htmlText) { + return "" + htmlText + ""; + } + + /** + * Cleans out input HTML string + * + * @param htmlInString The HTML string to cleanse + * + * @return The cleansed HTML String + */ + private String cleanseHTML(String htmlInString) { + + Document doc = Jsoup.parse(htmlInString); + + // Update all 'img' tags. + doc.select("img[src]").forEach(img -> img.attr("src", "")); + + return doc.html(); + } + + /** + * Refresh the panel to reflect the current show/hide images setting. + */ + @Messages({ + "HtmlPanel_showImagesToggleButton_show=Show Images", + "HtmlPanel_showImagesToggleButton_hide=Hide Images" + }) + private void refresh() { + if (false == htmlText.isEmpty()) { + if (showImagesToggleButton.isSelected()) { + showImagesToggleButton.setText(Bundle.HtmlPanel_showImagesToggleButton_hide()); + this.htmlbodyTextPane.setText(wrapInHtmlBody(htmlText)); + } else { + showImagesToggleButton.setText(Bundle.HtmlPanel_showImagesToggleButton_show()); + this.htmlbodyTextPane.setText(wrapInHtmlBody(cleanseHTML(htmlText))); + } + htmlbodyTextPane.setCaretPosition(0); + showImagesToggleButton.setEnabled(true); + } + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + htmlScrollPane = new javax.swing.JScrollPane(); + htmlbodyTextPane = new javax.swing.JTextPane(); + showImagesToggleButton = new javax.swing.JToggleButton(); + + htmlScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); + + htmlbodyTextPane.setEditable(false); + htmlScrollPane.setViewportView(htmlbodyTextPane); + + org.openide.awt.Mnemonics.setLocalizedText(showImagesToggleButton, org.openide.util.NbBundle.getMessage(HtmlPanel.class, "HtmlPanel.showImagesToggleButton.text")); // NOI18N + showImagesToggleButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + showImagesToggleButtonActionPerformed(evt); + } + }); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(0, 203, Short.MAX_VALUE) + .addComponent(showImagesToggleButton)) + .addComponent(htmlScrollPane) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(showImagesToggleButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(htmlScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 71, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + + private void showImagesToggleButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showImagesToggleButtonActionPerformed + refresh(); + }//GEN-LAST:event_showImagesToggleButtonActionPerformed + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JScrollPane htmlScrollPane; + private javax.swing.JTextPane htmlbodyTextPane; + private javax.swing.JToggleButton showImagesToggleButton; + // End of variables declaration//GEN-END:variables +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.form b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.form new file mode 100755 index 0000000000..a08d9e9b31 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.form @@ -0,0 +1,40 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.java new file mode 100755 index 0000000000..54c69265b7 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.java @@ -0,0 +1,130 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2019 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.contentviewers; + +import java.awt.Component; +import java.awt.Cursor; +import java.util.Arrays; +import java.util.List; +import java.util.logging.Level; +import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * A file content viewer for HTML files. + */ +@SuppressWarnings("PMD.SingularField") // UI widgets cause lots of false positives +final class HtmlViewer extends javax.swing.JPanel implements FileTypeViewer { + + private static final long serialVersionUID = 1L; + private static final Logger logger = Logger.getLogger(HtmlViewer.class.getName()); + + private static final String[] SUPPORTED_MIMETYPES = new String[]{"text/html"}; + + private BlackboardArtifact artifact; + private AbstractFile abstractFile; + + /** + * Creates new form HtmlViewerPanel + */ + HtmlViewer() { + initComponents(); + } + + /** + * Retrieve the HTML text content from the supplied file. + * + * @param abstractFile The file to read. + * + * @return The text content of the file. + */ + private String getHtmlText(AbstractFile abstractFile) { + try { + int fileSize = (int) abstractFile.getSize(); + byte[] buffer = new byte[fileSize]; + abstractFile.read(buffer, 0, fileSize); + return new String(buffer); + } catch (TskCoreException ex) { + logger.log(Level.SEVERE, String.format("Unable to read from file '%s' (id=%d).", + abstractFile.getName(), abstractFile.getId()), ex); + } + + return null; + } + + /** + * 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() { + + htmlPanel = new org.sleuthkit.autopsy.contentviewers.HtmlPanel(); + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(htmlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap()) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addComponent(htmlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap()) + ); + }// //GEN-END:initComponents + + + // Variables declaration - do not modify//GEN-BEGIN:variables + private org.sleuthkit.autopsy.contentviewers.HtmlPanel htmlPanel; + // End of variables declaration//GEN-END:variables + + @Override + public List getSupportedMIMETypes() { + return Arrays.asList(SUPPORTED_MIMETYPES); + } + + @Override + public void setFile(AbstractFile file) { + WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); + abstractFile = file; + htmlPanel.setHtmlText(getHtmlText(file)); + WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + } + + @Override + public Component getComponent() { + return this; + } + + @Override + public void resetComponent() { + htmlPanel.reset(); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.form b/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.form index c1400964a9..1172483699 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.form @@ -274,50 +274,17 @@ - - - - - - + - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java index ef631eeb02..bd66b35449 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2017-2018 Basis Technology Corp. + * Copyright 2017-2019 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -106,9 +106,12 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont attachmentsScrollPane.setViewportView(drp); msgbodyTabbedPane.setEnabledAt(ATTM_TAB_INDEX, true); - textAreas = Arrays.asList(headersTextArea, textbodyTextArea, htmlbodyTextPane, rtfbodyTextPane); + /* + * HTML tab uses the HtmlPanel instead of an internal text pane, so we + * use 'null' for that index. + */ + textAreas = Arrays.asList(headersTextArea, textbodyTextArea, null, rtfbodyTextPane); - Utilities.configureTextPaneAsHtml(htmlbodyTextPane); Utilities.configureTextPaneAsRtf(rtfbodyTextPane); resetComponent(); @@ -150,9 +153,7 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont textbodyScrollPane = new javax.swing.JScrollPane(); textbodyTextArea = new javax.swing.JTextArea(); htmlPane = new javax.swing.JPanel(); - htmlScrollPane = new javax.swing.JScrollPane(); - htmlbodyTextPane = new javax.swing.JTextPane(); - showImagesToggleButton = new javax.swing.JToggleButton(); + htmlPanel = new org.sleuthkit.autopsy.contentviewers.HtmlPanel(); rtfbodyScrollPane = new javax.swing.JScrollPane(); rtfbodyTextPane = new javax.swing.JTextPane(); attachmentsPanel = new javax.swing.JPanel(); @@ -265,35 +266,15 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.textbodyScrollPane.TabConstraints.tabTitle"), textbodyScrollPane); // NOI18N - htmlScrollPane.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); - - htmlbodyTextPane.setEditable(false); - htmlScrollPane.setViewportView(htmlbodyTextPane); - - org.openide.awt.Mnemonics.setLocalizedText(showImagesToggleButton, "Show Images"); - showImagesToggleButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - showImagesToggleButtonActionPerformed(evt); - } - }); - javax.swing.GroupLayout htmlPaneLayout = new javax.swing.GroupLayout(htmlPane); htmlPane.setLayout(htmlPaneLayout); htmlPaneLayout.setHorizontalGroup( htmlPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(htmlScrollPane) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, htmlPaneLayout.createSequentialGroup() - .addContainerGap(533, Short.MAX_VALUE) - .addComponent(showImagesToggleButton) - .addGap(3, 3, 3)) + .addComponent(htmlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 647, Short.MAX_VALUE) ); htmlPaneLayout.setVerticalGroup( htmlPaneLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(htmlPaneLayout.createSequentialGroup() - .addComponent(showImagesToggleButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(htmlScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 333, Short.MAX_VALUE) - .addGap(0, 0, 0)) + .addComponent(htmlPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 362, Short.MAX_VALUE) ); msgbodyTabbedPane.addTab(org.openide.util.NbBundle.getMessage(MessageContentViewer.class, "MessageContentViewer.htmlPane.TabConstraints.tabTitle"), htmlPane); // NOI18N @@ -358,26 +339,6 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont ); }// //GEN-END:initComponents - @NbBundle.Messages({ - "MessageContentViewer.showImagesToggleButton.hide.text=Hide Images", - "MessageContentViewer.showImagesToggleButton.text=Show Images"}) - private void showImagesToggleButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showImagesToggleButtonActionPerformed - try { - String htmlText = getAttributeValueSafe(artifact, TSK_EMAIL_CONTENT_HTML); - if (false == htmlText.isEmpty()) { - if (showImagesToggleButton.isSelected()) { - showImagesToggleButton.setText(Bundle.MessageContentViewer_showImagesToggleButton_hide_text()); - this.htmlbodyTextPane.setText(wrapInHtmlBody(htmlText)); - } else { - showImagesToggleButton.setText(Bundle.MessageContentViewer_showImagesToggleButton_text()); - this.htmlbodyTextPane.setText(wrapInHtmlBody(cleanseHTML(htmlText))); - } - } - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "Failed to get attributes for email message.", ex); //NON-NLS - } - }//GEN-LAST:event_showImagesToggleButtonActionPerformed - private void viewInNewWindowButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_viewInNewWindowButtonActionPerformed new NewWindowViewAction("View in new window", drpExplorerManager.getSelectedNodes()[0]).actionPerformed(evt); }//GEN-LAST:event_viewInNewWindowButtonActionPerformed @@ -396,12 +357,10 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont private javax.swing.JScrollPane headersScrollPane; private javax.swing.JTextArea headersTextArea; private javax.swing.JPanel htmlPane; - private javax.swing.JScrollPane htmlScrollPane; - private javax.swing.JTextPane htmlbodyTextPane; + private org.sleuthkit.autopsy.contentviewers.HtmlPanel htmlPanel; private javax.swing.JTabbedPane msgbodyTabbedPane; private javax.swing.JScrollPane rtfbodyScrollPane; private javax.swing.JTextPane rtfbodyTextPane; - private javax.swing.JToggleButton showImagesToggleButton; private javax.swing.JLabel subjectLabel; private javax.swing.JLabel subjectText; private javax.swing.JScrollPane textbodyScrollPane; @@ -505,9 +464,9 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont headersTextArea.setText(""); rtfbodyTextPane.setText(""); - htmlbodyTextPane.setText(""); + htmlPanel.reset(); //DLG: htmlbodyTextPane.setText(""); textbodyTextArea.setText(""); - showImagesToggleButton.setEnabled(false); + //DLG: showImagesToggleButton.setEnabled(false); msgbodyTabbedPane.setEnabled(false); } @@ -567,12 +526,15 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont String attributeText = getAttributeValueSafe(artifact, type); if (index == HTML_TAB_INDEX && StringUtils.isNotBlank(attributeText)) { - //special case for HTML, we need to 'cleanse' it - attributeText = wrapInHtmlBody(cleanseHTML(attributeText)); + htmlPanel.setHtmlText(attributeText); + } else { + JTextComponent textComponent = textAreas.get(index); + if (textComponent != null) { + textComponent.setText(attributeText); + textComponent.setCaretPosition(0); //make sure we start at the top + } } - JTextComponent textComponent = textAreas.get(index); - textComponent.setText(attributeText); - textComponent.setCaretPosition(0); //make sure we start at the top + final boolean hasText = attributeText.length() > 0; msgbodyTabbedPane.setEnabledAt(index, hasText); @@ -613,9 +575,9 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont directionText.setEnabled(false); ccLabel.setEnabled(true); - showImagesToggleButton.setEnabled(true); - showImagesToggleButton.setText("Show Images"); - showImagesToggleButton.setSelected(false); + //DLG: showImagesToggleButton.setEnabled(true); + //DLG: showImagesToggleButton.setText("Show Images"); + //DLG: showImagesToggleButton.setSelected(false); try { this.fromText.setText(getAttributeValueSafe(artifact, TSK_EMAIL_FROM)); From 59ddc074daf2adddd28bb7faaf208dcf93678b88 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 26 Feb 2019 01:51:48 -0500 Subject: [PATCH 05/20] Removed developer messages. --- .../autopsy/contentviewers/MessageContentViewer.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java index bd66b35449..00c87b3417 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MessageContentViewer.java @@ -464,9 +464,8 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont headersTextArea.setText(""); rtfbodyTextPane.setText(""); - htmlPanel.reset(); //DLG: htmlbodyTextPane.setText(""); + htmlPanel.reset(); textbodyTextArea.setText(""); - //DLG: showImagesToggleButton.setEnabled(false); msgbodyTabbedPane.setEnabled(false); } @@ -575,10 +574,6 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont directionText.setEnabled(false); ccLabel.setEnabled(true); - //DLG: showImagesToggleButton.setEnabled(true); - //DLG: showImagesToggleButton.setText("Show Images"); - //DLG: showImagesToggleButton.setSelected(false); - try { this.fromText.setText(getAttributeValueSafe(artifact, TSK_EMAIL_FROM)); this.fromText.setToolTipText(getAttributeValueSafe(artifact, TSK_EMAIL_FROM)); From 00cec7d4785fed80fc41bd8aa80916c848ede368 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Tue, 26 Feb 2019 02:05:08 -0500 Subject: [PATCH 06/20] Addressed Codacy issues. --- Core/src/org/sleuthkit/autopsy/contentviewers/HtmlPanel.java | 2 -- Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.java | 4 ---- 2 files changed, 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlPanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlPanel.java index 058848d00e..96badc44c3 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlPanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlPanel.java @@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.contentviewers; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.coreutils.Logger; /** * A file content viewer for HTML files. @@ -30,7 +29,6 @@ import org.sleuthkit.autopsy.coreutils.Logger; final class HtmlPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; - private static final Logger logger = Logger.getLogger(HtmlPanel.class.getName()); private String htmlText; diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.java index 54c69265b7..2aa1e41ffd 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.java @@ -26,7 +26,6 @@ import java.util.logging.Level; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.TskCoreException; /** @@ -40,9 +39,6 @@ final class HtmlViewer extends javax.swing.JPanel implements FileTypeViewer { private static final String[] SUPPORTED_MIMETYPES = new String[]{"text/html"}; - private BlackboardArtifact artifact; - private AbstractFile abstractFile; - /** * Creates new form HtmlViewerPanel */ From 8dd909b1b8f213084931e35eaec60a87120145f2 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Wed, 27 Feb 2019 11:58:17 -0500 Subject: [PATCH 07/20] Adding tagged artifacts --- .../report/CreatePortableCaseModule.java | 243 ++++++++++++++++-- 1 file changed, 225 insertions(+), 18 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/CreatePortableCaseModule.java b/Core/src/org/sleuthkit/autopsy/report/CreatePortableCaseModule.java index cb751fa53b..f295dc680b 100644 --- a/Core/src/org/sleuthkit/autopsy/report/CreatePortableCaseModule.java +++ b/Core/src/org/sleuthkit/autopsy/report/CreatePortableCaseModule.java @@ -38,6 +38,9 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.autopsy.datamodel.utils.FileTypeUtils.FileTypeCategory; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardArtifactTag; +import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.FileSystem; @@ -47,6 +50,7 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase.CaseDbTransaction; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskDataException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.Volume; import org.sleuthkit.datamodel.VolumeSystem; @@ -78,6 +82,15 @@ public class CreatePortableCaseModule implements GeneralReportModule { // Maps old TagName to new TagName private final Map oldTagNameToNewTagName = new HashMap<>(); + + // Map of old artifact type ID to new artifact type ID. There will only be changes if custom artifact types are present. + private final Map oldArtTypeIdToNewArtTypeId = new HashMap<>(); + + // Map of old attribute type ID to new attribute type ID. There will only be changes if custom attr types are present. + private final Map oldAttrTypeIdToNewAttrType = new HashMap<>(); + + // Map of old artifact ID to new artifact + private final Map oldArtifactIdToNewArtifact = new HashMap<>(); public CreatePortableCaseModule() { // Nothing to do here @@ -132,6 +145,8 @@ public class CreatePortableCaseModule implements GeneralReportModule { "CreatePortableCaseModule.generateReport.copyingTags=Copying tags...", "# {0} - tag name", "CreatePortableCaseModule.generateReport.copyingFiles=Copying files tagged as {0}...", + "# {0} - tag name", + "CreatePortableCaseModule.generateReport.copyingArtifacts=Copying artifacts tagged as {0}...", "# {0} - output folder", "CreatePortableCaseModule.generateReport.outputDirDoesNotExist=Output folder {0} does not exist", "# {0} - output folder", @@ -139,7 +154,10 @@ public class CreatePortableCaseModule implements GeneralReportModule { "CreatePortableCaseModule.generateReport.noTagsSelected=No tags selected for export.", "CreatePortableCaseModule.generateReport.caseClosed=Current case has been closed", "CreatePortableCaseModule.generateReport.errorCopyingTags=Error copying tags", - "CreatePortableCaseModule.generateReport.errorCopyingFiles=Error copying tagged files" + "CreatePortableCaseModule.generateReport.errorCopyingFiles=Error copying tagged files", + "CreatePortableCaseModule.generateReport.errorCopyingArtifacts=Error copying tagged artifacts", + "# {0} - attribute type name", + "CreatePortableCaseModule.generateReport.errorLookingUpAttrType=Error looking up attribute type {0}", }) @Override public void generateReport(String reportPath, ReportProgressPanel progressPanel) { @@ -222,6 +240,35 @@ public class CreatePortableCaseModule implements GeneralReportModule { handleError("Error copying tagged files", Bundle.CreatePortableCaseModule_generateReport_errorCopyingFiles(), ex, progressPanel); return; } + + // Set up tracking to support any custom artifact or attribute types + for (BlackboardArtifact.ARTIFACT_TYPE type:BlackboardArtifact.ARTIFACT_TYPE.values()) { + oldArtTypeIdToNewArtTypeId.put(type.getTypeID(), type.getTypeID()); + } + for (BlackboardAttribute.ATTRIBUTE_TYPE type:BlackboardAttribute.ATTRIBUTE_TYPE.values()) { + try { + oldAttrTypeIdToNewAttrType.put(type.getTypeID(), skCase.getAttributeType(type.getLabel())); + } catch (TskCoreException ex) { + handleError("Error looking up attribute name " + type.getLabel(), + Bundle.CreatePortableCaseModule_generateReport_errorLookingUpAttrType(type.getLabel()), + ex, progressPanel); + } + } + + // Copy the tagged artifacts and associated files + try { + for(TagName tagName:tagNames) { + // Check for cancellation + if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) { + return; + } + progressPanel.updateStatusLabel(Bundle.CreatePortableCaseModule_generateReport_copyingArtifacts(tagName.getDisplayName())); + addArtifactsToPortableCase(tagName, progressPanel); + } + } catch (TskCoreException ex) { + handleError("Error copying tagged artifacts", Bundle.CreatePortableCaseModule_generateReport_errorCopyingArtifacts(), ex, progressPanel); + return; + } // Close the case connections and clear out the maps cleanup(); @@ -298,10 +345,6 @@ public class CreatePortableCaseModule implements GeneralReportModule { * @param progressPanel * @throws TskCoreException */ - @NbBundle.Messages({ - "# {0} - File name", - "CreatePortableCaseModule.addFilesToPortableCase.copyingFile=Copying file {0}", - }) private void addFilesToPortableCase(TagName oldTagName, ReportProgressPanel progressPanel) throws TskCoreException { // Get all the tags in the current case @@ -317,19 +360,7 @@ public class CreatePortableCaseModule implements GeneralReportModule { Content content = tag.getContent(); if (content instanceof AbstractFile) { - AbstractFile file = (AbstractFile) content; - String filePath = file.getParentPath() + file.getName(); - progressPanel.updateStatusLabel(Bundle.CreatePortableCaseModule_addFilesToPortableCase_copyingFile(filePath)); - - long newFileId; - CaseDbTransaction trans = skCase.beginTransaction(); - try { - newFileId = copyContent(file, trans); - trans.commit(); - } catch (TskCoreException ex) { - trans.rollback(); - throw(ex); - } + long newFileId = copyContentToPortableCase(content, progressPanel); // Tag the file if (! oldTagNameToNewTagName.containsKey(tag.getName())) { @@ -340,6 +371,182 @@ public class CreatePortableCaseModule implements GeneralReportModule { } } + /** + * Add all artifacts with a given tag to the portable case. + * + * @param oldTagName + * @param progressPanel + * @throws TskCoreException + */ + private void addArtifactsToPortableCase(TagName oldTagName, ReportProgressPanel progressPanel) throws TskCoreException { + + List tags = currentCase.getServices().getTagsManager().getBlackboardArtifactTagsByTagName(oldTagName); + + // Copy the artifacts into the portable case along with their content and tag + for (BlackboardArtifactTag tag : tags) { + + // Check for cancellation + if (progressPanel.getStatus() == ReportProgressPanel.ReportStatus.CANCELED) { + return; + } + + // Copy the source content + Content content = tag.getContent(); + long newContentId = copyContentToPortableCase(content, progressPanel); + + // Copy the artifact + BlackboardArtifact newArtifact = copyArtifact(newContentId, tag.getArtifact()); + + // Tag the artfiact + if (! oldTagNameToNewTagName.containsKey(tag.getName())) { + throw new TskCoreException("TagName map is missing entry for ID " + tag.getName().getId() + " with display name " + tag.getName().getDisplayName()); + } + skCase.addBlackboardArtifactTag(newArtifact, oldTagNameToNewTagName.get(tag.getName()), tag.getComment()); + } + } + + // TODO + // custom artifact types + // cache + private BlackboardArtifact copyArtifact(long newContentId, BlackboardArtifact artifactToCopy) throws TskCoreException { + + if (oldArtifactIdToNewArtifact.containsKey(artifactToCopy.getArtifactID())) { + return oldArtifactIdToNewArtifact.get(artifactToCopy.getArtifactID()); + } + + // First create the associated artifact (if present) + BlackboardAttribute oldAssociatedAttribute = artifactToCopy.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT)); + List newAttrs = new ArrayList<>(); + if (oldAssociatedAttribute != null) { + BlackboardArtifact oldAssociatedArtifact = currentCase.getSleuthkitCase().getBlackboardArtifact(oldAssociatedAttribute.getValueLong()); + BlackboardArtifact newAssociatedArtifact = copyArtifact(newContentId, oldAssociatedArtifact); + newAttrs.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, + String.join(",", oldAssociatedAttribute.getSources()), newAssociatedArtifact.getArtifactID())); + } + + // Create the new artifact + int newArtifactTypeId = getNewArtifactTypeId(artifactToCopy); + BlackboardArtifact newArtifact = skCase.newBlackboardArtifact(newArtifactTypeId, newContentId); + List oldAttrs = artifactToCopy.getAttributes(); + + // Copy over each attribute, making sure the type is in the new case. + for (BlackboardAttribute oldAttr:oldAttrs) { + + // The associated artifact has already been handled + if (oldAttr.getAttributeType().getTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) { + continue; + } + + BlackboardAttribute.Type newAttributeType = getNewAttributeType(oldAttr); + switch (oldAttr.getValueType()) { + case BYTE: + newAttrs.add(new BlackboardAttribute(newAttributeType, String.join(",", oldAttr.getSources()), + oldAttr.getValueBytes())); + break; + case DOUBLE: + newAttrs.add(new BlackboardAttribute(newAttributeType, String.join(",", oldAttr.getSources()), + oldAttr.getValueDouble())); + break; + case INTEGER: + newAttrs.add(new BlackboardAttribute(newAttributeType, String.join(",", oldAttr.getSources()), + oldAttr.getValueInt())); + break; + case DATETIME: + case LONG: + newAttrs.add(new BlackboardAttribute(newAttributeType, String.join(",", oldAttr.getSources()), + oldAttr.getValueLong())); + break; + case STRING: + newAttrs.add(new BlackboardAttribute(newAttributeType, String.join(",", oldAttr.getSources()), + oldAttr.getValueString())); + break; + default: + throw new TskCoreException("Unexpected attribute value type found: " + oldAttr.getValueType().getLabel()); + } + } + + newArtifact.addAttributes(newAttrs); + + oldArtifactIdToNewArtifact.put(artifactToCopy.getArtifactID(), newArtifact); + return newArtifact; + } + + /** + * Get the artifact type ID in the portable case and create new artifact type if needed. + * For built-in artifacts this will be the same as the original. + * + * @param oldArtifactTypeId The artifact type ID in the current case + * + * @return The corresponding artifact type ID in the portable case + */ + private int getNewArtifactTypeId(BlackboardArtifact oldArtifact) throws TskCoreException { + if (oldArtTypeIdToNewArtTypeId.containsKey(oldArtifact.getArtifactTypeID())) { + return oldArtTypeIdToNewArtTypeId.get(oldArtifact.getArtifactTypeID()); + } + + BlackboardArtifact.Type oldCustomType = skCase.getArtifactType(oldArtifact.getArtifactTypeName()); + try { + BlackboardArtifact.Type newCustomType = skCase.addBlackboardArtifactType(oldCustomType.getTypeName(), oldCustomType.getDisplayName()); + oldArtTypeIdToNewArtTypeId.put(oldArtifact.getArtifactTypeID(), newCustomType.getTypeID()); + return newCustomType.getTypeID(); + } catch (TskDataException ex) { + throw new TskCoreException("Error creating new artifact type " + oldCustomType.getTypeName(), ex); + } + } + + /** + * Get the attribute type ID in the portable case and create new attribute type if needed. + * For built-in attributes this will be the same as the original. + * + * @param oldAttributeTypeId The attribute type ID in the current case + * + * @return The corresponding attribute type in the portable case + */ + private BlackboardAttribute.Type getNewAttributeType(BlackboardAttribute oldAttribute) throws TskCoreException { + BlackboardAttribute.Type oldAttrType = oldAttribute.getAttributeType(); + if (oldAttrTypeIdToNewAttrType.containsKey(oldAttrType.getTypeID())) { + return oldAttrTypeIdToNewAttrType.get(oldAttrType.getTypeID()); + } + + try { + BlackboardAttribute.Type newCustomType = skCase.addArtifactAttributeType(oldAttrType.getTypeName(), + oldAttrType.getValueType(), oldAttrType.getDisplayName()); + oldAttrTypeIdToNewAttrType.put(oldAttribute.getAttributeType().getTypeID(), newCustomType); + return newCustomType; + } catch (TskDataException ex) { + throw new TskCoreException("Error creating new attribute type " + oldAttrType.getTypeName(), ex); + } + } + + /** + * Top level method to copy a content object to the portable case. + * + * @param content + * @param progressPanel + * + * @return The object ID of the copied content in the portable case + * + * @throws TskCoreException + */ + @NbBundle.Messages({ + "# {0} - File name", + "CreatePortableCaseModule.copyContentToPortableCase.copyingFile=Copying file {0}", + }) + private long copyContentToPortableCase(Content content, ReportProgressPanel progressPanel) throws TskCoreException { + progressPanel.updateStatusLabel(Bundle.CreatePortableCaseModule_copyContentToPortableCase_copyingFile(content.getUniquePath())); + + long newFileId; + CaseDbTransaction trans = skCase.beginTransaction(); + try { + newFileId = copyContent(content, trans); + trans.commit(); + return newFileId; + } catch (TskCoreException ex) { + trans.rollback(); + throw(ex); + } + } + /** * Returns the object ID for the given content object in the portable case. * From 78b25ff0335c418c48309e5b9213ac4d3b051c7f Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Wed, 27 Feb 2019 13:41:55 -0500 Subject: [PATCH 08/20] Fixed custom artifact bug. Commenting and cleanup. --- .../report/CreatePortableCaseModule.java | 73 +++++++++++-------- 1 file changed, 41 insertions(+), 32 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/CreatePortableCaseModule.java b/Core/src/org/sleuthkit/autopsy/report/CreatePortableCaseModule.java index f295dc680b..98805e420e 100644 --- a/Core/src/org/sleuthkit/autopsy/report/CreatePortableCaseModule.java +++ b/Core/src/org/sleuthkit/autopsy/report/CreatePortableCaseModule.java @@ -70,7 +70,7 @@ public class CreatePortableCaseModule implements GeneralReportModule { FileTypeCategory.EXECUTABLE, FileTypeCategory.IMAGE, FileTypeCategory.VIDEO); private Case currentCase = null; - private SleuthkitCase skCase = null; + private SleuthkitCase portableSkCase = null; private File caseFolder = null; private File copiedFilesFolder = null; @@ -200,10 +200,10 @@ public class CreatePortableCaseModule implements GeneralReportModule { // Create the case. - // skCase and caseFolder will be set here. + // portableSkCase and caseFolder will be set here. progressPanel.updateStatusLabel(Bundle.CreatePortableCaseModule_generateReport_creatingCase()); createCase(outputDir, progressPanel); - if (skCase == null) { + if (portableSkCase == null) { // The error has already been handled return; } @@ -218,7 +218,7 @@ public class CreatePortableCaseModule implements GeneralReportModule { progressPanel.updateStatusLabel(Bundle.CreatePortableCaseModule_generateReport_copyingTags()); try { for(TagName tagName:tagNames) { - TagName newTagName = skCase.addOrUpdateTagName(tagName.getDisplayName(), tagName.getDescription(), tagName.getColor(), tagName.getKnownStatus()); + TagName newTagName = portableSkCase.addOrUpdateTagName(tagName.getDisplayName(), tagName.getDescription(), tagName.getColor(), tagName.getKnownStatus()); oldTagNameToNewTagName.put(tagName, newTagName); } } catch (TskCoreException ex) { @@ -247,7 +247,7 @@ public class CreatePortableCaseModule implements GeneralReportModule { } for (BlackboardAttribute.ATTRIBUTE_TYPE type:BlackboardAttribute.ATTRIBUTE_TYPE.values()) { try { - oldAttrTypeIdToNewAttrType.put(type.getTypeID(), skCase.getAttributeType(type.getLabel())); + oldAttrTypeIdToNewAttrType.put(type.getTypeID(), portableSkCase.getAttributeType(type.getLabel())); } catch (TskCoreException ex) { handleError("Error looking up attribute name " + type.getLabel(), Bundle.CreatePortableCaseModule_generateReport_errorLookingUpAttrType(type.getLabel()), @@ -279,7 +279,7 @@ public class CreatePortableCaseModule implements GeneralReportModule { /** * Create the case directory and case database. - * skCase will be set if this completes without error. + * portableSkCase will be set if this completes without error. * * @param outputDir The parent for the case folder * @param progressPanel @@ -305,7 +305,7 @@ public class CreatePortableCaseModule implements GeneralReportModule { // Create the case try { - skCase = currentCase.createPortableCase(caseName, caseFolder); + portableSkCase = currentCase.createPortableCase(caseName, caseFolder); } catch (TskCoreException ex) { handleError("Error creating case " + caseName + " in folder " + caseFolder.toString(), Bundle.CreatePortableCaseModule_createCase_errorCreatingCase(), ex, progressPanel); @@ -341,8 +341,9 @@ public class CreatePortableCaseModule implements GeneralReportModule { /** * Add all files with a given tag to the portable case. * - * @param oldTagName - * @param progressPanel + * @param oldTagName The TagName object from the current case + * @param progressPanel The progress panel + * * @throws TskCoreException */ private void addFilesToPortableCase(TagName oldTagName, ReportProgressPanel progressPanel) throws TskCoreException { @@ -366,7 +367,7 @@ public class CreatePortableCaseModule implements GeneralReportModule { if (! oldTagNameToNewTagName.containsKey(tag.getName())) { throw new TskCoreException("TagName map is missing entry for ID " + tag.getName().getId() + " with display name " + tag.getName().getDisplayName()); } - skCase.addContentTag(newIdToContent.get(newFileId), oldTagNameToNewTagName.get(tag.getName()), tag.getComment(), tag.getBeginByteOffset(), tag.getEndByteOffset()); + portableSkCase.addContentTag(newIdToContent.get(newFileId), oldTagNameToNewTagName.get(tag.getName()), tag.getComment(), tag.getBeginByteOffset(), tag.getEndByteOffset()); } } } @@ -374,8 +375,9 @@ public class CreatePortableCaseModule implements GeneralReportModule { /** * Add all artifacts with a given tag to the portable case. * - * @param oldTagName - * @param progressPanel + * @param oldTagName The TagName object from the current case + * @param progressPanel The progress panel + * * @throws TskCoreException */ private void addArtifactsToPortableCase(TagName oldTagName, ReportProgressPanel progressPanel) throws TskCoreException { @@ -401,13 +403,20 @@ public class CreatePortableCaseModule implements GeneralReportModule { if (! oldTagNameToNewTagName.containsKey(tag.getName())) { throw new TskCoreException("TagName map is missing entry for ID " + tag.getName().getId() + " with display name " + tag.getName().getDisplayName()); } - skCase.addBlackboardArtifactTag(newArtifact, oldTagNameToNewTagName.get(tag.getName()), tag.getComment()); + portableSkCase.addBlackboardArtifactTag(newArtifact, oldTagNameToNewTagName.get(tag.getName()), tag.getComment()); } } - // TODO - // custom artifact types - // cache + /** + * Copy an artifact into the new case. Will also copy any associated artifacts + * + * @param newContentId The content ID (in the portable case) of the source content + * @param artifactToCopy The artifact to copy + * + * @return The new artifact in the portable case + * + * @throws TskCoreException + */ private BlackboardArtifact copyArtifact(long newContentId, BlackboardArtifact artifactToCopy) throws TskCoreException { if (oldArtifactIdToNewArtifact.containsKey(artifactToCopy.getArtifactID())) { @@ -426,7 +435,7 @@ public class CreatePortableCaseModule implements GeneralReportModule { // Create the new artifact int newArtifactTypeId = getNewArtifactTypeId(artifactToCopy); - BlackboardArtifact newArtifact = skCase.newBlackboardArtifact(newArtifactTypeId, newContentId); + BlackboardArtifact newArtifact = portableSkCase.newBlackboardArtifact(newArtifactTypeId, newContentId); List oldAttrs = artifactToCopy.getAttributes(); // Copy over each attribute, making sure the type is in the new case. @@ -484,9 +493,9 @@ public class CreatePortableCaseModule implements GeneralReportModule { return oldArtTypeIdToNewArtTypeId.get(oldArtifact.getArtifactTypeID()); } - BlackboardArtifact.Type oldCustomType = skCase.getArtifactType(oldArtifact.getArtifactTypeName()); + BlackboardArtifact.Type oldCustomType = currentCase.getSleuthkitCase().getArtifactType(oldArtifact.getArtifactTypeName()); try { - BlackboardArtifact.Type newCustomType = skCase.addBlackboardArtifactType(oldCustomType.getTypeName(), oldCustomType.getDisplayName()); + BlackboardArtifact.Type newCustomType = portableSkCase.addBlackboardArtifactType(oldCustomType.getTypeName(), oldCustomType.getDisplayName()); oldArtTypeIdToNewArtTypeId.put(oldArtifact.getArtifactTypeID(), newCustomType.getTypeID()); return newCustomType.getTypeID(); } catch (TskDataException ex) { @@ -509,7 +518,7 @@ public class CreatePortableCaseModule implements GeneralReportModule { } try { - BlackboardAttribute.Type newCustomType = skCase.addArtifactAttributeType(oldAttrType.getTypeName(), + BlackboardAttribute.Type newCustomType = portableSkCase.addArtifactAttributeType(oldAttrType.getTypeName(), oldAttrType.getValueType(), oldAttrType.getDisplayName()); oldAttrTypeIdToNewAttrType.put(oldAttribute.getAttributeType().getTypeID(), newCustomType); return newCustomType; @@ -521,8 +530,8 @@ public class CreatePortableCaseModule implements GeneralReportModule { /** * Top level method to copy a content object to the portable case. * - * @param content - * @param progressPanel + * @param content The content object to copy + * @param progressPanel The progress panel * * @return The object ID of the copied content in the portable case * @@ -536,7 +545,7 @@ public class CreatePortableCaseModule implements GeneralReportModule { progressPanel.updateStatusLabel(Bundle.CreatePortableCaseModule_copyContentToPortableCase_copyingFile(content.getUniquePath())); long newFileId; - CaseDbTransaction trans = skCase.beginTransaction(); + CaseDbTransaction trans = portableSkCase.beginTransaction(); try { newFileId = copyContent(content, trans); trans.commit(); @@ -575,18 +584,18 @@ public class CreatePortableCaseModule implements GeneralReportModule { Content newContent; if (content instanceof Image) { Image image = (Image)content; - newContent = skCase.addImage(image.getType(), image.getSsize(), image.getSize(), image.getName(), + newContent = portableSkCase.addImage(image.getType(), image.getSsize(), image.getSize(), image.getName(), new ArrayList<>(), image.getTimeZone(), image.getMd5(), image.getSha1(), image.getSha256(), image.getDeviceId(), trans); } else if (content instanceof VolumeSystem) { VolumeSystem vs = (VolumeSystem)content; - newContent = skCase.addVolumeSystem(parentId, vs.getType(), vs.getOffset(), vs.getBlockSize(), trans); + newContent = portableSkCase.addVolumeSystem(parentId, vs.getType(), vs.getOffset(), vs.getBlockSize(), trans); } else if (content instanceof Volume) { Volume vs = (Volume)content; - newContent = skCase.addVolume(parentId, vs.getAddr(), vs.getStart(), vs.getLength(), + newContent = portableSkCase.addVolume(parentId, vs.getAddr(), vs.getStart(), vs.getLength(), vs.getDescription(), vs.getFlags(), trans); } else if (content instanceof FileSystem) { FileSystem fs = (FileSystem)content; - newContent = skCase.addFileSystem(parentId, fs.getImageOffset(), fs.getFsType(), fs.getBlock_size(), + newContent = portableSkCase.addFileSystem(parentId, fs.getImageOffset(), fs.getFsType(), fs.getBlock_size(), fs.getBlock_count(), fs.getRoot_inum(), fs.getFirst_inum(), fs.getLastInum(), fs.getName(), trans); } else if (content instanceof AbstractFile) { @@ -594,10 +603,10 @@ public class CreatePortableCaseModule implements GeneralReportModule { if (abstractFile instanceof LocalFilesDataSource) { LocalFilesDataSource localFilesDS = (LocalFilesDataSource)abstractFile; - newContent = skCase.addLocalFilesDataSource(localFilesDS.getDeviceId(), localFilesDS.getName(), localFilesDS.getTimeZone(), trans); + newContent = portableSkCase.addLocalFilesDataSource(localFilesDS.getDeviceId(), localFilesDS.getName(), localFilesDS.getTimeZone(), trans); } else { if (abstractFile.isDir()) { - newContent = skCase.addLocalDirectory(parentId, abstractFile.getName(), trans); + newContent = portableSkCase.addLocalDirectory(parentId, abstractFile.getName(), trans); } else { try { // Copy the file @@ -617,7 +626,7 @@ public class CreatePortableCaseModule implements GeneralReportModule { // Construct the relative path to the copied file String relativePath = FILE_FOLDER_NAME + File.separator + exportSubFolder + File.separator + fileName; - newContent = skCase.addLocalFile(abstractFile.getName(), relativePath, abstractFile.getSize(), + newContent = portableSkCase.addLocalFile(abstractFile.getName(), relativePath, abstractFile.getSize(), abstractFile.getCtime(), abstractFile.getCrtime(), abstractFile.getAtime(), abstractFile.getMtime(), abstractFile.getMd5Hash(), abstractFile.getKnown(), abstractFile.getMIMEType(), true, TskData.EncodingType.NONE, @@ -666,9 +675,9 @@ public class CreatePortableCaseModule implements GeneralReportModule { newIdToContent.clear(); oldTagNameToNewTagName.clear(); currentCase = null; - if (skCase != null) { + if (portableSkCase != null) { // We want to close the database connections here but it is currently not possible. JIRA-4736 - skCase = null; + portableSkCase = null; } caseFolder = null; copiedFilesFolder = null; From be304fc01e313675cceb72c5c876c106204e661a Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Wed, 27 Feb 2019 14:05:30 -0500 Subject: [PATCH 09/20] Removed invalid line. --- Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.java | 1 - 1 file changed, 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.java index 2aa1e41ffd..657c2aad38 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.java @@ -109,7 +109,6 @@ final class HtmlViewer extends javax.swing.JPanel implements FileTypeViewer { @Override public void setFile(AbstractFile file) { WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - abstractFile = file; htmlPanel.setHtmlText(getHtmlText(file)); WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); } From 076c76c13156d3e0785279c6066a34d0a04e0998 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Thu, 28 Feb 2019 00:09:28 -0500 Subject: [PATCH 10/20] Case and data source counts added. --- .../DataContentViewerOtherCases.form | 48 ++++------- .../DataContentViewerOtherCases.java | 80 ++++++++++++------- 2 files changed, 66 insertions(+), 62 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form index 1f1e497aa7..9fdbfcfb67 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form @@ -73,7 +73,7 @@ - + @@ -96,10 +96,10 @@ - + - + @@ -117,31 +117,28 @@ - - - - - + - + - + + + - - + + + - - - + @@ -198,26 +195,13 @@ - + - - + + - - - - - - - - - - - - - - + diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index 6082dce81b..fe5df99a0f 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -1,7 +1,7 @@ /* * Central Repository * - * Copyright 2015-2018 Basis Technology Corp. + * Copyright 2015-2019 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,10 +33,12 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; import javax.swing.JFileChooser; @@ -306,6 +308,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi tableModel.clearTable(); correlationAttributes.clear(); earliestCaseDate.setText(Bundle.DataContentViewerOtherCases_earliestCaseNotAvailable()); + foundInLabel.setText(""); } @Override @@ -337,6 +340,34 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi public int isPreferred(Node node) { return 1; } + + /** + * Set the number of unique cases and data sources. + */ + @Messages({ + "DataContentViewerOtherCases.foundIn.text=Found in %d cases and %d data sources." + }) + private void setOccurrenceCounts() { + DataContentViewerOtherCasesTableModel model = (DataContentViewerOtherCasesTableModel) otherCasesTable.getModel(); + + // Note: Relying on the case name isn't a fool-proof way of determining + // a case to be unique. We should improve this in the future. + int caseColumnIndex = DataContentViewerOtherCasesTableModel.TableColumns.CASE_NAME.ordinal(); + Set cases = new HashSet<>(); + for (int i=0; i < model.getRowCount(); i++) { + String caseName = (String) model.getValueAt(i, caseColumnIndex); + cases.add(caseName); + } + + int deviceColumnIndex = DataContentViewerOtherCasesTableModel.TableColumns.DEVICE.ordinal(); + Set devices = new HashSet<>(); + for (int i=0; i < model.getRowCount(); i++) { + String deviceId = (String) model.getValueAt(i, deviceColumnIndex); + devices.add(deviceId); + } + + foundInLabel.setText(String.format(Bundle.DataContentViewerOtherCases_foundIn_text(), cases.size(), devices.size())); + } /** * Get the associated BlackboardArtifact from a node, if it exists. @@ -720,7 +751,9 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi } else { setColumnWidths(); } + setEarliestCaseDate(); + setOccurrenceCounts(); } /** @@ -772,7 +805,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi otherCasesTable = new javax.swing.JTable(); earliestCaseLabel = new javax.swing.JLabel(); earliestCaseDate = new javax.swing.JLabel(); - tableStatusPanel = new javax.swing.JPanel(); + foundInLabel = new javax.swing.JLabel(); rightClickPopupMenu.addPopupMenuListener(new javax.swing.event.PopupMenuListener() { public void popupMenuCanceled(javax.swing.event.PopupMenuEvent evt) { @@ -818,44 +851,31 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi org.openide.awt.Mnemonics.setLocalizedText(earliestCaseDate, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.earliestCaseDate.text")); // NOI18N - tableStatusPanel.setPreferredSize(new java.awt.Dimension(1500, 16)); - - javax.swing.GroupLayout tableStatusPanelLayout = new javax.swing.GroupLayout(tableStatusPanel); - tableStatusPanel.setLayout(tableStatusPanelLayout); - tableStatusPanelLayout.setHorizontalGroup( - tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 0, Short.MAX_VALUE) - ); - tableStatusPanelLayout.setVerticalGroup( - tableStatusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 16, Short.MAX_VALUE) - ); + org.openide.awt.Mnemonics.setLocalizedText(foundInLabel, org.openide.util.NbBundle.getMessage(DataContentViewerOtherCases.class, "DataContentViewerOtherCases.foundInLabel.text")); // NOI18N javax.swing.GroupLayout tableContainerPanelLayout = new javax.swing.GroupLayout(tableContainerPanel); tableContainerPanel.setLayout(tableContainerPanelLayout); tableContainerPanelLayout.setHorizontalGroup( tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, tableContainerPanelLayout.createSequentialGroup() - .addComponent(tableStatusPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 1282, Short.MAX_VALUE) - .addGap(218, 218, 218)) - .addComponent(tableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(tableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 1508, Short.MAX_VALUE) .addGroup(tableContainerPanelLayout.createSequentialGroup() .addComponent(earliestCaseLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(earliestCaseDate) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGap(66, 66, 66) + .addComponent(foundInLabel) + .addGap(0, 1157, Short.MAX_VALUE)) ); tableContainerPanelLayout.setVerticalGroup( tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, tableContainerPanelLayout.createSequentialGroup() - .addComponent(tableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 27, Short.MAX_VALUE) - .addGap(2, 2, 2) + .addComponent(tableScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 71, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(tableContainerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(earliestCaseLabel) - .addComponent(earliestCaseDate)) - .addGap(0, 0, 0) - .addComponent(tableStatusPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, 0)) + .addComponent(earliestCaseDate) + .addComponent(foundInLabel)) + .addGap(6, 6, 6)) ); javax.swing.GroupLayout otherCasesPanelLayout = new javax.swing.GroupLayout(otherCasesPanel); @@ -868,10 +888,10 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi ); otherCasesPanelLayout.setVerticalGroup( otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 483, Short.MAX_VALUE) + .addGap(0, 61, Short.MAX_VALUE) .addGroup(otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(otherCasesPanelLayout.createSequentialGroup() - .addComponent(tableContainerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 59, Short.MAX_VALUE) + .addComponent(tableContainerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 61, Short.MAX_VALUE) .addGap(0, 0, 0))) ); @@ -883,7 +903,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(otherCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 59, Short.MAX_VALUE) + .addComponent(otherCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 61, Short.MAX_VALUE) ); }// //GEN-END:initComponents @@ -907,6 +927,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi private javax.swing.JLabel earliestCaseDate; private javax.swing.JLabel earliestCaseLabel; private javax.swing.JMenuItem exportToCSVMenuItem; + private javax.swing.JLabel foundInLabel; private javax.swing.JPanel otherCasesPanel; private javax.swing.JTable otherCasesTable; private javax.swing.JPopupMenu rightClickPopupMenu; @@ -915,7 +936,6 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi private javax.swing.JMenuItem showCommonalityMenuItem; private javax.swing.JPanel tableContainerPanel; private javax.swing.JScrollPane tableScrollPane; - private javax.swing.JPanel tableStatusPanel; // End of variables declaration//GEN-END:variables /** From 6a6e41e8b7bf86ce324b0c6e32d19b0a68803921 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Thu, 28 Feb 2019 00:15:17 -0500 Subject: [PATCH 11/20] Sort columns by case name, then data source. --- .../DataContentViewerOtherCases.java | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index 6082dce81b..f6419c9bbb 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -46,9 +46,13 @@ import static javax.swing.JOptionPane.DEFAULT_OPTION; import static javax.swing.JOptionPane.PLAIN_MESSAGE; import static javax.swing.JOptionPane.ERROR_MESSAGE; import javax.swing.JPanel; +import javax.swing.RowSorter; +import javax.swing.SortOrder; import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.table.TableCellRenderer; import javax.swing.table.TableColumn; +import javax.swing.table.TableModel; +import javax.swing.table.TableRowSorter; import org.joda.time.DateTimeZone; import org.joda.time.LocalDateTime; import org.openide.nodes.Node; @@ -138,7 +142,20 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi // Set background of every nth row as light grey. TableCellRenderer renderer = new DataContentViewerOtherCasesTableCellRenderer(); otherCasesTable.setDefaultRenderer(Object.class, renderer); - + + // Configure column sorting. + TableRowSorter sorter = new TableRowSorter<>(otherCasesTable.getModel()); + otherCasesTable.setRowSorter(sorter); + List sortKeys = new ArrayList<>(); + + int caseNameColumnIndex = DataContentViewerOtherCasesTableModel.TableColumns.CASE_NAME.ordinal(); + sortKeys.add(new RowSorter.SortKey(caseNameColumnIndex, SortOrder.ASCENDING)); + + int dataSourceColumnIndex = DataContentViewerOtherCasesTableModel.TableColumns.DATA_SOURCE.ordinal(); + sortKeys.add(new RowSorter.SortKey(dataSourceColumnIndex, SortOrder.ASCENDING)); + + sorter.setSortKeys(sortKeys); + sorter.sort(); } @Messages({"DataContentViewerOtherCases.correlatedArtifacts.isEmpty=There are no files or artifacts to correlate.", From 9594c031df90536ec7851a89f6122e106b91b5b8 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 28 Feb 2019 17:56:23 -0500 Subject: [PATCH 12/20] 4782 add incrementing integer to beggining of extracted picture names for doc --- .../MSOfficeEmbeddedContentExtractor.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java index 16c2b0e3e8..26f4c3d961 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java @@ -302,8 +302,9 @@ class MSOfficeEmbeddedContentExtractor { } List listOfExtractedImages = new ArrayList<>(); byte[] data = null; + int pictureNumber = 0; for (Picture picture : listOfAllPictures) { - String fileName = picture.suggestFullFileName(); + String fileName = String.valueOf(pictureNumber) + picture.suggestFullFileName(); try { data = picture.getContent(); } catch (Exception ex) { @@ -312,6 +313,7 @@ class MSOfficeEmbeddedContentExtractor { writeExtractedImage(Paths.get(outputFolderPath, fileName).toString(), data); // TODO Extract more info from the Picture viz ctime, crtime, atime, mtime listOfExtractedImages.add(new ExtractedFile(fileName, getFileRelativePath(fileName), picture.getSize())); + pictureNumber++; } return listOfExtractedImages; From a22a84566dd033565e74c881f14b73ab3579823e Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 28 Feb 2019 18:05:09 -0500 Subject: [PATCH 13/20] 4782 add non hex character to name to account for variable lenght names --- .../MSOfficeEmbeddedContentExtractor.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java index 26f4c3d961..02a03fcb81 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java @@ -302,9 +302,9 @@ class MSOfficeEmbeddedContentExtractor { } List listOfExtractedImages = new ArrayList<>(); byte[] data = null; - int pictureNumber = 0; + int pictureNumber = 0; //added to ensure uniqueness in cases where suggestFullFileName returns duplicates for (Picture picture : listOfAllPictures) { - String fileName = String.valueOf(pictureNumber) + picture.suggestFullFileName(); + String fileName = String.valueOf(pictureNumber) +"-"+ picture.suggestFullFileName(); try { data = picture.getContent(); } catch (Exception ex) { From 94225be5a76988437ee29b610359cfbcdd6ee97d Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 28 Feb 2019 18:10:22 -0500 Subject: [PATCH 14/20] 4782 make file name determination for .doc files simaler to other files --- .../embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java index 02a03fcb81..fc84ecfa59 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java @@ -304,7 +304,7 @@ class MSOfficeEmbeddedContentExtractor { byte[] data = null; int pictureNumber = 0; //added to ensure uniqueness in cases where suggestFullFileName returns duplicates for (Picture picture : listOfAllPictures) { - String fileName = String.valueOf(pictureNumber) +"-"+ picture.suggestFullFileName(); + String fileName = UNKNOWN_IMAGE_NAME_PREFIX +pictureNumber + picture.suggestFileExtension(); try { data = picture.getContent(); } catch (Exception ex) { From 2a19dc71aa82c0fc74d47521a2dbd3c012e09069 Mon Sep 17 00:00:00 2001 From: William Schaefer Date: Thu, 28 Feb 2019 18:16:04 -0500 Subject: [PATCH 15/20] 4782 add missing dot before extension to new file names for embedded images --- .../embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java index fc84ecfa59..d9c142563b 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java +++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java @@ -304,7 +304,7 @@ class MSOfficeEmbeddedContentExtractor { byte[] data = null; int pictureNumber = 0; //added to ensure uniqueness in cases where suggestFullFileName returns duplicates for (Picture picture : listOfAllPictures) { - String fileName = UNKNOWN_IMAGE_NAME_PREFIX +pictureNumber + picture.suggestFileExtension(); + String fileName = UNKNOWN_IMAGE_NAME_PREFIX +pictureNumber +"."+ picture.suggestFileExtension(); try { data = picture.getContent(); } catch (Exception ex) { From 9f31d3d4e02021ea8937941267a9d36a44071982 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Thu, 28 Feb 2019 23:56:58 -0500 Subject: [PATCH 16/20] Reset viewport. --- .../autopsy/contentviewers/MediaViewImagePanel.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java index e501b136d5..b98c350d68 100644 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/MediaViewImagePanel.java @@ -126,7 +126,6 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan scene.getStylesheets().add(MediaViewImagePanel.class.getResource("MediaViewImagePanel.css").toExternalForm()); //NOI18N fxPanel.setScene(scene); - //bind size of image to that of scene, while keeping proportions fxImageView.setSmooth(true); fxImageView.setCache(true); @@ -142,11 +141,13 @@ class MediaViewImagePanel extends JPanel implements MediaFileViewer.MediaViewPan } /** - * clear the displayed image + * Clear the displayed image */ public void reset() { Platform.runLater(() -> { + fxImageView.setViewport(new Rectangle2D(0, 0, 0, 0)); fxImageView.setImage(null); + scrollPane.setContent(null); scrollPane.setContent(fxImageView); }); From 3e153f0c33a78d978fc8b5a6b5aea3a22670055f Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 1 Mar 2019 01:13:53 -0500 Subject: [PATCH 17/20] Additional mime-type support; reposition button. --- .../sleuthkit/autopsy/contentviewers/HtmlPanel.form | 6 +++--- .../sleuthkit/autopsy/contentviewers/HtmlPanel.java | 11 +++++++---- .../sleuthkit/autopsy/contentviewers/HtmlViewer.java | 5 ++++- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlPanel.form b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlPanel.form index ec9f0fc569..54e6d45006 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlPanel.form +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlPanel.form @@ -16,11 +16,11 @@ - - + + + - diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlPanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlPanel.java index 96badc44c3..76dd7b1f3a 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlPanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlPanel.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.contentviewers; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.coreutils.Logger; /** * A file content viewer for HTML files. @@ -29,6 +30,7 @@ import org.openide.util.NbBundle.Messages; final class HtmlPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; + private static final Logger logger = Logger.getLogger(HtmlPanel.class.getName()); private String htmlText; @@ -103,6 +105,7 @@ final class HtmlPanel extends javax.swing.JPanel { showImagesToggleButton.setText(Bundle.HtmlPanel_showImagesToggleButton_show()); this.htmlbodyTextPane.setText(wrapInHtmlBody(cleanseHTML(htmlText))); } + htmlbodyTextPane.setCaretPosition(0); showImagesToggleButton.setEnabled(true); } @@ -137,10 +140,10 @@ final class HtmlPanel extends javax.swing.JPanel { this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGap(0, 203, Short.MAX_VALUE) - .addComponent(showImagesToggleButton)) - .addComponent(htmlScrollPane) + .addComponent(htmlScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 300, Short.MAX_VALUE) + .addGroup(layout.createSequentialGroup() + .addComponent(showImagesToggleButton) + .addGap(0, 0, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.java b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.java index 657c2aad38..ff22d952e7 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlViewer.java @@ -37,7 +37,10 @@ final class HtmlViewer extends javax.swing.JPanel implements FileTypeViewer { private static final long serialVersionUID = 1L; private static final Logger logger = Logger.getLogger(HtmlViewer.class.getName()); - private static final String[] SUPPORTED_MIMETYPES = new String[]{"text/html"}; + private static final String[] SUPPORTED_MIMETYPES = new String[]{ + "text/html", + "application/xhtml+xml" + }; /** * Creates new form HtmlViewerPanel From 7262cbbfe3eb56bb860f793b8be1ffc82d86fff2 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 1 Mar 2019 01:17:37 -0500 Subject: [PATCH 18/20] Removed unused logger. --- Core/src/org/sleuthkit/autopsy/contentviewers/HtmlPanel.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlPanel.java b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlPanel.java index 76dd7b1f3a..1699536c94 100755 --- a/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlPanel.java +++ b/Core/src/org/sleuthkit/autopsy/contentviewers/HtmlPanel.java @@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.contentviewers; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.coreutils.Logger; /** * A file content viewer for HTML files. @@ -30,7 +29,6 @@ import org.sleuthkit.autopsy.coreutils.Logger; final class HtmlPanel extends javax.swing.JPanel { private static final long serialVersionUID = 1L; - private static final Logger logger = Logger.getLogger(HtmlPanel.class.getName()); private String htmlText; From fa60adcb261375a40ad49ab44f84af62906ed238 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 1 Mar 2019 11:40:38 -0500 Subject: [PATCH 19/20] Additional count parameter; handling edge case. --- .../contentviewer/Bundle.properties | 1 + .../DataContentViewerOtherCases.form | 4 +-- .../DataContentViewerOtherCases.java | 32 +++++++++++-------- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/Bundle.properties b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/Bundle.properties index 2a9cd7b456..aa2b4b9297 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/Bundle.properties @@ -6,3 +6,4 @@ DataContentViewerOtherCases.showCommonalityMenuItem.text=Show Frequency DataContentViewerOtherCases.earliestCaseDate.text=Earliest Case Date DataContentViewerOtherCases.earliestCaseLabel.toolTipText= DataContentViewerOtherCases.earliestCaseLabel.text=Central Repository Starting Date: +DataContentViewerOtherCases.foundInLabel.text= diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form index 9fdbfcfb67..53f6f6fc4b 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.form @@ -73,7 +73,7 @@ - + @@ -99,7 +99,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index fe5df99a0f..823c1a3a05 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -345,28 +345,34 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi * Set the number of unique cases and data sources. */ @Messages({ - "DataContentViewerOtherCases.foundIn.text=Found in %d cases and %d data sources." + "DataContentViewerOtherCases.foundIn.text=Found %d instances in %d cases and %d data sources." }) private void setOccurrenceCounts() { DataContentViewerOtherCasesTableModel model = (DataContentViewerOtherCasesTableModel) otherCasesTable.getModel(); - // Note: Relying on the case name isn't a fool-proof way of determining - // a case to be unique. We should improve this in the future. int caseColumnIndex = DataContentViewerOtherCasesTableModel.TableColumns.CASE_NAME.ordinal(); + int deviceColumnIndex = DataContentViewerOtherCasesTableModel.TableColumns.DEVICE.ordinal(); + + /* + * We also need a unique set of data sources. We rely on device ID for + * this. To mitigate edge cases where a device ID could be duplicated + * in the same case (e.g. "report.xml"), we put the device ID and case + * name in a key-value pair. + * + * Note: Relying on the case name isn't a fool-proof way of determining + * a case to be unique. We should improve this in the future. + */ Set cases = new HashSet<>(); + Map devices = new HashMap(); + for (int i=0; i < model.getRowCount(); i++) { String caseName = (String) model.getValueAt(i, caseColumnIndex); - cases.add(caseName); - } - - int deviceColumnIndex = DataContentViewerOtherCasesTableModel.TableColumns.DEVICE.ordinal(); - Set devices = new HashSet<>(); - for (int i=0; i < model.getRowCount(); i++) { String deviceId = (String) model.getValueAt(i, deviceColumnIndex); - devices.add(deviceId); + cases.add(caseName); + devices.put(deviceId, caseName); } - foundInLabel.setText(String.format(Bundle.DataContentViewerOtherCases_foundIn_text(), cases.size(), devices.size())); + foundInLabel.setText(String.format(Bundle.DataContentViewerOtherCases_foundIn_text(), model.getRowCount(), cases.size(), devices.size())); } /** @@ -891,7 +897,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi .addGap(0, 61, Short.MAX_VALUE) .addGroup(otherCasesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(otherCasesPanelLayout.createSequentialGroup() - .addComponent(tableContainerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 61, Short.MAX_VALUE) + .addComponent(tableContainerPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 53, Short.MAX_VALUE) .addGap(0, 0, 0))) ); @@ -903,7 +909,7 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(otherCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 61, Short.MAX_VALUE) + .addComponent(otherCasesPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 53, Short.MAX_VALUE) ); }// //GEN-END:initComponents From 672e20bd6bbf20704a053c7fb4cf481e1bf8e6ca Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 1 Mar 2019 11:42:15 -0500 Subject: [PATCH 20/20] Typo fix. --- .../contentviewer/DataContentViewerOtherCases.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java index 823c1a3a05..db5f99dd96 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java @@ -354,10 +354,10 @@ public class DataContentViewerOtherCases extends JPanel implements DataContentVi int deviceColumnIndex = DataContentViewerOtherCasesTableModel.TableColumns.DEVICE.ordinal(); /* - * We also need a unique set of data sources. We rely on device ID for - * this. To mitigate edge cases where a device ID could be duplicated - * in the same case (e.g. "report.xml"), we put the device ID and case - * name in a key-value pair. + * We need a unique set of data sources. We rely on device ID for this. + * To mitigate edge cases where a device ID could be duplicated in the + * same case (e.g. "report.xml"), we put the device ID and case name in + * a key-value pair. * * Note: Relying on the case name isn't a fool-proof way of determining * a case to be unique. We should improve this in the future.