diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java index c4fe110c9e94faeb0d0d45b51dd83b6b16cf006e..53822532bb777ad5c04959faae48b373408510af 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypes.java @@ -74,6 +74,7 @@ public final class FileTypes implements AutopsyVisitableItem { FileTypes(SleuthkitCase skCase) { this.skCase = skCase; + updateShowCounts(); } @Override diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java index f8323c89b8b9454da8b8c503254943d626a32a5d..e5bd41b6e8ddbd49046e6b5144b0f188d2b9b1f2 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByMimeType.java @@ -149,9 +149,10 @@ private void populateHashMap() { this.typesRoot = typesRoot; this.pcl = (PropertyChangeEvent evt) -> { String eventType = evt.getPropertyName(); - if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) - || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())) { - + if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString()) + || eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString()) + || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString()) + || eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) { /** * Checking for a current case is a stop gap measure until a * different way of handling the closing of cases is worked out. @@ -160,7 +161,7 @@ private void populateHashMap() { */ try { Case.getCurrentCase(); - typesRoot.updateShowCounts(); + typesRoot.updateShowCounts(); populateHashMap(); } catch (IllegalStateException notUsed) { /** @@ -285,9 +286,9 @@ class MediaTypeNode extends DisplayableItemNode { @NbBundle.Messages({"FileTypesByMimeTypeNode.createSheet.mediaType.name=Type", "FileTypesByMimeTypeNode.createSheet.mediaType.displayName=Type", "FileTypesByMimeTypeNode.createSheet.mediaType.desc=no description"}) - + MediaTypeNode(String name) { - super(Children.create(new MediaTypeNodeChildren(name), true), Lookups.singleton(name)); + super(Children.create(new MediaTypeNodeChildren(name), true), Lookups.singleton(name)); setName(name); setDisplayName(name); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); @@ -360,6 +361,7 @@ public void update(Observable o, Object arg) { * media subtype is the portion of the MIME type following the /. */ class MediaSubTypeNode extends FileTypes.BGCountUpdatingNode { + @NbBundle.Messages({"FileTypesByMimeTypeNode.createSheet.mediaSubtype.name=Subtype", "FileTypesByMimeTypeNode.createSheet.mediaSubtype.displayName=Subtype", "FileTypesByMimeTypeNode.createSheet.mediaSubtype.desc=no description"}) @@ -392,7 +394,8 @@ public boolean isLeafTypeNode() { public <T> T accept(DisplayableItemNodeVisitor< T> v) { return v.visit(this); } - @Override + + @Override protected Sheet createSheet() { Sheet s = super.createSheet(); Sheet.Set ss = s.get(Sheet.PROPERTIES); diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchPanel.form b/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchPanel.form index 2dfc5af1c30cb73002a693dedf62c257ef868bfb..b06f6d4c17287d32a22b9046f8fecee5f69b6a45 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchPanel.form +++ b/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchPanel.form @@ -109,9 +109,6 @@ <ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="NameSearchPanel.searchTextField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/> </Property> </Properties> - <Events> - <EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="searchTextFieldMouseClicked"/> - </Events> </Component> <Component class="javax.swing.JLabel" name="noteNameLabel"> <Properties> diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchPanel.java index 7e4d902e00d15a4126519d280cb6a87ba5e68c91..cf197c4e00dac97c16c2d6744bc87941f6466f3c 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/NameSearchPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier <at> sleuthkit <dot> org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,7 +26,6 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.beans.PropertyChangeListener; import javax.swing.JCheckBox; import javax.swing.JMenuItem; import javax.swing.JTextField; @@ -39,6 +38,8 @@ */ class NameSearchPanel extends javax.swing.JPanel { + private static final long serialVersionUID = 1L; + /** * Creates new form NameSearchPanel */ @@ -143,11 +144,6 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { searchTextField.setFont(searchTextField.getFont().deriveFont(searchTextField.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); searchTextField.setText(org.openide.util.NbBundle.getMessage(NameSearchPanel.class, "NameSearchPanel.searchTextField.text")); // NOI18N - searchTextField.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseClicked(java.awt.event.MouseEvent evt) { - searchTextFieldMouseClicked(evt); - } - }); noteNameLabel.setFont(noteNameLabel.getFont().deriveFont(noteNameLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 10)); noteNameLabel.setText(org.openide.util.NbBundle.getMessage(NameSearchPanel.class, "NameSearchPanel.noteNameLabel.text")); // NOI18N @@ -181,10 +177,6 @@ public void mouseClicked(java.awt.event.MouseEvent evt) { ); }// </editor-fold>//GEN-END:initComponents - private void searchTextFieldMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_searchTextFieldMouseClicked - - this.nameCheckBox.setSelected(true); }//GEN-LAST:event_searchTextFieldMouseClicked - private void nameCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nameCheckBoxActionPerformed setComponentsEnabled(); firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchPanel.form b/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchPanel.form index 7987a8a031bab5f37d373bc911ff58e09e3c0f18..dcdab6f80249d36cd5cd105d0969b100e908a9cd 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchPanel.form +++ b/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchPanel.form @@ -93,9 +93,6 @@ <Connection code="0" type="code"/> </Property> </Properties> - <Events> - <EventHandler event="mouseClicked" listener="java.awt.event.MouseListener" parameters="java.awt.event.MouseEvent" handler="sizeTextFieldMouseClicked"/> - </Events> <AuxValues> <AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new JFormattedTextField(NumberFormat.getIntegerInstance())"/> </AuxValues> diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchPanel.java index 5e508744c7b9021ce9aca03bb8b3b71d4f55fe1d..3add97924791b4130bcfa84fdd938040e7eb6a01 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/SizeSearchPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011-2017 Basis Technology Corp. * Contact: carrier <at> sleuthkit <dot> org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,6 +32,8 @@ */ class SizeSearchPanel extends javax.swing.JPanel { + private static final long serialVersionUID = 1L; + /** * Creates new form SizeSearchPanel */ @@ -123,11 +125,6 @@ private void initComponents() { sizeUnitComboBox.setModel(new javax.swing.DefaultComboBoxModel<String>(new String[] { "Byte(s)", "KB", "MB", "GB", "TB" })); sizeTextField.setValue(0); - sizeTextField.addMouseListener(new java.awt.event.MouseAdapter() { - public void mouseClicked(java.awt.event.MouseEvent evt) { - sizeTextFieldMouseClicked(evt); - } - }); sizeCompareComboBox.setModel(new javax.swing.DefaultComboBoxModel<String>(new String[] { "equal to", "greater than", "less than" })); @@ -161,11 +158,6 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { ); }// </editor-fold>//GEN-END:initComponents - private void sizeTextFieldMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_sizeTextFieldMouseClicked - this.sizeCheckBox.setSelected(true); - this.sizeTextField.selectAll(); // select all so user can change it easily - }//GEN-LAST:event_sizeTextFieldMouseClicked - private void sizeCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_sizeCheckBoxActionPerformed setComponentsEnabled(); firePropertyChange(FileSearchPanel.EVENT.CHECKED.toString(), null, null); diff --git a/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java b/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java index f1cad5531c25d52248fa6fc67cb1bd88e183f369..771380c415104df58e1bc78660bf0f1fa8ba2180 100644 --- a/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/ingest/IngestMonitor.java @@ -36,7 +36,7 @@ /** * Monitors disk space and memory and cancels ingest if disk space runs low. * <p> - * Note: This should be a singleton and currrently is used as such, with the + * Note: This should be a singleton and currently is used as such, with the * only instance residing in the IngestManager class. */ public final class IngestMonitor { @@ -191,6 +191,7 @@ public void actionPerformed(ActionEvent e) { } logMemoryUsage(); + logDiskSpaceUsage(); if (!enoughDiskSpace()) { /* @@ -212,6 +213,14 @@ public void actionPerformed(ActionEvent e) { private void logMemoryUsage() { MONITOR_LOGGER.log(Level.INFO, PlatformUtil.getAllMemUsageInfo()); } + + /** + * Writes current disk space usage of the drive where case dir resides to log. + */ + private void logDiskSpaceUsage() { + final long freeSpace = root.getFreeSpace(); + logger.log(Level.INFO, "Available disk space on drive where case dir resides is {0} (bytes)", freeSpace); //NON-NLS + } /** * Determines whether there is enough disk space to continue running @@ -242,18 +251,20 @@ private boolean enoughDiskSpace() { * @return free space in bytes */ private long getFreeSpace() throws SecurityException { + // always return "UNKNOWN", see note below + return DISK_FREE_SPACE_UNKNOWN; + + /* NOTE: use and accuracy of this code for network drives needs to be investigated and validated final long freeSpace = root.getFreeSpace(); if (0 == freeSpace) { - /* - * Check for a network drive, some network filesystems always - * return zero. - */ + // Check for a network drive, some network filesystems always + // return zero. final String monitoredPath = root.getAbsolutePath(); if (monitoredPath.startsWith("\\\\") || monitoredPath.startsWith("//")) { return DISK_FREE_SPACE_UNKNOWN; } } - return freeSpace; + return freeSpace;*/ } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseManager.java index 1b95cd87bebf41c2186b2882038c6a0376b79cb9..0be466fe4b1a6f494db1ee54e42ced39e6cd4b71 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseManager.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestCaseManager.java @@ -60,11 +60,6 @@ synchronized static AutoIngestCaseManager getInstance() { * auto ingest. */ private AutoIngestCaseManager() { - /* - * Disable the new case action because review mode is only for looking - * at cases created by automated ingest. - */ - CallableSystemAction.get(CaseNewAction.class).setEnabled(false); /* * Permanently delete the "Open Recent Cases" item in the "File" menu. @@ -108,16 +103,5 @@ synchronized void openCase(Path caseMetadataFilePath) throws CaseActionException * Open the case. */ Case.openAsCurrentCase(caseMetadataFilePath.toString()); - - /** - * Disable the add data source action in auto ingest examiner mode. This - * has to be done here because Case.open() calls Case.doCaseChange() and - * the latter method enables the action. Since Case.doCaseChange() - * enables the menus on EDT by calling SwingUtilities.invokeLater(), we - * have to do the same thing here to maintain the order of execution. - */ - SwingUtilities.invokeLater(() -> { - CallableSystemAction.get(AddImageAction.class).setEnabled(false); - }); } } diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestUserPreferences.java b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestUserPreferences.java index e5548f250ecacd351bfd5c51d290f00315f3d73a..f98eb1a9091687ae8fcec42c96c99de0a7c045c7 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestUserPreferences.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/AutoIngestUserPreferences.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2015 Basis Technology Corp. + * Copyright 2017 Basis Technology Corp. * Contact: carrier <at> sleuthkit <dot> org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -44,6 +44,7 @@ public final class AutoIngestUserPreferences { private static final String SLEEP_BETWEEN_CASES_TIME = "SleepBetweenCasesTime"; // NON-NLS private static final String SHOW_TOOLS_WARNING = "ShowToolsWarning"; // NON-NLS private static final String MAX_NUM_TIMES_TO_PROCESS_IMAGE = "MaxNumTimesToAttemptToProcessImage"; // NON-NLS + private static final int DEFAULT_MAX_TIMES_TO_PROCESS_IMAGE = 0; private static final String MAX_CONCURRENT_NODES_FOR_ONE_CASE = "MaxConcurrentNodesForOneCase"; // NON-NLS private static final String STATUS_DATABASE_LOGGING_ENABLED = "StatusDatabaseLoggingEnabled"; // NON-NLS private static final String LOGGING_DB_HOSTNAME_OR_IP = "LoggingHostnameOrIP"; // NON-NLS @@ -246,13 +247,13 @@ public static void setSecondsToSleepBetweenCases(int value) { * is used to avoid endless attempts to process an image folder with corrupt * data that causes a crash. * - * @return int maximum number of attempts, default is 2. + * @return int maximum number of attempts, default is 0. */ public static int getMaxNumTimesToProcessImage() { if (ModuleSettings.settingExists(UserPreferences.SETTINGS_PROPERTIES, MAX_NUM_TIMES_TO_PROCESS_IMAGE)) { return Integer.parseInt(ModuleSettings.getConfigSetting(UserPreferences.SETTINGS_PROPERTIES, MAX_NUM_TIMES_TO_PROCESS_IMAGE)); } - return 2; + return DEFAULT_MAX_TIMES_TO_PROCESS_IMAGE; } /** diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/StartupWindow.java b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/StartupWindow.java index a9a6a0d269d6e85d9ed0d963cac1f5f95ea52f56..5e038d1ae220d45ae2bf61a714ea9743c0d04251 100644 --- a/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/StartupWindow.java +++ b/Experimental/src/org/sleuthkit/autopsy/experimental/configuration/StartupWindow.java @@ -83,7 +83,6 @@ private void init() { public void open() { if (caseManagementPanel != null) { - caseManagementPanel.updateView(); caseManagementPanel.setCursor(Cursor.getDefaultCursor()); } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java index 983433256714560a863adf3720c140a4f1fec68e..45205b0ca725f548849e3a565656307c17c2f712 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/RegexQuery.java @@ -206,8 +206,8 @@ public QueryResults performQuery() throws NoOpenCoreException { for (KeywordHit hit : keywordHits) { hitsMultiMap.put(new Keyword(hit.getHit(), true, true, originalKeyword.getListName(), originalKeyword.getOriginalTerm()), hit); } - } catch (TskException ex) { - // + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Error creating keyword hits", ex); //NON-NLS } } @@ -228,7 +228,7 @@ public QueryResults performQuery() throws NoOpenCoreException { return results; } - private List<KeywordHit> createKeywordHits(SolrDocument solrDoc) throws TskException { + private List<KeywordHit> createKeywordHits(SolrDocument solrDoc) throws TskCoreException { List<KeywordHit> hits = new ArrayList<>(); final String docId = solrDoc.getFieldValue(Server.Schema.ID.toString()).toString(); @@ -237,83 +237,93 @@ private List<KeywordHit> createKeywordHits(SolrDocument solrDoc) throws TskExcep final Collection<Object> content_str = solrDoc.getFieldValues(Server.Schema.CONTENT_STR.toString()); final Pattern pattern = Pattern.compile(keywordString); - for (Object content_obj : content_str) { - String content = (String) content_obj; - Matcher hitMatcher = pattern.matcher(content); - int offset = 0; - - while (hitMatcher.find(offset)) { - StringBuilder snippet = new StringBuilder(); - - // If the location of the hit is beyond this chunk (i.e. it - // exists in the overlap region), we skip the hit. It will - // show up again as a hit in the chunk following this one. - if (chunkSize != null && hitMatcher.start() >= chunkSize) { - break; - } + try { + for (Object content_obj : content_str) { + String content = (String) content_obj; + Matcher hitMatcher = pattern.matcher(content); + int offset = 0; + + while (hitMatcher.find(offset)) { + StringBuilder snippet = new StringBuilder(); + + // If the location of the hit is beyond this chunk (i.e. it + // exists in the overlap region), we skip the hit. It will + // show up again as a hit in the chunk following this one. + if (chunkSize != null && hitMatcher.start() >= chunkSize) { + break; + } - String hit = hitMatcher.group(); - - offset = hitMatcher.end(); - - // We attempt to reduce false positives for phone numbers and IP address hits - // by querying Solr for hits delimited by a set of known boundary characters. - // See KeywordSearchList.PHONE_NUMBER_REGEX for an example. - // Because of this the hits may contain an extra character at the beginning or end that - // needs to be chopped off, unless the user has supplied their own wildcard suffix - // as part of the regex. - if (!queryStringContainsWildcardSuffix - && (originalKeyword.getArtifactAttributeType() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER - || originalKeyword.getArtifactAttributeType() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IP_ADDRESS)) { - if (originalKeyword.getArtifactAttributeType() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER) { - // For phone numbers replace all non numeric characters (except "(") at the start of the hit. - hit = hit.replaceAll("^[^0-9\\(]", ""); - } else { - // Replace all non numeric characters at the start of the hit. - hit = hit.replaceAll("^[^0-9]", ""); + String hit = hitMatcher.group(); + + offset = hitMatcher.end(); + + // We attempt to reduce false positives for phone numbers and IP address hits + // by querying Solr for hits delimited by a set of known boundary characters. + // See KeywordSearchList.PHONE_NUMBER_REGEX for an example. + // Because of this the hits may contain an extra character at the beginning or end that + // needs to be chopped off, unless the user has supplied their own wildcard suffix + // as part of the regex. + if (!queryStringContainsWildcardSuffix + && (originalKeyword.getArtifactAttributeType() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER + || originalKeyword.getArtifactAttributeType() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_IP_ADDRESS)) { + if (originalKeyword.getArtifactAttributeType() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER) { + // For phone numbers replace all non numeric characters (except "(") at the start of the hit. + hit = hit.replaceAll("^[^0-9\\(]", ""); + } else { + // Replace all non numeric characters at the start of the hit. + hit = hit.replaceAll("^[^0-9]", ""); + } + // Replace all non numeric at the end of the hit. + hit = hit.replaceAll("[^0-9]$", ""); } - // Replace all non numeric at the end of the hit. - hit = hit.replaceAll("[^0-9]$", ""); - } - if (originalKeyword.getArtifactAttributeType() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL) { - // Reduce false positives by eliminating email address hits that are either - // too short or are not for valid top level domains. - if (hit.length() < MIN_EMAIL_ADDR_LENGTH - || !DomainValidator.getInstance(true).isValidTld(hit.substring(hit.lastIndexOf('.')))) { - continue; + if (originalKeyword.getArtifactAttributeType() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL) { + // Reduce false positives by eliminating email address hits that are either + // too short or are not for valid top level domains. + if (hit.length() < MIN_EMAIL_ADDR_LENGTH + || !DomainValidator.getInstance(true).isValidTld(hit.substring(hit.lastIndexOf('.')))) { + continue; + } } - } - /* + /* * If searching for credit card account numbers, do a Luhn check * on the term and discard it if it does not pass. - */ - if (originalKeyword.getArtifactAttributeType() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER) { - Matcher ccnMatcher = CREDIT_CARD_NUM_PATTERN.matcher(hit); - if (ccnMatcher.find()) { - final String ccn = CharMatcher.anyOf(" -").removeFrom(ccnMatcher.group("ccn")); - if (false == TermsComponentQuery.CREDIT_CARD_NUM_LUHN_CHECK.isValid(ccn)) { + */ + if (originalKeyword.getArtifactAttributeType() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CARD_NUMBER) { + Matcher ccnMatcher = CREDIT_CARD_NUM_PATTERN.matcher(hit); + if (ccnMatcher.find()) { + final String ccn = CharMatcher.anyOf(" -").removeFrom(ccnMatcher.group("ccn")); + if (false == TermsComponentQuery.CREDIT_CARD_NUM_LUHN_CHECK.isValid(ccn)) { + continue; + } + } else { continue; } - } else { - continue; } - } - /** - * Get the snippet from the document if keyword search is - * configured to use snippets. - */ - int maxIndex = content.length() - 1; - snippet.append(content.substring(Integer.max(0, hitMatcher.start() - 20), Integer.max(0, hitMatcher.start()))); - snippet.appendCodePoint(171); - snippet.append(hit); - snippet.appendCodePoint(171); - snippet.append(content.substring(Integer.min(maxIndex, hitMatcher.end()), Integer.min(maxIndex, hitMatcher.end() + 20))); - - hits.add(new KeywordHit(docId, snippet.toString(), hit)); + /** + * Get the snippet from the document if keyword search is + * configured to use snippets. + */ + int maxIndex = content.length() - 1; + snippet.append(content.substring(Integer.max(0, hitMatcher.start() - 20), Integer.max(0, hitMatcher.start()))); + snippet.appendCodePoint(171); + snippet.append(hit); + snippet.appendCodePoint(171); + snippet.append(content.substring(Integer.min(maxIndex, hitMatcher.end()), Integer.min(maxIndex, hitMatcher.end() + 20))); + + hits.add(new KeywordHit(docId, snippet.toString(), hit)); + } } + } catch (TskCoreException ex) { + throw ex; + } catch (Throwable error) { + /* NOTE: Matcher.find() is known to throw StackOverflowError in rare cases (see JIRA-2700). + StackOverflowError is an error, not an exception, and therefore needs to be caught + as a Throwable. When this occurs we should re-throw the error as TskCoreException so that it is + logged by the calling method and move on to the next Solr document. */ + throw new TskCoreException("Failed to create keyword hits for Solr document id " + docId + " due to " + error.getMessage()); } return hits; } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SolrSearchService.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SolrSearchService.java index 0a765bc04aeb1d620ea873e43ddbda345c68f168..79174ba134aa5a6edeac6a96025d104532db161a 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SolrSearchService.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/SolrSearchService.java @@ -30,6 +30,7 @@ import javax.swing.JOptionPane; import javax.swing.SwingUtilities; import org.apache.commons.lang.math.NumberUtils; +import org.apache.commons.io.FileUtils; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.impl.HttpSolrServer; import org.openide.util.NbBundle; @@ -61,6 +62,8 @@ public class SolrSearchService implements KeywordSearchService, AutopsyService { private static final String BAD_IP_ADDRESS_FORMAT = "ioexception occurred when talking to server"; //NON-NLS private static final String SERVER_REFUSED_CONNECTION = "server refused connection"; //NON-NLS private static final int IS_REACHABLE_TIMEOUT_MS = 1000; + private static final int LARGE_INDEX_SIZE_GB = 50; + private static final int GIANT_INDEX_SIZE_GB = 500; private static final Logger logger = Logger.getLogger(SolrSearchService.class.getName()); /** @@ -198,9 +201,8 @@ public String getServiceName() { * Creates/opens the Solr core/text index for a case * * @param context The case context. - * * @throws - * org.sleuthkit.autopsy.framework.AutopsyService.AutopsyServiceException + * org.sleuthkit.autopsy.appservices.AutopsyService.AutopsyServiceException */ @Override @NbBundle.Messages({ @@ -211,6 +213,8 @@ public String getServiceName() { "SolrSearch.checkingForLatestIndex.msg=Looking for text index with latest Solr and schema version", "SolrSearch.indentifyingIndex.msg=Identifying text index to use", "SolrSearch.openCore.msg=Opening text index", + "SolrSearch.openLargeCore.msg=Opening text index. This may take several minutes.", + "SolrSearch.openGiantCore.msg=Opening text index. Text index for this case is very large and may take long time to load.", "SolrSearch.complete.msg=Text index successfully opened"}) public void openCaseResources(CaseContext context) throws AutopsyServiceException { if (context.cancelRequested()) { @@ -322,7 +326,17 @@ public void openCaseResources(CaseContext context) throws AutopsyServiceExceptio // open core try { - progress.progress(Bundle.SolrSearch_openCore_msg(), totalNumProgressUnits - 1); + // check text index size to gauge estimated time to open/load the index + long indexSizeInBytes = FileUtils.sizeOfDirectory(new File(currentVersionIndex.getIndexPath())); + long sizeInGb = indexSizeInBytes / 1000000000; + if (sizeInGb < LARGE_INDEX_SIZE_GB) { + progress.progress(Bundle.SolrSearch_openCore_msg(), totalNumProgressUnits - 1); + } else if (sizeInGb >= LARGE_INDEX_SIZE_GB && sizeInGb < GIANT_INDEX_SIZE_GB) { + progress.switchToIndeterminate(Bundle.SolrSearch_openLargeCore_msg()); + } else { + progress.switchToIndeterminate(Bundle.SolrSearch_openGiantCore_msg()); + } + KeywordSearch.getServer().openCoreForCase(theCase, currentVersionIndex); } catch (KeywordSearchModuleException ex) { throw new AutopsyServiceException(String.format("Failed to open or create core for %s", caseDirPath), ex); @@ -332,11 +346,11 @@ public void openCaseResources(CaseContext context) throws AutopsyServiceExceptio } /** + * Closes the open core. * * @param context - * * @throws - * org.sleuthkit.autopsy.framework.AutopsyService.AutopsyServiceException + * org.sleuthkit.autopsy.appservices.AutopsyService.AutopsyServiceException */ @Override public void closeCaseResources(CaseContext context) throws AutopsyServiceException { diff --git a/NEWS.txt b/NEWS.txt index 351a8f2d9ff8e2c65a3ac49affa210581d6109af..2f24eede9e6868cd501aa450bb758ac5f6d4858b 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -1,4 +1,9 @@ ---------------- VERSION 4.4.1 -------------- +- A new central repository feature has been added to the optional +CentralRepository plug-in (NetBeans module); this optional feature includes a +database (SQLite or PostgreSQL) and logic for correlating artifacts across +cases; results are displayed using an Interesting Artifacts branch of the +Interesting Items tree and an Other Data Sources content viewer. - Case deletion is now done using a Case menu item and both single-user and general (not auto ingest) multi-user cases can be deleted. - Results viewer (top right area of desktop application) sorts are persistent @@ -6,12 +11,8 @@ and can be applied to either the table viewer or the thumbnail viewer. - Content viewers (bottom right area of desktop application) now resize correctly. - The View Source File in Directory context menu item now works correctly. -- Tagged image files in the HTML report are now displayed full-size. -- A new central repository feature has been added to the optional -CentralRepository plug-in (NetBeans module; this optional feature includes a -database (SQLite or PostgreSQL) and logic for correlating artifacts across -cases; results are displayed using an Interesting Artifacts branch of the -Interesting Items tree and an Other Data Sources content viewer. +- Tagged image files in the HTML report are now displayed full-size. +- Some general UI responsiveness issues have been addressed. - Some potential deadlocks during ingest have been eliminated. - Assorted small enhancements and bug fixes are included. diff --git a/nbproject/project.properties b/nbproject/project.properties index 8cceb63bc8e758629c360904b19334573eecfdd9..03d618afe67b9cb72bc2b772e0c9b5dd8338ffd1 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -6,8 +6,8 @@ app.name=${branding.token} ### if left unset, version will default to today's date app.version=4.4.1 ### build.type must be one of: DEVELOPMENT, RELEASE -build.type=RELEASE -#build.type=DEVELOPMENT +#build.type=RELEASE +build.type=DEVELOPMENT project.org.netbeans.progress=org-netbeans-api-progress project.org.sleuthkit.autopsy.centralrepository=CentralRepository