From 49850bfd98c4a001a07983c8056c0855b3274fa2 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Wed, 11 Oct 2017 17:33:54 -0400 Subject: [PATCH 01/32] Further factored out the functionality into a separate class --- .../IdentifyDataSourceProcessors.java | 46 +++++++++++++++++++ .../autoingest/AutoIngestManager.java | 34 ++++++-------- 2 files changed, 60 insertions(+), 20 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/datasourceprocessors/IdentifyDataSourceProcessors.java diff --git a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/IdentifyDataSourceProcessors.java b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/IdentifyDataSourceProcessors.java new file mode 100755 index 0000000000..9cdef77a7f --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/IdentifyDataSourceProcessors.java @@ -0,0 +1,46 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.datasourceprocessors; + +import java.nio.file.Path; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import org.openide.util.Lookup; +import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException; + +/** + * A utility class to find Data Source Processors + */ +public class IdentifyDataSourceProcessors { + + /** + * A utility method to find all Data Source Processors (DSP) that are able + * to process the input data source. Only the DSPs that implement + * AutoIngestDataSourceProcessor interface are used. + * + * @param dataSourcePath Full path to the data source + * @return Hash map of all DSPs that can process the data source along with + * their confidence score + * @throws + * org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException + */ + public static Map getDataSourceProcessor(Path dataSourcePath) throws AutoIngestDataSourceProcessorException { + + // lookup all AutomatedIngestDataSourceProcessors + Collection processorCandidates = Lookup.getDefault().lookupAll(AutoIngestDataSourceProcessor.class); + + Map validDataSourceProcessorsMap = new HashMap<>(); + for (AutoIngestDataSourceProcessor processor : processorCandidates) { + int confidence = processor.canProcess(dataSourcePath); + if (confidence > 0) { + validDataSourceProcessorsMap.put(processor, confidence); + } + } + + return validDataSourceProcessorsMap; + } +} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index 18d33b5c69..3dd17332d2 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -93,6 +93,7 @@ import org.sleuthkit.autopsy.experimental.configuration.SharedConfiguration; import org.sleuthkit.autopsy.experimental.configuration.SharedConfiguration.SharedConfigurationException; import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor; import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException; +import org.sleuthkit.autopsy.datasourceprocessors.IdentifyDataSourceProcessors; import org.sleuthkit.autopsy.ingest.IngestJob; import org.sleuthkit.autopsy.ingest.IngestJob.CancellationReason; import org.sleuthkit.autopsy.ingest.IngestJobSettings; @@ -2204,7 +2205,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang return; } - DataSource dataSource = identifyDataSource(caseForJob); + DataSource dataSource = identifyDataSource(); if (null == dataSource) { currentJob.setProcessingStage(AutoIngestJob.Stage.COMPLETED, Date.from(Instant.now())); return; @@ -2257,7 +2258,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang * interrupted while blocked, i.e., * if auto ingest is shutting down. */ - private DataSource identifyDataSource(Case caseForJob) throws AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException { + private DataSource identifyDataSource() throws AutoIngestAlertFileException, AutoIngestJobLoggerException, InterruptedException { Manifest manifest = currentJob.getManifest(); Path manifestPath = manifest.getFilePath(); SYS_LOGGER.log(Level.INFO, "Identifying data source for {0} ", manifestPath); @@ -2276,7 +2277,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang String deviceId = manifest.getDeviceId(); return new DataSource(deviceId, dataSourcePath); } - + /** * Passes the data source for the current job through a data source * processor that adds it to the case database. @@ -2306,21 +2307,14 @@ public final class AutoIngestManager extends Observable implements PropertyChang try { caseForJob.notifyAddingDataSource(taskId); - // lookup all AutomatedIngestDataSourceProcessors - Collection processorCandidates = Lookup.getDefault().lookupAll(AutoIngestDataSourceProcessor.class); - - Map validDataSourceProcessorsMap = new HashMap<>(); - for (AutoIngestDataSourceProcessor processor : processorCandidates) { - try { - int confidence = processor.canProcess(dataSource.getPath()); - if (confidence > 0) { - validDataSourceProcessorsMap.put(processor, confidence); - } - } catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) { - SYS_LOGGER.log(Level.SEVERE, "Exception while determining whether data source processor {0} can process {1}", new Object[]{processor.getDataSourceType(), dataSource.getPath()}); - // rethrow the exception. It will get caught & handled upstream and will result in AIM auto-pause. - throw ex; - } + Map validDataSourceProcessorsMap; + try { + // lookup all AutomatedIngestDataSourceProcessors and poll which ones are able to process the current data source + validDataSourceProcessorsMap = IdentifyDataSourceProcessors.getDataSourceProcessor(dataSource.getPath()); + } catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) { + SYS_LOGGER.log(Level.SEVERE, "Exception while determining best data source processor for {0}", dataSource.getPath()); + // rethrow the exception. It will get caught & handled upstream and will result in AIM auto-pause. + throw ex; } // did we find a data source processor that can process the data source @@ -2650,7 +2644,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang } } - + /** * A data source processor progress monitor does nothing. There is * currently no mechanism for showing or recording data source processor @@ -3032,7 +3026,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang } } - + static final class AutoIngestManagerException extends Exception { private static final long serialVersionUID = 1L; From 3ac0792922ec0647f3d2ccf47ad16b9bf8c26e7d Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 12 Oct 2017 16:19:27 -0400 Subject: [PATCH 02/32] Refactored AddDataSourceCallback and DataSource out of AIM --- .../autoingest/AddDataSourceCallback.java | 85 +++++++++++++ .../autoingest/AutoIngestManager.java | 120 +----------------- .../experimental/autoingest/DataSource.java | 55 ++++++++ .../IdentifyDataSourceProcessors.java | 7 +- 4 files changed, 146 insertions(+), 121 deletions(-) create mode 100755 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddDataSourceCallback.java create mode 100755 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSource.java rename {Core/src/org/sleuthkit/autopsy/datasourceprocessors => Experimental/src/org/sleuthkit/autopsy/experimental/autoingest}/IdentifyDataSourceProcessors.java (83%) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddDataSourceCallback.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddDataSourceCallback.java new file mode 100755 index 0000000000..f566dffb73 --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddDataSourceCallback.java @@ -0,0 +1,85 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.experimental.autoingest; + +import java.util.List; +import java.util.UUID; +import javax.annotation.concurrent.Immutable; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; +import org.sleuthkit.datamodel.Content; + + +/** + * A "callback" that collects the results of running a data source processor on + * a data source and unblocks the job processing thread when the data source + * processor finishes running in its own thread. + */ +@Immutable +class AddDataSourceCallback extends DataSourceProcessorCallback { + + private final Case caseForJob; + private final DataSource dataSourceInfo; + private final UUID taskId; + private final Object lock; + + /** + * Constructs a "callback" that collects the results of running a data + * source processor on a data source and unblocks the job processing thread + * when the data source processor finishes running in its own thread. + * + * @param caseForJob The case for the current job. + * @param dataSourceInfo The data source + * @param taskId The task id to associate with ingest job events. + */ + AddDataSourceCallback(Case caseForJob, DataSource dataSourceInfo, UUID taskId, Object lock) { + this.caseForJob = caseForJob; + this.dataSourceInfo = dataSourceInfo; + this.taskId = taskId; + this.lock = lock; + } + + /** + * Called by the data source processor when it finishes running in its own + * thread. + * + * @param result The result code for the processing of the data source. + * @param errorMessages Any error messages generated during the processing + * of the data source. + * @param dataSourceContent The content produced by processing the data + * source. + */ + @Override + public void done(DataSourceProcessorCallback.DataSourceProcessorResult result, List errorMessages, List dataSourceContent) { + if (!dataSourceContent.isEmpty()) { + caseForJob.notifyDataSourceAdded(dataSourceContent.get(0), taskId); + } else { + caseForJob.notifyFailedAddingDataSource(taskId); + } + dataSourceInfo.setDataSourceProcessorOutput(result, errorMessages, dataSourceContent); + dataSourceContent.addAll(dataSourceContent); + synchronized (lock) { + lock.notify(); + } + } + + /** + * Called by the data source processor when it finishes running in its own + * thread, if that thread is the AWT (Abstract Window Toolkit) event + * dispatch thread (EDT). + * + * @param result The result code for the processing of the data source. + * @param errorMessages Any error messages generated during the processing + * of the data source. + * @param dataSourceContent The content produced by processing the data + * source. + */ + @Override + public void doneEDT(DataSourceProcessorCallback.DataSourceProcessorResult result, List errorMessages, List dataSources) { + done(result, errorMessages, dataSources); + } + +} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index 3dd17332d2..90fbf678e2 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -93,7 +93,6 @@ import org.sleuthkit.autopsy.experimental.configuration.SharedConfiguration; import org.sleuthkit.autopsy.experimental.configuration.SharedConfiguration.SharedConfigurationException; import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor; import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException; -import org.sleuthkit.autopsy.datasourceprocessors.IdentifyDataSourceProcessors; import org.sleuthkit.autopsy.ingest.IngestJob; import org.sleuthkit.autopsy.ingest.IngestJob.CancellationReason; import org.sleuthkit.autopsy.ingest.IngestJobSettings; @@ -2277,7 +2276,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang String deviceId = manifest.getDeviceId(); return new DataSource(deviceId, dataSourcePath); } - + /** * Passes the data source for the current job through a data source * processor that adds it to the case database. @@ -2300,7 +2299,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang SYS_LOGGER.log(Level.INFO, "Adding data source for {0} ", manifestPath); currentJob.setProcessingStage(AutoIngestJob.Stage.ADDING_DATA_SOURCE, Date.from(Instant.now())); UUID taskId = UUID.randomUUID(); - DataSourceProcessorCallback callBack = new AddDataSourceCallback(caseForJob, dataSource, taskId); + DataSourceProcessorCallback callBack = new AddDataSourceCallback(caseForJob, dataSource, taskId, ingestLock); DataSourceProcessorProgressMonitor progressMonitor = new DoNothingDSPProgressMonitor(); Path caseDirectoryPath = currentJob.getCaseDirectoryPath(); AutoIngestJobLogger jobLogger = new AutoIngestJobLogger(manifestPath, manifest.getDataSourceFileName(), caseDirectoryPath); @@ -2571,79 +2570,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang jobLogger.logFileExportError(); } } - - /** - * A "callback" that collects the results of running a data source - * processor on a data source and unblocks the job processing thread - * when the data source processor finishes running in its own thread. - */ - @Immutable - class AddDataSourceCallback extends DataSourceProcessorCallback { - - private final Case caseForJob; - private final DataSource dataSourceInfo; - private final UUID taskId; - - /** - * Constructs a "callback" that collects the results of running a - * data source processor on a data source and unblocks the job - * processing thread when the data source processor finishes running - * in its own thread. - * - * @param caseForJob The case for the current job. - * @param dataSourceInfo The data source - * @param taskId The task id to associate with ingest job - * events. - */ - AddDataSourceCallback(Case caseForJob, DataSource dataSourceInfo, UUID taskId) { - this.caseForJob = caseForJob; - this.dataSourceInfo = dataSourceInfo; - this.taskId = taskId; - } - - /** - * Called by the data source processor when it finishes running in - * its own thread. - * - * @param result The result code for the processing of - * the data source. - * @param errorMessages Any error messages generated during the - * processing of the data source. - * @param dataSourceContent The content produced by processing the - * data source. - */ - @Override - public void done(DataSourceProcessorCallback.DataSourceProcessorResult result, List errorMessages, List dataSourceContent) { - if (!dataSourceContent.isEmpty()) { - caseForJob.notifyDataSourceAdded(dataSourceContent.get(0), taskId); - } else { - caseForJob.notifyFailedAddingDataSource(taskId); - } - dataSourceInfo.setDataSourceProcessorOutput(result, errorMessages, dataSourceContent); - dataSourceContent.addAll(dataSourceContent); - synchronized (ingestLock) { - ingestLock.notify(); - } - } - - /** - * Called by the data source processor when it finishes running in - * its own thread, if that thread is the AWT (Abstract Window - * Toolkit) event dispatch thread (EDT). - * - * @param result The result code for the processing of - * the data source. - * @param errorMessages Any error messages generated during the - * processing of the data source. - * @param dataSourceContent The content produced by processing the - * data source. - */ - @Override - public void doneEDT(DataSourceProcessorCallback.DataSourceProcessorResult result, List errorMessages, List dataSources) { - done(result, errorMessages, dataSources); - } - - } /** * A data source processor progress monitor does nothing. There is @@ -2984,48 +2910,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang PARTIALLY_DELETED, FULLY_DELETED } - - @ThreadSafe - private static final class DataSource { - - private final String deviceId; - private final Path path; - private DataSourceProcessorResult resultCode; - private List errorMessages; - private List content; - - DataSource(String deviceId, Path path) { - this.deviceId = deviceId; - this.path = path; - } - - String getDeviceId() { - return deviceId; - } - - Path getPath() { - return this.path; - } - - synchronized void setDataSourceProcessorOutput(DataSourceProcessorResult result, List errorMessages, List content) { - this.resultCode = result; - this.errorMessages = new ArrayList<>(errorMessages); - this.content = new ArrayList<>(content); - } - - synchronized DataSourceProcessorResult getResultDataSourceProcessorResultCode() { - return resultCode; - } - - synchronized List getDataSourceProcessorErrorMessages() { - return new ArrayList<>(errorMessages); - } - - synchronized List getContent() { - return new ArrayList<>(content); - } - - } static final class AutoIngestManagerException extends Exception { diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSource.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSource.java new file mode 100755 index 0000000000..b655bfe0ae --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSource.java @@ -0,0 +1,55 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.experimental.autoingest; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.concurrent.ThreadSafe; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback.DataSourceProcessorResult; +import org.sleuthkit.datamodel.Content; + +@ThreadSafe +class DataSource { + + private final String deviceId; + private final Path path; + private DataSourceProcessorResult resultCode; + private List errorMessages; + private List content; + + DataSource(String deviceId, Path path) { + this.deviceId = deviceId; + this.path = path; + } + + String getDeviceId() { + return deviceId; + } + + Path getPath() { + return this.path; + } + + synchronized void setDataSourceProcessorOutput(DataSourceProcessorResult result, List errorMessages, List content) { + this.resultCode = result; + this.errorMessages = new ArrayList<>(errorMessages); + this.content = new ArrayList<>(content); + } + + synchronized DataSourceProcessorResult getResultDataSourceProcessorResultCode() { + return resultCode; + } + + synchronized List getDataSourceProcessorErrorMessages() { + return new ArrayList<>(errorMessages); + } + + synchronized List getContent() { + return new ArrayList<>(content); + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/IdentifyDataSourceProcessors.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/IdentifyDataSourceProcessors.java similarity index 83% rename from Core/src/org/sleuthkit/autopsy/datasourceprocessors/IdentifyDataSourceProcessors.java rename to Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/IdentifyDataSourceProcessors.java index 9cdef77a7f..d6673ad580 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/IdentifyDataSourceProcessors.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/IdentifyDataSourceProcessors.java @@ -3,19 +3,20 @@ * To change this template file, choose Tools | Templates * and open the template in the editor. */ -package org.sleuthkit.autopsy.datasourceprocessors; +package org.sleuthkit.autopsy.experimental.autoingest; import java.nio.file.Path; import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.openide.util.Lookup; +import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor; import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException; /** * A utility class to find Data Source Processors */ -public class IdentifyDataSourceProcessors { +class IdentifyDataSourceProcessors { /** * A utility method to find all Data Source Processors (DSP) that are able @@ -28,7 +29,7 @@ public class IdentifyDataSourceProcessors { * @throws * org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException */ - public static Map getDataSourceProcessor(Path dataSourcePath) throws AutoIngestDataSourceProcessorException { + static Map getDataSourceProcessor(Path dataSourcePath) throws AutoIngestDataSourceProcessorException { // lookup all AutomatedIngestDataSourceProcessors Collection processorCandidates = Lookup.getDefault().lookupAll(AutoIngestDataSourceProcessor.class); From 10d239dd25f062faaeac857e5f0cbe7d9cb009e2 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Tue, 17 Oct 2017 14:47:32 -0400 Subject: [PATCH 03/32] 3142: Experiment with adding a JUnit TestSuite to the automated unit tests --- KeywordSearch/build.xml | 24 +++++++++- .../keywordsearch/KeywordSearchTestSuite.java | 45 +++++++++++++++++++ 2 files changed, 67 insertions(+), 2 deletions(-) create mode 100755 KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchTestSuite.java diff --git a/KeywordSearch/build.xml b/KeywordSearch/build.xml index d02cb92727..5fe021fff8 100755 --- a/KeywordSearch/build.xml +++ b/KeywordSearch/build.xml @@ -6,8 +6,21 @@ Builds, tests, and runs the project org.sleuthkit.autopsy.keywordsearch. + + + + - + + + + + + + + + + @@ -39,5 +52,12 @@ - + + + + + + + + diff --git a/KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchTestSuite.java b/KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchTestSuite.java new file mode 100755 index 0000000000..31f84701cd --- /dev/null +++ b/KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchTestSuite.java @@ -0,0 +1,45 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.keywordsearch; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; +/** + * + * @author + */ +@RunWith(Suite.class) +@Suite.SuiteClasses({CreditCardValidatorTest.class}) +public class KeywordSearchTestSuite { + public KeywordSearchTestSuite() { + } + + @BeforeClass + public static void setUpClass() throws Exception { + } + + @AfterClass + public static void tearDownClass() throws Exception { + } + + @Before + public void setUp() throws Exception { + } + + @After + public void tearDown() throws Exception { + } + + @Ignore + public static void main(String[] args) { + System.out.println("main method"); + } +} From 62a51ba326aaa8023d57afaf51cd521161709a4e Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Wed, 18 Oct 2017 14:56:45 -0400 Subject: [PATCH 04/32] 3124: Clean up the debug output line --- .../sleuthkit/autopsy/keywordsearch/KeywordSearchTestSuite.java | 1 - 1 file changed, 1 deletion(-) diff --git a/KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchTestSuite.java b/KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchTestSuite.java index 31f84701cd..848483084b 100755 --- a/KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchTestSuite.java +++ b/KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchTestSuite.java @@ -40,6 +40,5 @@ public class KeywordSearchTestSuite { @Ignore public static void main(String[] args) { - System.out.println("main method"); } } From 89f48e8c384e5504ffc515618e9d7897c4368ac5 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Wed, 18 Oct 2017 16:23:01 -0400 Subject: [PATCH 05/32] First cut at ArchiveExtractorDataSourceProcessor and ArchiveFilePanel --- .../autoingest/AddDataSourceCallback.java | 19 +- .../ArchiveExtractorDataSourceProcessor.java | 260 ++++++++++++++++ .../autoingest/ArchiveFilePanel.form | 94 ++++++ .../autoingest/ArchiveFilePanel.java | 280 ++++++++++++++++++ .../experimental/autoingest/Bundle.properties | 6 + .../experimental/autoingest/DataSource.java | 19 +- .../IdentifyDataSourceProcessors.java | 19 +- 7 files changed, 688 insertions(+), 9 deletions(-) create mode 100755 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDataSourceProcessor.java create mode 100755 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveFilePanel.form create mode 100755 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveFilePanel.java diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddDataSourceCallback.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddDataSourceCallback.java index f566dffb73..db19fc2fbc 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddDataSourceCallback.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddDataSourceCallback.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.experimental.autoingest; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDataSourceProcessor.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDataSourceProcessor.java new file mode 100755 index 0000000000..19dbd61f4a --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDataSourceProcessor.java @@ -0,0 +1,260 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.experimental.autoingest; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.List; +import java.util.UUID; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import javax.swing.JPanel; +import javax.swing.filechooser.FileFilter; +import org.apache.commons.io.FilenameUtils; +import org.openide.util.NbBundle; +import org.openide.util.lookup.ServiceProvider; +import org.openide.util.lookup.ServiceProviders; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.GeneralFilter; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; +import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor; + +/** + * A data source processor that handles archive files. Implements the + * DataSourceProcessor service provider interface to allow integration with the + * add data source wizard. It also provides a run method overload to allow it to + * be used independently of the wizard. + */ +@ServiceProviders(value={ + @ServiceProvider(service=DataSourceProcessor.class), + @ServiceProvider(service=AutoIngestDataSourceProcessor.class)} +) +public class ArchiveExtractorDataSourceProcessor implements DataSourceProcessor, AutoIngestDataSourceProcessor { + + private final static String DATA_SOURCE_TYPE = NbBundle.getMessage(ArchiveExtractorDataSourceProcessor.class, "ArchiveExtractorDataSourceProcessor.dsType.text"); + + private static GeneralFilter zipFilter; + private static List archiveFilters = new ArrayList<>(); + + private static final String AUTO_INGEST_MODULE_OUTPUT_DIR = "AutoIngest"; + + private final ArchiveFilePanel configPanel; + private String deviceId; + private String imagePath; + private boolean setDataSourceOptionsCalled; + + /** + * Constructs an archive data source processor that + * implements the DataSourceProcessor service provider interface to allow + * integration with the add data source wizard. It also provides a run + * method overload to allow it to be used independently of the wizard. + */ + public ArchiveExtractorDataSourceProcessor() { + String[] extensions = ArchiveUtil.getSupportedArchiveTypes(); + zipFilter = new GeneralFilter(Arrays.asList(extensions), ""); + archiveFilters.add(zipFilter); + configPanel = ArchiveFilePanel.createInstance(ArchiveExtractorDataSourceProcessor.class.getName(), archiveFilters); + } + + @Override + public int canProcess(Path dataSourcePath) throws AutoIngestDataSourceProcessorException { + // check whether this is an archive + if (isArchive(dataSourcePath)){ + // return "high confidence" value + return 100; + } + return 0; + } + + @Override + public void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) throws AutoIngestDataSourceProcessorException { + if (isArchive(dataSourcePath)) { + // extract the archive and pass the extracted folder as input + Path extractedDataSourcePath = Paths.get(""); + try { + Case currentCase = Case.getCurrentCase(); + extractedDataSourcePath = extractDataSource(Paths.get(currentCase.getModuleDirectory()), dataSourcePath); + } catch (Exception ex) { + throw new AutoIngestDataSourceProcessorException(NbBundle.getMessage(ArchiveExtractorDataSourceProcessor.class, "ArchiveExtractorDataSourceProcessor.process.exception.text"), ex); + } + run(deviceId, extractedDataSourcePath.toString(), progressMonitor, callBack); + } + } + + @Override + public String getDataSourceType() { + return DATA_SOURCE_TYPE; + } + + /** + * Gets the panel that allows a user to select a data source and do any + * configuration required by the data source. The panel is less than 544 + * pixels wide and less than 173 pixels high. + * + * @return A selection and configuration panel for this data source + * processor. + */ + @Override + public JPanel getPanel() { + configPanel.readSettings(); + configPanel.select(); + return configPanel; + } + + /** + * Indicates whether the settings in the selection and configuration panel + * are valid and complete. + * + * @return True if the settings are valid and complete and the processor is + * ready to have its run method called, false otherwise. + */ + @Override + public boolean isPanelValid() { + return configPanel.validatePanel(); + } + + /** + * Adds a data source to the case database using a background task in a + * separate thread and the settings provided by the selection and + * configuration panel. Returns as soon as the background task is started. + * The background task uses a callback object to signal task completion and + * return results. + * + * This method should not be called unless isPanelValid returns true. + * + * @param progressMonitor Progress monitor that will be used by the + * background task to report progress. + * @param callback Callback that will be used by the background task + * to return results. + */ + @Override + public void run(DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { + if (!setDataSourceOptionsCalled) { + configPanel.storeSettings(); + deviceId = UUID.randomUUID().toString(); + imagePath = configPanel.getContentPaths(); + } + run(deviceId, imagePath, progressMonitor, callback); + } + + /** + * Adds a data source to the case database using a background task in a + * separate thread and the given settings instead of those provided by the + * selection and configuration panel. Returns as soon as the background task + * is started and uses the callback object to signal task completion and + * return results. + * + * This method should not be called unless isPanelValid returns true. + * + * @param progressMonitor Progress monitor that will be used by the + * background task to report progress. + * @param callback Callback that will be used by the background task + * to return results. + */ + public void run(String deviceId, String imageFolderPath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { + //List imageFilePaths = getImageFilePaths(imageFolderPath); + //addImagesTask = new AddCellebritePhysicalReportTask(deviceId, imageFilePaths, timeZone, progressMonitor, callback); + //new Thread(addImagesTask).start(); + } + + @Override + public void cancel() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public void reset() { + deviceId = null; + imagePath = null; + configPanel.reset(); + setDataSourceOptionsCalled = false; + } + + private static boolean isArchive(Path dataSourcePath) throws AutoIngestDataSourceProcessorException { + String fileName = dataSourcePath.getFileName().toString(); + // check whether it's a zip archive file that can be extracted + return isAcceptedByFiler(new File(fileName), archiveFilters); + } + + private static boolean isAcceptedByFiler(File file, List filters) { + for (FileFilter filter : filters) { + if (filter.accept(file)) { + return true; + } + } + return false; + } + + /** + * Extracts the contents of a ZIP archive submitted as a data source to a + * subdirectory of the auto ingest module output directory. + * + * @throws IOException if there is a problem extracting the data source from + * the archive. + */ + private static Path extractDataSource(Path outputDirectoryPath, Path dataSourcePath) throws IOException { + String dataSourceFileNameNoExt = FilenameUtils.removeExtension(dataSourcePath.getFileName().toString()); + Path destinationFolder = Paths.get(outputDirectoryPath.toString(), + AUTO_INGEST_MODULE_OUTPUT_DIR, + dataSourceFileNameNoExt + "_" + TimeStampUtils.createTimeStamp()); + Files.createDirectories(destinationFolder); + + int BUFFER_SIZE = 524288; // Read/write 500KB at a time + File sourceZipFile = dataSourcePath.toFile(); + ZipFile zipFile; + zipFile = new ZipFile(sourceZipFile, ZipFile.OPEN_READ); + Enumeration zipFileEntries = zipFile.entries(); + try { + while (zipFileEntries.hasMoreElements()) { + ZipEntry entry = zipFileEntries.nextElement(); + String currentEntry = entry.getName(); + File destFile = new File(destinationFolder.toString(), currentEntry); + destFile = new File(destinationFolder.toString(), destFile.getName()); + File destinationParent = destFile.getParentFile(); + destinationParent.mkdirs(); + if (!entry.isDirectory()) { + BufferedInputStream is = new BufferedInputStream(zipFile.getInputStream(entry)); + int currentByte; + byte data[] = new byte[BUFFER_SIZE]; + try (FileOutputStream fos = new FileOutputStream(destFile); BufferedOutputStream dest = new BufferedOutputStream(fos, BUFFER_SIZE)) { + currentByte = is.read(data, 0, BUFFER_SIZE); + while (currentByte != -1) { + dest.write(data, 0, currentByte); + currentByte = is.read(data, 0, BUFFER_SIZE); + } + } + } + } + } finally { + zipFile.close(); + } + return destinationFolder; + } +} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveFilePanel.form b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveFilePanel.form new file mode 100755 index 0000000000..af9347df0c --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveFilePanel.form @@ -0,0 +1,94 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveFilePanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveFilePanel.java new file mode 100755 index 0000000000..e368a18c4f --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveFilePanel.java @@ -0,0 +1,280 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.experimental.autoingest; + +import java.io.File; +import java.util.List; +import java.util.logging.Level; +import javax.swing.JFileChooser; +import javax.swing.JPanel; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.filechooser.FileFilter; +import org.apache.commons.lang3.StringUtils; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.Case; +import static org.sleuthkit.autopsy.experimental.autoingest.Bundle.*; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; +import org.sleuthkit.autopsy.coreutils.DriveUtils; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.sleuthkit.autopsy.coreutils.ModuleSettings; +import org.sleuthkit.autopsy.coreutils.PathValidator; + +/** + * Panel for adding an archive file which is supported by 7zip library (e.g. + * "zip", "rar", "arj", "7z", "7zip", "gzip, etc). Allows the user to select a + * file. + */ +public class ArchiveFilePanel extends JPanel implements DocumentListener { + + private static final Logger logger = Logger.getLogger(ArchiveFilePanel.class.getName()); + private static final String PROP_LASTIMAGE_PATH = "LBL_LastImage_PATH"; //NON-NLS + + private final JFileChooser fileChooser = new JFileChooser(); + + /** + * Externally supplied name is used to store settings + */ + private final String contextName; + + /** + * Creates new form ArchiveFilePanel + * + * @param context A string context name used to read/store last + * used settings. + * @param fileChooserFilters A list of filters to be used with the + * FileChooser. + */ + private ArchiveFilePanel(String context, List fileChooserFilters) { + this.contextName = context; + initComponents(); + + errorLabel.setVisible(false); + + fileChooser.setDragEnabled(false); + fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); + fileChooser.setMultiSelectionEnabled(false); + fileChooserFilters.forEach(fileChooser::addChoosableFileFilter); + if (fileChooserFilters.isEmpty() == false) { + fileChooser.setFileFilter(fileChooserFilters.get(0)); + } + } + + /** + * Creates and returns an instance of a ArchiveFilePanel. + * + * @param context A string context name used to read/store last + * used settings. + * @param fileChooserFilters A list of filters to be used with the + * FileChooser. + * + * @return instance of the ArchiveFilePanel + */ + public static synchronized ArchiveFilePanel createInstance(String context, List fileChooserFilters) { + ArchiveFilePanel instance = new ArchiveFilePanel(context, fileChooserFilters); + // post-constructor initialization of listener support without leaking references of uninitialized objects + instance.pathTextField.getDocument().addDocumentListener(instance); + return instance; + } + + /** + * 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. + */ + // //GEN-BEGIN:initComponents + private void initComponents() { + + pathLabel = new javax.swing.JLabel(); + browseButton = new javax.swing.JButton(); + pathTextField = new javax.swing.JTextField(); + errorLabel = new javax.swing.JLabel(); + + setMinimumSize(new java.awt.Dimension(0, 65)); + setPreferredSize(new java.awt.Dimension(403, 65)); + + org.openide.awt.Mnemonics.setLocalizedText(pathLabel, org.openide.util.NbBundle.getMessage(ArchiveFilePanel.class, "ArchiveFilePanel.pathLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(ArchiveFilePanel.class, "ArchiveFilePanel.browseButton.text")); // NOI18N + browseButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + browseButtonActionPerformed(evt); + } + }); + + pathTextField.setText(org.openide.util.NbBundle.getMessage(ArchiveFilePanel.class, "ArchiveFilePanel.pathTextField.text")); // NOI18N + + errorLabel.setForeground(new java.awt.Color(255, 0, 0)); + org.openide.awt.Mnemonics.setLocalizedText(errorLabel, org.openide.util.NbBundle.getMessage(ArchiveFilePanel.class, "ArchiveFilePanel.errorLabel.text")); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(pathTextField) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(browseButton) + .addGap(2, 2, 2)) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(pathLabel) + .addComponent(errorLabel)) + .addGap(0, 277, Short.MAX_VALUE)) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(pathLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(browseButton) + .addComponent(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(3, 3, 3) + .addComponent(errorLabel) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + ); + }// //GEN-END:initComponents + + private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed + String oldText = getContentPaths(); + // set the current directory of the FileChooser if the ImagePath Field is valid + File currentDir = new File(oldText); + if (currentDir.exists()) { + fileChooser.setCurrentDirectory(currentDir); + } + + if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { + String path = fileChooser.getSelectedFile().getPath(); + setContentPath(path); + } + + updateHelper(); + }//GEN-LAST:event_browseButtonActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton browseButton; + private javax.swing.JLabel errorLabel; + private javax.swing.JLabel pathLabel; + private javax.swing.JTextField pathTextField; + // End of variables declaration//GEN-END:variables + + /** + * Get the path of the user selected archive. + * + * @return the image path + */ + public String getContentPaths() { + return pathTextField.getText(); + } + + /** + * Set the path of the archive file. + * + * @param s path of the archive file + */ + public void setContentPath(String s) { + pathTextField.setText(s); + } + + public void reset() { + //reset the UI elements to default + pathTextField.setText(null); + } + + /** + * Should we enable the next button of the wizard? + * + * @return true if a proper image has been selected, false otherwise + */ + @NbBundle.Messages("DataSourceOnCDriveError.text=Warning: Path to multi-user data source is on \"C:\" drive") + public boolean validatePanel() { + errorLabel.setVisible(false); + String path = getContentPaths(); + if (StringUtils.isBlank(path)) { + return false; + } + + // display warning if there is one (but don't disable "next" button) + if (false == PathValidator.isValid(path, Case.getCurrentCase().getCaseType())) { + errorLabel.setVisible(true); + errorLabel.setText(Bundle.DataSourceOnCDriveError_text()); + } + + return new File(path).isFile() + || DriveUtils.isPhysicalDrive(path) + || DriveUtils.isPartition(path); + } + + public void storeSettings() { + String archivePathName = getContentPaths(); + if (null != archivePathName) { + String archivePath = archivePathName.substring(0, archivePathName.lastIndexOf(File.separator) + 1); + ModuleSettings.setConfigSetting(contextName, PROP_LASTIMAGE_PATH, archivePath); + } + } + + public void readSettings() { + String lastArchivePath = ModuleSettings.getConfigSetting(contextName, PROP_LASTIMAGE_PATH); + if (StringUtils.isNotBlank(lastArchivePath)) { + setContentPath(lastArchivePath); + } + } + + @Override + public void insertUpdate(DocumentEvent e) { + updateHelper(); + } + + @Override + public void removeUpdate(DocumentEvent e) { + updateHelper(); + } + + @Override + public void changedUpdate(DocumentEvent e) { + updateHelper(); + } + + /** + * Update functions are called by the pathTextField which has this set as + * it's DocumentEventListener. Each update function fires a property change + * to be caught by the parent panel. + * + */ + @NbBundle.Messages({"ArchiveFilePanel.moduleErr=Module Error", + "ArchiveFilePanel.moduleErr.msg=A module caused an error listening to ArchiveFilePanel updates." + + " See log to determine which module. Some data could be incomplete.\n"}) + private void updateHelper() { + try { + firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true); + } catch (Exception e) { + logger.log(Level.SEVERE, "ArchiveFilePanel listener threw exception", e); //NON-NLS + MessageNotifyUtil.Notify.error(ArchiveFilePanel_moduleErr(), ArchiveFilePanel_moduleErr_msg()); + } + } + + /** + * Set the focus to the pathTextField. + */ + public void select() { + pathTextField.requestFocusInWindow(); + } +} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties index 422c7a56c4..ec32087dbf 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties @@ -247,3 +247,9 @@ AutoIngestDashboard.prioritizeJobButton.toolTipText=Move the selected job to the AutoIngestDashboard.prioritizeJobButton.text=Prioritize &Job AutoIngestDashboard.prioritizeCaseButton.toolTipText=Move all images associated with a case to top of Pending queue. AutoIngestDashboard.prioritizeCaseButton.text=Prioritize &Case +ArchiveExtractorDataSourceProcessor.dsType.text=Archive file +ArchiveExtractorDataSourceProcessor.process.exception.text=Exception while trying to extract archive +ArchiveFilePanel.pathLabel.text=Browse for an archive file: +ArchiveFilePanel.browseButton.text=Browse +ArchiveFilePanel.pathTextField.text= +ArchiveFilePanel.errorLabel.text=Error Label \ No newline at end of file diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSource.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSource.java index b655bfe0ae..db9d3d5ad9 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSource.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSource.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.experimental.autoingest; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/IdentifyDataSourceProcessors.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/IdentifyDataSourceProcessors.java index d6673ad580..b566d99aac 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/IdentifyDataSourceProcessors.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/IdentifyDataSourceProcessors.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.experimental.autoingest; From ab4f586f3213c5823f1841e7bad6f7bb3889a490 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Wed, 18 Oct 2017 16:40:35 -0400 Subject: [PATCH 06/32] Created dummy AddArchiveTask --- .../autoingest/AddArchiveTask.java | 84 +++++++++++++++++++ .../ArchiveExtractorDataSourceProcessor.java | 38 ++++++--- .../autoingest/AutoIngestManager.java | 5 -- 3 files changed, 109 insertions(+), 18 deletions(-) create mode 100755 Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java new file mode 100755 index 0000000000..e0878d05ee --- /dev/null +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -0,0 +1,84 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.experimental.autoingest; + +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; +import org.sleuthkit.autopsy.coreutils.Logger; + +/* + * A runnable that adds an archive data source to the case database. + */ +public class AddArchiveTask implements Runnable { + + private final Logger logger = Logger.getLogger(AddArchiveTask.class.getName()); + private final String deviceId; + private final String imagePath; + private final DataSourceProcessorProgressMonitor progressMonitor; + private final DataSourceProcessorCallback callback; + private boolean criticalErrorOccurred; + + /* + * The cancellation requested flag and SleuthKit add image process are + * guarded by a monitor (called a lock here to avoid confusion with the + * progress monitor) to synchronize cancelling the process (setting the flag + * and calling its stop method) and calling either its commit or revert + * method. The built-in monitor of the add image process can't be used for + * this because it is already used to synchronize its run (init part), + * commit, revert, and currentDirectory methods. + * + * TODO (AUT-2021): Merge SleuthkitJNI.AddImageProcess and AddImageTask + */ + private final Object tskAddImageProcessLock; + + /** + * Constructs a runnable task that adds an image to the case database. + * + * @param deviceId An ASCII-printable identifier for the device associated + * with the data source that is intended to be unique across multiple cases + * (e.g., a UUID). + * @param imagePath Path to the image file. + * @param progressMonitor Progress monitor to report progress during + * processing. + * @param callback Callback to call when processing is done. + */ + AddArchiveTask(String deviceId, String imagePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { + this.deviceId = deviceId; + this.imagePath = imagePath; + this.callback = callback; + this.progressMonitor = progressMonitor; + tskAddImageProcessLock = new Object(); + } + + /** + * Adds the archive to the case database. + */ + @Override + public void run() { + + } + + + /* + * Attempts to cancel adding the image to the case database. + */ + public void cancelTask() { + + } +} diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDataSourceProcessor.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDataSourceProcessor.java index 19dbd61f4a..4512e1d349 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDataSourceProcessor.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDataSourceProcessor.java @@ -61,7 +61,7 @@ public class ArchiveExtractorDataSourceProcessor implements DataSourceProcessor, private final static String DATA_SOURCE_TYPE = NbBundle.getMessage(ArchiveExtractorDataSourceProcessor.class, "ArchiveExtractorDataSourceProcessor.dsType.text"); private static GeneralFilter zipFilter; - private static List archiveFilters = new ArrayList<>(); + private static final List archiveFilters = new ArrayList<>(); private static final String AUTO_INGEST_MODULE_OUTPUT_DIR = "AutoIngest"; @@ -70,6 +70,8 @@ public class ArchiveExtractorDataSourceProcessor implements DataSourceProcessor, private String imagePath; private boolean setDataSourceOptionsCalled; + private AddArchiveTask addArchiveTask; + /** * Constructs an archive data source processor that * implements the DataSourceProcessor service provider interface to allow @@ -171,22 +173,32 @@ public class ArchiveExtractorDataSourceProcessor implements DataSourceProcessor, * is started and uses the callback object to signal task completion and * return results. * - * This method should not be called unless isPanelValid returns true. - * - * @param progressMonitor Progress monitor that will be used by the - * background task to report progress. - * @param callback Callback that will be used by the background task - * to return results. + * @param deviceId An ASCII-printable identifier for the device + * associated with the data source that is + * intended to be unique across multiple cases + * (e.g., a UUID). + * @param imagePath Path to the image file. + * @param progressMonitor Progress monitor for reporting progress + * during processing. + * @param callback Callback to call when processing is done. */ - public void run(String deviceId, String imageFolderPath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { - //List imageFilePaths = getImageFilePaths(imageFolderPath); - //addImagesTask = new AddCellebritePhysicalReportTask(deviceId, imageFilePaths, timeZone, progressMonitor, callback); - //new Thread(addImagesTask).start(); - } + public void run(String deviceId, String imagePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { + addArchiveTask = new AddArchiveTask(deviceId, imagePath, progressMonitor, callback); + new Thread(addArchiveTask).start(); + } + /** + * Requests cancellation of the background task that adds a data source to + * the case database, after the task is started using the run method. This + * is a "best effort" cancellation, with no guarantees that the case + * database will be unchanged. If cancellation succeeded, the list of new + * data sources returned by the background task will be empty. + */ @Override public void cancel() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + if (null != addArchiveTask) { + addArchiveTask.cancelTask(); + } } @Override diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index f15cf9f5dc..7ffb67ae05 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -37,7 +37,6 @@ import java.time.Duration; import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.EnumSet; @@ -59,9 +58,6 @@ import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.stream.Collectors; import javax.annotation.concurrent.GuardedBy; -import javax.annotation.concurrent.Immutable; -import javax.annotation.concurrent.ThreadSafe; -import org.openide.util.Exceptions; import org.openide.util.Lookup; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case.CaseType; @@ -101,7 +97,6 @@ import org.sleuthkit.autopsy.ingest.IngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestJobStartResult; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestModuleError; -import org.sleuthkit.datamodel.Content; /** * An auto ingest manager is responsible for processing auto ingest jobs defined From 881fdb4c9723c3c7a6d98310f7c8a3424451e1e5 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Thu, 19 Oct 2017 14:44:17 +0200 Subject: [PATCH 07/32] set initial group sorting to Priority minor cleanup for clarity and conciseness --- .../imagegallery/ImageGalleryController.java | 4 +- .../datamodel/grouping/DrawableGroup.java | 5 +-- .../datamodel/grouping/GroupManager.java | 38 ++++++++----------- .../datamodel/grouping/GroupSortBy.java | 18 +++++++-- 4 files changed, 32 insertions(+), 33 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java index ba2de01a6c..74c28d55b8 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/ImageGalleryController.java @@ -236,9 +236,7 @@ public final class ImageGalleryController { undoManager.clear(); }); - regroupDisabled.addListener((Observable observable) -> { - checkForGroups(); - }); + regroupDisabled.addListener(observable -> checkForGroups()); IngestManager ingestManager = IngestManager.getInstance(); PropertyChangeListener ingestEventHandler = diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java index 1e914522ac..3ef949c9c9 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/DrawableGroup.java @@ -128,9 +128,7 @@ public class DrawableGroup implements Comparable { LOGGER.log(Level.WARNING, "could not access case during getFilesWithHashSetHitsCount()"); //NON-NLS } } - return hashSetHitsCount.get(); - } public ReadOnlyLongProperty hashSetHitsCountProperty() { @@ -226,7 +224,6 @@ public class DrawableGroup implements Comparable { // By default, sort by group key name @Override public int compareTo(DrawableGroup other) { - return this.groupKey.getValueDisplayName().compareTo(other.groupKey.getValueDisplayName()); + return getGroupByValueDislpayName().compareTo(other.getGroupByValueDislpayName()); } - } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index ae9e17bb4a..dc31145c2f 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -122,7 +122,7 @@ public class GroupManager { /* * --- current grouping/sorting attributes --- */ - private volatile GroupSortBy sortBy = GroupSortBy.NONE; + private volatile GroupSortBy sortBy = GroupSortBy.PRIORITY; private volatile DrawableAttribute groupBy = DrawableAttribute.PATH; private volatile SortOrder sortOrder = SortOrder.ASCENDING; @@ -156,7 +156,6 @@ public class GroupManager { */ public GroupManager(ImageGalleryController controller) { this.controller = controller; - } /** @@ -188,7 +187,7 @@ public class GroupManager { * the groups the given file is a part of * * @return a a set of {@link GroupKey}s representing the group(s) the given - * file is a part of + * file is a part of */ synchronized public Set> getGroupKeysForFileID(Long fileID) { try { @@ -208,7 +207,7 @@ public class GroupManager { * @param groupKey * * @return return the DrawableGroup (if it exists) for the given GroupKey, - * or null if no group exists for that key. + * or null if no group exists for that key. */ @Nullable public DrawableGroup getGroupForKey(@Nonnull GroupKey groupKey) { @@ -284,7 +283,7 @@ public class GroupManager { * no-op * * @param groupKey the value of groupKey - * @param fileID the value of file + * @param fileID the value of file */ public synchronized DrawableGroup removeFromGroup(GroupKey groupKey, final Long fileID) { //get grouping this file would be in @@ -512,7 +511,7 @@ public class GroupManager { * @param groupBy * @param sortBy * @param sortOrder - * @param force true to force a full db query regroup + * @param force true to force a full db query regroup */ public synchronized > void regroup(final DrawableAttribute groupBy, final GroupSortBy sortBy, final SortOrder sortOrder, Boolean force) { @@ -530,9 +529,7 @@ public class GroupManager { } groupByTask = new ReGroupTask<>(groupBy, sortBy, sortOrder); - Platform.runLater(() -> { - regroupProgress.bind(groupByTask.progressProperty()); - }); + Platform.runLater(() -> regroupProgress.bind(groupByTask.progressProperty())); regroupExecutor.submit(groupByTask); } else { // resort the list of groups @@ -583,10 +580,7 @@ public class GroupManager { DrawableGroup group = g; if (group != null) { //if there is aleady a group that was previously deemed fully analyzed, then add this newly analyzed file to it. - Platform.runLater(() -> { - group.addFile(fileID); - }); - + Platform.runLater(() -> group.addFile(fileID)); } } @@ -682,9 +676,9 @@ public class GroupManager { } else { group = new DrawableGroup(groupKey, fileIDs, groupSeen); controller.getCategoryManager().registerListener(group); - group.seenProperty().addListener((o, oldSeen, newSeen) -> { - Platform.runLater(() -> markGroupSeen(group, newSeen)); - }); + group.seenProperty().addListener((o, oldSeen, newSeen) -> + Platform.runLater(() -> markGroupSeen(group, newSeen)) + ); groupMap.put(groupKey, group); } } @@ -693,7 +687,7 @@ public class GroupManager { analyzedGroups.add(group); if (Objects.isNull(task)) { FXCollections.sort(analyzedGroups, applySortOrder(sortOrder, sortBy)); - } + } } markGroupSeen(group, groupSeen); }); @@ -743,17 +737,17 @@ public class GroupManager { "# {0} - groupBy attribute Name", "# {1} - atribute value", "ReGroupTask.progressUpdate=regrouping files by {0} : {1}"}) - private class ReGroupTask> extends LoggedTask { + private class ReGroupTask> extends LoggedTask { private ProgressHandle groupProgress; - private final DrawableAttribute groupBy; + private final DrawableAttribute groupBy; private final GroupSortBy sortBy; private final SortOrder sortOrder; - ReGroupTask(DrawableAttribute groupBy, GroupSortBy sortBy, SortOrder sortOrder) { + ReGroupTask(DrawableAttribute groupBy, GroupSortBy sortBy, SortOrder sortOrder) { super(Bundle.ReGroupTask_displayTitle(groupBy.attrName.toString(), sortBy.getDisplayName(), sortOrder.toString()), true); this.groupBy = groupBy; @@ -780,13 +774,13 @@ public class GroupManager { }); // Get the list of group keys - final List vals = findValuesForAttribute(groupBy); + final List vals = findValuesForAttribute(groupBy); groupProgress.start(vals.size()); int p = 0; // For each key value, partially create the group and add it to the list. - for (final A val : vals) { + for (final AttrType val : vals) { if (isCancelled()) { return null;//abort } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupSortBy.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupSortBy.java index 20d47e2952..65e1870de8 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupSortBy.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupSortBy.java @@ -37,24 +37,34 @@ public class GroupSortBy implements Comparator { /** * sort the groups by the number of files in each */ - public final static GroupSortBy FILE_COUNT = new GroupSortBy(Bundle.GroupSortBy_groupSize(), "folder-open-image.png", Comparator.comparing(DrawableGroup::getSize)); + public final static GroupSortBy FILE_COUNT = + new GroupSortBy(Bundle.GroupSortBy_groupSize(), "folder-open-image.png", + Comparator.comparing(DrawableGroup::getSize)); /** * sort the groups by the natural order of the grouping value ( eg group * them by path alphabetically ) */ - public final static GroupSortBy GROUP_BY_VALUE = new GroupSortBy(Bundle.GroupSortBy_groupName(), "folder-rename.png", Comparator.comparing(DrawableGroup::getGroupByValueDislpayName)); + public final static GroupSortBy GROUP_BY_VALUE = + new GroupSortBy(Bundle.GroupSortBy_groupName(), "folder-rename.png", + Comparator.comparing(DrawableGroup::getGroupByValueDislpayName)); /** * don't sort the groups just use what ever order they come in (ingest * order) */ - public final static GroupSortBy NONE = new GroupSortBy(Bundle.GroupSortBy_none(), "prohibition.png", new AllEqualComparator<>()); + public final static GroupSortBy NONE = + new GroupSortBy(Bundle.GroupSortBy_none(), "prohibition.png", + new AllEqualComparator<>()); /** * sort the groups by some priority metric to be determined and implemented */ - public final static GroupSortBy PRIORITY = new GroupSortBy(Bundle.GroupSortBy_priority(), "hashset_hits.png", Comparator.comparing(DrawableGroup::getHashHitDensity).thenComparing(Comparator.comparing(DrawableGroup::getUncategorizedCount)).reversed()); + public final static GroupSortBy PRIORITY = + new GroupSortBy(Bundle.GroupSortBy_priority(), "hashset_hits.png", + Comparator.comparing(DrawableGroup::getHashHitDensity) + .thenComparing(Comparator.comparing(DrawableGroup::getUncategorizedCount)) + .reversed()); @Override public int compare(DrawableGroup o1, DrawableGroup o2) { From 0bf5896e87c8d0ac8fe238d19f9740c27ef6ffc3 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Thu, 19 Oct 2017 11:06:23 -0400 Subject: [PATCH 08/32] 3124: update the comments --- .../keywordsearch/KeywordSearchTestSuite.java | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchTestSuite.java b/KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchTestSuite.java index 848483084b..373a2eedd1 100755 --- a/KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchTestSuite.java +++ b/KeywordSearch/test/unit/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchTestSuite.java @@ -1,7 +1,20 @@ /* - * To change this license header, choose License Headers in Project Properties. - * To change this template file, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.keywordsearch; @@ -12,10 +25,7 @@ import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.runner.RunWith; import org.junit.runners.Suite; -/** - * - * @author - */ + @RunWith(Suite.class) @Suite.SuiteClasses({CreditCardValidatorTest.class}) public class KeywordSearchTestSuite { From 98f01f5921a2690b785ace903e64e1577aa32913 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Thu, 19 Oct 2017 11:48:13 -0400 Subject: [PATCH 09/32] 3116: Update the credit card account HMTL report title from Accounts: CREDIT_CARD to Accounts: Credit Card --- .../org/sleuthkit/autopsy/report/TableReportGenerator.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java index 234ed1509c..ee435787aa 100755 --- a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java @@ -44,6 +44,7 @@ import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.Account; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -174,7 +175,11 @@ class TableReportGenerator { * does not require a artifact name, so we make a synthetic * compund name by appending a ":" and the account type. */ - final String compundDataTypeName = BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getDisplayName() + ": " + accountType; + String accountDisplayname = accountType; + if (accountType != null && accountType.equals(Account.Type.CREDIT_CARD.name())) { + accountDisplayname = Account.Type.CREDIT_CARD.getDisplayName(); + } + final String compundDataTypeName = BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getDisplayName() + ": " + accountDisplayname; writeTableForDataType(new ArrayList<>(groupedArtifacts.get(accountType)), type, compundDataTypeName, comment); } } else { From 11b66c1648a4c4fb015bfe41613ae54eabdd1efb Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 19 Oct 2017 16:23:31 -0400 Subject: [PATCH 10/32] Moved archive handling code into ArchiveUtil for code re-use --- .../autoingest/AddArchiveTask.java | 26 +++++++ ....java => ArchiveExtractorDSProcessor.java} | 68 +++---------------- .../experimental/autoingest/ArchiveUtil.java | 34 +++++++++- 3 files changed, 67 insertions(+), 61 deletions(-) rename Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/{ArchiveExtractorDataSourceProcessor.java => ArchiveExtractorDSProcessor.java} (77%) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index e0878d05ee..4d744803c9 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -18,9 +18,15 @@ */ package org.sleuthkit.autopsy.experimental.autoingest; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.Content; /* * A runnable that adds an archive data source to the case database. @@ -33,6 +39,8 @@ public class AddArchiveTask implements Runnable { private final DataSourceProcessorProgressMonitor progressMonitor; private final DataSourceProcessorCallback callback; private boolean criticalErrorOccurred; + + private static final String AUTO_INGEST_MODULE_OUTPUT_DIR = "AutoIngest"; /* * The cancellation requested flag and SleuthKit add image process are @@ -71,7 +79,25 @@ public class AddArchiveTask implements Runnable { */ @Override public void run() { + if (!ArchiveUtil.isArchive(Paths.get(imagePath))) { + List errorMessages = new ArrayList<>(); + errorMessages.add("Input data source is not a valid datasource: " + imagePath.toString()); + List newDataSources = new ArrayList<>(); + DataSourceProcessorCallback.DataSourceProcessorResult result; + result = DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS; + callback.done(result, errorMessages, newDataSources); + } + // extract the archive and pass the extracted folder as input + Path extractedDataSourcePath = Paths.get(""); + try { + Case currentCase = Case.getCurrentCase(); + //extractedDataSourcePath = extractDataSource(Paths.get(currentCase.getModuleDirectory()), imagePath); + } catch (Exception ex) { + //throw new AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException(NbBundle.getMessage(ArchiveExtractorDSProcessor.class, "ArchiveExtractorDataSourceProcessor.process.exception.text"), ex); + } + + // do processing } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDataSourceProcessor.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java similarity index 77% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDataSourceProcessor.java rename to Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java index 4512e1d349..6fa8238dc3 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDataSourceProcessor.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java @@ -18,29 +18,12 @@ */ package org.sleuthkit.autopsy.experimental.autoingest; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Enumeration; -import java.util.List; import java.util.UUID; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; import javax.swing.JPanel; -import javax.swing.filechooser.FileFilter; -import org.apache.commons.io.FilenameUtils; import org.openide.util.NbBundle; import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProviders; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.GeneralFilter; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; @@ -56,15 +39,10 @@ import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor; @ServiceProvider(service=DataSourceProcessor.class), @ServiceProvider(service=AutoIngestDataSourceProcessor.class)} ) -public class ArchiveExtractorDataSourceProcessor implements DataSourceProcessor, AutoIngestDataSourceProcessor { - - private final static String DATA_SOURCE_TYPE = NbBundle.getMessage(ArchiveExtractorDataSourceProcessor.class, "ArchiveExtractorDataSourceProcessor.dsType.text"); - - private static GeneralFilter zipFilter; - private static final List archiveFilters = new ArrayList<>(); - - private static final String AUTO_INGEST_MODULE_OUTPUT_DIR = "AutoIngest"; +public class ArchiveExtractorDSProcessor implements DataSourceProcessor, AutoIngestDataSourceProcessor { + private final static String DATA_SOURCE_TYPE = NbBundle.getMessage(ArchiveExtractorDSProcessor.class, "ArchiveExtractorDataSourceProcessor.dsType.text"); + private final ArchiveFilePanel configPanel; private String deviceId; private String imagePath; @@ -78,17 +56,14 @@ public class ArchiveExtractorDataSourceProcessor implements DataSourceProcessor, * integration with the add data source wizard. It also provides a run * method overload to allow it to be used independently of the wizard. */ - public ArchiveExtractorDataSourceProcessor() { - String[] extensions = ArchiveUtil.getSupportedArchiveTypes(); - zipFilter = new GeneralFilter(Arrays.asList(extensions), ""); - archiveFilters.add(zipFilter); - configPanel = ArchiveFilePanel.createInstance(ArchiveExtractorDataSourceProcessor.class.getName(), archiveFilters); + public ArchiveExtractorDSProcessor() { + configPanel = ArchiveFilePanel.createInstance(ArchiveExtractorDSProcessor.class.getName(), ArchiveUtil.getArchiveFilters()); } @Override public int canProcess(Path dataSourcePath) throws AutoIngestDataSourceProcessorException { // check whether this is an archive - if (isArchive(dataSourcePath)){ + if (ArchiveUtil.isArchive(dataSourcePath)){ // return "high confidence" value return 100; } @@ -97,17 +72,7 @@ public class ArchiveExtractorDataSourceProcessor implements DataSourceProcessor, @Override public void process(String deviceId, Path dataSourcePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callBack) throws AutoIngestDataSourceProcessorException { - if (isArchive(dataSourcePath)) { - // extract the archive and pass the extracted folder as input - Path extractedDataSourcePath = Paths.get(""); - try { - Case currentCase = Case.getCurrentCase(); - extractedDataSourcePath = extractDataSource(Paths.get(currentCase.getModuleDirectory()), dataSourcePath); - } catch (Exception ex) { - throw new AutoIngestDataSourceProcessorException(NbBundle.getMessage(ArchiveExtractorDataSourceProcessor.class, "ArchiveExtractorDataSourceProcessor.process.exception.text"), ex); - } - run(deviceId, extractedDataSourcePath.toString(), progressMonitor, callBack); - } + run(deviceId, dataSourcePath.toString(), progressMonitor, callBack); } @Override @@ -208,21 +173,6 @@ public class ArchiveExtractorDataSourceProcessor implements DataSourceProcessor, configPanel.reset(); setDataSourceOptionsCalled = false; } - - private static boolean isArchive(Path dataSourcePath) throws AutoIngestDataSourceProcessorException { - String fileName = dataSourcePath.getFileName().toString(); - // check whether it's a zip archive file that can be extracted - return isAcceptedByFiler(new File(fileName), archiveFilters); - } - - private static boolean isAcceptedByFiler(File file, List filters) { - for (FileFilter filter : filters) { - if (filter.accept(file)) { - return true; - } - } - return false; - } /** * Extracts the contents of a ZIP archive submitted as a data source to a @@ -230,7 +180,7 @@ public class ArchiveExtractorDataSourceProcessor implements DataSourceProcessor, * * @throws IOException if there is a problem extracting the data source from * the archive. - */ + private static Path extractDataSource(Path outputDirectoryPath, Path dataSourcePath) throws IOException { String dataSourceFileNameNoExt = FilenameUtils.removeExtension(dataSourcePath.getFileName().toString()); Path destinationFolder = Paths.get(outputDirectoryPath.toString(), @@ -268,5 +218,5 @@ public class ArchiveExtractorDataSourceProcessor implements DataSourceProcessor, zipFile.close(); } return destinationFolder; - } + } */ } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveUtil.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveUtil.java index 9683deb5c6..b7a2926092 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveUtil.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveUtil.java @@ -26,7 +26,9 @@ import java.io.RandomAccessFile; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import javax.swing.filechooser.FileFilter; import net.sf.sevenzipjbinding.ISequentialOutStream; import net.sf.sevenzipjbinding.ISevenZipInArchive; import net.sf.sevenzipjbinding.SevenZip; @@ -35,18 +37,46 @@ import net.sf.sevenzipjbinding.SevenZipNativeInitializationException; import net.sf.sevenzipjbinding.impl.RandomAccessFileInStream; import net.sf.sevenzipjbinding.simple.ISimpleInArchive; import net.sf.sevenzipjbinding.simple.ISimpleInArchiveItem; +import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.casemodule.GeneralFilter; /** * Set of utilities that handles archive file extraction. Uses 7zip library. */ final class ArchiveUtil { - static final String[] SUPPORTED_EXTENSIONS = {"zip", "rar", "arj", "7z", "7zip", "gzip", "gz", "bzip2", "tar", "tgz",}; // NON-NLS - + private static final String[] SUPPORTED_EXTENSIONS = {"zip", "rar", "arj", "7z", "7zip", "gzip", "gz", "bzip2", "tar", "tgz",}; // NON-NLS + private static final List ARCHIVE_EXTS = Arrays.asList(".zip", ".rar", ".arj", ".7z", ".7zip", ".gzip", ".gz", ".bzip2", ".tar", ".tgz"); //NON-NLS + @NbBundle.Messages("GeneralFilter.archiveDesc.text=Archive Files (.zip, .rar, .arj, .7z, .7zip, .gzip, .gz, .bzip2, .tar, .tgz)") + private static final String ARCHIVE_DESC = Bundle.GeneralFilter_archiveDesc_text(); + private static final GeneralFilter SEVEN_ZIP_FILTER = new GeneralFilter(ARCHIVE_EXTS, ARCHIVE_DESC); + private static final List ARCHIVE_FILTERS = new ArrayList<>(); + static { + ARCHIVE_FILTERS.add(SEVEN_ZIP_FILTER); + } private ArchiveUtil() { } + static List getArchiveFilters() { + return ARCHIVE_FILTERS; + } + + static boolean isArchive(Path dataSourcePath) { + String fileName = dataSourcePath.getFileName().toString(); + // check whether it's a zip archive file that can be extracted + return isAcceptedByFiler(new File(fileName), ARCHIVE_FILTERS); + } + + private static boolean isAcceptedByFiler(File file, List filters) { + for (FileFilter filter : filters) { + if (filter.accept(file)) { + return true; + } + } + return false; + } + /** * Enum of mime types which support archive extraction */ From 0fcea2306670bffda9e35b7bd569c50e9352e484 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Thu, 19 Oct 2017 16:58:26 -0400 Subject: [PATCH 11/32] Removed a log entry to log available disk space every minute --- Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java index f6580a3cbc..08c619209f 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java @@ -192,7 +192,7 @@ public final class IngestMonitor { } logMemoryUsage(); - logDiskSpaceUsage(); + //logDiskSpaceUsage(); // this creates a log entry every minute if (!enoughDiskSpace()) { /* From c7f39ea83612f8b937b8177d92eb287eaa00fa66 Mon Sep 17 00:00:00 2001 From: millmanorama Date: Fri, 20 Oct 2017 14:18:44 +0200 Subject: [PATCH 12/32] initialize toolbar with GroupSortBy from GroupManager --- .../imagegallery/datamodel/grouping/GroupManager.java | 2 +- .../src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index dc31145c2f..5c02f5abd1 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -465,7 +465,7 @@ public class GroupManager { } } - public Comparator getSortBy() { + public GroupSortBy getSortBy() { return sortBy; } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java index 2dc85cbfd9..bdc43c1c06 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java @@ -180,8 +180,8 @@ public class Toolbar extends ToolBar { sortChooser = new SortChooser<>(GroupSortBy.getValues()); sortChooser.comparatorProperty().addListener((observable, oldComparator, newComparator) -> { - final boolean orderEnabled = newComparator == GroupSortBy.NONE || newComparator == GroupSortBy.PRIORITY; - sortChooser.setSortOrderDisabled(orderEnabled); + final boolean orderDisabled = newComparator == GroupSortBy.NONE || newComparator == GroupSortBy.PRIORITY; + sortChooser.setSortOrderDisabled(orderDisabled); final SortChooser.ValueType valueType = newComparator == GroupSortBy.GROUP_BY_VALUE ? SortChooser.ValueType.LEXICOGRAPHIC : SortChooser.ValueType.NUMERIC; sortChooser.setValueType(valueType); @@ -189,7 +189,7 @@ public class Toolbar extends ToolBar { }); sortChooser.sortOrderProperty().addListener(queryInvalidationListener); - sortChooser.setComparator(GroupSortBy.PRIORITY); + sortChooser.setComparator(controller.getGroupManager().getSortBy()); getItems().add(1, sortChooser); sortHelpImageView.setCursor(Cursor.HAND); From 3731a9cd0fcf79a58caf82778d309d7ae27a6aa2 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Fri, 20 Oct 2017 09:36:16 -0400 Subject: [PATCH 13/32] 3134: If there is no tag results, popup a message and not doing the report generating. --- .../AddTaggedHashesToHashDbConfigPanel.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java index 93dad76f89..cc820672e0 100755 --- a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java @@ -34,6 +34,7 @@ import javax.swing.JOptionPane; import javax.swing.ListCellRenderer; import javax.swing.ListModel; import javax.swing.event.ListDataListener; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; @@ -41,7 +42,7 @@ import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager; import org.sleuthkit.autopsy.modules.hashdatabase.HashLookupSettingsPanel; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; - +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; /** * Instances of this class are used to configure the report module plug in that * provides a convenient way to add content hashes to hash set databases. @@ -67,6 +68,9 @@ class AddTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { populateHashSetComponents(); } + @Messages({ + "No_Tagged_File_Selected=There is no tagged results." + }) private void populateTagNameComponents() { // Get the tag names in use for the current case. try { @@ -94,9 +98,13 @@ class AddTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { public void mousePressed(MouseEvent evt) { JList list = (JList) evt.getSource(); int index = list.locationToIndex(evt.getPoint()); - String value = tagsNamesListModel.getElementAt(index); - tagNameSelections.put(value, !tagNameSelections.get(value)); - list.repaint(); + if (index > -1) { + String value = tagsNamesListModel.getElementAt(index); + tagNameSelections.put(value, !tagNameSelections.get(value)); + list.repaint(); + } else { + MessageNotifyUtil.Message.warn(Bundle.No_Tagged_File_Selected()); + } } }); } From 67cab4672fa99ea3cb1fe72ca30087e5efdd58bb Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 20 Oct 2017 13:29:20 -0400 Subject: [PATCH 14/32] Fix add/remove property change listener code for KeywordSearch UI classes --- .../autopsy/keywordsearch/GlobalListSettingsPanel.java | 2 ++ .../keywordsearch/KeywordSearchGlobalSettingsPanel.java | 7 +++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListSettingsPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListSettingsPanel.java index cb7aac9018..e28cd75654 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListSettingsPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/GlobalListSettingsPanel.java @@ -138,12 +138,14 @@ final class GlobalListSettingsPanel extends javax.swing.JPanel implements Option @Override public void addPropertyChangeListener(PropertyChangeListener l) { + super.addPropertyChangeListener(l); listsManagementPanel.addPropertyChangeListener(l); editListPanel.addPropertyChangeListener(l); } @Override public void removePropertyChangeListener(PropertyChangeListener l) { + super.removePropertyChangeListener(l); listsManagementPanel.removePropertyChangeListener(l); editListPanel.removePropertyChangeListener(l); } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalSettingsPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalSettingsPanel.java index 1756bfc1ec..93fa053dd4 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalSettingsPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalSettingsPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2016 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,11 +28,12 @@ import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; */ final class KeywordSearchGlobalSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel { + private static final long serialVersionUID = 1L; private GlobalListSettingsPanel listsPanel; private KeywordSearchGlobalLanguageSettingsPanel languagesPanel; private KeywordSearchGlobalSearchSettingsPanel generalPanel; - public KeywordSearchGlobalSettingsPanel() { + KeywordSearchGlobalSettingsPanel() { initComponents(); customizeComponents(); } @@ -53,6 +54,7 @@ final class KeywordSearchGlobalSettingsPanel extends IngestModuleGlobalSettingsP @Override public void addPropertyChangeListener(PropertyChangeListener l) { + super.addPropertyChangeListener(l); listsPanel.addPropertyChangeListener(l); languagesPanel.addPropertyChangeListener(l); generalPanel.addPropertyChangeListener(l); @@ -60,6 +62,7 @@ final class KeywordSearchGlobalSettingsPanel extends IngestModuleGlobalSettingsP @Override public void removePropertyChangeListener(PropertyChangeListener l) { + super.removePropertyChangeListener(l); listsPanel.removePropertyChangeListener(l); languagesPanel.removePropertyChangeListener(l); generalPanel.removePropertyChangeListener(l); From 19a8249fddc15494d00d82d0a83d64de14c5fc41 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Mon, 23 Oct 2017 14:34:28 -0400 Subject: [PATCH 15/32] Extracting contents of archive to case output folder --- .../autoingest/AddArchiveTask.java | 53 +++++++++---------- .../ArchiveExtractorDSProcessor.java | 14 ++--- .../autoingest/ArchiveFilePanel.java | 12 ++--- 3 files changed, 38 insertions(+), 41 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index 4d744803c9..3a92d14452 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -22,6 +22,7 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; +import org.apache.commons.io.FilenameUtils; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; @@ -35,43 +36,30 @@ public class AddArchiveTask implements Runnable { private final Logger logger = Logger.getLogger(AddArchiveTask.class.getName()); private final String deviceId; - private final String imagePath; + private final String archivePath; private final DataSourceProcessorProgressMonitor progressMonitor; private final DataSourceProcessorCallback callback; private boolean criticalErrorOccurred; - + private static final String AUTO_INGEST_MODULE_OUTPUT_DIR = "AutoIngest"; - /* - * The cancellation requested flag and SleuthKit add image process are - * guarded by a monitor (called a lock here to avoid confusion with the - * progress monitor) to synchronize cancelling the process (setting the flag - * and calling its stop method) and calling either its commit or revert - * method. The built-in monitor of the add image process can't be used for - * this because it is already used to synchronize its run (init part), - * commit, revert, and currentDirectory methods. - * - * TODO (AUT-2021): Merge SleuthkitJNI.AddImageProcess and AddImageTask - */ - private final Object tskAddImageProcessLock; - /** - * Constructs a runnable task that adds an image to the case database. + * Constructs a runnable task that adds an archive and data sources + * contained in the archive to the case database. * * @param deviceId An ASCII-printable identifier for the device associated * with the data source that is intended to be unique across multiple cases * (e.g., a UUID). - * @param imagePath Path to the image file. + * @param archivePath Path to the archive file. * @param progressMonitor Progress monitor to report progress during * processing. * @param callback Callback to call when processing is done. */ - AddArchiveTask(String deviceId, String imagePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { + AddArchiveTask(String deviceId, String archivePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { this.deviceId = deviceId; - this.imagePath = imagePath; + this.archivePath = archivePath; this.callback = callback; this.progressMonitor = progressMonitor; - tskAddImageProcessLock = new Object(); } /** @@ -79,9 +67,9 @@ public class AddArchiveTask implements Runnable { */ @Override public void run() { - if (!ArchiveUtil.isArchive(Paths.get(imagePath))) { + if (!ArchiveUtil.isArchive(Paths.get(archivePath))) { List errorMessages = new ArrayList<>(); - errorMessages.add("Input data source is not a valid datasource: " + imagePath.toString()); + errorMessages.add("Input data source is not a valid datasource: " + archivePath.toString()); List newDataSources = new ArrayList<>(); DataSourceProcessorCallback.DataSourceProcessorResult result; result = DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS; @@ -89,22 +77,31 @@ public class AddArchiveTask implements Runnable { } // extract the archive and pass the extracted folder as input - Path extractedDataSourcePath = Paths.get(""); + Path destinationFolder = Paths.get(""); try { Case currentCase = Case.getCurrentCase(); - //extractedDataSourcePath = extractDataSource(Paths.get(currentCase.getModuleDirectory()), imagePath); + + // get file name without extension + String dataSourceFileNameNoExt = FilenameUtils.removeExtension(archivePath); + + // create folder to extract archive to + destinationFolder = Paths.get(currentCase.getModuleDirectory(), dataSourceFileNameNoExt + "_" + TimeStampUtils.createTimeStamp()); + destinationFolder.toFile().mkdirs(); + + // extract contents of ZIP archive into destination folder + ArchiveUtil.unpackArchiveFile(archivePath, destinationFolder.toString()); } catch (Exception ex) { //throw new AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException(NbBundle.getMessage(ArchiveExtractorDSProcessor.class, "ArchiveExtractorDataSourceProcessor.process.exception.text"), ex); } // do processing + return; } - - + /* - * Attempts to cancel adding the image to the case database. + * Attempts to cancel adding the archive to the case database. */ public void cancelTask() { - + } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java index 6fa8238dc3..2eb066a366 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java @@ -45,7 +45,7 @@ public class ArchiveExtractorDSProcessor implements DataSourceProcessor, AutoIng private final ArchiveFilePanel configPanel; private String deviceId; - private String imagePath; + private String archivePath; private boolean setDataSourceOptionsCalled; private AddArchiveTask addArchiveTask; @@ -126,9 +126,9 @@ public class ArchiveExtractorDSProcessor implements DataSourceProcessor, AutoIng if (!setDataSourceOptionsCalled) { configPanel.storeSettings(); deviceId = UUID.randomUUID().toString(); - imagePath = configPanel.getContentPaths(); + archivePath = configPanel.getContentPaths(); } - run(deviceId, imagePath, progressMonitor, callback); + run(deviceId, archivePath, progressMonitor, callback); } /** @@ -142,13 +142,13 @@ public class ArchiveExtractorDSProcessor implements DataSourceProcessor, AutoIng * associated with the data source that is * intended to be unique across multiple cases * (e.g., a UUID). - * @param imagePath Path to the image file. + * @param archivePath Path to the archive file. * @param progressMonitor Progress monitor for reporting progress * during processing. * @param callback Callback to call when processing is done. */ - public void run(String deviceId, String imagePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { - addArchiveTask = new AddArchiveTask(deviceId, imagePath, progressMonitor, callback); + public void run(String deviceId, String archivePath, DataSourceProcessorProgressMonitor progressMonitor, DataSourceProcessorCallback callback) { + addArchiveTask = new AddArchiveTask(deviceId, archivePath, progressMonitor, callback); new Thread(addArchiveTask).start(); } @@ -169,7 +169,7 @@ public class ArchiveExtractorDSProcessor implements DataSourceProcessor, AutoIng @Override public void reset() { deviceId = null; - imagePath = null; + archivePath = null; configPanel.reset(); setDataSourceOptionsCalled = false; } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveFilePanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveFilePanel.java index e368a18c4f..e4b261ea3b 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveFilePanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveFilePanel.java @@ -45,7 +45,7 @@ import org.sleuthkit.autopsy.coreutils.PathValidator; public class ArchiveFilePanel extends JPanel implements DocumentListener { private static final Logger logger = Logger.getLogger(ArchiveFilePanel.class.getName()); - private static final String PROP_LASTIMAGE_PATH = "LBL_LastImage_PATH"; //NON-NLS + private static final String PROP_LAST_ARCHIVE_PATH = "LBL_LastImage_PATH"; //NON-NLS private final JFileChooser fileChooser = new JFileChooser(); @@ -155,7 +155,7 @@ public class ArchiveFilePanel extends JPanel implements DocumentListener { private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed String oldText = getContentPaths(); - // set the current directory of the FileChooser if the ImagePath Field is valid + // set the current directory of the FileChooser if the ArchivePath Field is valid File currentDir = new File(oldText); if (currentDir.exists()) { fileChooser.setCurrentDirectory(currentDir); @@ -179,7 +179,7 @@ public class ArchiveFilePanel extends JPanel implements DocumentListener { /** * Get the path of the user selected archive. * - * @return the image path + * @return the archive path */ public String getContentPaths() { return pathTextField.getText(); @@ -202,7 +202,7 @@ public class ArchiveFilePanel extends JPanel implements DocumentListener { /** * Should we enable the next button of the wizard? * - * @return true if a proper image has been selected, false otherwise + * @return true if a proper archive has been selected, false otherwise */ @NbBundle.Messages("DataSourceOnCDriveError.text=Warning: Path to multi-user data source is on \"C:\" drive") public boolean validatePanel() { @@ -227,12 +227,12 @@ public class ArchiveFilePanel extends JPanel implements DocumentListener { String archivePathName = getContentPaths(); if (null != archivePathName) { String archivePath = archivePathName.substring(0, archivePathName.lastIndexOf(File.separator) + 1); - ModuleSettings.setConfigSetting(contextName, PROP_LASTIMAGE_PATH, archivePath); + ModuleSettings.setConfigSetting(contextName, PROP_LAST_ARCHIVE_PATH, archivePath); } } public void readSettings() { - String lastArchivePath = ModuleSettings.getConfigSetting(contextName, PROP_LASTIMAGE_PATH); + String lastArchivePath = ModuleSettings.getConfigSetting(contextName, PROP_LAST_ARCHIVE_PATH); if (StringUtils.isNotBlank(lastArchivePath)) { setContentPath(lastArchivePath); } From 0f309e15b5b5dec0d62626d1fe6b777811e65885 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Mon, 23 Oct 2017 14:57:12 -0400 Subject: [PATCH 16/32] Fixes and improvements --- .../autoingest/AddArchiveTask.java | 41 +++++++++++++------ 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index 3a92d14452..2ad57bde9a 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -22,7 +22,9 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; +import java.util.logging.Level; import org.apache.commons.io.FilenameUtils; +import org.openide.util.Exceptions; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; @@ -41,7 +43,7 @@ public class AddArchiveTask implements Runnable { private final DataSourceProcessorCallback callback; private boolean criticalErrorOccurred; - private static final String AUTO_INGEST_MODULE_OUTPUT_DIR = "AutoIngest"; + private static final String ARCHIVE_EXTRACTOR_MODULE_OUTPUT_DIR = "Archive Extractor"; /** * Constructs a runnable task that adds an archive and data sources @@ -67,11 +69,13 @@ public class AddArchiveTask implements Runnable { */ @Override public void run() { + List errorMessages = new ArrayList<>(); + List newDataSources = new ArrayList<>(); + DataSourceProcessorCallback.DataSourceProcessorResult result; if (!ArchiveUtil.isArchive(Paths.get(archivePath))) { - List errorMessages = new ArrayList<>(); - errorMessages.add("Input data source is not a valid datasource: " + archivePath.toString()); - List newDataSources = new ArrayList<>(); - DataSourceProcessorCallback.DataSourceProcessorResult result; + criticalErrorOccurred = true; + logger.log(Level.SEVERE, String.format("Input data source is not a valid datasource: %s", archivePath)); //NON-NLS + errorMessages.add("Input data source is not a valid datasource: " + archivePath); result = DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS; callback.done(result, errorMessages, newDataSources); } @@ -81,21 +85,32 @@ public class AddArchiveTask implements Runnable { try { Case currentCase = Case.getCurrentCase(); - // get file name without extension - String dataSourceFileNameNoExt = FilenameUtils.removeExtension(archivePath); + // get file name without full path or extension + String dataSourceFileNameNoExt = FilenameUtils.getBaseName(archivePath); // create folder to extract archive to - destinationFolder = Paths.get(currentCase.getModuleDirectory(), dataSourceFileNameNoExt + "_" + TimeStampUtils.createTimeStamp()); + destinationFolder = Paths.get(currentCase.getModuleDirectory(), ARCHIVE_EXTRACTOR_MODULE_OUTPUT_DIR, dataSourceFileNameNoExt + "_" + TimeStampUtils.createTimeStamp()); destinationFolder.toFile().mkdirs(); // extract contents of ZIP archive into destination folder ArchiveUtil.unpackArchiveFile(archivePath, destinationFolder.toString()); - } catch (Exception ex) { - //throw new AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException(NbBundle.getMessage(ArchiveExtractorDSProcessor.class, "ArchiveExtractorDataSourceProcessor.process.exception.text"), ex); + + // do processing + + } catch (ArchiveUtil.ArchiveExtractionException ex) { + criticalErrorOccurred = true; + errorMessages.add(ex.getMessage()); + logger.log(Level.SEVERE, String.format("Critical error occurred while extracting archive %s", archivePath), ex); //NON-NLS + } finally { + if (criticalErrorOccurred) { + result = DataSourceProcessorCallback.DataSourceProcessorResult.CRITICAL_ERRORS; + } else if (!errorMessages.isEmpty()) { + result = DataSourceProcessorCallback.DataSourceProcessorResult.NONCRITICAL_ERRORS; + } else { + result = DataSourceProcessorCallback.DataSourceProcessorResult.NO_ERRORS; + } + callback.done(result, errorMessages, newDataSources); } - - // do processing - return; } /* From 5f9c5facce8c7c399760f6123d9c9b38280eae49 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Mon, 23 Oct 2017 15:20:12 -0400 Subject: [PATCH 17/32] Commented out some functionality for now --- .../experimental/autoingest/AddArchiveTask.java | 10 +++++----- .../autoingest/ArchiveExtractorDSProcessor.java | 8 ++++---- .../experimental/autoingest/AutoIngestManager.java | 1 - 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index 2ad57bde9a..54e8ec40f7 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -24,7 +24,6 @@ import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import org.apache.commons.io.FilenameUtils; -import org.openide.util.Exceptions; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor; @@ -32,7 +31,8 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.Content; /* - * A runnable that adds an archive data source to the case database. + * A runnable that adds an archive data source as well as data sources + * contained in the archive to the case database. */ public class AddArchiveTask implements Runnable { @@ -46,7 +46,7 @@ public class AddArchiveTask implements Runnable { private static final String ARCHIVE_EXTRACTOR_MODULE_OUTPUT_DIR = "Archive Extractor"; /** - * Constructs a runnable task that adds an archive and data sources + * Constructs a runnable task that adds an archive as well as data sources * contained in the archive to the case database. * * @param deviceId An ASCII-printable identifier for the device associated @@ -93,11 +93,11 @@ public class AddArchiveTask implements Runnable { destinationFolder.toFile().mkdirs(); // extract contents of ZIP archive into destination folder - ArchiveUtil.unpackArchiveFile(archivePath, destinationFolder.toString()); + //ArchiveUtil.unpackArchiveFile(archivePath, destinationFolder.toString()); // do processing - } catch (ArchiveUtil.ArchiveExtractionException ex) { + } catch (Exception ex) { criticalErrorOccurred = true; errorMessages.add(ex.getMessage()); logger.log(Level.SEVERE, String.format("Critical error occurred while extracting archive %s", archivePath), ex); //NON-NLS diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java index 2eb066a366..0103815e1a 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java @@ -35,10 +35,10 @@ import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor; * add data source wizard. It also provides a run method overload to allow it to * be used independently of the wizard. */ -@ServiceProviders(value={ - @ServiceProvider(service=DataSourceProcessor.class), - @ServiceProvider(service=AutoIngestDataSourceProcessor.class)} -) +//@ServiceProviders(value={ +// @ServiceProvider(service=DataSourceProcessor.class), +// @ServiceProvider(service=AutoIngestDataSourceProcessor.class)} +//) public class ArchiveExtractorDSProcessor implements DataSourceProcessor, AutoIngestDataSourceProcessor { private final static String DATA_SOURCE_TYPE = NbBundle.getMessage(ArchiveExtractorDSProcessor.class, "ArchiveExtractorDataSourceProcessor.dsType.text"); diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index 7ffb67ae05..8d7df1b6c0 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -1449,7 +1449,6 @@ public final class AutoIngestManager extends Observable implements PropertyChang */ private final class JobProcessingTask implements Runnable { - private static final String AUTO_INGEST_MODULE_OUTPUT_DIR = "AutoIngest"; private final Object ingestLock; private final Object pauseLock; @GuardedBy("pauseLock") From 0451208df814b432dda3fae51a1028b7a41cb209 Mon Sep 17 00:00:00 2001 From: Eugene Livis Date: Mon, 23 Oct 2017 16:28:52 -0400 Subject: [PATCH 18/32] Code review comments --- Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java | 2 -- .../autopsy/experimental/autoingest/AddArchiveTask.java | 2 +- .../autoingest/ArchiveExtractorDSProcessor.java | 6 ++++-- .../autopsy/experimental/autoingest/ArchiveFilePanel.java | 2 +- .../autopsy/experimental/autoingest/AutoIngestManager.java | 2 +- .../autopsy/experimental/autoingest/Bundle.properties | 2 -- ...ourceProcessors.java => DataSourceProcessorUtility.java} | 5 ++++- 7 files changed, 11 insertions(+), 10 deletions(-) rename Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/{IdentifyDataSourceProcessors.java => DataSourceProcessorUtility.java} (96%) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java index 08c619209f..8aeda52597 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java @@ -192,8 +192,6 @@ public final class IngestMonitor { } logMemoryUsage(); - //logDiskSpaceUsage(); // this creates a log entry every minute - if (!enoughDiskSpace()) { /* * Shut down ingest by cancelling all ingest jobs. diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java index 54e8ec40f7..3bc76e61fd 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AddArchiveTask.java @@ -34,7 +34,7 @@ import org.sleuthkit.datamodel.Content; * A runnable that adds an archive data source as well as data sources * contained in the archive to the case database. */ -public class AddArchiveTask implements Runnable { +class AddArchiveTask implements Runnable { private final Logger logger = Logger.getLogger(AddArchiveTask.class.getName()); private final String deviceId; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java index 0103815e1a..a649b0f37a 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveExtractorDSProcessor.java @@ -39,9 +39,11 @@ import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor; // @ServiceProvider(service=DataSourceProcessor.class), // @ServiceProvider(service=AutoIngestDataSourceProcessor.class)} //) +@NbBundle.Messages({ + "ArchiveDSP.dsType.text=Archive file"}) public class ArchiveExtractorDSProcessor implements DataSourceProcessor, AutoIngestDataSourceProcessor { - - private final static String DATA_SOURCE_TYPE = NbBundle.getMessage(ArchiveExtractorDSProcessor.class, "ArchiveExtractorDataSourceProcessor.dsType.text"); + + private final static String DATA_SOURCE_TYPE = Bundle.ArchiveDSP_dsType_text(); private final ArchiveFilePanel configPanel; private String deviceId; diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveFilePanel.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveFilePanel.java index e4b261ea3b..e5285d9e75 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveFilePanel.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/ArchiveFilePanel.java @@ -42,7 +42,7 @@ import org.sleuthkit.autopsy.coreutils.PathValidator; * "zip", "rar", "arj", "7z", "7zip", "gzip, etc). Allows the user to select a * file. */ -public class ArchiveFilePanel extends JPanel implements DocumentListener { +class ArchiveFilePanel extends JPanel implements DocumentListener { private static final Logger logger = Logger.getLogger(ArchiveFilePanel.class.getName()); private static final String PROP_LAST_ARCHIVE_PATH = "LBL_LastImage_PATH"; //NON-NLS diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java index 8d7df1b6c0..2f2f22fb0d 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java @@ -2316,7 +2316,7 @@ public final class AutoIngestManager extends Observable implements PropertyChang Map validDataSourceProcessorsMap; try { // lookup all AutomatedIngestDataSourceProcessors and poll which ones are able to process the current data source - validDataSourceProcessorsMap = IdentifyDataSourceProcessors.getDataSourceProcessor(dataSource.getPath()); + validDataSourceProcessorsMap = DataSourceProcessorUtility.getDataSourceProcessor(dataSource.getPath()); } catch (AutoIngestDataSourceProcessor.AutoIngestDataSourceProcessorException ex) { SYS_LOGGER.log(Level.SEVERE, "Exception while determining best data source processor for {0}", dataSource.getPath()); // rethrow the exception. It will get caught & handled upstream and will result in AIM auto-pause. diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties index ec32087dbf..edac418672 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties @@ -247,8 +247,6 @@ AutoIngestDashboard.prioritizeJobButton.toolTipText=Move the selected job to the AutoIngestDashboard.prioritizeJobButton.text=Prioritize &Job AutoIngestDashboard.prioritizeCaseButton.toolTipText=Move all images associated with a case to top of Pending queue. AutoIngestDashboard.prioritizeCaseButton.text=Prioritize &Case -ArchiveExtractorDataSourceProcessor.dsType.text=Archive file -ArchiveExtractorDataSourceProcessor.process.exception.text=Exception while trying to extract archive ArchiveFilePanel.pathLabel.text=Browse for an archive file: ArchiveFilePanel.browseButton.text=Browse ArchiveFilePanel.pathTextField.text= diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/IdentifyDataSourceProcessors.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSourceProcessorUtility.java similarity index 96% rename from Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/IdentifyDataSourceProcessors.java rename to Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSourceProcessorUtility.java index b566d99aac..6f88d70a28 100755 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/IdentifyDataSourceProcessors.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/DataSourceProcessorUtility.java @@ -29,7 +29,10 @@ import org.sleuthkit.autopsy.datasourceprocessors.AutoIngestDataSourceProcessor. /** * A utility class to find Data Source Processors */ -class IdentifyDataSourceProcessors { +class DataSourceProcessorUtility { + + private DataSourceProcessorUtility() { + } /** * A utility method to find all Data Source Processors (DSP) that are able From 35f84dce94484a1cc61436b07bc6594768667bd9 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 25 Oct 2017 12:39:47 -0400 Subject: [PATCH 19/32] Modify construction of KeywordSearchGlobalSettingsPanel --- .../keywordsearch/KeywordSearchGlobalSettingsPanel.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalSettingsPanel.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalSettingsPanel.java index 93fa053dd4..8e820b4c74 100755 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalSettingsPanel.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchGlobalSettingsPanel.java @@ -29,9 +29,9 @@ import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel; final class KeywordSearchGlobalSettingsPanel extends IngestModuleGlobalSettingsPanel implements OptionsPanel { private static final long serialVersionUID = 1L; - private GlobalListSettingsPanel listsPanel; - private KeywordSearchGlobalLanguageSettingsPanel languagesPanel; - private KeywordSearchGlobalSearchSettingsPanel generalPanel; + private final GlobalListSettingsPanel listsPanel = new GlobalListSettingsPanel(); + private final KeywordSearchGlobalLanguageSettingsPanel languagesPanel = new KeywordSearchGlobalLanguageSettingsPanel(); + private final KeywordSearchGlobalSearchSettingsPanel generalPanel = new KeywordSearchGlobalSearchSettingsPanel(); KeywordSearchGlobalSettingsPanel() { initComponents(); @@ -41,9 +41,6 @@ final class KeywordSearchGlobalSettingsPanel extends IngestModuleGlobalSettingsP @NbBundle.Messages({"KeywordSearchGlobalSettingsPanel.Title=Global Keyword Search Settings"}) private void customizeComponents() { setName(Bundle.KeywordSearchGlobalSettingsPanel_Title()); - listsPanel = new GlobalListSettingsPanel(); - languagesPanel = new KeywordSearchGlobalLanguageSettingsPanel(); - generalPanel = new KeywordSearchGlobalSearchSettingsPanel(); tabbedPane.insertTab(NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel.customizeComponents.listTabTitle"), null, listsPanel, NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel.customizeComponents.listLabToolTip"), 0); tabbedPane.insertTab(NbBundle.getMessage(this.getClass(), "KeywordSearchConfigurationPanel.customizeComponents.stringExtTitle"), null, From e57eb6a5dbb753e1c0b3b966fcd3ca7e688bd60e Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Wed, 25 Oct 2017 14:45:38 -0400 Subject: [PATCH 20/32] 3134: As Ann suggested, remove the pop up message while index out of bound --- .../taggedhashes/AddTaggedHashesToHashDbConfigPanel.java | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java index cc820672e0..1066973f58 100755 --- a/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/taggedhashes/AddTaggedHashesToHashDbConfigPanel.java @@ -34,7 +34,6 @@ import javax.swing.JOptionPane; import javax.swing.ListCellRenderer; import javax.swing.ListModel; import javax.swing.event.ListDataListener; -import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; @@ -42,7 +41,6 @@ import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager; import org.sleuthkit.autopsy.modules.hashdatabase.HashLookupSettingsPanel; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; /** * Instances of this class are used to configure the report module plug in that * provides a convenient way to add content hashes to hash set databases. @@ -68,9 +66,6 @@ class AddTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { populateHashSetComponents(); } - @Messages({ - "No_Tagged_File_Selected=There is no tagged results." - }) private void populateTagNameComponents() { // Get the tag names in use for the current case. try { @@ -102,8 +97,6 @@ class AddTaggedHashesToHashDbConfigPanel extends javax.swing.JPanel { String value = tagsNamesListModel.getElementAt(index); tagNameSelections.put(value, !tagNameSelections.get(value)); list.repaint(); - } else { - MessageNotifyUtil.Message.warn(Bundle.No_Tagged_File_Selected()); } } }); From af6fb2fceec93b2548602834999151f210f40749 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Wed, 25 Oct 2017 15:00:05 -0400 Subject: [PATCH 21/32] 3116: A more generic way to get account display name for all availabe account types. --- .../org/sleuthkit/autopsy/report/TableReportGenerator.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java index ee435787aa..3df94c1d1c 100755 --- a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java @@ -176,8 +176,11 @@ class TableReportGenerator { * compund name by appending a ":" and the account type. */ String accountDisplayname = accountType; - if (accountType != null && accountType.equals(Account.Type.CREDIT_CARD.name())) { - accountDisplayname = Account.Type.CREDIT_CARD.getDisplayName(); + for (Account.Type acct : Account.Type.values()) { + if (acct.equals(Account.Type.valueOf(accountType))) { + accountDisplayname = acct.getDisplayName(); + break; + } } final String compundDataTypeName = BlackboardArtifact.ARTIFACT_TYPE.TSK_ACCOUNT.getDisplayName() + ": " + accountDisplayname; writeTableForDataType(new ArrayList<>(groupedArtifacts.get(accountType)), type, compundDataTypeName, comment); From 1f4419f928c8b4f5aca150dd9a116b2eb23bf016 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Thu, 26 Oct 2017 10:02:12 -0400 Subject: [PATCH 22/32] 2969: More validation on File Search By Attributes --- .../autopsy/filesearch/DateSearchFilter.java | 98 ++++++++++++------- .../autopsy/filesearch/DateSearchPanel.java | 18 ++++ .../autopsy/filesearch/HashSearchFilter.java | 4 +- .../autopsy/filesearch/SizeSearchFilter.java | 24 +++++ 4 files changed, 108 insertions(+), 36 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java index 205db56998..8cabb1e9cc 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java @@ -40,8 +40,12 @@ import javax.swing.JSeparator; import javax.swing.ListCellRenderer; import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; +import javax.swing.event.CaretEvent; +import javax.swing.event.CaretListener; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; +import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; /** * Filters file date properties (modified/created/etc.. times) @@ -79,25 +83,10 @@ class DateSearchFilter extends AbstractFileSearchFilter { String query = "NULL"; DateSearchPanel panel = this.getComponent(); - // first, get the selected timeZone from the dropdown list - String tz = this.getComponent().getTimeZoneComboBox().getSelectedItem().toString(); - String tzID = tz.substring(tz.indexOf(" ") + 1); // 1 index after the space is the ID - TimeZone selectedTZ = TimeZone.getTimeZone(tzID); // - // convert the date from the selected timezone to get the GMT long fromDate = 0; String startDateValue = panel.getDateFromTextField().getText(); - Calendar startDate = null; - try { - DateFormat sdf = new SimpleDateFormat("MM/dd/yyyy"); - sdf.setTimeZone(selectedTZ); // get the time in the selected timezone - Date temp = sdf.parse(startDateValue); - - startDate = Calendar.getInstance(new SimpleTimeZone(0, "GMT")); //NON-NLS - startDate.setTime(temp); // convert to GMT - } catch (ParseException ex) { - // for now, no need to show the error message to the user here - } + Calendar startDate = getCalendarDate(startDateValue); if (!startDateValue.isEmpty()) { if (startDate != null) { fromDate = startDate.getTimeInMillis() / 1000; // divided by 1000 because we want to get the seconds, not miliseconds @@ -106,31 +95,13 @@ class DateSearchFilter extends AbstractFileSearchFilter { long toDate = 0; String endDateValue = panel.getDateToTextField().getText(); - Calendar endDate = null; - try { - DateFormat sdf = new SimpleDateFormat("MM/dd/yyyy"); - sdf.setTimeZone(selectedTZ); // get the time in the selected timezone - Date temp2 = sdf.parse(endDateValue); - - endDate = Calendar.getInstance(new SimpleTimeZone(0, "GMT")); //NON-NLS - endDate.setTime(temp2); // convert to GMT - endDate.set(Calendar.HOUR, endDate.get(Calendar.HOUR) + 24); // get the next 24 hours - } catch (ParseException ex) { - // for now, no need to show the error message to the user here - } + Calendar endDate = getCalendarDate(endDateValue); if (!endDateValue.isEmpty()) { if (endDate != null) { toDate = endDate.getTimeInMillis() / 1000; // divided by 1000 because we want to get the seconds, not miliseconds } } - // If they put the dates in backwards, help them out. - if (fromDate > toDate) { - long temp = toDate; - toDate = fromDate; - fromDate = temp; - } - final boolean modifiedChecked = panel.getModifiedCheckBox().isSelected(); final boolean changedChecked = panel.getChangedCheckBox().isSelected(); final boolean accessedChecked = panel.getAccessedCheckBox().isSelected(); @@ -206,13 +177,70 @@ class DateSearchFilter extends AbstractFileSearchFilter { return timeZones; } + private TimeZone getSelectedTimeZone() { + String tz = this.getComponent().getTimeZoneComboBox().getSelectedItem().toString(); + String tzID = tz.substring(tz.indexOf(" ") + 1); // 1 index after the space is the ID + TimeZone selectedTZ = TimeZone.getTimeZone(tzID); // + return selectedTZ; + } + + private Calendar getCalendarDate(String dateValue) { + TimeZone selectedTZ = getSelectedTimeZone(); + Calendar inputDate = null; + try { + DateFormat sdf = new SimpleDateFormat("MM/dd/yyyy"); + sdf.setTimeZone(selectedTZ); // get the time in the selected timezone + Date temp = sdf.parse(dateValue); + + inputDate = Calendar.getInstance(new SimpleTimeZone(0, "GMT")); //NON-NLS + inputDate.setTime(temp); // convert to GMT + } catch (ParseException ex) { + // for now, no need to show the error message to the user here + } + return inputDate; + } + @Override public void addActionListener(ActionListener l) { getComponent().addActionListener(l); } @Override + @Messages ({ + "End_Date_Before_Start_Date=The end date should be after the start date." + }) public boolean isValid() { + + final DateSearchPanel panel = this.getComponent(); + + panel.getDateFromTextField().addCaretListener(new CaretListener() { + @Override + public void caretUpdate(CaretEvent ce) { + String startDateValue = panel.getDateFromTextField().getText(); + Calendar startDate = getCalendarDate(startDateValue); + String endDateValue = panel.getDateToTextField().getText(); + Calendar endDate = getCalendarDate(endDateValue); + + if (startDate != null && startDate.after(endDate)) { + MessageNotifyUtil.Message.warn(Bundle.End_Date_Before_Start_Date()); + } + } + }); + + panel.getDateToTextField().addCaretListener(new CaretListener() { + @Override + public void caretUpdate(CaretEvent ce) { + String startDateValue = panel.getDateFromTextField().getText(); + Calendar startDate = getCalendarDate(startDateValue); + String endDateValue = panel.getDateToTextField().getText(); + Calendar endDate = getCalendarDate(endDateValue); + + if (endDate != null && endDate.before(startDate)) { + MessageNotifyUtil.Message.warn(Bundle.End_Date_Before_Start_Date()); + } + } + }); + return this.getComponent().isValidSearch(); } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java index 7867a5ebd6..82c51d78b1 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java @@ -20,6 +20,8 @@ package org.sleuthkit.autopsy.filesearch; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; import java.text.DateFormat; import java.text.ParseException; import java.util.Date; @@ -50,6 +52,20 @@ class DateSearchPanel extends javax.swing.JPanel { dateFromTextField.setComponentPopupMenu(rightClickMenu); dateToTextField.setComponentPopupMenu(rightClickMenu); + //Block or disable user input to date time field + dateFromTextField.addKeyListener(new KeyAdapter() { + @Override + public void keyTyped(KeyEvent e) { + e.consume(); // ignore event + } + }); + dateToTextField.addKeyListener(new KeyAdapter() { + @Override + public void keyTyped(KeyEvent e) { + e.consume(); // ignore event + } + }); + ActionListener actList = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -365,6 +381,7 @@ class DateSearchPanel extends javax.swing.JPanel { if (evt.getNewValue() instanceof Date) { setToDate((Date) evt.getNewValue()); } + }//GEN-LAST:event_dateToPopupChanged private void dateCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_dateCheckBoxActionPerformed @@ -399,6 +416,7 @@ class DateSearchPanel extends javax.swing.JPanel { if (date != null) { dateStringResult = dateFormat.format(date); } + dateFromTextField.setText(dateStringResult); dateFromButtonCalendar.setTargetDate(date); } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java index 951f4b206e..6bbb732a16 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.filesearch; import java.awt.event.ActionListener; +import javax.swing.JTextField; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.filesearch.FileSearchFilter.FilterValidationException; @@ -61,6 +62,7 @@ class HashSearchFilter extends AbstractFileSearchFilter { @Override public boolean isValid() { - return !this.getComponent().getSearchTextField().getText().isEmpty(); + JTextField inputHashData = this.getComponent().getSearchTextField(); + return !inputHashData.getText().isEmpty() || inputHashData.getText().length() == 32 || inputHashData.getText().matches("[0-9a-fA-F]+"); } } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchFilter.java index ca43dac7e0..d045f486c3 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchFilter.java @@ -19,8 +19,12 @@ package org.sleuthkit.autopsy.filesearch; import java.awt.event.ActionListener; +import javax.swing.InputVerifier; import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JFormattedTextField; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; import org.sleuthkit.autopsy.filesearch.FileSearchFilter.FilterValidationException; /** @@ -74,7 +78,27 @@ class SizeSearchFilter extends AbstractFileSearchFilter { } @Override + @NbBundle.Messages ({ + "Non_Negative_Number=Please input a non negative number." + }) public boolean isValid() { + this.getComponent().getSizeTextField().setInputVerifier(new InputVerifier() { + @Override + public boolean verify(JComponent input) { + String inputText = ((JFormattedTextField) input).getText(); + try { + int inputInt = Integer.parseInt(inputText); + if (inputInt < 0) { + MessageNotifyUtil.Message.warn(Bundle.Non_Negative_Number()); + return false; + } + } catch (NumberFormatException | NullPointerException e) { + MessageNotifyUtil.Message.warn(Bundle.Non_Negative_Number()); + return false; + } + return true; + } + }); return true; } } From db1b35a4dd89014d664e3156e0981f51f7b1b06e Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Thu, 26 Oct 2017 10:15:45 -0400 Subject: [PATCH 23/32] Simply turn the textfield to non editable to block user input for data time --- .../autopsy/filesearch/DateSearchPanel.form | 2 ++ .../autopsy/filesearch/DateSearchPanel.java | 15 ++------------- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.form b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.form index e92d57fdd9..59082745da 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.form +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.form @@ -149,6 +149,7 @@ + @@ -208,6 +209,7 @@ + diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java index 82c51d78b1..b67f076c6d 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java @@ -52,19 +52,6 @@ class DateSearchPanel extends javax.swing.JPanel { dateFromTextField.setComponentPopupMenu(rightClickMenu); dateToTextField.setComponentPopupMenu(rightClickMenu); - //Block or disable user input to date time field - dateFromTextField.addKeyListener(new KeyAdapter() { - @Override - public void keyTyped(KeyEvent e) { - e.consume(); // ignore event - } - }); - dateToTextField.addKeyListener(new KeyAdapter() { - @Override - public void keyTyped(KeyEvent e) { - e.consume(); // ignore event - } - }); ActionListener actList = new ActionListener() { @Override @@ -192,6 +179,7 @@ class DateSearchPanel extends javax.swing.JPanel { selectAllMenuItem.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.selectAllMenuItem.text")); // NOI18N rightClickMenu.add(selectAllMenuItem); + dateToTextField.setEditable(false); dateToTextField.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.dateToTextField.text")); // NOI18N dateToTextField.addFocusListener(new java.awt.event.FocusAdapter() { public void focusLost(java.awt.event.FocusEvent evt) { @@ -213,6 +201,7 @@ class DateSearchPanel extends javax.swing.JPanel { jLabel3.setFont(new java.awt.Font("Tahoma", 0, 10)); // NOI18N jLabel3.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.jLabel3.text")); // NOI18N + dateFromTextField.setEditable(false); dateFromTextField.setText(org.openide.util.NbBundle.getMessage(DateSearchPanel.class, "DateSearchPanel.dateFromTextField.text")); // NOI18N dateFromTextField.addFocusListener(new java.awt.event.FocusAdapter() { public void focusLost(java.awt.event.FocusEvent evt) { From 3cd0cc1518cbf3b5b8d7eaaa6801bd5f65098116 Mon Sep 17 00:00:00 2001 From: Ann Priestman Date: Thu, 26 Oct 2017 13:51:30 -0400 Subject: [PATCH 24/32] Add error text handling to File Search by Attribute panel --- .../filesearch/AbstractFileSearchFilter.java | 13 ++++++- .../autopsy/filesearch/Bundle.properties | 3 +- .../autopsy/filesearch/FileSearchFilter.java | 7 ++++ .../autopsy/filesearch/FileSearchPanel.form | 28 ++++++++++++-- .../autopsy/filesearch/FileSearchPanel.java | 37 +++++++++++++------ 5 files changed, 71 insertions(+), 17 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/AbstractFileSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/AbstractFileSearchFilter.java index 67f65be80b..149e11afa5 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/AbstractFileSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/AbstractFileSearchFilter.java @@ -31,9 +31,20 @@ import javax.swing.JComponent; abstract class AbstractFileSearchFilter implements FileSearchFilter { final private T component; - + private String lastErrorMessage; + AbstractFileSearchFilter(T component) { this.component = component; + this.lastErrorMessage = ""; + } + + void setLastError(String mes){ + lastErrorMessage = mes; + } + + @Override + public String getLastError(){ + return this.lastErrorMessage; } @Override diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties b/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties index fff8007fd4..bb91c8e05c 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties @@ -57,4 +57,5 @@ MimeTypePanel.jLabel1.text=*Note: Multiple MIME types can be selected FileSearchPanel.searchButton.text=Search MimeTypePanel.mimeTypeCheckBox.text=MIME Type: HashSearchPanel.md5CheckBox.text=MD5: -HashSearchPanel.emptyHashMsg.text=Must enter something for hash search. \ No newline at end of file +HashSearchPanel.emptyHashMsg.text=Must enter something for hash search. +FileSearchPanel.errorLabel.text=\ diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchFilter.java index 457db56570..db16fdd1e0 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchFilter.java @@ -47,6 +47,13 @@ interface FileSearchFilter { * @return Whether the panel has valid input for search. */ boolean isValid(); + + /** + * Get the last error recorded during the call to isValid + * + * @return Description of why the filter is invalid + */ + String getLastError(); /** * Gets predicate expression to include in the SQL filter expression diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.form b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.form index dbb90bea12..a64489bb01 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.form +++ b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.form @@ -23,7 +23,9 @@ - + + + @@ -32,9 +34,14 @@ - - - + + + + + + + + @@ -63,6 +70,19 @@ + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java index d7efb0b46f..2a27be8297 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java @@ -111,13 +111,7 @@ class FileSearchPanel extends javax.swing.JPanel { } }); } - - addListenerToAll(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - search(); - } - }); + searchButton.setEnabled(isValidSearch()); } @@ -130,11 +124,13 @@ class FileSearchPanel extends javax.swing.JPanel { if (filter.isEnabled()) { enabled = true; if (!filter.isValid()) { + errorLabel.setText(filter.getLastError()); return false; } } } + errorLabel.setText(""); return enabled; } @@ -280,6 +276,7 @@ class FileSearchPanel extends javax.swing.JPanel { filterPanel = new javax.swing.JPanel(); searchButton = new javax.swing.JButton(); + errorLabel = new javax.swing.JLabel(); setPreferredSize(new java.awt.Dimension(300, 300)); @@ -288,6 +285,14 @@ class FileSearchPanel extends javax.swing.JPanel { filterPanel.setLayout(new javax.swing.BoxLayout(filterPanel, javax.swing.BoxLayout.Y_AXIS)); searchButton.setText(org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.searchButton.text")); // NOI18N + searchButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + searchButtonActionPerformed(evt); + } + }); + + errorLabel.setForeground(new java.awt.Color(255, 51, 51)); + errorLabel.setText(org.openide.util.NbBundle.getMessage(FileSearchPanel.class, "FileSearchPanel.errorLabel.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -295,21 +300,31 @@ class FileSearchPanel extends javax.swing.JPanel { layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(filterPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addContainerGap() + .addComponent(errorLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(searchButton) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addComponent(filterPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGap(0, 0, 0) - .addComponent(searchButton) + .addComponent(filterPanel, javax.swing.GroupLayout.DEFAULT_SIZE, 266, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addComponent(searchButton) + .addGroup(layout.createSequentialGroup() + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(errorLabel))) .addContainerGap()) ); }// //GEN-END:initComponents + private void searchButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_searchButtonActionPerformed + search(); + }//GEN-LAST:event_searchButtonActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel errorLabel; private javax.swing.JPanel filterPanel; private javax.swing.JButton searchButton; // End of variables declaration//GEN-END:variables From 9f637c8be4fbf6089bc5b833248d7d95258fca29 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Fri, 27 Oct 2017 09:22:38 -0400 Subject: [PATCH 25/32] 2969: Verify the input data is valid from isValid() in the filter class --- .../autopsy/filesearch/DateSearchFilter.java | 48 ++++++------------- .../autopsy/filesearch/DateSearchPanel.java | 39 ++++++++++++++- .../autopsy/filesearch/FileSearchPanel.java | 1 - .../autopsy/filesearch/HashSearchFilter.java | 23 +++++++-- .../autopsy/filesearch/SizeSearchFilter.java | 35 ++++++-------- .../autopsy/filesearch/SizeSearchPanel.java | 20 ++++++++ 6 files changed, 106 insertions(+), 60 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java index 8cabb1e9cc..0f06839b50 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java @@ -40,12 +40,9 @@ import javax.swing.JSeparator; import javax.swing.ListCellRenderer; import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; -import javax.swing.event.CaretEvent; -import javax.swing.event.CaretListener; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.openide.util.NbBundle.Messages; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; /** * Filters file date properties (modified/created/etc.. times) @@ -207,41 +204,26 @@ class DateSearchFilter extends AbstractFileSearchFilter { @Override @Messages ({ - "End_Date_Before_Start_Date=The end date should be after the start date." + "End.date.before.start.date=The end date should be after the start date.", + "No.checkbox.selected=Non of the date search checkbox is selected." }) public boolean isValid() { - final DateSearchPanel panel = this.getComponent(); + DateSearchPanel panel = this.getComponent(); + Calendar startDate = getCalendarDate(panel.getDateFromTextField().getText()); + Calendar endDate = getCalendarDate(panel.getDateToTextField().getText()); - panel.getDateFromTextField().addCaretListener(new CaretListener() { - @Override - public void caretUpdate(CaretEvent ce) { - String startDateValue = panel.getDateFromTextField().getText(); - Calendar startDate = getCalendarDate(startDateValue); - String endDateValue = panel.getDateToTextField().getText(); - Calendar endDate = getCalendarDate(endDateValue); - - if (startDate != null && startDate.after(endDate)) { - MessageNotifyUtil.Message.warn(Bundle.End_Date_Before_Start_Date()); - } - } - }); + if ((startDate != null && startDate.after(endDate)) || (endDate != null && endDate.before(startDate))) { + setLastError(Bundle.End_date_before_start_date()); + return false; + } - panel.getDateToTextField().addCaretListener(new CaretListener() { - @Override - public void caretUpdate(CaretEvent ce) { - String startDateValue = panel.getDateFromTextField().getText(); - Calendar startDate = getCalendarDate(startDateValue); - String endDateValue = panel.getDateToTextField().getText(); - Calendar endDate = getCalendarDate(endDateValue); - - if (endDate != null && endDate.before(startDate)) { - MessageNotifyUtil.Message.warn(Bundle.End_Date_Before_Start_Date()); - } - } - }); - - return this.getComponent().isValidSearch(); + if (!panel.isValidSearch()) { + setLastError(Bundle.No_checkbox_selected()); + return false; + } + + return true; } /** diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java index b67f076c6d..b9f490041b 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchPanel.java @@ -20,8 +20,6 @@ package org.sleuthkit.autopsy.filesearch; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.awt.event.KeyAdapter; -import java.awt.event.KeyEvent; import java.text.DateFormat; import java.text.ParseException; import java.util.Date; @@ -31,6 +29,8 @@ import javax.swing.JComboBox; import javax.swing.JFormattedTextField; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; /** * Subpanel with controls for file data filtering. @@ -77,6 +77,41 @@ class DateSearchPanel extends javax.swing.JPanel { copyMenuItem.addActionListener(actList); pasteMenuItem.addActionListener(actList); selectAllMenuItem.addActionListener(actList); + this.dateFromTextField.getDocument().addDocumentListener(new DocumentListener() { + @Override + public void insertUpdate(DocumentEvent e) { + firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + } + + @Override + public void removeUpdate(DocumentEvent e) { + firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + } + + @Override + public void changedUpdate(DocumentEvent e) { + firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + } + }); + + this.dateToTextField.getDocument().addDocumentListener(new DocumentListener() { + @Override + public void insertUpdate(DocumentEvent e) { + firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + } + + @Override + public void removeUpdate(DocumentEvent e) { + firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + } + + @Override + public void changedUpdate(DocumentEvent e) { + firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + } + }); + + this.setComponentsEnabled(); } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java index 2a27be8297..f6c72df611 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/FileSearchPanel.java @@ -27,7 +27,6 @@ package org.sleuthkit.autopsy.filesearch; import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; -import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java index 6bbb732a16..c760ec8f52 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java @@ -19,8 +19,8 @@ package org.sleuthkit.autopsy.filesearch; import java.awt.event.ActionListener; -import javax.swing.JTextField; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.filesearch.FileSearchFilter.FilterValidationException; /** @@ -61,8 +61,25 @@ class HashSearchFilter extends AbstractFileSearchFilter { } @Override + @Messages({ + "Empty.hash=Hash data is empty.", + "# {0} - hash data length", "Wrong.length=Input lenght({0}), doesn't match the MD5 length(32).", + "Wrong.character=Input data is an invalid MD5 hex data." + }) public boolean isValid() { - JTextField inputHashData = this.getComponent().getSearchTextField(); - return !inputHashData.getText().isEmpty() || inputHashData.getText().length() == 32 || inputHashData.getText().matches("[0-9a-fA-F]+"); + String inputHashData = this.getComponent().getSearchTextField().getText(); + if (inputHashData.isEmpty()) { + setLastError(Bundle.Empty_hash()); + return false; + } + if (inputHashData.length() != 32) { + setLastError(Bundle.Wrong_length(inputHashData.length())); + return false; + } + if (!inputHashData.matches("[0-9a-fA-F]+")) { + setLastError(Bundle.Wrong_character()); + return false; + } + return true; } } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchFilter.java index d045f486c3..22643c6868 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchFilter.java @@ -19,12 +19,9 @@ package org.sleuthkit.autopsy.filesearch; import java.awt.event.ActionListener; -import javax.swing.InputVerifier; import javax.swing.JComboBox; -import javax.swing.JComponent; -import javax.swing.JFormattedTextField; import org.openide.util.NbBundle; -import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.filesearch.FileSearchFilter.FilterValidationException; /** @@ -78,27 +75,23 @@ class SizeSearchFilter extends AbstractFileSearchFilter { } @Override - @NbBundle.Messages ({ - "Non_Negative_Number=Please input a non negative number." + @Messages ({ + "Non.negative.number=Input size data is a negative number.", + "Not.a.number=Input size data is not a number." }) public boolean isValid() { - this.getComponent().getSizeTextField().setInputVerifier(new InputVerifier() { - @Override - public boolean verify(JComponent input) { - String inputText = ((JFormattedTextField) input).getText(); - try { - int inputInt = Integer.parseInt(inputText); - if (inputInt < 0) { - MessageNotifyUtil.Message.warn(Bundle.Non_Negative_Number()); - return false; - } - } catch (NumberFormatException | NullPointerException e) { - MessageNotifyUtil.Message.warn(Bundle.Non_Negative_Number()); + String input = this.getComponent().getSizeTextField().getText(); + + try { + int inputInt = Integer.parseInt(input); + if (inputInt < 0) { + setLastError(Bundle.Non_negative_number()); return false; } - return true; - } - }); + } catch (NumberFormatException | NullPointerException e) { + setLastError(Bundle.Not_a_number()); + return false; + } return true; } } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchPanel.java index 3add979247..51aa688619 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchPanel.java @@ -25,6 +25,8 @@ import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JFormattedTextField; import javax.swing.JMenuItem; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; /** * @@ -65,6 +67,24 @@ class SizeSearchPanel extends javax.swing.JPanel { copyMenuItem.addActionListener(actList); pasteMenuItem.addActionListener(actList); selectAllMenuItem.addActionListener(actList); + this.sizeTextField.getDocument().addDocumentListener(new DocumentListener() { + @Override + public void insertUpdate(DocumentEvent e) { + firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + } + + @Override + public void removeUpdate(DocumentEvent e) { + firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + } + + @Override + public void changedUpdate(DocumentEvent e) { + firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); + } + }); + + } From a9caa221410f7864be772ca4248c5963ad76a90b Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Fri, 27 Oct 2017 09:49:39 -0400 Subject: [PATCH 26/32] 2969: update the Messages by using classname.messeges format --- .../autopsy/filesearch/DateSearchFilter.java | 8 ++++---- .../autopsy/filesearch/HashSearchFilter.java | 12 ++++++------ .../autopsy/filesearch/SizeSearchFilter.java | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java index 0f06839b50..a8e9724342 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java @@ -204,8 +204,8 @@ class DateSearchFilter extends AbstractFileSearchFilter { @Override @Messages ({ - "End.date.before.start.date=The end date should be after the start date.", - "No.checkbox.selected=Non of the date search checkbox is selected." + "DateSearchFilter.endDateBeforeStartDate=The end date should be after the start date.", + "DateSearchFilter.noCheckboxSelected=Non of the date search checkbox is selected." }) public boolean isValid() { @@ -214,12 +214,12 @@ class DateSearchFilter extends AbstractFileSearchFilter { Calendar endDate = getCalendarDate(panel.getDateToTextField().getText()); if ((startDate != null && startDate.after(endDate)) || (endDate != null && endDate.before(startDate))) { - setLastError(Bundle.End_date_before_start_date()); + setLastError(Bundle.DateSearchFilter_endDateBeforeStartDate()); return false; } if (!panel.isValidSearch()) { - setLastError(Bundle.No_checkbox_selected()); + setLastError(Bundle.DateSearchFilter_noCheckboxSelected()); return false; } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java index c760ec8f52..61d39c8de3 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java @@ -62,22 +62,22 @@ class HashSearchFilter extends AbstractFileSearchFilter { @Override @Messages({ - "Empty.hash=Hash data is empty.", - "# {0} - hash data length", "Wrong.length=Input lenght({0}), doesn't match the MD5 length(32).", - "Wrong.character=Input data is an invalid MD5 hex data." + "HashSearchFilter.emptyHash=Hash data is empty.", + "# {0} - hash data length", "HashSearchFilter.wrongLength=Input lenght({0}), doesn't match the MD5 length(32).", + "HashSearchFilter.wrongCharacter=Input data is an invalid MD5 hex data." }) public boolean isValid() { String inputHashData = this.getComponent().getSearchTextField().getText(); if (inputHashData.isEmpty()) { - setLastError(Bundle.Empty_hash()); + setLastError(Bundle.HashSearchFilter_emptyHash()); return false; } if (inputHashData.length() != 32) { - setLastError(Bundle.Wrong_length(inputHashData.length())); + setLastError(Bundle.HashSearchFilter_wrongLength(inputHashData.length())); return false; } if (!inputHashData.matches("[0-9a-fA-F]+")) { - setLastError(Bundle.Wrong_character()); + setLastError(Bundle.HashSearchFilter_wrongCharacter()); return false; } return true; diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchFilter.java index 22643c6868..8377caf974 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchFilter.java @@ -76,8 +76,8 @@ class SizeSearchFilter extends AbstractFileSearchFilter { @Override @Messages ({ - "Non.negative.number=Input size data is a negative number.", - "Not.a.number=Input size data is not a number." + "SizeSearchFilter.nonNegativeNumber=Input size data is a negative number.", + "SizeSearchFilter.notANumber=Input size data is not a number." }) public boolean isValid() { String input = this.getComponent().getSizeTextField().getText(); @@ -85,11 +85,11 @@ class SizeSearchFilter extends AbstractFileSearchFilter { try { int inputInt = Integer.parseInt(input); if (inputInt < 0) { - setLastError(Bundle.Non_negative_number()); + setLastError(Bundle.SizeSearchFilter_nonNegativeNumber()); return false; } } catch (NumberFormatException | NullPointerException e) { - setLastError(Bundle.Not_a_number()); + setLastError(Bundle.SizeSearchFilter_notANumber()); return false; } return true; From 40a9b58ac65cd51b6270e5085e31e682274376b1 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Fri, 27 Oct 2017 09:56:41 -0400 Subject: [PATCH 27/32] 2969: Adding one more step as classname.errorMessage.message --- .../autopsy/filesearch/DateSearchFilter.java | 8 ++++---- .../autopsy/filesearch/HashSearchFilter.java | 12 ++++++------ .../autopsy/filesearch/SizeSearchFilter.java | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java index a8e9724342..3279a81f3e 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java @@ -204,8 +204,8 @@ class DateSearchFilter extends AbstractFileSearchFilter { @Override @Messages ({ - "DateSearchFilter.endDateBeforeStartDate=The end date should be after the start date.", - "DateSearchFilter.noCheckboxSelected=Non of the date search checkbox is selected." + "DateSearchFilter.errorMessage.endDateBeforeStartDate=The end date should be after the start date.", + "DateSearchFilter.errorMessage.noCheckboxSelected=Non of the date search checkbox is selected." }) public boolean isValid() { @@ -214,12 +214,12 @@ class DateSearchFilter extends AbstractFileSearchFilter { Calendar endDate = getCalendarDate(panel.getDateToTextField().getText()); if ((startDate != null && startDate.after(endDate)) || (endDate != null && endDate.before(startDate))) { - setLastError(Bundle.DateSearchFilter_endDateBeforeStartDate()); + setLastError(Bundle.DateSearchFilter_errorMessage_endDateBeforeStartDate()); return false; } if (!panel.isValidSearch()) { - setLastError(Bundle.DateSearchFilter_noCheckboxSelected()); + setLastError(Bundle.DateSearchFilter_errorMessage_noCheckboxSelected()); return false; } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java index 61d39c8de3..6204109372 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java @@ -62,22 +62,22 @@ class HashSearchFilter extends AbstractFileSearchFilter { @Override @Messages({ - "HashSearchFilter.emptyHash=Hash data is empty.", - "# {0} - hash data length", "HashSearchFilter.wrongLength=Input lenght({0}), doesn't match the MD5 length(32).", - "HashSearchFilter.wrongCharacter=Input data is an invalid MD5 hex data." + "HashSearchFilter.errorMessage.emptyHash=Hash data is empty.", + "# {0} - hash data length", "HashSearchFilter.errorMessage.wrongLength=Input lenght({0}), doesn't match the MD5 length(32).", + "HashSearchFilter.errorMessage.wrongCharacter=Input data is an invalid MD5 hex data." }) public boolean isValid() { String inputHashData = this.getComponent().getSearchTextField().getText(); if (inputHashData.isEmpty()) { - setLastError(Bundle.HashSearchFilter_emptyHash()); + setLastError(Bundle.HashSearchFilter_errorMessage_emptyHash()); return false; } if (inputHashData.length() != 32) { - setLastError(Bundle.HashSearchFilter_wrongLength(inputHashData.length())); + setLastError(Bundle.HashSearchFilter_errorMessage_wrongLength(inputHashData.length())); return false; } if (!inputHashData.matches("[0-9a-fA-F]+")) { - setLastError(Bundle.HashSearchFilter_wrongCharacter()); + setLastError(Bundle.HashSearchFilter_errorMessage_wrongCharacter()); return false; } return true; diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchFilter.java index 8377caf974..cf5d4f9e73 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchFilter.java @@ -76,8 +76,8 @@ class SizeSearchFilter extends AbstractFileSearchFilter { @Override @Messages ({ - "SizeSearchFilter.nonNegativeNumber=Input size data is a negative number.", - "SizeSearchFilter.notANumber=Input size data is not a number." + "SizeSearchFilter.errorMessage.nonNegativeNumber=Input size data is a negative number.", + "SizeSearchFilter.errorMessage.notANumber=Input size data is not a number." }) public boolean isValid() { String input = this.getComponent().getSizeTextField().getText(); @@ -85,11 +85,11 @@ class SizeSearchFilter extends AbstractFileSearchFilter { try { int inputInt = Integer.parseInt(input); if (inputInt < 0) { - setLastError(Bundle.SizeSearchFilter_nonNegativeNumber()); + setLastError(Bundle.SizeSearchFilter_errorMessage_nonNegativeNumber()); return false; } } catch (NumberFormatException | NullPointerException e) { - setLastError(Bundle.SizeSearchFilter_notANumber()); + setLastError(Bundle.SizeSearchFilter_errorMessage_notANumber()); return false; } return true; From 1fcc0caa6886976d06f7c79983630a1ae8740c8d Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Fri, 27 Oct 2017 11:36:59 -0400 Subject: [PATCH 28/32] 2969: Update the error message for no checkbox is selected error. --- Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java index 3279a81f3e..3291c5ae42 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/DateSearchFilter.java @@ -205,7 +205,7 @@ class DateSearchFilter extends AbstractFileSearchFilter { @Override @Messages ({ "DateSearchFilter.errorMessage.endDateBeforeStartDate=The end date should be after the start date.", - "DateSearchFilter.errorMessage.noCheckboxSelected=Non of the date search checkbox is selected." + "DateSearchFilter.errorMessage.noCheckboxSelected=At least one date type checkbox must be selected." }) public boolean isValid() { From 763c0fa03c610f92b99c288ed1e47a3d37eb42e6 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Fri, 27 Oct 2017 13:59:48 -0400 Subject: [PATCH 29/32] 2969: update MD5 error messages --- .../org/sleuthkit/autopsy/filesearch/HashSearchFilter.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java index 6204109372..e63fce305e 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java @@ -63,8 +63,8 @@ class HashSearchFilter extends AbstractFileSearchFilter { @Override @Messages({ "HashSearchFilter.errorMessage.emptyHash=Hash data is empty.", - "# {0} - hash data length", "HashSearchFilter.errorMessage.wrongLength=Input lenght({0}), doesn't match the MD5 length(32).", - "HashSearchFilter.errorMessage.wrongCharacter=Input data is an invalid MD5 hex data." + "# {0} - hash data length", "HashSearchFilter.errorMessage.wrongLength=Input lenght({0}), doesn''t match the MD5 length(32).", + "HashSearchFilter.errorMessage.wrongCharacter=MD5 contains invalid hex characters." }) public boolean isValid() { String inputHashData = this.getComponent().getSearchTextField().getText(); From 450faba4190ef3ec72f6462556fd88defa7986a3 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\dgrove" Date: Fri, 27 Oct 2017 17:57:56 -0400 Subject: [PATCH 30/32] Modified labels and titles for filters. --- Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java | 5 ++++- .../autopsy/modules/interestingitems/Bundle.properties | 4 +--- .../modules/interestingitems/FilesSetDefsPanel.java | 9 ++++++--- .../autopsy/modules/interestingitems/FilesSetPanel.java | 4 ++-- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java index 3110947488..249ded2020 100755 --- a/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/ProfilePanel.java @@ -33,7 +33,8 @@ import org.sleuthkit.autopsy.ingest.IngestProfiles.IngestProfile; */ class ProfilePanel extends IngestModuleGlobalSettingsPanel { - @NbBundle.Messages({"ProfilePanel.profileDescLabel.text=Description:", + @NbBundle.Messages({"ProfilePanel.title.text=Profile", + "ProfilePanel.profileDescLabel.text=Description:", "ProfilePanel.profileNameLabel.text=Profile Name:", "ProfilePanel.newProfileText=NewEmptyProfile", "ProfilePanel.messages.profilesMustBeNamed=Ingest profile must be named.", @@ -50,6 +51,7 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel { */ ProfilePanel() { initComponents(); + setName(org.openide.util.NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.title.text")); settings = new IngestJobSettings(NEW_PROFILE_NAME); ingestSettingsPanel = new IngestJobSettingsPanel(settings); ingestSettingsPanel.setPastJobsButtonVisible(false); @@ -59,6 +61,7 @@ class ProfilePanel extends IngestModuleGlobalSettingsPanel { ProfilePanel(IngestProfile selectedProfile) { initComponents(); + setName(org.openide.util.NbBundle.getMessage(ProfilePanel.class, "ProfilePanel.title.text")); profile = selectedProfile; profileDescArea.setText(profile.getDescription()); profileNameField.setText(profile.getName()); diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties index df63e98d2e..f38bcbc815 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/Bundle.properties @@ -4,8 +4,6 @@ OpenIDE-Module-Short-Description=Interesting Files Identifier ingest module. OpenIDE-Module-Name=Interesting Files Identifier OptionsCategory_Name_InterestingItemDefinitions=Interesting Files OptionsCategory_Keywords_InterestingItemDefinitions=InterestingItemDefinitions -OptionsCategory_Name_FileIngestFilterDefinitions=File Ingest Filter -OptionsCategory_Keywords_FileIngestFilterDefinitions=FileIngestFilterDefinitions InterestingItemsIdentifierIngestModule.moduleName=Interesting Files Identifier InterestingItemsIdentifierIngestModule.moduleDescription=Identifies interesting items as defined by interesting item rule sets. FilesSetPanel.interesting.title=Interesting Files Set @@ -45,7 +43,7 @@ FilesSetRulePanel.fileSizeCheck.text=File Size: FilesSetRulePanel.filesRadioButton.text=Files FilesSetRulePanel.dirsRadioButton.text=Directories FilesSetDefsPanel.interesting.setsListLabel.text=Rule Sets: -FilesSetDefsPanel.ingest.setsListLabel.text=File Ingest Filters: +FilesSetDefsPanel.ingest.setsListLabel.text=File Filters: FilesSetDefsPanel.interesting.jTextArea1.text=This module allows you to find files that match specified criteria. Each set has a list of rules, which will match on their chosen file characteristics. A file need only match one rule to be found. FilesSetDefsPanel.ingest.jTextArea1.text=Add rules so that only a subset of the files in a data source are analyzed. Rules are organized into sets and only one set can be used at a time. A file need only match one rule to be analyzed. FilesSetDefsPanel.interesting.editSetButton.text=Edit Set diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java index f989d24971..c67051be97 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetDefsPanel.java @@ -77,6 +77,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp private final JButton okButton = new JButton("OK"); private final JButton cancelButton = new JButton("Cancel"); private final PANEL_TYPE panelType; + private final String filterDialogTitle; private final String ruleDialogTitle; private boolean canBeEnabled = true; @@ -109,7 +110,8 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp this.jLabel7.setVisible(false); this.fileSizeUnitComboBox.setVisible(false); this.fileSizeSpinner.setVisible(false); - this.ruleDialogTitle = "FilesSetPanel.ingest.title"; + this.filterDialogTitle = "FilesSetPanel.filter.title"; + this.ruleDialogTitle = "FilesSetPanel.rule.title"; this.jLabel8.setVisible(false); this.equalitySignComboBox.setVisible(false); this.ignoreKnownFilesCheckbox.setVisible(false); @@ -124,13 +126,14 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp org.openide.awt.Mnemonics.setLocalizedText(deleteSetButton, org.openide.util.NbBundle.getMessage(FilesSetDefsPanel.class, "FilesSetDefsPanel.ingest.deleteSetButton.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(jLabel6, org.openide.util.NbBundle.getMessage(FilesSetDefsPanel.class, "FilesSetDefsPanel.ingest.jLabel6.text")); // NOI18N } else { + this.filterDialogTitle = "FilesSetPanel.interesting.title"; this.ruleDialogTitle = "FilesSetPanel.interesting.title"; this.ingoreUnallocCheckbox.setVisible(false); } } @NbBundle.Messages({"FilesSetDefsPanel.Interesting.Title=Global Interesting Items Settings", - "FilesSetDefsPanel.Ingest.Title=File Ingest Filter Settings"}) + "FilesSetDefsPanel.Ingest.Title=File Filter Settings"}) private void customInit() { if (panelType == PANEL_TYPE.FILE_INGEST_FILTERS) { setName(Bundle.FilesSetDefsPanel_Ingest_Title()); @@ -408,7 +411,7 @@ public final class FilesSetDefsPanel extends IngestModuleGlobalSettingsPanel imp // feedback when isValidDefinition() is called. int option = JOptionPane.OK_OPTION; do { - option = JOptionPane.showConfirmDialog(null, panel, NbBundle.getMessage(FilesSetPanel.class, ruleDialogTitle), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); + option = JOptionPane.showConfirmDialog(null, panel, NbBundle.getMessage(FilesSetPanel.class, filterDialogTitle), JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); } while (option == JOptionPane.OK_OPTION && !panel.isValidDefinition()); // While adding new ruleset(selectedSet == null), if rule set with same name already exists, do not add to the filesSets hashMap. diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetPanel.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetPanel.java index 962c18c8e1..51539b5806 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesSetPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2014-2016 Basis Technology Corp. + * Copyright 2014-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,7 +29,7 @@ import org.sleuthkit.autopsy.modules.interestingitems.FilesSetDefsPanel.PANEL_TY */ public class FilesSetPanel extends javax.swing.JPanel { - @NbBundle.Messages({"FilesSetPanel.ingest.title=File Ingest Filter", "FilesSetPanel.ingest.createNewFilter=Create/edit file ingest filters...", "FilesSetPanel.ingest.messages.filtersMustBeNamed=File ingest filters must be named."}) + @NbBundle.Messages({"FilesSetPanel.filter.title=File Filter", "FilesSetPanel.rule.title=File Filter Rule", "FilesSetPanel.ingest.createNewFilter=Create/edit file ingest filters...", "FilesSetPanel.ingest.messages.filtersMustBeNamed=File ingest filters must be named."}) private static final String CREATE_NEW_FILE_INGEST_FILTER = Bundle.FilesSetPanel_ingest_createNewFilter(); private final String mustBeNamedErrorText; From 33fdb5899938a6f951c21a3c6a022e6e29f2ec98 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Mon, 30 Oct 2017 11:15:44 -0400 Subject: [PATCH 31/32] 2969: Add validation messages for Name, MIME type and known status --- .../autopsy/filesearch/KnownStatusSearchFilter.java | 10 +++++++++- .../sleuthkit/autopsy/filesearch/MimeTypeFilter.java | 10 +++++++++- .../sleuthkit/autopsy/filesearch/NameSearchFilter.java | 10 +++++++++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java index 5f52afa035..677f0116e9 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.filesearch; import java.awt.event.ActionListener; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.datamodel.TskData.FileKnown; /** @@ -85,7 +86,14 @@ class KnownStatusSearchFilter extends AbstractFileSearchFilter { } @Override + @Messages ({ + "MimeTypeFilter.errorMessage.emptyMimeType=At least one MIME type must be selected." + }) public boolean isValid() { - return !this.getComponent().getMimeTypesSelected().isEmpty(); + if(this.getComponent().getMimeTypesSelected().isEmpty()){ + setLastError(Bundle.MimeTypeFilter_errorMessage_emptyMimeType()); + return false; + } + return true; } } diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchFilter.java index ee70ebd5e1..2b204c8ca8 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchFilter.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.filesearch; import java.awt.event.ActionListener; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.filesearch.FileSearchFilter.FilterValidationException; /** @@ -64,7 +65,14 @@ class NameSearchFilter extends AbstractFileSearchFilter { } @Override + @Messages ({ + "NameSearchFilter.errorMessage.emtpyName=Please input a name to search." + }) public boolean isValid() { - return !this.getComponent().getSearchTextField().getText().isEmpty(); + if(this.getComponent().getSearchTextField().getText().isEmpty()) { + setLastError(Bundle.NameSearchFilter_errorMessage_emtpyName()); + return false; + } + return true; } } From adc3f3e635fbbcfec9187bed17d63ae15e78cf49 Mon Sep 17 00:00:00 2001 From: "U-BASIS\\zhaohui" Date: Mon, 30 Oct 2017 15:44:43 -0400 Subject: [PATCH 32/32] 2969. fix typo --- Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java index e63fce305e..d77fe5826e 100755 --- a/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/HashSearchFilter.java @@ -63,7 +63,7 @@ class HashSearchFilter extends AbstractFileSearchFilter { @Override @Messages({ "HashSearchFilter.errorMessage.emptyHash=Hash data is empty.", - "# {0} - hash data length", "HashSearchFilter.errorMessage.wrongLength=Input lenght({0}), doesn''t match the MD5 length(32).", + "# {0} - hash data length", "HashSearchFilter.errorMessage.wrongLength=Input length({0}), doesn''t match the MD5 length(32).", "HashSearchFilter.errorMessage.wrongCharacter=MD5 contains invalid hex characters." }) public boolean isValid() {