diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties index a712c1bdb74c41660d045c174a69e0dc851b83ed..964b2df827f4010d4c78f2c5ddc905408e06926e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bundle.properties @@ -80,17 +80,6 @@ DataSourcesNode.name=Data Sources DataSourcesNode.createSheet.name.name=Name DataSourcesNode.createSheet.name.displayName=Name DataSourcesNode.createSheet.name.desc=no description -DeletedContent.fsDelFilter.text=File System -DeletedContent.allDelFilter.text=All -DeletedContent.deletedContentsNode.name=Deleted Files -DeletedContent.createSheet.name.name=Name -DeletedContent.createSheet.name.displayName=Name -DeletedContent.createSheet.name.desc=no description -DeletedContent.createSheet.filterType.name=Type -DeletedContent.createSheet.filterType.displayName=Type -DeletedContent.createSheet.filterType.desc=no description -DeletedContent.createKeys.maxObjects.msg=There are more Deleted Files than can be displayed. Only the first {0} Deleted Files will be shown. -DeletedContent.createNodeForKey.typeNotSupported.msg=Not supported for this type of Displayable Item\: {0} DirectoryNode.parFolder.text=[parent folder] DirectoryNode.curFolder.text=[current folder] DirectoryNode.getActions.viewFileInDir.text=View File in Directory diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java index 589dfc4c86d2c52b33383fb1fb4cee10e212c6c2..28921410663022e02c53708a21992b6ddabbf4f8 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java @@ -1,15 +1,20 @@ /* * Autopsy Forensic Browser +<<<<<<< HEAD * * Copyright 2013-2017 Basis Technology Corp. +======= + * + * Copyright 2011-2017 Basis Technology Corp. +>>>>>>> upstream/rc-2.8.3 * Contact: carrier <at> sleuthkit <dot> 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. @@ -39,6 +44,7 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.coreutils.Logger; +import static org.sleuthkit.autopsy.datamodel.Bundle.*; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; @@ -58,14 +64,15 @@ public class DeletedContent implements AutopsyVisitableItem { private SleuthkitCase skCase; + @NbBundle.Messages({"DeletedContent.fsDelFilter.text=File System", + "DeletedContent.allDelFilter.text=All"}) public enum DeletedContentFilter implements AutopsyVisitableItem { - FS_DELETED_FILTER(0, - "FS_DELETED_FILTER", //NON-NLS - NbBundle.getMessage(DeletedContent.class, "DeletedContent.fsDelFilter.text")), - ALL_DELETED_FILTER(1, - "ALL_DELETED_FILTER", //NON-NLS - NbBundle.getMessage(DeletedContent.class, "DeletedContent.allDelFilter.text")); + FS_DELETED_FILTER(0, "FS_DELETED_FILTER", //NON-NLS + Bundle.DeletedContent_fsDelFilter_text()), + ALL_DELETED_FILTER(1, "ALL_DELETED_FILTER", //NON-NLS + Bundle.DeletedContent_allDelFilter_text()); + private int id; private String name; private String displayName; @@ -110,15 +117,13 @@ public SleuthkitCase getSleuthkitCase() { public static class DeletedContentsNode extends DisplayableItemNode { - private static final String NAME = NbBundle.getMessage(DeletedContent.class, - "DeletedContent.deletedContentsNode.name"); - private SleuthkitCase skCase; + @NbBundle.Messages("DeletedContent.deletedContentsNode.name=Deleted Files") + private static final String NAME = Bundle.DeletedContent_deletedContentsNode_name(); DeletedContentsNode(SleuthkitCase skCase) { super(Children.create(new DeletedContentsChildren(skCase), true), Lookups.singleton(NAME)); super.setName(NAME); super.setDisplayName(NAME); - this.skCase = skCase; this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png"); //NON-NLS } @@ -133,6 +138,9 @@ public <T> T accept(DisplayableItemNodeVisitor<T> v) { } @Override + @NbBundle.Messages({ + "DeletedContent.createSheet.name.displayName=Name", + "DeletedContent.createSheet.name.desc=no description"}) protected Sheet createSheet() { Sheet s = super.createSheet(); Sheet.Set ss = s.get(Sheet.PROPERTIES); @@ -141,9 +149,9 @@ protected Sheet createSheet() { s.put(ss); } - ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "DeletedContent.createSheet.name.name"), - NbBundle.getMessage(this.getClass(), "DeletedContent.createSheet.name.displayName"), - NbBundle.getMessage(this.getClass(), "DeletedContent.createSheet.name.desc"), + ss.put(new NodeProperty<>("Name", //NON-NLS + Bundle.DeletedContent_createSheet_name_displayName(), + Bundle.DeletedContent_createSheet_name_desc(), NAME)); return s; } @@ -303,6 +311,9 @@ public <T> T accept(DisplayableItemNodeVisitor<T> v) { } @Override + @NbBundle.Messages({ + "DeletedContent.createSheet.filterType.displayName=Type", + "DeletedContent.createSheet.filterType.desc=no description"}) protected Sheet createSheet() { Sheet s = super.createSheet(); Sheet.Set ss = s.get(Sheet.PROPERTIES); @@ -311,10 +322,9 @@ protected Sheet createSheet() { s.put(ss); } - ss.put(new NodeProperty<>( - NbBundle.getMessage(this.getClass(), "DeletedContent.createSheet.filterType.name"), - NbBundle.getMessage(this.getClass(), "DeletedContent.createSheet.filterType.displayName"), - NbBundle.getMessage(this.getClass(), "DeletedContent.createSheet.filterType.desc"), + ss.put(new NodeProperty<>("Type", //NON_NLS + Bundle.DeletedContent_createSheet_filterType_displayName(), + Bundle.DeletedContent_createSheet_filterType_desc(), filter.getDisplayName())); return s; @@ -334,7 +344,7 @@ public String getItemType() { return DisplayableItemNode.FILE_PARENT_NODE_KEY; } } - + static class DeletedContentChildren extends ChildFactory.Detachable<AbstractFile> { private final SleuthkitCase skCase; @@ -375,6 +385,9 @@ protected void removeNotify() { } @Override + @NbBundle.Messages("DeletedContent.createKeys.maxObjects.msg=" + + "There are more Deleted Files than can be displayed." + + " Only the first {0} Deleted Files will be shown.") protected boolean createKeys(List<AbstractFile> list) { List<AbstractFile> queryList = runFsQuery(); if (queryList.size() == MAX_OBJECTS) { @@ -385,9 +398,8 @@ protected boolean createKeys(List<AbstractFile> list) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), NbBundle.getMessage(this.getClass(), - "DeletedContent.createKeys.maxObjects.msg", - MAX_OBJECTS - 1)); + JOptionPane.showMessageDialog(WindowManager.getDefault().getMainWindow(), + DeletedContent_createKeys_maxObjects_msg(MAX_OBJECTS - 1)); } }); } @@ -435,7 +447,11 @@ static private String makeQuery(DeletedContent.DeletedContentFilter filter) { } query += " LIMIT " + MAX_OBJECTS; //NON-NLS +<<<<<<< HEAD +======= + +>>>>>>> upstream/rc-2.8.3 return query; } @@ -456,6 +472,9 @@ private List<AbstractFile> runFsQuery() { /** * Get children count without actually loading all nodes * + * @param sleuthkitCase + * @param filter + * * @return */ static long calculateItems(SleuthkitCase sleuthkitCase, DeletedContent.DeletedContentFilter filter) { @@ -468,6 +487,7 @@ static long calculateItems(SleuthkitCase sleuthkitCase, DeletedContent.DeletedCo } @Override + @NbBundle.Messages("DeletedContent.createNodeForKey.typeNotSupported.msg=Not supported for this type of Displayable Item: {0}") protected Node createNodeForKey(AbstractFile key) { return key.accept(new ContentVisitor.Default<AbstractNode>() { public FileNode visit(AbstractFile f) { @@ -495,9 +515,7 @@ public FileNode visit(Directory f) { @Override protected AbstractNode defaultVisit(Content di) { - throw new UnsupportedOperationException(NbBundle.getMessage(this.getClass(), - "DeletedContent.createNodeForKey.typeNotSupported.msg", - di.toString())); + throw new UnsupportedOperationException(Bundle.DeletedContent_createNodeForKey_typeNotSupported_msg(di.toString())); } }); } 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; }