From e3940da25be2b35f4ec59e8bc2caf399c5bf9bc1 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 19 Sep 2013 15:27:13 -0400 Subject: [PATCH 001/169] Added TagsManager class skeleton integrated with Services --- .../autopsy/casemodule/services/Services.java | 11 ++++- .../casemodule/services/TagsManager.java | 40 +++++++++++++++++++ 2 files changed, 49 insertions(+), 2 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java index 8718406d5c..3cb8764f6f 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java @@ -2,7 +2,7 @@ * * Autopsy Forensic Browser * - * Copyright 2012 Basis Technology Corp. + * Copyright 2012-2013 Basis Technology Corp. * * Copyright 2012 42six Solutions. * Contact: aebadirad 42six com @@ -37,21 +37,28 @@ public class Services implements Closeable { // NOTE: all new services added to Services class must be added to this list // of services. - private List services = new ArrayList(); + private List services = new ArrayList<>(); // services private FileManager fileManager; + private TagsManager tagsManager; public Services(SleuthkitCase tskCase) { this.tskCase = tskCase; //create and initialize FileManager as early as possibly in the new/opened Case fileManager = new FileManager(tskCase); services.add(fileManager); + tagsManager = new TagsManager(tskCase); + services.add(tagsManager); } public FileManager getFileManager() { return fileManager; } + + public TagsManager getTagsManager() { + return tagsManager; + } @Override public void close() throws IOException { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java new file mode 100755 index 0000000000..07151aa809 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -0,0 +1,40 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 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.casemodule.services; + +import java.io.Closeable; +import java.io.IOException; +import org.sleuthkit.datamodel.SleuthkitCase; + +/** + * A instance of this class functions as an Autopsy service that manages the + * creation, updating, and deletion of tags applied to files and artifacts by + * users. + */ +public class TagsManager implements Closeable { + private final SleuthkitCase database; + + TagsManager(SleuthkitCase database) { + this.database = database; + } + + @Override + public void close() throws IOException { + } +} From a40481f5f862d294a72fc83acc90bc0452457261 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 25 Sep 2013 16:44:56 -0400 Subject: [PATCH 002/169] Filled out new tags API for data, DTOs --- .../autopsy/casemodule/services/Services.java | 1 + .../casemodule/services/TagsManager.java | 221 +++++++++++++++++- .../directorytree/TagAbstractFileAction.java | 34 ++- .../TagBlackboardArtifactAction.java | 34 ++- 4 files changed, 273 insertions(+), 17 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java index 3cb8764f6f..069b13ef2e 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java @@ -48,6 +48,7 @@ public class Services implements Closeable { //create and initialize FileManager as early as possibly in the new/opened Case fileManager = new FileManager(tskCase); services.add(fileManager); + tagsManager = new TagsManager(tskCase); services.add(tagsManager); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 07151aa809..ef9d3f6934 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -20,21 +20,228 @@ package org.sleuthkit.autopsy.casemodule.services; import java.io.Closeable; import java.io.IOException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import org.sleuthkit.autopsy.coreutils.ModuleSettings; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.BlackboardArtifactTag; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TagType; +import org.sleuthkit.datamodel.TskCoreException; /** - * A instance of this class functions as an Autopsy service that manages the - * creation, updating, and deletion of tags applied to files and artifacts by - * users. + * A singleton instance of this class functions as an Autopsy service that + * manages the creation, updating, and deletion of tags applied to Content and + * BlackboardArtifacts objects by users. */ public class TagsManager implements Closeable { - private final SleuthkitCase database; + private static final String TAGS_SETTINGS_FILE_NAME = "tags"; + private static final String TAG_TYPES_SETTING_KEY = "tagTypes"; + private final SleuthkitCase tskCase; + private final HashMap tagTypes = new HashMap<>(); + + TagsManager(SleuthkitCase tskCase) { + this.tskCase = tskCase; + loadTagTypesFromTagSettings(); + } + + private void loadTagTypesFromTagSettings() { + // Get any tag types already added to the current case. + try { + List currentTagTypes = tskCase.getTagTypes(); + for (TagType tagType : currentTagTypes) { + tagTypes.put(tagType.getDisplayName(), tagType); + } + } + catch (TskCoreException ex) { + Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag types from the current case", ex); + } + + // Read the saved tag types, if any, from the tags settings file and + // add them to the current case if they haven't already been added, e.g, + // when the case was last opened. + String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_FILE_NAME, TAG_TYPES_SETTING_KEY); + if (null != setting && !setting.isEmpty()) { + // Read the tag types setting and break in into tag type tuples. + List tagTypeTuples = Arrays.asList(setting.split(";")); - TagsManager(SleuthkitCase database) { - this.database = database; + // Parse each tuple and add the tag types to the current case, one + // at a time to gracefully discard any duplicates or corrupt tuples. + for (String tagTypeTuple : tagTypeTuples) { + String[] tagTypeAttributes = tagTypeTuple.split(","); + if (!tagTypes.containsKey(tagTypeAttributes[0])) { + TagType tagType = new TagType(tagTypeAttributes[0], tagTypeAttributes[1], TagType.HTML_COLOR.getColorByName(tagTypeAttributes[2])); + try { + tskCase.addTagType(tagType); + tagTypes.put(tagType.getDisplayName(),tagType); + } + catch(TskCoreException ex) { + Logger.getLogger(TagsManager.class.getName()).log(Level.WARNING, "Failed to add saved " + tagType.getDisplayName() + " tag type to the current case", ex); + } + } + } + + saveTagTypesToTagsSettings(); + } + } + + private void saveTagTypesToTagsSettings() { + if (!tagTypes.isEmpty()) { + StringBuilder setting = new StringBuilder(); + for (TagType tagType : tagTypes.values()) { + if (setting.length() != 0) { + setting.append(";"); + } + setting.append(tagType.getDisplayName()).append(","); + setting.append(tagType.getDescription()).append(","); + setting.append(tagType.getColor().name()); + } + + ModuleSettings.setConfigSetting(TAGS_SETTINGS_FILE_NAME, TAG_TYPES_SETTING_KEY, setting.toString()); + } + } + + /** + * Gets a list of all tag types currently available for tagging content or + * blackboard artifacts. + * @return A list, possibly empty, of TagType data transfer objects (DTOs). + * @throws TskCoreException + */ + public List getTagTypes() throws TskCoreException { + return tskCase.getTagTypes(); + } + + /** + * Adds a new tag type to the current case and to the tags settings file. + * @param displayName The display name for the new tag type. + * @return A TagType object representing the new type on success, null on failure. + * @throws TskCoreException + */ + public TagType addTagType(String displayName) throws TagTypeAlreadyExistsException, TskCoreException { + return addTagType(displayName, "", TagType.HTML_COLOR.NONE); + } + + /** + * Adds a new tag type to the current case and to the tags settings file. + * @param displayName The display name for the new tag type. + * @param description The description for the new tag type. + * @return A TagType object representing the new type on success, null on failure. + * @throws TskCoreException + */ + public TagType addTagType(String displayName, String description) throws TagTypeAlreadyExistsException, TskCoreException { + return addTagType(displayName, description, TagType.HTML_COLOR.NONE); + } + + /** + * Adds a new tag type to the current case and to the tags settings file. + * @param displayName The display name for the new tag type. + * @param description The description for the new tag type. + * @param color The HTML color to associate with the new tag type. + * @return A TagType object representing the new type. + * @throws TskCoreException + */ + public synchronized TagType addTagType(String displayName, String description, TagType.HTML_COLOR color) throws TagTypeAlreadyExistsException, TskCoreException { + if (tagTypes.containsKey(displayName)) { + throw new TagTypeAlreadyExistsException(); + } + + TagType newTagType = new TagType(displayName, description, color); + tskCase.addTagType(newTagType); + tagTypes.put(newTagType.getDisplayName(), newTagType); + saveTagTypesToTagsSettings(); + return newTagType; + } + + public class TagTypeAlreadyExistsException extends Exception { + } + + /** + * Tags a Content object. + * @param content The Content to tag. + * @param tagType The type of tag to add. + * @throws TskCoreException + */ + public void addContentTag(Content content, TagType tagType) throws TskCoreException { + addContentTag(content, tagType, "", 0, content.getSize()); + } + + /** + * Tags a Content object. + * @param content The Content to tag. + * @param tagType The type of tag to add. + * @param comment A comment to store with the tag. + * @throws TskCoreException + */ + public void addContentTag(Content content, TagType tagType, String comment) throws TskCoreException { + addContentTag(content, tagType, comment, 0, content.getSize() - 1); + } + + /** + * Tags a Content object or a portion of a content object. + * @param content The Content to tag. + * @param tagType The type of tag to add. + * @param comment A comment to store with the tag. + * @param beginByteOffset Designates the beginning of a tagged extent. + * @param endByteOffset Designates the end of a tagged extent. + * @throws TskCoreException + */ + public void addContentTag(Content content, TagType tagType, String comment, long beginByteOffset, long endByteOffset) throws IllegalArgumentException, TskCoreException { + if (beginByteOffset < 0) { + throw new IllegalArgumentException("Content extent incorrect: beginByteOffset < 0"); + } + + if (endByteOffset <= beginByteOffset) { + throw new IllegalArgumentException("Content extent incorrect: endByteOffset <= beginByteOffset"); + } + + if (endByteOffset > content.getSize() - 1) { + throw new IllegalArgumentException("Content extent incorrect: endByteOffset exceeds content size"); + } + + tskCase.addContentTag(new ContentTag(content, tagType, comment, beginByteOffset, endByteOffset)); + } + + /** + * Deletes a content tag. + * @param tag The tag to delete. + * @throws TskCoreException + */ + public void deleteContentTag(ContentTag tag) throws TskCoreException { + tskCase.deleteContentTag(tag); + } + + /** + * Tags a BlackboardArtifact object. + * @param artifact The BlackboardArtifact to tag. + * @param tagType The type of tag to add. + * @throws TskCoreException + */ + public void addBlackboardArtifactTag(BlackboardArtifact artifact, TagType tagType) throws TskCoreException { + addBlackboardArtifactTag(artifact, tagType, ""); + } + + /** + * Tags a BlackboardArtifact object. + * @param artifact The BlackboardArtifact to tag. + * @param tagType The type of tag to add. + * @param comment A comment to store with the tag. + * @throws TskCoreException + */ + public void addBlackboardArtifactTag(BlackboardArtifact artifact, TagType tagType, String comment) throws TskCoreException { + tskCase.addBlackboardArtifactTag(new BlackboardArtifactTag(artifact, tagType, comment)); + } + + void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException { + tskCase.deleteBlackboardArtifactTag(tag); } @Override - public void close() throws IOException { + public void close() throws IOException { + saveTagTypesToTagsSettings(); } } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java index 657673ac74..b7d3c39e17 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java @@ -20,12 +20,19 @@ package org.sleuthkit.autopsy.directorytree; import java.awt.event.ActionEvent; import java.util.Collection; +import java.util.logging.Level; import javax.swing.AbstractAction; import javax.swing.JMenuItem; +import javax.swing.JOptionPane; import org.openide.util.Utilities; import org.openide.util.actions.Presenter; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.services.TagsManager; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.Tags; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.TagType; +import org.sleuthkit.datamodel.TskCoreException; public class TagAbstractFileAction extends AbstractAction implements Presenter.Popup { // This class is a singleton to support multi-selection of nodes, since @@ -60,11 +67,28 @@ public class TagAbstractFileAction extends AbstractAction implements Presenter.P } @Override - protected void applyTag(String tagName, String comment) { - Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); - for (AbstractFile file : selectedFiles) { - Tags.createTag(file, tagName, comment); - } + protected void applyTag(String tagDisplayName, String comment) { + try { + TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + TagType tagType = tagsManager.addTagType(tagDisplayName); + + Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); + for (AbstractFile file : selectedFiles) { + Tags.createTag(file, tagDisplayName, comment); + try { + tagsManager.addContentTag(file, tagType); + } + catch (TskCoreException ex) { + Logger.getLogger(TagAbstractFileMenu.class.getName()).log(Level.SEVERE, "Error tagging content", ex); + } + } + } + catch (TagsManager.TagTypeAlreadyExistsException ex) { + JOptionPane.showMessageDialog(null, "A " + tagDisplayName + " tag type has already been defined.", "Duplicate Tag Type", JOptionPane.ERROR_MESSAGE); + } + catch (TskCoreException ex) { + Logger.getLogger(TagAbstractFileMenu.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag type", ex); + } } } } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagBlackboardArtifactAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/TagBlackboardArtifactAction.java index 3d1a9641b3..3f2c8fd407 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/TagBlackboardArtifactAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/TagBlackboardArtifactAction.java @@ -20,12 +20,19 @@ package org.sleuthkit.autopsy.directorytree; import java.awt.event.ActionEvent; import java.util.Collection; +import java.util.logging.Level; import javax.swing.AbstractAction; import javax.swing.JMenuItem; +import javax.swing.JOptionPane; import org.openide.util.Utilities; import org.openide.util.actions.Presenter; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.services.TagsManager; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.Tags; import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.TagType; +import org.sleuthkit.datamodel.TskCoreException; public class TagBlackboardArtifactAction extends AbstractAction implements Presenter.Popup { // This class is a singleton to support multi-selection of nodes, since @@ -61,11 +68,28 @@ public class TagBlackboardArtifactAction extends AbstractAction implements Prese } @Override - protected void applyTag(String tagName, String comment) { - Collection selectedArtifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class); - for (BlackboardArtifact artifact : selectedArtifacts) { - Tags.createTag(artifact, tagName, comment); - } + protected void applyTag(String tagDisplayName, String comment) { + try { + TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + TagType tagType = tagsManager.addTagType(tagDisplayName); + + Collection selectedArtifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class); + for (BlackboardArtifact artifact : selectedArtifacts) { + Tags.createTag(artifact, tagDisplayName, comment); + try { + tagsManager.addBlackboardArtifactTag(artifact, tagType); + } + catch (TskCoreException ex) { + Logger.getLogger(TagBlackboardArtifactMenu.class.getName()).log(Level.SEVERE, "Error tagging result", ex); + } + } + } + catch (TagsManager.TagTypeAlreadyExistsException ex) { + JOptionPane.showMessageDialog(null, "A " + tagDisplayName + " tag type has already been defined.", "Duplicate Tag Type", JOptionPane.ERROR_MESSAGE); + } + catch (TskCoreException ex) { + Logger.getLogger(TagBlackboardArtifactMenu.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag type", ex); + } } } } From 6a911794362549fde53b24c256cb2e9fe86c3202 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 2 Oct 2013 10:20:39 -0400 Subject: [PATCH 003/169] Ongoing work on new tags API --- .../autopsy/casemodule/services/TagsManager.java | 2 +- .../autopsy/directorytree/TagAbstractFileAction.java | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index ef9d3f6934..2ae7426655 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -167,7 +167,7 @@ public class TagsManager implements Closeable { * @throws TskCoreException */ public void addContentTag(Content content, TagType tagType) throws TskCoreException { - addContentTag(content, tagType, "", 0, content.getSize()); + addContentTag(content, tagType, "", 0, content.getSize() - 1); } /** diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java index b7d3c39e17..5afbf89fef 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java @@ -75,12 +75,12 @@ public class TagAbstractFileAction extends AbstractAction implements Presenter.P Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); for (AbstractFile file : selectedFiles) { Tags.createTag(file, tagDisplayName, comment); - try { - tagsManager.addContentTag(file, tagType); - } - catch (TskCoreException ex) { - Logger.getLogger(TagAbstractFileMenu.class.getName()).log(Level.SEVERE, "Error tagging content", ex); - } +// try { +// tagsManager.addContentTag(file, tagType); +// } +// catch (TskCoreException ex) { +// Logger.getLogger(TagAbstractFileMenu.class.getName()).log(Level.SEVERE, "Error tagging content", ex); +// } } } catch (TagsManager.TagTypeAlreadyExistsException ex) { From 4f4b8e057d25459281552daded2aacd88d074a7e Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Wed, 9 Oct 2013 14:35:52 -0400 Subject: [PATCH 004/169] Add support for loading KDB (SQLite) hash index files. --- .../autopsy/hashdatabase/HashDb.java | 22 +++++++++++++++---- .../hashdatabase/HashDbAddDatabaseDialog.java | 7 +++--- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index 9a08234eab..6f623157a6 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -57,7 +57,8 @@ public class HashDb implements Comparable { } // Suffix added to the end of a database name to get its index file - private static final String INDEX_SUFFIX = "-md5.idx"; + private static final String INDEX_SUFFIX = ".kdb"; + private static final String INDEX_SUFFIX_OLD = "-md5.idx"; private String name; private List databasePaths; // TODO: Length limited to one for now... @@ -230,7 +231,7 @@ public class HashDb implements Comparable { * @return true if index */ static boolean isIndexPath(String path) { - return path.endsWith(INDEX_SUFFIX); + return (path.endsWith(INDEX_SUFFIX) || path.endsWith(INDEX_SUFFIX_OLD)); } /** @@ -239,11 +240,15 @@ public class HashDb implements Comparable { * @return */ static String toDatabasePath(String indexPath) { - return indexPath.substring(0, indexPath.lastIndexOf(INDEX_SUFFIX)); + if (indexPath.endsWith(INDEX_SUFFIX_OLD)) { + return indexPath.substring(0, indexPath.lastIndexOf(INDEX_SUFFIX_OLD)); + } else { + return indexPath.substring(0, indexPath.lastIndexOf(INDEX_SUFFIX)); + } } /** - * Derives image path from an database path by appending the suffix. + * Derives index path from an database path by appending the suffix. * @param databasePath * @return */ @@ -251,6 +256,15 @@ public class HashDb implements Comparable { return databasePath.concat(INDEX_SUFFIX); } + /** + * Derives old-format index path from an database path by appending the suffix. + * @param databasePath + * @return + */ + static String toOldIndexPath(String databasePath) { + return databasePath.concat(INDEX_SUFFIX_OLD); + } + /** * Calls Sleuth Kit method via JNI to determine whether there is an * index for the given path diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.java index cb635520fe..56e5427355 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.java @@ -55,7 +55,7 @@ final class HashDbAddDatabaseDialog extends javax.swing.JDialog { void customizeComponents() { fc.setDragEnabled(false); fc.setFileSelectionMode(JFileChooser.FILES_ONLY); - String[] EXTENSION = new String[] { "txt", "idx", "hash", "Hash", "hsh"}; + String[] EXTENSION = new String[] { "txt", "kdb", "idx", "hash", "Hash", "hsh"}; FileNameExtensionFilter filter = new FileNameExtensionFilter( "Hash Database File", EXTENSION); fc.setFileFilter(filter); @@ -285,8 +285,9 @@ final class HashDbAddDatabaseDialog extends javax.swing.JDialog { } try { File db = new File(databasePathTextField.getText()); - File idx = new File(databasePathTextField.getText() + "-md5.idx"); - if (!db.exists() && !idx.exists()) { + File idx = new File(databasePathTextField.getText() + ".kdb"); + File idx_old = new File(databasePathTextField.getText() + "-md5.idx"); + if (!db.exists() && !idx.exists() && !idx_old.exists()) { JOptionPane.showMessageDialog(this, "Selected file does not exist"); return; } From 7b52520f9022141a2af55c6ba9f404c44b15764d Mon Sep 17 00:00:00 2001 From: raman-bt Date: Fri, 11 Oct 2013 12:16:07 -0400 Subject: [PATCH 005/169] Cleanup of Add Image/DataSource Wizard. Pass #1. --- .../AddImageWizardChooseDataSourcePanel.java | 7 + .../AddImageWizardChooseDataSourceVisual.java | 81 ++- .../AddImageWizardIngestConfigPanel.java | 96 ++- .../casemodule/AddImageWizardIterator.java | 13 +- .../autopsy/casemodule/ContentTypePanel.java | 28 +- .../autopsy/casemodule/DSPCallback.java | 42 ++ .../casemodule/DataSourceProcessor.java | 87 +++ .../autopsy/casemodule/ImageDSProcessor.java | 566 ++++++++++++++++++ .../autopsy/casemodule/ImageFilePanel.java | 4 +- .../autopsy/casemodule/LocalDiskPanel.java | 4 +- .../autopsy/casemodule/LocalFilesPanel.java | 4 +- 11 files changed, 905 insertions(+), 27 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/DSPCallback.java create mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/DataSourceProcessor.java create mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java index 39a00baacc..7fb2a69b0b 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java @@ -43,6 +43,7 @@ class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Panel datasourceProcessorsMap = new HashMap();; + + /** * Creates new form AddImageVisualPanel1 @@ -75,13 +87,55 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { } private void customInit() { + + + discoverDataSourceProcessors(); + model = new ContentTypeModel(); typeComboBox.setModel(model); typeComboBox.setSelectedIndex(0); typePanel.setLayout(new BorderLayout()); - updateCurrentPanel(ImageFilePanel.getDefault()); + + //updateCurrentPanel(ImageFilePanel.getDefault()); + updateCurrentPanel(model.getElementAt(0)); } + private void discoverDataSourceProcessors() { + + //datasourceHandlersMap.clear(); + logger.log(Level.INFO, "RAMAN discoverDataSourceProcessors()..."); + + // RAMAN TBD: hack for now + { + //ContentTypePanel.RegisterPanel(ImageFilePanel.getDefault()); + //ContentTypePanel.RegisterPanel(LocalDiskPanel.getDefault()); + //ContentTypePanel.RegisterPanel(LocalFilesPanel.getDefault()); + } + + for (DataSourceProcessor dsProcessor: Lookup.getDefault().lookupAll(DataSourceProcessor.class)) { + + logger.log(Level.INFO, "RAMAN discoverDataSourceHandlers(): found an instance of DataSourceHandler"); + + + String dsType = dsProcessor.getType(); + JPanel panel = dsProcessor.getPanel(); + String validate = dsProcessor.validatePanel(); + //dshandler.run(null); + //String[] errors = dshandler.getErrors(); + + if (!datasourceProcessorsMap.containsKey(dsProcessor.getType()) ) { + + // Regsiter the panel for the discovered DS handler here + ContentTypePanel.RegisterPanel(dsProcessor.getPanel()); + + datasourceProcessorsMap.put(dsProcessor.getType(), dsProcessor); + } + + } + + + } + /** * Changes the current panel to the given panel. * @@ -105,7 +159,7 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { } }); currentPanel.select(); - if (currentPanel.getContentType().equals(ContentType.LOCAL)) { + if (currentPanel.getContentType().equals("LOCAL")) { //disable image specific options noFatOrphansCheckbox.setEnabled(false); descLabel.setEnabled(false); @@ -118,6 +172,25 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { updateUI(null); } + /** + * Returns the currently selected DS handler in the combobox + * + * + * @return name the name of this panel + */ + public DataSourceProcessor GetCurrentDSProcessor() { + + logger.log(Level.INFO, "RAMAN GetCurrentDSProcessor()..."); + // get the type of the currently selected panel and then look up + // the correspodning DS Handler in the map + String dsType = currentPanel.getContentType(); + + DataSourceProcessor dsProcessor = datasourceProcessorsMap.get(dsType); + + return dsProcessor; + + } + /** * Returns the name of the this panel. This name will be shown on the left * panel of the "Add Image" wizard panel. @@ -143,7 +216,7 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { * * @return data source selected */ - public ContentType getContentType() { + public String getContentType() { return currentPanel.getContentType(); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java index 3f5b77e281..dab6bf7318 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java @@ -37,7 +37,7 @@ import javax.swing.event.ChangeListener; import org.openide.WizardDescriptor; import org.openide.util.HelpCtx; import org.openide.util.Lookup; -import org.sleuthkit.autopsy.casemodule.ContentTypePanel.ContentType; +//import org.sleuthkit.autopsy.casemodule.ContentTypePanel.ContentType; import org.sleuthkit.autopsy.casemodule.services.FileManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.PlatformUtil; @@ -73,7 +73,7 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel messages = ingestConfig.setContext(AddImageWizardIngestConfigPanel.class.getCanonicalName()); if (messages.isEmpty() == false) { @@ -188,12 +193,13 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel errList, List contents) { + dataSourceProcessorDone(result, errList, contents ); + } + + }; + // Kick off the DSProcessor + dsProcessor.run(settings, progressPanel, cbObj); + } + private void cancelDataSourceProcessing() { + logger.log(Level.INFO, "RAMAN cancelDataSourceProcessing()."); + dsProcessor.cancel(); + } + + private void dataSourceProcessorDone(DSPCallback.DSP_Result result, List errList, List contents) { + logger.log(Level.INFO, "RAMAN dataSourceProcessorDone()."); + + // RAMAN TBD + // check if there is any new content and kick off ingest.... + + // RAMAN TBD: check the result + + // RAMAN TBD: if errors, display them on the progress panel + + // disbale the cleanup task + cleanupTask.disable(); + + + newContents.clear(); + newContents.addAll(contents); + + //notify the case + if (!newContents.isEmpty()) { + Case.getCurrentCase().addLocalDataSource(newContents.get(0)); + } + + // Start ingest if we can + startIngest(); + + } /** * Class for getting the currently processing directory. * @@ -313,7 +389,7 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel> getPanels() { if (panels == null) { - AddImageWizardAddingProgressPanel wizPanel = new AddImageWizardAddingProgressPanel(); panels = new ArrayList>(); - panels.add(new AddImageWizardChooseDataSourcePanel()); - panels.add(new AddImageWizardIngestConfigPanel(action, wizPanel)); - panels.add(wizPanel); + + AddImageWizardAddingProgressPanel progressPanel = new AddImageWizardAddingProgressPanel(); + + AddImageWizardChooseDataSourcePanel dsPanel = new AddImageWizardChooseDataSourcePanel(progressPanel); + AddImageWizardIngestConfigPanel ingestConfigPanel = new AddImageWizardIngestConfigPanel(dsPanel, action, progressPanel); + + panels.add(dsPanel); + panels.add(ingestConfigPanel); + panels.add(progressPanel); String[] steps = new String[panels.size()]; for (int i = 0; i < panels.size(); i++) { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ContentTypePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/ContentTypePanel.java index 07664d9401..4b2f4aada8 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ContentTypePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ContentTypePanel.java @@ -20,17 +20,39 @@ package org.sleuthkit.autopsy.casemodule; import java.beans.PropertyChangeListener; import javax.swing.JPanel; +import java.util.ArrayList; +import java.util.List; abstract class ContentTypePanel extends JPanel { - public enum ContentType{IMAGE, DISK, LOCAL}; + // Collection of panels that are dynamically discovered and registered + private static List registeredPanels = new ArrayList();; + + public static void RegisterPanel(ContentTypePanel panel) + { + // RAMAN TBD: check if this panel is already regsitered... + + registeredPanels.add(panel); + + + } + //public enum ContentType{IMAGE, DISK, LOCAL}; + + + private String contentType; /** * Returns a list off all the panels extending ImageTypePanel. * @return list of all ImageTypePanels */ public static ContentTypePanel[] getPanels() { - return new ContentTypePanel[] {ImageFilePanel.getDefault(), LocalDiskPanel.getDefault(), LocalFilesPanel.getDefault() }; + //return new ContentTypePanel[] {ImageFilePanel.getDefault(), LocalDiskPanel.getDefault(), LocalFilesPanel.getDefault() }; + + + + + + return registeredPanels.toArray(new ContentTypePanel[registeredPanels.size()]); } /** @@ -50,7 +72,7 @@ abstract class ContentTypePanel extends JPanel { * Get content type (image, disk, local file) of the source this wizard panel is for * @return ContentType of the source panel */ - abstract public ContentType getContentType(); + abstract public String getContentType(); /** * Returns if the next button should be enabled in the current wizard. diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/DSPCallback.java b/Core/src/org/sleuthkit/autopsy/casemodule/DSPCallback.java new file mode 100644 index 0000000000..58ec4d8ce0 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/DSPCallback.java @@ -0,0 +1,42 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.casemodule; + +import java.awt.EventQueue; +import java.util.List; +import org.sleuthkit.datamodel.Content; + +/** + * + * @author raman + */ +public abstract class DSPCallback { + + public enum DSP_Result + { + NO_ERRORS, + CRITICAL_ERRORS, + NONCRITICAL_ERRORS, + }; + + void done(DSP_Result result, List errList, List newContents) + { + + final DSP_Result resultf = result; + final List errListf = errList; + final List newContentsf = newContents; + + // Invoke doneEDT() that runs on the EDT . + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + doneEDT(resultf, errListf, newContentsf ); + + } + }); + } + + abstract void doneEDT(DSP_Result result, List errList, List newContents); +}; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/DataSourceProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/DataSourceProcessor.java new file mode 100644 index 0000000000..123d26275b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/DataSourceProcessor.java @@ -0,0 +1,87 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2013 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.casemodule; + +import java.util.List; +import javax.swing.JPanel; +import org.openide.WizardDescriptor; +import org.sleuthkit.autopsy.casemodule.AddImageWizardAddingProgressPanel; +import org.sleuthkit.autopsy.casemodule.ContentTypePanel; +import org.sleuthkit.datamodel.Content; + +public interface DataSourceProcessor { + + + + + // public DataSourceProcessor createInstance(); + + + /** + * Returns the type of Data Source it handles. + * This name gets displayed in the drop-down listbox + **/ + String getType(); + + /** + * Returns the picker panel to be displayed along with any other + * runtime options supported by the data source handler. + **/ + ContentTypePanel getPanel(); + + /** + * Called to validate the input data in the panel. + * Returns null if no errors, or + * Returns a string describing the error if there are errors. + **/ + String validatePanel(); + + /** + * Called to invoke the handling of Data source in the background. + * Returns after starting the background thread + * @param settings wizard settings to read/store properties + * @param progressPanel progress panel to be updated while processing + * + **/ + void run(WizardDescriptor settings, AddImageWizardAddingProgressPanel progressPanel, DSPCallback dspCallback); + + /** + * Called after run() is done to get the new content added by the handler. + * Returns a list of content added by the data source handler + **/ + // List getNewContents(); + + + /** + * Called to get the list of errors. + **/ + // String[] getErrors(); + + /** + * Called to cancel the background processing. + * + * TODO look into current use cases to see if this should wait until it has stopped or not. + **/ + void cancel(); + + + + + +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java new file mode 100644 index 0000000000..e44c0f32a1 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java @@ -0,0 +1,566 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.casemodule; + +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Window; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import javax.swing.JPanel; +import javax.swing.JProgressBar; +import javax.swing.SwingUtilities; +import javax.swing.SwingWorker; +import org.openide.WizardDescriptor; +import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.PlatformUtil; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.Image; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.SleuthkitJNI; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskDataException; +import org.sleuthkit.datamodel.TskException; + +/** + * + * @author raman + */ +@ServiceProvider(service = DataSourceProcessor.class) +public class ImageDSProcessor implements DataSourceProcessor { + + static final Logger logger = Logger.getLogger(ImageDSProcessor.class.getName()); + + private ImageFilePanel imageFilePanel; + private AddImageTask addImageTask; + private CurrentDirectoryFetcher fetcher; + + private boolean addImageDone = false; + private boolean cancelled = false; + + DSPCallback callbackObj = null; + + public ImageDSProcessor() { + logger.log(Level.INFO, "RAMAN ImageDSHandler()..."); + + // Create the config panel + imageFilePanel = ImageFilePanel.getDefault(); + + } + + /**** + @Override + public ImageDSProcessor createInstance() { + return new ImageDSProcessor(); + } + *****/ + + + @Override + public String getType() { + + logger.log(Level.INFO, "RAMAN getName()..."); + + return imageFilePanel.getContentType(); + + } + + + @Override + public ContentTypePanel getPanel() { + + logger.log(Level.INFO, "RAMAN getPanel()..."); + + return imageFilePanel; + } + + @Override + public String validatePanel() { + + logger.log(Level.INFO, "RAMAN validatePanel()..."); + + return null; + + } + + @Override + public void run(WizardDescriptor settings, AddImageWizardAddingProgressPanel progressPanel, DSPCallback cbObj) { + + logger.log(Level.INFO, "RAMAN run()..."); + + callbackObj = cbObj; + addImageDone = false; + cancelled = false; + + addImageTask = new AddImageTask(settings, progressPanel, cbObj); + addImageTask.execute(); + + return; + } + + /*** + @Override + public String[] getErrors() { + + logger.log(Level.INFO, "RAMAN getErrors()..."); + + // RAMAN TBD + return null; + } + *****/ + + @Override + public void cancel() { + + logger.log(Level.INFO, "RAMAN cancelProcessing()..."); + + cancelled = true; + addImageTask.cancelTask(); + + return; + } + + /***** + @Override + public List getNewContents() { + return addImageTask.getNewContents(); + } + * *****/ + + + private static class CurrentDirectoryFetcher extends SwingWorker { + + //AddImageWizardIngestConfigPanel.AddImageTask task; + JProgressBar progressBar; + AddImageWizardAddingProgressVisual progressVisual; + SleuthkitJNI.CaseDbHandle.AddImageProcess process; + + CurrentDirectoryFetcher(JProgressBar aProgressBar, AddImageWizardAddingProgressVisual wiz, SleuthkitJNI.CaseDbHandle.AddImageProcess proc) { + this.progressVisual = wiz; + this.process = proc; + this.progressBar = aProgressBar; + } + + /** + * @return the currently processing directory + */ + @Override + protected Integer doInBackground() { + try { + while (progressBar.getValue() < 100 || progressBar.isIndeterminate()) { //TODO Rely on state variable in AddImgTask class + + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + progressVisual.setCurrentDirText(process.currentDirectory()); + } + }); + + Thread.sleep(2 * 1000); + } + return 1; + } catch (InterruptedException ie) { + return -1; + } + } + } + + + private class AddImageTask extends SwingWorker { + + private JProgressBar progressBar; + private Case currentCase; + // true if the process was requested to stop + private boolean cancelled = false; + //true if revert has been invoked. + private boolean reverted = false; + private boolean hasCritError = false; + private boolean addImagedone = false; + + + //private String errorString = null; + private List errorList = new ArrayList(); + + private WizardDescriptor wizDescriptor; + + private Logger logger = Logger.getLogger(AddImageTask.class.getName()); + private AddImageWizardAddingProgressPanel progressPanel; + private DSPCallback callbackObj; + + private final List newContents = Collections.synchronizedList(new ArrayList()); + + private SleuthkitJNI.CaseDbHandle.AddImageProcess addImageProcess; + + protected AddImageTask(WizardDescriptor settings, AddImageWizardAddingProgressPanel aProgressPanel, DSPCallback cbObj ) { + this.progressPanel = aProgressPanel; + this.progressBar = progressPanel.getComponent().getProgressBar(); + currentCase = Case.getCurrentCase(); + + this.callbackObj = cbObj; + this.wizDescriptor = settings; + } + + /** + * Starts the addImage process, but does not commit the results. + * + * @return + * + * @throws Exception + */ + @Override + protected Integer doInBackground() { + + logger.log(Level.INFO, "RAMAN: doInBackground()"); + + this.setProgress(0); + + errorList.clear(); + + /**** RAMAN TBD: a higher level caller should set up the cleanup task and then call DataSourceHandler.cancelProcessing() + * + // Add a cleanup task to interrupt the backgroud process if the + // wizard exits while the background process is running. + AddImageAction.CleanupTask cancelledWhileRunning = action.new CleanupTask() { + @Override + void cleanup() throws Exception { + logger.log(Level.INFO, "Add image process interrupted."); + addImageTask.interrupt(); //it might take time to truly interrupt + } + }; + * *************************/ + + + try { + //lock DB for writes in EWT thread + //wait until lock acquired in EWT + EventQueue.invokeAndWait(new Runnable() { + @Override + public void run() { + SleuthkitCase.dbWriteLock(); + } + }); + } catch (InterruptedException ex) { + logger.log(Level.WARNING, "Errors occurred while running add image, could not acquire lock. ", ex); + return 0; + + } catch (InvocationTargetException ex) { + logger.log(Level.WARNING, "Errors occurred while running add image, could not acquire lock. ", ex); + return 0; + } + + + String dataSourcePath = (String) wizDescriptor.getProperty(AddImageAction.DATASOURCEPATH_PROP); + String dataSourceType = (String) wizDescriptor.getProperty(AddImageAction.DATASOURCETYPE_PROP); + String timeZone = wizDescriptor.getProperty(AddImageAction.TIMEZONE_PROP).toString(); + boolean noFatOrphans = ((Boolean) wizDescriptor.getProperty(AddImageAction.NOFATORPHANS_PROP)).booleanValue(); + + + addImageProcess = currentCase.makeAddImageProcess(timeZone, true, noFatOrphans); + fetcher = new CurrentDirectoryFetcher(this.progressBar, progressPanel.getComponent(), addImageProcess); + //RAMAN TBD: handle the cleanup task + //cancelledWhileRunning.enable(); + try { + progressPanel.setStateStarted(); + fetcher.execute(); + addImageProcess.run(new String[]{dataSourcePath}); + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Core errors occurred while running add image. ", ex); + //critical core/system error and process needs to be interrupted + hasCritError = true; + //errorString = ex.getMessage(); + errorList.add(ex.getMessage()); + } catch (TskDataException ex) { + logger.log(Level.WARNING, "Data errors occurred while running add image. ", ex); + //errorString = ex.getMessage(); + errorList.add(ex.getMessage()); + } finally { + // process is over, doesn't need to be dealt with if cancel happens + //RAMAN TBD: handle the cleanup task + //cancelledWhileRunning.disable(); + + } + + return 0; + } + + /** + * Commit the finished AddImageProcess, and cancel the CleanupTask that + * would have reverted it. + * + * @param settings property set to get AddImageProcess and CleanupTask + * from + * + * @throws Exception if commit or adding the image to the case failed + */ + private void commitImage(WizardDescriptor settings) throws Exception { + + logger.log(Level.INFO, "RAMAN: commitImage()..."); + + String contentPath = (String) settings.getProperty(AddImageAction.DATASOURCEPATH_PROP); + + String timezone = settings.getProperty(AddImageAction.TIMEZONE_PROP).toString(); + settings.putProperty(AddImageAction.IMAGEID_PROP, ""); + + long imageId = 0; + try { + imageId = addImageProcess.commit(); + } catch (TskException e) { + logger.log(Level.WARNING, "Errors occured while committing the image", e); + errorList.add(e.getMessage()); + } finally { + //commit done, unlock db write in EWT thread + //before doing anything else + SleuthkitCase.dbWriteUnlock(); + + if (imageId != 0) { + Image newImage = Case.getCurrentCase().addImage(contentPath, imageId, timezone); + + //while we have the image, verify the size of its contents + String verificationErrors = newImage.verifyImageSize(); + if (verificationErrors.equals("") == false) { + //data error (non-critical) + errorList.add(verificationErrors); + //progressPanel.addErrors(verificationErrors, false); + } + + /*** RAMAN TBD: how to handle the newContent notification back to IngestConfigPanel **/ + newContents.add(newImage); + + settings.putProperty(AddImageAction.IMAGEID_PROP, imageId); + } + + // Can't bail and revert image add after commit, so disable image cleanup + // task + + // RAMAN TBD: cleanup task should be handled by the caller + // cleanupImage.disable(); + + settings.putProperty(AddImageAction.IMAGECLEANUPTASK_PROP, null); + + logger.log(Level.INFO, "Image committed, imageId: " + imageId); + logger.log(Level.INFO, PlatformUtil.getAllMemUsageInfo()); + + } + } + + /** + * + * (called by EventDispatch Thread after doInBackground finishes) + * + * Must Not return without invoking the callBack. + */ + @Override + protected void done() { + + logger.log(Level.INFO, "RAMAN: done()..."); + + //these are required to stop the CurrentDirectoryFetcher + progressBar.setIndeterminate(false); + setProgress(100); + + addImageDone = true; + + // attempt actions that might fail and force the process to stop + + if (cancelled || hasCritError) { + logger.log(Level.INFO, "Handling errors or interruption that occured in add image process"); + revert(); + if (hasCritError) { + //core error + // RAMAN TBD: Error reporting needs to be removed from here. All errors are returned to caller directly. + //progressPanel.addErrors(errorString, true); + } + // Do not return yet. Callback must be called + } + if (!errorList.isEmpty()) { + //data error (non-critical) + logger.log(Level.INFO, "Handling non-critical errors that occured in add image process"); + + // RAMAN TBD: Error reporting needs to be removed from here. All errors are returned to caller directly. + //progressPanel.addErrors(errorString, false); + } + + // When everything happens without an error: + if (!(cancelled || hasCritError)) { + + try { + + + /* ***************************** + * RAMAN TBD: the caller needs to handle the cleanup ??? + // the add-image process needs to be reverted if the wizard doesn't finish + cleanupImage = action.new CleanupTask() { + //note, CleanupTask runs inside EWT thread + @Override + void cleanup() throws Exception { + logger.log(Level.INFO, "Running cleanup task after add image process"); + revert(); + } + }; + cleanupImage.enable(); + * ************************/ + + //if (errorString == null) { // complete progress bar + if (errorList.isEmpty() ) { // complete progress bar + progressPanel.getComponent().setProgressBarTextAndColor("*Data Source added.", 100, Color.black); + } + + // RAMAN TBD: this should not be happening in here - caller should do this + + // Get attention for the process finish + java.awt.Toolkit.getDefaultToolkit().beep(); //BEEP! + AddImageWizardAddingProgressVisual panel = progressPanel.getComponent(); + if (panel != null) { + Window w = SwingUtilities.getWindowAncestor(panel); + if (w != null) { + w.toFront(); + } + } + + // Tell the panel we're done + progressPanel.setStateFinished(); + + + if (newContents.isEmpty()) { + if (addImageProcess != null) { // and if we're done configuring ingest + // commit anything + try { + commitImage(wizDescriptor); + } catch (Exception ex) { + // Log error/display warning + logger.log(Level.SEVERE, "Error adding image to case.", ex); + } + } else { + logger.log(Level.SEVERE, "Missing image process object"); + } + } + + else //already commited? + { + logger.log(Level.INFO, "Assuming image already committed, will not commit."); + + } + + + + + // Start ingest if we can + // RAMAN TBD - remove this from here + //startIngest(); + + } catch (Exception ex) { + //handle unchecked exceptions post image add + + logger.log(Level.WARNING, "Unexpected errors occurred while running post add image cleanup. ", ex); + + progressPanel.getComponent().setProgressBarTextAndColor("*Failed to add image.", 0, Color.black); // set error message + + // Log error/display warning + + logger.log(Level.SEVERE, "Error adding image to case", ex); + } finally { + + + } + } + + // invoke the callBack, unless the caller cancelled + if (!cancelled) + doCallBack(); + + } + + + void doCallBack() + { + logger.log(Level.INFO, "RAMAN In doCallback()"); + + DSPCallback.DSP_Result result; + + if (hasCritError) { + result = DSPCallback.DSP_Result.CRITICAL_ERRORS; + } + else if (!errorList.isEmpty()) { + result = DSPCallback.DSP_Result.NONCRITICAL_ERRORS; + } + else { + result = DSPCallback.DSP_Result.NO_ERRORS; + } + + callbackObj.done(result, errorList, newContents); + } + + /***** + public List getNewContents() { + + return newContents; + + } + * ********/ + + void cancelTask() { + + logger.log(Level.INFO, "RAMAN: cancelTask()..."); + + cancelled = true; + + if (!addImageDone) { + try { + addImageTask.interrupt(); + } + catch (Exception ex) { + logger.log(Level.SEVERE, "Failed to interrup the add image task..."); + } + } + else { + try { + addImageTask.revert(); + } + catch(Exception ex) { + logger.log(Level.SEVERE, "Failed to revert the add image task..."); + } + } + } + void interrupt() throws Exception { + + logger.log(Level.INFO, "RAMAN: interrupt()..."); + + //interrupted = true; + try { + logger.log(Level.INFO, "interrupt() add image process"); + addImageProcess.stop(); //it might take time to truly stop processing and writing to db + } catch (TskException ex) { + throw new Exception("Error stopping add-image process.", ex); + } + } + + //runs in EWT + void revert() { + + logger.log(Level.INFO, "RAMAN: revert()..."); + if (!reverted) { + + try { + logger.log(Level.INFO, "Revert after add image process"); + try { + addImageProcess.revert(); + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Error reverting add image process", ex); + } + } finally { + //unlock db write within EWT thread + SleuthkitCase.dbWriteUnlock(); + } + reverted = true; + } + } + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java index a71ad31681..3bc25fe42d 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java @@ -158,8 +158,8 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener } @Override - public ContentType getContentType() { - return ContentType.IMAGE; + public String getContentType() { + return "IMAGE"; } @Override diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java index 6a51382940..f007189683 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java @@ -153,8 +153,8 @@ public class LocalDiskPanel extends ContentTypePanel { } @Override - public ContentType getContentType() { - return ContentType.DISK; + public String getContentType() { + return "DISK"; } /** diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java index 7d07033ac1..4af5cf0ab9 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java @@ -79,8 +79,8 @@ public class LocalFilesPanel extends ContentTypePanel { } @Override - public ContentType getContentType() { - return ContentType.LOCAL; + public String getContentType() { + return "LOCAL"; } @Override From f401b39d14e1901f6e8b5464047312b165f7263a Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 11 Oct 2013 12:32:19 -0400 Subject: [PATCH 006/169] Interim checkin of new tags API --- .../autopsy/actions/Bundle.properties | 11 + .../TagAbstractFileAction.java | 49 ++-- .../TagAndCommentDialog.form | 16 +- .../TagAndCommentDialog.java | 3 +- .../TagBlackboardArtifactAction.java | 43 ++- .../{directorytree => actions}/TagMenu.java | 5 +- .../TagSleuthKitDataModelObjectAction.java | 70 +++++ .../casemodule/services/TagsManager.java | 253 ++++++++++-------- .../datamodel/AbstractContentChildren.java | 6 +- .../autopsy/datamodel/AutopsyItemVisitor.java | 9 +- .../datamodel/BlackboardArtifactTagNode.java | 75 ++++++ .../autopsy/datamodel/ContentTagNode.java | 74 +++++ .../autopsy/datamodel/ContentTagTypeNode.java | 95 +++++++ .../autopsy/datamodel/DirectoryNode.java | 2 +- .../datamodel/DisplayableItemNodeVisitor.java | 47 +++- .../sleuthkit/autopsy/datamodel/FileNode.java | 2 +- .../autopsy/datamodel/LayoutFileNode.java | 2 +- .../autopsy/datamodel/LocalFileNode.java | 2 +- .../autopsy/datamodel/ResultsNode.java | 4 +- .../datamodel/RootContentChildren.java | 6 + .../autopsy/datamodel/TagNameNode.java | 106 ++++++++ .../sleuthkit/autopsy/datamodel/TagsNode.java | 82 ++++++ .../autopsy/datamodel/TagsNodeKey.java | 34 +++ .../datamodel/VirtualDirectoryNode.java | 2 +- .../BlackboardArtifactTagTypeNode.java | 99 +++++++ .../autopsy/directorytree/Bundle.properties | 8 - .../directorytree/CreateTagDialog.java | 1 - .../directorytree/DataResultFilterNode.java | 2 + .../DirectoryTreeTopComponent.java | 2 +- .../ExplorerNodeActionVisitor.java | 1 + .../KeywordSearchFilterNode.java | 2 +- 31 files changed, 918 insertions(+), 195 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/actions/Bundle.properties rename Core/src/org/sleuthkit/autopsy/{directorytree => actions}/TagAbstractFileAction.java (59%) rename Core/src/org/sleuthkit/autopsy/{directorytree => actions}/TagAndCommentDialog.form (81%) rename Core/src/org/sleuthkit/autopsy/{directorytree => actions}/TagAndCommentDialog.java (99%) rename Core/src/org/sleuthkit/autopsy/{directorytree => actions}/TagBlackboardArtifactAction.java (67%) rename Core/src/org/sleuthkit/autopsy/{directorytree => actions}/TagMenu.java (93%) create mode 100755 Core/src/org/sleuthkit/autopsy/actions/TagSleuthKitDataModelObjectAction.java create mode 100755 Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java create mode 100755 Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java create mode 100755 Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java create mode 100755 Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java create mode 100755 Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java create mode 100755 Core/src/org/sleuthkit/autopsy/datamodel/TagsNodeKey.java create mode 100755 Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java diff --git a/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties new file mode 100755 index 0000000000..b0c06a74df --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties @@ -0,0 +1,11 @@ +# To change this template, choose Tools | Templates +# and open the template in the editor. + +TagAndCommentDialog.cancelButton.text=Cancel +TagAndCommentDialog.newTagButton.text=New Tag +TagAndCommentDialog.tagCombo.toolTipText=Select tag to use +TagAndCommentDialog.tagLabel.text=Tag: +TagAndCommentDialog.commentLabel.text=Comment: +TagAndCommentDialog.commentText.toolTipText=Enter an optional tag comment or leave blank +TagAndCommentDialog.commentText.text= +TagAndCommentDialog.okButton.text=OK diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java b/Core/src/org/sleuthkit/autopsy/actions/TagAbstractFileAction.java similarity index 59% rename from Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java rename to Core/src/org/sleuthkit/autopsy/actions/TagAbstractFileAction.java index 5afbf89fef..b90ebac286 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/TagAbstractFileAction.java @@ -16,25 +16,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.directorytree; +package org.sleuthkit.autopsy.actions; -import java.awt.event.ActionEvent; import java.util.Collection; import java.util.logging.Level; -import javax.swing.AbstractAction; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import org.openide.util.Utilities; -import org.openide.util.actions.Presenter; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.Tags; import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.TagType; +import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; -public class TagAbstractFileAction extends AbstractAction implements Presenter.Popup { +/** + * Instances of this Action allow users to apply tags to content. + */ +public class TagAbstractFileAction extends TagSleuthKitDataModelObjectAction { // This class is a singleton to support multi-selection of nodes, since // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every // node in the array returns a reference to the same action object from Node.getActions(boolean). @@ -51,44 +51,33 @@ public class TagAbstractFileAction extends AbstractAction implements Presenter.P } @Override - public JMenuItem getPopupPresenter() { - return new TagAbstractFileMenu(); + protected JMenuItem getContextMenu() { + return new TagAbstractFileMenu(); } - @Override - public void actionPerformed(ActionEvent e) { - // Do nothing - this action should never be performed. - // Submenu actions are invoked instead. - } - private static class TagAbstractFileMenu extends TagMenu { + private class TagAbstractFileMenu extends TagMenu { public TagAbstractFileMenu() { super(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class).size() > 1 ? "Tag Files" : "Tag File"); } @Override protected void applyTag(String tagDisplayName, String comment) { - try { + TagName tagName = getTagName(tagDisplayName, comment); + if (tagName != null) { TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); - TagType tagType = tagsManager.addTagType(tagDisplayName); - Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); for (AbstractFile file : selectedFiles) { Tags.createTag(file, tagDisplayName, comment); -// try { -// tagsManager.addContentTag(file, tagType); -// } -// catch (TskCoreException ex) { -// Logger.getLogger(TagAbstractFileMenu.class.getName()).log(Level.SEVERE, "Error tagging content", ex); -// } + try { + tagsManager.addContentTag(file, tagName); + } + catch (TskCoreException ex) { + Logger.getLogger(TagAbstractFileMenu.class.getName()).log(Level.SEVERE, "Error tagging result", ex); + JOptionPane.showMessageDialog(null, "Unable to tag " + file.getName() + ".", "Tagging Error", JOptionPane.ERROR_MESSAGE); + } } } - catch (TagsManager.TagTypeAlreadyExistsException ex) { - JOptionPane.showMessageDialog(null, "A " + tagDisplayName + " tag type has already been defined.", "Duplicate Tag Type", JOptionPane.ERROR_MESSAGE); - } - catch (TskCoreException ex) { - Logger.getLogger(TagAbstractFileMenu.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag type", ex); - } } } -} +} \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagAndCommentDialog.form b/Core/src/org/sleuthkit/autopsy/actions/TagAndCommentDialog.form similarity index 81% rename from Core/src/org/sleuthkit/autopsy/directorytree/TagAndCommentDialog.form rename to Core/src/org/sleuthkit/autopsy/actions/TagAndCommentDialog.form index 1bacfb8942..268c5b5f77 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/TagAndCommentDialog.form +++ b/Core/src/org/sleuthkit/autopsy/actions/TagAndCommentDialog.form @@ -78,7 +78,7 @@ - + @@ -91,7 +91,7 @@ - + @@ -104,7 +104,7 @@ - + @@ -114,31 +114,31 @@ - + - + - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagAndCommentDialog.java b/Core/src/org/sleuthkit/autopsy/actions/TagAndCommentDialog.java similarity index 99% rename from Core/src/org/sleuthkit/autopsy/directorytree/TagAndCommentDialog.java rename to Core/src/org/sleuthkit/autopsy/actions/TagAndCommentDialog.java index 4d00770205..6c390ac720 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/TagAndCommentDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/TagAndCommentDialog.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.directorytree; +package org.sleuthkit.autopsy.actions; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; @@ -30,6 +30,7 @@ import javax.swing.JFrame; import javax.swing.KeyStroke; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.datamodel.Tags; +import org.sleuthkit.autopsy.directorytree.CreateTagDialog; /** * Tag dialog for tagging files and results. User enters an optional comment. diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagBlackboardArtifactAction.java b/Core/src/org/sleuthkit/autopsy/actions/TagBlackboardArtifactAction.java similarity index 67% rename from Core/src/org/sleuthkit/autopsy/directorytree/TagBlackboardArtifactAction.java rename to Core/src/org/sleuthkit/autopsy/actions/TagBlackboardArtifactAction.java index 3f2c8fd407..ebda9eb87f 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/TagBlackboardArtifactAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/TagBlackboardArtifactAction.java @@ -16,25 +16,25 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.directorytree; +package org.sleuthkit.autopsy.actions; -import java.awt.event.ActionEvent; import java.util.Collection; import java.util.logging.Level; -import javax.swing.AbstractAction; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import org.openide.util.Utilities; -import org.openide.util.actions.Presenter; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.Tags; +import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.TagType; import org.sleuthkit.datamodel.TskCoreException; -public class TagBlackboardArtifactAction extends AbstractAction implements Presenter.Popup { +/** + * Instances of this Action allow users to apply tags to blackboard artifacts. + */ +public class TagBlackboardArtifactAction extends TagSleuthKitDataModelObjectAction { // This class is a singleton to support multi-selection of nodes, since // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every // node in the array returns a reference to the same action object from Node.getActions(boolean). @@ -49,47 +49,34 @@ public class TagBlackboardArtifactAction extends AbstractAction implements Prese private TagBlackboardArtifactAction() { } - + @Override - public JMenuItem getPopupPresenter() { - return new TagBlackboardArtifactMenu(); + protected JMenuItem getContextMenu() { + return new TagBlackboardArtifactMenu(); } - @Override - public void actionPerformed(ActionEvent e) { - // Do nothing - this action should never be performed. - // Submenu actions are invoked instead. - } - - - private static class TagBlackboardArtifactMenu extends TagMenu { + private class TagBlackboardArtifactMenu extends TagMenu { public TagBlackboardArtifactMenu() { super(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class).size() > 1 ? "Tag Results" : "Tag Result"); } @Override protected void applyTag(String tagDisplayName, String comment) { - try { + TagName tagName = getTagName(tagDisplayName, comment); + if (tagName != null) { TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); - TagType tagType = tagsManager.addTagType(tagDisplayName); - Collection selectedArtifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class); for (BlackboardArtifact artifact : selectedArtifacts) { Tags.createTag(artifact, tagDisplayName, comment); try { - tagsManager.addBlackboardArtifactTag(artifact, tagType); + tagsManager.addBlackboardArtifactTag(artifact, tagName); } - catch (TskCoreException ex) { + catch (TskCoreException ex) { Logger.getLogger(TagBlackboardArtifactMenu.class.getName()).log(Level.SEVERE, "Error tagging result", ex); + JOptionPane.showMessageDialog(null, "Unable to tag " + artifact.getDisplayName() + ".", "Tagging Error", JOptionPane.ERROR_MESSAGE); } } } - catch (TagsManager.TagTypeAlreadyExistsException ex) { - JOptionPane.showMessageDialog(null, "A " + tagDisplayName + " tag type has already been defined.", "Duplicate Tag Type", JOptionPane.ERROR_MESSAGE); - } - catch (TskCoreException ex) { - Logger.getLogger(TagBlackboardArtifactMenu.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag type", ex); - } } } } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagMenu.java b/Core/src/org/sleuthkit/autopsy/actions/TagMenu.java similarity index 93% rename from Core/src/org/sleuthkit/autopsy/directorytree/TagMenu.java rename to Core/src/org/sleuthkit/autopsy/actions/TagMenu.java index de6b9c5033..a680e626bc 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/TagMenu.java +++ b/Core/src/org/sleuthkit/autopsy/actions/TagMenu.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.directorytree; +package org.sleuthkit.autopsy.actions; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -24,6 +24,8 @@ import java.util.TreeSet; import javax.swing.JMenu; import javax.swing.JMenuItem; import org.sleuthkit.autopsy.datamodel.Tags; +import org.sleuthkit.autopsy.directorytree.CreateTagDialog; +import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; import org.sleuthkit.datamodel.BlackboardArtifact; /** @@ -91,6 +93,7 @@ public abstract class TagMenu extends JMenu { private void refreshDirectoryTree() { //TODO instead should send event to node children, which will call its refresh() / refreshKeys() + // RJCTODO: Explain what is going on here and pare to one refreshTree() call. DirectoryTreeTopComponent viewer = DirectoryTreeTopComponent.findInstance(); viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE); viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT); diff --git a/Core/src/org/sleuthkit/autopsy/actions/TagSleuthKitDataModelObjectAction.java b/Core/src/org/sleuthkit/autopsy/actions/TagSleuthKitDataModelObjectAction.java new file mode 100755 index 0000000000..2796b1ef7c --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/actions/TagSleuthKitDataModelObjectAction.java @@ -0,0 +1,70 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 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.actions; + +import java.awt.event.ActionEvent; +import java.util.logging.Level; +import javax.swing.AbstractAction; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import org.openide.util.actions.Presenter; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.services.TagsManager; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskCoreException; + +abstract class TagSleuthKitDataModelObjectAction extends AbstractAction implements Presenter.Popup { + abstract protected JMenuItem getContextMenu(); + + @Override + public JMenuItem getPopupPresenter() { + return getContextMenu(); + } + + @Override + public void actionPerformed(ActionEvent e) { + // Do nothing - this action should never be performed. + // Context actions are invoked instead. + } + + protected TagName getTagName(String tagDisplayName, String comment) { + TagName tagName = null; + try { + TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + if (tagsManager.tagNameExists(tagDisplayName)) { + tagName = tagsManager.getTagName(tagDisplayName); + } + else { + try { + tagName = tagsManager.addTagName(tagDisplayName); + } + catch (TskCoreException ex) { + Logger.getLogger(TagSleuthKitDataModelObjectAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex); + JOptionPane.showMessageDialog(null, "Unable to add the " + tagDisplayName + " tag name to the case.", "Tagging Error", JOptionPane.ERROR_MESSAGE); + return null; + } + } + } + catch (TagsManager.TagNameAlreadyExistsException ex) { + JOptionPane.showMessageDialog(null, "A " + tagDisplayName + " tag name has already been defined.", "Duplicate Tag Error", JOptionPane.ERROR_MESSAGE); + } + return tagName; + } +} \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 2ae7426655..47675cb5f4 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.casemodule.services; import java.io.Closeable; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -31,166 +32,133 @@ import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.SleuthkitCase; -import org.sleuthkit.datamodel.TagType; +import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; /** * A singleton instance of this class functions as an Autopsy service that * manages the creation, updating, and deletion of tags applied to Content and - * BlackboardArtifacts objects by users. + * BlackboardArtifacts objects by users. */ public class TagsManager implements Closeable { private static final String TAGS_SETTINGS_FILE_NAME = "tags"; - private static final String TAG_TYPES_SETTING_KEY = "tagTypes"; + private static final String TAG_NAMES_SETTING_KEY = "tagNames"; private final SleuthkitCase tskCase; - private final HashMap tagTypes = new HashMap<>(); + private final HashMap tagNames = new HashMap<>(); TagsManager(SleuthkitCase tskCase) { this.tskCase = tskCase; - loadTagTypesFromTagSettings(); + loadTagNamesFromTagSettings(); } - private void loadTagTypesFromTagSettings() { - // Get any tag types already added to the current case. + /** + * Gets a list of all tag names currently available for tagging content or + * blackboard artifacts. + * @return [out] A list, possibly empty, of TagName data transfer objects (DTOs). + */ + public void getTagNames(List tagNames) { try { - List currentTagTypes = tskCase.getTagTypes(); - for (TagType tagType : currentTagTypes) { - tagTypes.put(tagType.getDisplayName(), tagType); - } + tagNames.clear(); + tskCase.getTagNames(tagNames); } catch (TskCoreException ex) { - Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag types from the current case", ex); + Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names from the current case", ex); + } + } + + /** + * RJCTODO: Discard or properly comment + */ + public boolean tagNameExists(String tagDisplayName) { + return tagNames.containsKey(tagDisplayName); + } + + /** + * RJCTODO: Discard or properly comment + */ + public TagName getTagName(String tagDisplayName) { + if (!tagNames.containsKey(tagDisplayName)) { + // RJCTODO: Throw exception } - // Read the saved tag types, if any, from the tags settings file and - // add them to the current case if they haven't already been added, e.g, - // when the case was last opened. - String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_FILE_NAME, TAG_TYPES_SETTING_KEY); - if (null != setting && !setting.isEmpty()) { - // Read the tag types setting and break in into tag type tuples. - List tagTypeTuples = Arrays.asList(setting.split(";")); - - // Parse each tuple and add the tag types to the current case, one - // at a time to gracefully discard any duplicates or corrupt tuples. - for (String tagTypeTuple : tagTypeTuples) { - String[] tagTypeAttributes = tagTypeTuple.split(","); - if (!tagTypes.containsKey(tagTypeAttributes[0])) { - TagType tagType = new TagType(tagTypeAttributes[0], tagTypeAttributes[1], TagType.HTML_COLOR.getColorByName(tagTypeAttributes[2])); - try { - tskCase.addTagType(tagType); - tagTypes.put(tagType.getDisplayName(),tagType); - } - catch(TskCoreException ex) { - Logger.getLogger(TagsManager.class.getName()).log(Level.WARNING, "Failed to add saved " + tagType.getDisplayName() + " tag type to the current case", ex); - } - } - } - - saveTagTypesToTagsSettings(); - } - } - - private void saveTagTypesToTagsSettings() { - if (!tagTypes.isEmpty()) { - StringBuilder setting = new StringBuilder(); - for (TagType tagType : tagTypes.values()) { - if (setting.length() != 0) { - setting.append(";"); - } - setting.append(tagType.getDisplayName()).append(","); - setting.append(tagType.getDescription()).append(","); - setting.append(tagType.getColor().name()); - } - - ModuleSettings.setConfigSetting(TAGS_SETTINGS_FILE_NAME, TAG_TYPES_SETTING_KEY, setting.toString()); - } + return tagNames.get(tagDisplayName); } /** - * Gets a list of all tag types currently available for tagging content or - * blackboard artifacts. - * @return A list, possibly empty, of TagType data transfer objects (DTOs). + * Adds a new tag name to the current case and to the tags settings file. + * @param displayName The display name for the new tag name. + * @return A TagName object representing the new tag name on success, null on failure. * @throws TskCoreException */ - public List getTagTypes() throws TskCoreException { - return tskCase.getTagTypes(); + public TagName addTagName(String displayName) throws TagNameAlreadyExistsException, TskCoreException { + return addTagName(displayName, "", TagName.HTML_COLOR.NONE); } /** - * Adds a new tag type to the current case and to the tags settings file. - * @param displayName The display name for the new tag type. - * @return A TagType object representing the new type on success, null on failure. + * Adds a new tag name to the current case and to the tags settings file. + * @param displayName The display name for the new tag name. + * @param description The description for the new tag name. + * @return A TagName object representing the new tag name on success, null on failure. * @throws TskCoreException */ - public TagType addTagType(String displayName) throws TagTypeAlreadyExistsException, TskCoreException { - return addTagType(displayName, "", TagType.HTML_COLOR.NONE); + public TagName addTagName(String displayName, String description) throws TagNameAlreadyExistsException, TskCoreException { + return addTagName(displayName, description, TagName.HTML_COLOR.NONE); } /** - * Adds a new tag type to the current case and to the tags settings file. - * @param displayName The display name for the new tag type. - * @param description The description for the new tag type. - * @return A TagType object representing the new type on success, null on failure. + * Adds a new tag name to the current case and to the tags settings file. + * @param displayName The display name for the new tag name. + * @param description The description for the new tag name. + * @param color The HTML color to associate with the new tag name. + * @return A TagName object representing the new tag name. * @throws TskCoreException */ - public TagType addTagType(String displayName, String description) throws TagTypeAlreadyExistsException, TskCoreException { - return addTagType(displayName, description, TagType.HTML_COLOR.NONE); - } - - /** - * Adds a new tag type to the current case and to the tags settings file. - * @param displayName The display name for the new tag type. - * @param description The description for the new tag type. - * @param color The HTML color to associate with the new tag type. - * @return A TagType object representing the new type. - * @throws TskCoreException - */ - public synchronized TagType addTagType(String displayName, String description, TagType.HTML_COLOR color) throws TagTypeAlreadyExistsException, TskCoreException { - if (tagTypes.containsKey(displayName)) { - throw new TagTypeAlreadyExistsException(); + public synchronized TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TagNameAlreadyExistsException, TskCoreException { + if (tagNames.containsKey(displayName)) { + throw new TagNameAlreadyExistsException(); } - TagType newTagType = new TagType(displayName, description, color); - tskCase.addTagType(newTagType); - tagTypes.put(newTagType.getDisplayName(), newTagType); - saveTagTypesToTagsSettings(); - return newTagType; + TagName newTagName = new TagName(displayName, description, color); + tskCase.addTagName(newTagName); + tagNames.put(newTagName.getDisplayName(), newTagName); + saveTagNamesToTagsSettings(); + return newTagName; } - public class TagTypeAlreadyExistsException extends Exception { + public class TagNameAlreadyExistsException extends Exception { } /** * Tags a Content object. * @param content The Content to tag. - * @param tagType The type of tag to add. + * @param tagName The type of tag to add. * @throws TskCoreException */ - public void addContentTag(Content content, TagType tagType) throws TskCoreException { - addContentTag(content, tagType, "", 0, content.getSize() - 1); + public void addContentTag(Content content, TagName tagName) throws TskCoreException { + addContentTag(content, tagName, "", 0, content.getSize() - 1); } /** * Tags a Content object. * @param content The Content to tag. - * @param tagType The type of tag to add. + * @param tagName The name to use for the tag. * @param comment A comment to store with the tag. * @throws TskCoreException */ - public void addContentTag(Content content, TagType tagType, String comment) throws TskCoreException { - addContentTag(content, tagType, comment, 0, content.getSize() - 1); + public void addContentTag(Content content, TagName tagName, String comment) throws TskCoreException { + addContentTag(content, tagName, comment, 0, content.getSize() - 1); } /** * Tags a Content object or a portion of a content object. * @param content The Content to tag. - * @param tagType The type of tag to add. + * @param tagName The name to use for the tag. * @param comment A comment to store with the tag. * @param beginByteOffset Designates the beginning of a tagged extent. * @param endByteOffset Designates the end of a tagged extent. * @throws TskCoreException */ - public void addContentTag(Content content, TagType tagType, String comment, long beginByteOffset, long endByteOffset) throws IllegalArgumentException, TskCoreException { + public void addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws IllegalArgumentException, TskCoreException { if (beginByteOffset < 0) { throw new IllegalArgumentException("Content extent incorrect: beginByteOffset < 0"); } @@ -203,7 +171,7 @@ public class TagsManager implements Closeable { throw new IllegalArgumentException("Content extent incorrect: endByteOffset exceeds content size"); } - tskCase.addContentTag(new ContentTag(content, tagType, comment, beginByteOffset, endByteOffset)); + tskCase.addContentTag(new ContentTag(content, tagName, comment, beginByteOffset, endByteOffset)); } /** @@ -218,30 +186,105 @@ public class TagsManager implements Closeable { /** * Tags a BlackboardArtifact object. * @param artifact The BlackboardArtifact to tag. - * @param tagType The type of tag to add. + * @param tagName The name to use for the tag. * @throws TskCoreException */ - public void addBlackboardArtifactTag(BlackboardArtifact artifact, TagType tagType) throws TskCoreException { - addBlackboardArtifactTag(artifact, tagType, ""); + public void addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName) throws TskCoreException { + addBlackboardArtifactTag(artifact, tagName, ""); } /** * Tags a BlackboardArtifact object. * @param artifact The BlackboardArtifact to tag. - * @param tagType The type of tag to add. + * @param tagName The name to use for the tag. * @param comment A comment to store with the tag. * @throws TskCoreException */ - public void addBlackboardArtifactTag(BlackboardArtifact artifact, TagType tagType, String comment) throws TskCoreException { - tskCase.addBlackboardArtifactTag(new BlackboardArtifactTag(artifact, tagType, comment)); + public void addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException { + tskCase.addBlackboardArtifactTag(new BlackboardArtifactTag(artifact, tagName, comment)); } void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException { tskCase.deleteBlackboardArtifactTag(tag); } + /** + * RJCTODO + * @param tagName + * @return + */ + public void getContentTags(TagName tagName, List tags) { + // RJCTODO: Implement + } + + /** + * RJCTODO + * @param tagName + * @return + */ + public void getBlackboardArtifactTags(TagName tagName, List tags) { + // RJCTODO: Implement + } + @Override public void close() throws IOException { - saveTagTypesToTagsSettings(); + saveTagNamesToTagsSettings(); } + + private void loadTagNamesFromTagSettings() { + // Get any tag names already defined for the current case. + try { + ArrayList currentTagNames = new ArrayList<>(); + tskCase.getTagNames(currentTagNames); + for (TagName tagName : currentTagNames) { + tagNames.put(tagName.getDisplayName(), tagName); + } + } + catch (TskCoreException ex) { + Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag types from the current case", ex); + } + + // Read the saved tag names, if any, from the tags settings file and + // add them to the current case if they haven't already been added, e.g, + // when the case was last opened. + String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_FILE_NAME, TAG_NAMES_SETTING_KEY); + if (null != setting && !setting.isEmpty()) { + // Read the tag types setting and break in into tag type tuples. + List tagNameTuples = Arrays.asList(setting.split(";")); + + // Parse each tuple and add the tag types to the current case, one + // at a time to gracefully discard any duplicates or corrupt tuples. + for (String tagNameTuple : tagNameTuples) { + String[] tagNameAttributes = tagNameTuple.split(","); + if (!tagNames.containsKey(tagNameAttributes[0])) { + TagName tagName = new TagName(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.getColorByName(tagNameAttributes[2])); + try { + tskCase.addTagName(tagName); + tagNames.put(tagName.getDisplayName(),tagName); + } + catch(TskCoreException ex) { + Logger.getLogger(TagsManager.class.getName()).log(Level.WARNING, "Failed to add saved " + tagName.getDisplayName() + " tag name to the current case", ex); + } + } + } + + saveTagNamesToTagsSettings(); + } + } + + private void saveTagNamesToTagsSettings() { + if (!tagNames.isEmpty()) { + StringBuilder setting = new StringBuilder(); + for (TagName tagName : tagNames.values()) { + if (setting.length() != 0) { + setting.append(";"); + } + setting.append(tagName.getDisplayName()).append(","); + setting.append(tagName.getDescription()).append(","); + setting.append(tagName.getColor().name()); + } + + ModuleSettings.setConfigSetting(TAGS_SETTINGS_FILE_NAME, TAG_NAMES_SETTING_KEY, setting.toString()); + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java index 97d9e99524..5df4ad782e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java @@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.datamodel; import org.openide.nodes.AbstractNode; import org.openide.nodes.Children.Keys; import org.openide.nodes.Node; -import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode; import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode; import org.sleuthkit.datamodel.DerivedFile; import org.sleuthkit.datamodel.Directory; @@ -161,6 +160,11 @@ abstract class AbstractContentChildren extends Keys { return t.new TagsRootNode(); } + @Override + public AbstractNode visit(TagsNodeKey tagsNodeKey) { + return new TagsNode(); + } + @Override public AbstractNode visit(DataSources i) { try { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java index 428db99c76..0a3133a018 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java @@ -54,12 +54,14 @@ public interface AutopsyItemVisitor { T visit(Tags t); + T visit(TagsNodeKey tagsNodeKey); + T visit(DataSources i); T visit(Views v); T visit(Results r); - + static abstract public class Default implements AutopsyItemVisitor { protected abstract T defaultVisit(AutopsyVisitableItem ec); @@ -139,6 +141,11 @@ public interface AutopsyItemVisitor { return defaultVisit(t); } + @Override + public T visit(TagsNodeKey tagsNodeKey) { + return defaultVisit(tagsNodeKey); + } + @Override public T visit(DataSources i) { return defaultVisit(i); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java new file mode 100755 index 0000000000..bc9c79c823 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java @@ -0,0 +1,75 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 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.datamodel; + +import org.openide.nodes.Children; +import org.openide.nodes.Sheet; +import org.openide.util.lookup.Lookups; +import org.sleuthkit.datamodel.BlackboardArtifactTag; + +/** + * Instances of this class wrap BlackboardArtifactTag objects. In the Autopsy + * presentation of the SleuthKit data model, they are leaf nodes of a sub-tree + * organized as follows: there is a tags root node with tag name child nodes; + * tag name nodes have tag type child nodes; tag type nodes are the parents of + * either content or blackboard artifact tag nodes. + */ +public class BlackboardArtifactTagNode extends DisplayableItemNode { + private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; // RJCTODO: Want better icons? + + public BlackboardArtifactTagNode(BlackboardArtifactTag tag) { + super(Children.LEAF, Lookups.singleton(tag)); + super.setName(tag.getArtifact().getDisplayName()); + super.setDisplayName(tag.getArtifact().getDisplayName()); + this.setIconBaseWithExtension(ICON_PATH); + } + + @Override + protected Sheet createSheet() { + // RJCTODO: Make additional properties as needed for DataResultViewers + Sheet propertySheet = super.createSheet(); + Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES); + if (properties == null) { + properties = Sheet.createPropertiesSet(); + propertySheet.put(properties); + } + + properties.put(new NodeProperty("Name", "Name", "", getName())); + + return propertySheet; + } + + @Override + public T accept(DisplayableItemNodeVisitor v) { + // See classes derived from DisplayableItemNodeVisitor + // for behavior added using the Visitor pattern. + return v.visit(this); + } + + @Override + public DisplayableItemNode.TYPE getDisplayableItemNodeType() { + return DisplayableItemNode.TYPE.META; // RJCTODO: Is this right? What is this stuff for? + } + + @Override + public boolean isLeafTypeNode() { + return true; + } +} + diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java new file mode 100755 index 0000000000..c583e57d16 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java @@ -0,0 +1,74 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 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.datamodel; + +import org.openide.nodes.Children; +import org.openide.nodes.Sheet; +import org.openide.util.lookup.Lookups; +import org.sleuthkit.datamodel.ContentTag; + +/** + * Instances of this class wrap ContentTag objects. In the Autopsy + * presentation of the SleuthKit data model, they are leaf nodes of a tree + * consisting of content and blackboard artifact tags, grouped first by tag + * type, then by tag name. + */ +public class ContentTagNode extends DisplayableItemNode { + private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; + + public ContentTagNode(ContentTag tag) { + super(Children.LEAF, Lookups.singleton(tag)); + super.setName(tag.getContent().getName()); + super.setDisplayName(tag.getContent().getName()); + this.setIconBaseWithExtension(ICON_PATH); + } + + @Override + protected Sheet createSheet() { + // RJCTODO: Make additional properties as needed for DataResultViewers + Sheet propertySheet = super.createSheet(); + Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES); + if (properties == null) { + properties = Sheet.createPropertiesSet(); + propertySheet.put(properties); + } + + properties.put(new NodeProperty("Name", "Name", "", getName())); + + return propertySheet; + } + + @Override + public T accept(DisplayableItemNodeVisitor v) { + // See classes derived from DisplayableItemNodeVisitor + // for behavior added using the Visitor pattern. + return v.visit(this); + } + + @Override + public DisplayableItemNode.TYPE getDisplayableItemNodeType() { + return DisplayableItemNode.TYPE.META; // RJCTODO: Is this right? What is this stuff for? + } + + @Override + public boolean isLeafTypeNode() { + return true; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java new file mode 100755 index 0000000000..e4a20c80bb --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java @@ -0,0 +1,95 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 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.datamodel; + +import java.util.List; +import org.openide.nodes.ChildFactory; +import org.openide.nodes.Children; +import org.openide.nodes.Node; +import org.openide.nodes.Sheet; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.TagName; + +/** + * Instances of this class are are elements of a directory tree sub-tree + * consisting of content and blackboard artifact tags, grouped first by tag type, + * then by tag name. + */ +public class ContentTagTypeNode extends DisplayableItemNode { + private static final String DISPLAY_NAME = "Content Tags"; + private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; + + public ContentTagTypeNode(TagName tagName) { + super(Children.create(new ContentTagNodeFactory(tagName), true)); + super.setName(DISPLAY_NAME); + super.setDisplayName(DISPLAY_NAME); + this.setIconBaseWithExtension(ICON_PATH); + } + + @Override + protected Sheet createSheet() { + Sheet propertySheet = super.createSheet(); + Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES); + if (properties == null) { + properties = Sheet.createPropertiesSet(); + propertySheet.put(properties); + } + + properties.put(new NodeProperty("Name", "Name", "", getName())); + + return propertySheet; + } + + @Override + public T accept(DisplayableItemNodeVisitor v) { + return v.visit(this); + } + + @Override + public DisplayableItemNode.TYPE getDisplayableItemNodeType() { + return DisplayableItemNode.TYPE.META; + } + + @Override + public boolean isLeafTypeNode() { + return false; + } + + private static class ContentTagNodeFactory extends ChildFactory { + private final TagName tagName; + + ContentTagNodeFactory(TagName tagName) { + this.tagName = tagName; + } + + @Override + protected boolean createKeys(List keys) { + // Use the content tags bearing the specified tag name as the keys. + Case.getCurrentCase().getServices().getTagsManager().getContentTags(tagName, keys); + return true; + } + + @Override + protected Node createNodeForKey(ContentTag key) { + // The content tags to be wrapped are used as the keys. + return new ContentTagNode(key); + } + } +} \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java index 3c4d33c253..0bf83b433e 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java @@ -23,7 +23,7 @@ import java.util.List; import javax.swing.Action; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; +import org.sleuthkit.autopsy.actions.TagAbstractFileAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Directory; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java index 6e42c7d611..b4d820bec2 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011 - 2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,9 +33,10 @@ import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode; import org.sleuthkit.autopsy.datamodel.Tags.TagNodeRoot; import org.sleuthkit.autopsy.datamodel.Tags.TagsNodeRoot; import org.sleuthkit.autopsy.datamodel.Tags.TagsRootNode; +import org.sleuthkit.autopsy.directorytree.BlackboardArtifactTagTypeNode; /** - * Visitor pattern for DisplayableItemNodes + * Visitor pattern implementation for DisplayableItemNodes */ public interface DisplayableItemNodeVisitor { @@ -91,6 +92,18 @@ public interface DisplayableItemNodeVisitor { T visit(TagNodeRoot tnr); + T visit(TagsNode node); + + T visit(TagNameNode node); + + T visit(ContentTagTypeNode node); + + T visit(ContentTagNode node); + + T visit(BlackboardArtifactTagTypeNode node); + + T visit(BlackboardArtifactTagNode node); + T visit(ViewsNode vn); T visit(ResultsNode rn); @@ -278,5 +291,35 @@ public interface DisplayableItemNodeVisitor { public T visit(TagNodeRoot tnr) { return defaultVisit(tnr); } + + @Override + public T visit(TagsNode node) { + return defaultVisit(node); + } + + @Override + public T visit(TagNameNode node) { + return defaultVisit(node); + } + + @Override + public T visit(ContentTagTypeNode node) { + return defaultVisit(node); + } + + @Override + public T visit(ContentTagNode node) { + return defaultVisit(node); + } + + @Override + public T visit(BlackboardArtifactTagTypeNode node) { + return defaultVisit(node); + } + + @Override + public T visit(BlackboardArtifactTagNode node) { + return defaultVisit(node); + } } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java index 9ca87fd8a7..cb971c64a1 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java @@ -25,7 +25,7 @@ import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; +import org.sleuthkit.autopsy.actions.TagAbstractFileAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java index 9224131ad6..e1e991a3c7 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java @@ -27,7 +27,7 @@ import org.openide.nodes.Sheet; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; +import org.sleuthkit.autopsy.actions.TagAbstractFileAction; import org.sleuthkit.datamodel.LayoutFile; import org.sleuthkit.datamodel.TskData; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java index 78711736b9..48f49a60c8 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java @@ -30,7 +30,7 @@ import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; +import org.sleuthkit.autopsy.actions.TagAbstractFileAction; import org.sleuthkit.datamodel.AbstractFile; /** diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java index 7ebe1d8674..065470a7b3 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java @@ -19,7 +19,6 @@ package org.sleuthkit.autopsy.datamodel; import java.util.Arrays; -import org.openide.nodes.AbstractNode; import org.openide.nodes.Sheet; import org.openide.util.lookup.Lookups; import org.sleuthkit.datamodel.SleuthkitCase; @@ -36,7 +35,8 @@ public class ResultsNode extends DisplayableItemNode { new KeywordHits(sleuthkitCase), new HashsetHits(sleuthkitCase), new EmailExtracted(sleuthkitCase), - new Tags(sleuthkitCase) //TODO move to the top of the tree + new Tags(sleuthkitCase), //TODO move to the top of the tree + new TagsNodeKey() )), Lookups.singleton(NAME)); setName(NAME); setDisplayName(NAME); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java index 1d9bc7fb42..27b1a5ac84 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java @@ -85,12 +85,16 @@ public class RootContentChildren extends AbstractContentChildren { case TSK_TAG_FILE: if (o instanceof Tags) this.refreshKey(o); + if (o instanceof TagsNodeKey) + this.refreshKey(o); break; //TODO check case TSK_TAG_ARTIFACT: if (o instanceof Tags) this.refreshKey(o); + if (o instanceof TagsNodeKey) + this.refreshKey(o); break; default: if (o instanceof ExtractedContent) @@ -107,6 +111,8 @@ public class RootContentChildren extends AbstractContentChildren { this.refreshKey(o); else if (o instanceof Tags) this.refreshKey(o); + else if (o instanceof TagsNodeKey) + this.refreshKey(o); else if (o instanceof ExtractedContent) this.refreshKey(o); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java new file mode 100755 index 0000000000..1555b4eca9 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java @@ -0,0 +1,106 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 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.datamodel; + +import java.util.List; +import org.openide.nodes.ChildFactory; +import org.openide.nodes.Children; +import org.openide.nodes.Node; +import org.openide.nodes.Sheet; +import org.sleuthkit.autopsy.directorytree.BlackboardArtifactTagTypeNode; +import org.sleuthkit.datamodel.TagName; + +/** + * Instances of this class are elements of Node hierarchies consisting of + * content and blackboard artifact tags, grouped first by tag type, then by + * tag name. + */ +public class TagNameNode extends DisplayableItemNode { + private static final String CONTENT_TAG_TYPE_NODE_KEY = "Content Tags"; + private static final String BLACKBOARD_ARTIFACT_TAG_TYPE_NODE_KEY = "Result Tags"; + private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; + private final TagName tagName; + + public TagNameNode(TagName tagName) { + super(Children.create(new TagTypeNodeFactory(tagName), true)); + this.tagName = tagName; + super.setName(tagName.getDisplayName()); + super.setDisplayName(tagName.getDisplayName()); + this.setIconBaseWithExtension(ICON_PATH); + } + + @Override + protected Sheet createSheet() { + Sheet propertySheet = super.createSheet(); + Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES); + if (properties == null) { + properties = Sheet.createPropertiesSet(); + propertySheet.put(properties); + } + + properties.put(new NodeProperty("Name", "Name", tagName.getDescription(), getName())); + + return propertySheet; + } + + @Override + public T accept(DisplayableItemNodeVisitor v) { + // See classes derived from DisplayableItemNodeVisitor + // for behavior added using the Visitor pattern. + return v.visit(this); + } + + @Override + public DisplayableItemNode.TYPE getDisplayableItemNodeType() { + return DisplayableItemNode.TYPE.META; // RJCTODO: What do these types mean and how are they used? What is correct? + } + + @Override + public boolean isLeafTypeNode() { + return false; + } + + private static class TagTypeNodeFactory extends ChildFactory { + private final TagName tagName; + + TagTypeNodeFactory(TagName tagName) { + this.tagName = tagName; + } + + @Override + protected boolean createKeys(List keys) { + keys.add(CONTENT_TAG_TYPE_NODE_KEY); + keys.add(BLACKBOARD_ARTIFACT_TAG_TYPE_NODE_KEY); + return true; + } + + @Override + protected Node createNodeForKey(String key) { + switch (key) { + case CONTENT_TAG_TYPE_NODE_KEY: + return new ContentTagTypeNode(tagName); + case BLACKBOARD_ARTIFACT_TAG_TYPE_NODE_KEY: + return new BlackboardArtifactTagTypeNode(tagName); + default: + return null; // RJCTODO: Programming error decide how to handle. + } + } + } +} + diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java new file mode 100755 index 0000000000..b630a37600 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java @@ -0,0 +1,82 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 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.datamodel; + +import java.util.List; +import org.openide.nodes.ChildFactory; +import org.openide.nodes.Children; +import org.openide.nodes.Node; +import org.openide.nodes.Sheet; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.TagName; + +/** + * Instances of this class are the root nodes of tree that is a sub-tree of the + * Autopsy presentation of the SleuthKit data model. The sub-tree consists of + * content and blackboard artifact tags, grouped first by tag type, then by + * tag name. + */ +public class TagsNode extends DisplayableItemNode { + private static final String DISPLAY_NAME = "Tags"; + private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; + + public TagsNode() { + super(Children.create(new TagsNodeChildFactory(), true)); + super.setName(DISPLAY_NAME); + super.setDisplayName(DISPLAY_NAME); + this.setIconBaseWithExtension(ICON_PATH); + } + + @Override + public T accept(DisplayableItemNodeVisitor v) { + return v.visit(this); + } + + @Override + protected Sheet createSheet() { + Sheet propertySheet = super.createSheet(); + Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES); + if (properties == null) { + properties = Sheet.createPropertiesSet(); + propertySheet.put(properties); + } + + properties.put(new NodeProperty("Name", "Name", "", getName())); + + return propertySheet; + } + + @Override + public DisplayableItemNode.TYPE getDisplayableItemNodeType() { + return DisplayableItemNode.TYPE.ARTIFACT; + } + + private static class TagsNodeChildFactory extends ChildFactory { + @Override + protected boolean createKeys(List keys) { + Case.getCurrentCase().getServices().getTagsManager().getTagNames(keys); + return true; + } + + @Override + protected Node createNodeForKey(TagName key) { + return new TagNameNode(key); + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/TagsNodeKey.java b/Core/src/org/sleuthkit/autopsy/datamodel/TagsNodeKey.java new file mode 100755 index 0000000000..2e98898724 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/TagsNodeKey.java @@ -0,0 +1,34 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 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.datamodel; + +/** + * Instances of this class act as keys for use by instances of the + * RootContentChildren class. RootContentChildren is a NetBeans child node + * factory built on top of the NetBeans Children.Keys class. + */ +public class TagsNodeKey implements AutopsyVisitableItem { + // Creation of a TagsNode object corresponding to TagsNodeKey object is done + // by a CreateAutopsyNodeVisitor dispatched from the AbstractContentChildren + // override of Children.Keys.createNodes(). + @Override + public T accept(AutopsyItemVisitor v) { + return v.visit(this); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java index 756a376d11..af63757bef 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java @@ -27,7 +27,7 @@ import org.openide.nodes.Sheet; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; +import org.sleuthkit.autopsy.actions.TagAbstractFileAction; import org.sleuthkit.datamodel.VirtualDirectory; import org.sleuthkit.datamodel.TskData; diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java new file mode 100755 index 0000000000..6f5c6d07f8 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java @@ -0,0 +1,99 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 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.directorytree; + +import java.util.List; +import org.openide.nodes.ChildFactory; +import org.openide.nodes.Children; +import org.openide.nodes.Node; +import org.openide.nodes.Sheet; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.datamodel.BlackboardArtifactTagNode; +import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; +import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor; +import org.sleuthkit.autopsy.datamodel.NodeProperty; +import org.sleuthkit.datamodel.BlackboardArtifactTag; +import org.sleuthkit.datamodel.TagName; + +/** + * Instances of this class are elements in a sub-tree of the Autopsy + * presentation of the SleuthKit data model. The sub-tree consists of content + * and blackboard artifact tags, grouped first by tag type, then by tag name. + */ +public class BlackboardArtifactTagTypeNode extends DisplayableItemNode { + private static final String DISPLAY_NAME = "Result Tags"; + private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; // RJCTODO: Different icon? + + public BlackboardArtifactTagTypeNode(TagName tagName) { + super(Children.create(new BlackboardArtifactTagNodeFactory(tagName), true)); + super.setName(DISPLAY_NAME); + super.setDisplayName(DISPLAY_NAME); + this.setIconBaseWithExtension(ICON_PATH); + } + + @Override + protected Sheet createSheet() { + Sheet propertySheet = super.createSheet(); + Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES); + if (properties == null) { + properties = Sheet.createPropertiesSet(); + propertySheet.put(properties); + } + + properties.put(new NodeProperty("Name", "Name", "", getName())); + + return propertySheet; + } + + @Override + public T accept(DisplayableItemNodeVisitor v) { + return v.visit(this); + } + + @Override + public DisplayableItemNode.TYPE getDisplayableItemNodeType() { + return DisplayableItemNode.TYPE.META; // RJCTODO: Is this right? + } + + @Override + public boolean isLeafTypeNode() { + return true; + } + + private static class BlackboardArtifactTagNodeFactory extends ChildFactory { + private final TagName tagName; + + BlackboardArtifactTagNodeFactory(TagName tagName) { + this.tagName = tagName; + } + + @Override + protected boolean createKeys(List keys) { + // Use the blackboard artifact tags bearing the specified tag name as the keys. + Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTags(tagName, keys); + return true; + } + + @Override + protected Node createNodeForKey(BlackboardArtifactTag key) { + // The blackboard artifact tags to be wrapped are used as the keys. + return new BlackboardArtifactTagNode(key); + } + } +} \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties index 481f8e930e..41d0090399 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties @@ -53,11 +53,3 @@ CreateTagDialog.tagNameField.text= CreateTagDialog.tagNameLabel.text=Tag Name: CreateTagDialog.preexistingLabel.text=Pre-existing Tags: CreateTagDialog.newTagPanel.border.title=New Tag -TagAndCommentDialog.tagLabel.text=Tag: -TagAndCommentDialog.tagCombo.toolTipText=Select tag to use -TagAndCommentDialog.cancelButton.text=Cancel -TagAndCommentDialog.okButton.text=OK -TagAndCommentDialog.commentText.toolTipText=Enter an optional tag comment or leave blank -TagAndCommentDialog.commentText.text= -TagAndCommentDialog.commentLabel.text=Comment: -TagAndCommentDialog.newTagButton.text=New Tag diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/CreateTagDialog.java b/Core/src/org/sleuthkit/autopsy/directorytree/CreateTagDialog.java index 8fb571cf06..3ab800a2a5 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/CreateTagDialog.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/CreateTagDialog.java @@ -48,7 +48,6 @@ public class CreateTagDialog extends JDialog { } private void init() { - setTitle("Create a new tag"); initComponents(); diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index 8ccc8a7405..375f848006 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -18,6 +18,8 @@ */ package org.sleuthkit.autopsy.directorytree; +import org.sleuthkit.autopsy.actions.TagBlackboardArtifactAction; +import org.sleuthkit.autopsy.actions.TagAbstractFileAction; import java.awt.event.ActionEvent; import java.beans.PropertyVetoException; import java.util.ArrayList; diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index 05ae16d893..da741faa4c 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -787,7 +787,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat * Refreshes the nodes in the tree to reflect updates in the database should * be called in the gui thread */ - void refreshTree(final BlackboardArtifact.ARTIFACT_TYPE... types) { + public void refreshTree(final BlackboardArtifact.ARTIFACT_TYPE... types) { //save current selection Node selectedNode = getSelectedNode(); final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext()); diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java index 72601900a9..80872c0d9f 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.directorytree; +import org.sleuthkit.autopsy.actions.TagAbstractFileAction; import java.awt.Toolkit; import java.awt.Dimension; import java.awt.Font; diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java index 968631e27a..264e5ae6b1 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java @@ -30,7 +30,7 @@ import org.openide.util.lookup.Lookups; import org.openide.util.lookup.ProxyLookup; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; -import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; +import org.sleuthkit.autopsy.actions.TagAbstractFileAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.datamodel.Content; From 79cab5df5755ac6b16234042c38d39689c459314 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 11 Oct 2013 17:46:19 -0400 Subject: [PATCH 007/169] Interim commit of work on new tags API --- Core/nbproject/project.xml | 437 +++++++++--------- .../AddBlackboardArtifactTagAction.java | 70 +++ .../autopsy/actions/AddContentTagAction.java | 70 +++ .../autopsy/actions/AddTagAction.java | 147 ++++++ .../autopsy/actions/Bundle.properties | 23 +- ...g.form => GetTagNameAndCommentDialog.form} | 16 +- ...g.java => GetTagNameAndCommentDialog.java} | 116 +++-- .../GetTagNameDialog.form} | 12 +- .../GetTagNameDialog.java} | 187 ++++---- .../actions/TagAbstractFileAction.java | 83 ---- .../actions/TagBlackboardArtifactAction.java | 82 ---- .../sleuthkit/autopsy/actions/TagMenu.java | 103 ----- .../TagSleuthKitDataModelObjectAction.java | 70 --- .../autopsy/datamodel/ArtifactTypeNode.java | 5 - .../datamodel/BlackboardArtifactNode.java | 5 - .../datamodel/BlackboardArtifactTagNode.java | 5 - .../autopsy/datamodel/Bookmarks.java | 25 +- .../autopsy/datamodel/ContentTagNode.java | 5 - .../autopsy/datamodel/ContentTagTypeNode.java | 5 - .../autopsy/datamodel/DataSourcesNode.java | 6 +- .../autopsy/datamodel/DeletedContent.java | 11 +- .../autopsy/datamodel/DirectoryNode.java | 14 +- .../datamodel/DisplayableItemNode.java | 39 +- .../autopsy/datamodel/EmailExtracted.java | 27 +- .../datamodel/ExtractedContentNode.java | 10 +- .../sleuthkit/autopsy/datamodel/FileNode.java | 9 +- .../sleuthkit/autopsy/datamodel/FileSize.java | 11 +- .../autopsy/datamodel/FileTypeNode.java | 5 - .../autopsy/datamodel/FileTypesNode.java | 10 +- .../autopsy/datamodel/HashsetHits.java | 11 +- .../autopsy/datamodel/ImageNode.java | 10 +- .../autopsy/datamodel/KeywordHits.java | 25 +- .../autopsy/datamodel/LayoutFileNode.java | 14 +- .../autopsy/datamodel/LocalFileNode.java | 10 +- .../datamodel/RecentFilesFilterNode.java | 5 - .../autopsy/datamodel/RecentFilesNode.java | 6 +- .../autopsy/datamodel/ResultsNode.java | 10 +- .../autopsy/datamodel/TagNameNode.java | 5 - .../org/sleuthkit/autopsy/datamodel/Tags.java | 20 +- .../sleuthkit/autopsy/datamodel/TagsNode.java | 12 +- .../autopsy/datamodel/TagsNodeKey.java | 4 +- .../autopsy/datamodel/ViewsNode.java | 10 +- .../datamodel/VirtualDirectoryNode.java | 9 +- .../autopsy/datamodel/VolumeNode.java | 10 +- .../BlackboardArtifactTagTypeNode.java | 5 - .../autopsy/directorytree/Bundle.properties | 6 - .../directorytree/DataResultFilterNode.java | 24 +- .../ExplorerNodeActionVisitor.java | 12 +- .../KeywordSearchFilterNode.java | 4 +- .../sleuthkit/autopsy/timeline/Timeline.java | 6 +- 50 files changed, 828 insertions(+), 998 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java create mode 100755 Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java create mode 100755 Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java rename Core/src/org/sleuthkit/autopsy/actions/{TagAndCommentDialog.form => GetTagNameAndCommentDialog.form} (87%) rename Core/src/org/sleuthkit/autopsy/actions/{TagAndCommentDialog.java => GetTagNameAndCommentDialog.java} (72%) rename Core/src/org/sleuthkit/autopsy/{directorytree/CreateTagDialog.form => actions/GetTagNameDialog.form} (87%) rename Core/src/org/sleuthkit/autopsy/{directorytree/CreateTagDialog.java => actions/GetTagNameDialog.java} (68%) delete mode 100755 Core/src/org/sleuthkit/autopsy/actions/TagAbstractFileAction.java delete mode 100755 Core/src/org/sleuthkit/autopsy/actions/TagBlackboardArtifactAction.java delete mode 100644 Core/src/org/sleuthkit/autopsy/actions/TagMenu.java delete mode 100755 Core/src/org/sleuthkit/autopsy/actions/TagSleuthKitDataModelObjectAction.java diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml index 9b49c8e266..1887e9a87b 100644 --- a/Core/nbproject/project.xml +++ b/Core/nbproject/project.xml @@ -1,218 +1,219 @@ - - - org.netbeans.modules.apisupport.project - - - org.sleuthkit.autopsy.core - - - - org.netbeans.api.progress - - - - 1 - 1.28.1 - - - - org.netbeans.core - - - - 2 - - - - - org.netbeans.core.startup - - - - 1 - - - - - org.netbeans.modules.javahelp - - - - 1 - 2.27.1 - - - - org.netbeans.modules.options.api - - - - 1 - 1.26.1 - - - - org.netbeans.modules.settings - - - - 1 - 1.35.1 - - - - org.netbeans.spi.quicksearch - - - - 1.14.1 - - - - org.netbeans.swing.outline - - - - 1.20.1 - - - - org.netbeans.swing.plaf - - - - 1.25.1 - - - - org.netbeans.swing.tabcontrol - - - - 1.36.1 - - - - org.openide.actions - - - - 6.26.1 - - - - org.openide.awt - - - - 7.46.1 - - - - org.openide.dialogs - - - - 7.25.1 - - - - org.openide.explorer - - - - 6.45.1 - - - - org.openide.filesystems - - - - 7.62.1 - - - - org.openide.modules - - - - 7.32.1 - - - - org.openide.nodes - - - - 7.28.1 - - - - org.openide.text - - - - 6.49.1 - - - - org.openide.util - - - - 8.25.1 - - - - org.openide.util.lookup - - - - 8.15.1 - - - - org.openide.windows - - - - 6.55.1 - - - - org.sleuthkit.autopsy.corelibs - - - - 3 - 1.0 - - - - - org.sleuthkit.autopsy.casemodule - org.sleuthkit.autopsy.casemodule.services - org.sleuthkit.autopsy.core - org.sleuthkit.autopsy.corecomponentinterfaces - org.sleuthkit.autopsy.corecomponents - org.sleuthkit.autopsy.coreutils - org.sleuthkit.autopsy.datamodel - org.sleuthkit.autopsy.directorytree - org.sleuthkit.autopsy.filesearch - org.sleuthkit.autopsy.ingest - org.sleuthkit.autopsy.menuactions - org.sleuthkit.autopsy.report - org.sleuthkit.datamodel - - - ext/sqlite-jdbc-3.7.8-SNAPSHOT.jar - release/modules/ext/sqlite-jdbc-3.7.8-SNAPSHOT.jar - - - ext/Tsk_DataModel.jar - release/modules/ext/Tsk_DataModel.jar - - - - + + + org.netbeans.modules.apisupport.project + + + org.sleuthkit.autopsy.core + + + + org.netbeans.api.progress + + + + 1 + 1.28.1 + + + + org.netbeans.core + + + + 2 + + + + + org.netbeans.core.startup + + + + 1 + + + + + org.netbeans.modules.javahelp + + + + 1 + 2.27.1 + + + + org.netbeans.modules.options.api + + + + 1 + 1.26.1 + + + + org.netbeans.modules.settings + + + + 1 + 1.35.1 + + + + org.netbeans.spi.quicksearch + + + + 1.14.1 + + + + org.netbeans.swing.outline + + + + 1.20.1 + + + + org.netbeans.swing.plaf + + + + 1.25.1 + + + + org.netbeans.swing.tabcontrol + + + + 1.36.1 + + + + org.openide.actions + + + + 6.26.1 + + + + org.openide.awt + + + + 7.46.1 + + + + org.openide.dialogs + + + + 7.25.1 + + + + org.openide.explorer + + + + 6.45.1 + + + + org.openide.filesystems + + + + 7.62.1 + + + + org.openide.modules + + + + 7.32.1 + + + + org.openide.nodes + + + + 7.28.1 + + + + org.openide.text + + + + 6.49.1 + + + + org.openide.util + + + + 8.25.1 + + + + org.openide.util.lookup + + + + 8.15.1 + + + + org.openide.windows + + + + 6.55.1 + + + + org.sleuthkit.autopsy.corelibs + + + + 3 + 1.0 + + + + + org.sleuthkit.autopsy.actions + org.sleuthkit.autopsy.casemodule + org.sleuthkit.autopsy.casemodule.services + org.sleuthkit.autopsy.core + org.sleuthkit.autopsy.corecomponentinterfaces + org.sleuthkit.autopsy.corecomponents + org.sleuthkit.autopsy.coreutils + org.sleuthkit.autopsy.datamodel + org.sleuthkit.autopsy.directorytree + org.sleuthkit.autopsy.filesearch + org.sleuthkit.autopsy.ingest + org.sleuthkit.autopsy.menuactions + org.sleuthkit.autopsy.report + org.sleuthkit.datamodel + + + ext/sqlite-jdbc-3.7.8-SNAPSHOT.jar + release/modules/ext/sqlite-jdbc-3.7.8-SNAPSHOT.jar + + + ext/Tsk_DataModel.jar + release/modules/ext/Tsk_DataModel.jar + + + + diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java new file mode 100755 index 0000000000..303a773e17 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java @@ -0,0 +1,70 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 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.actions; + +import java.util.Collection; +import java.util.logging.Level; +import javax.swing.JOptionPane; +import org.openide.util.Utilities; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.Tags; +import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Instances of this Action allow users to apply tags to blackboard artifacts. + */ +public class AddBlackboardArtifactTagAction extends AddTagAction { + // This class is a singleton to support multi-selection of nodes, since + // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every + // node in the array returns a reference to the same action object from Node.getActions(boolean). + private static AddBlackboardArtifactTagAction instance; + + public static synchronized AddBlackboardArtifactTagAction getInstance() { + if (null == instance) { + instance = new AddBlackboardArtifactTagAction(); + } + return instance; + } + + private AddBlackboardArtifactTagAction() { + } + + @Override + protected String getActionDisplayName() { + return Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class).size() > 1 ? "Tag Results" : "Tag Result"; + } + + @Override + protected void addTag(TagName tagName, String comment) { + Collection selectedArtifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class); + for (BlackboardArtifact artifact : selectedArtifacts) { + Tags.createTag(artifact, tagName.getDisplayName(), comment); //RJCTODO: Jettision this + try { + Case.getCurrentCase().getServices().getTagsManager().addBlackboardArtifactTag(artifact, tagName, comment); + } + catch (TskCoreException ex) { + Logger.getLogger(AddBlackboardArtifactTagAction.class.getName()).log(Level.SEVERE, "Error tagging result", ex); + JOptionPane.showMessageDialog(null, "Unable to tag " + artifact.getDisplayName() + ".", "Tagging Error", JOptionPane.ERROR_MESSAGE); + } + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java new file mode 100755 index 0000000000..813fde02af --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java @@ -0,0 +1,70 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 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.actions; + +import java.util.Collection; +import java.util.logging.Level; +import javax.swing.JOptionPane; +import org.openide.util.Utilities; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.Tags; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Instances of this Action allow users to apply tags to content. + */ +public class AddContentTagAction extends AddTagAction { + // This class is a singleton to support multi-selection of nodes, since + // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every + // node in the array returns a reference to the same action object from Node.getActions(boolean). + private static AddContentTagAction instance; + + public static synchronized AddContentTagAction getInstance() { + if (null == instance) { + instance = new AddContentTagAction(); + } + return instance; + } + + private AddContentTagAction() { + } + + @Override + protected String getActionDisplayName() { + return Utilities.actionsGlobalContext().lookupAll(AbstractFile.class).size() > 1 ? "Tag Files" : "Tag File"; + } + + @Override + protected void addTag(TagName tagName, String comment) { + Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); + for (AbstractFile file : selectedFiles) { + Tags.createTag(file, tagName.getDisplayName(), comment); //RJCTODO: Jettision this + try { + Case.getCurrentCase().getServices().getTagsManager().addContentTag(file, tagName, comment); + } + catch (TskCoreException ex) { + Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error tagging result", ex); + JOptionPane.showMessageDialog(null, "Unable to tag " + file.getName() + ".", "Tagging Error", JOptionPane.ERROR_MESSAGE); + } + } + } +} \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java new file mode 100755 index 0000000000..9e52cd1ece --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java @@ -0,0 +1,147 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 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.actions; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.util.ArrayList; +import javax.swing.AbstractAction; +import javax.swing.JMenu; +import javax.swing.JMenuItem; +import org.openide.util.actions.Presenter; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.services.TagsManager; +import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.TagName; + +/** + * An abstract base class for Actions that allow users to tag SleuthKit data + * model objects. + */ +abstract class AddTagAction extends AbstractAction implements Presenter.Popup { + private static final String NO_COMMENT = ""; + + @Override + public JMenuItem getPopupPresenter() { + return new TagMenu(); + } + + @Override + public void actionPerformed(ActionEvent e) { + } + + /** + * Template method to allow derived classes to provide a string for for a + * menu item label. + */ + abstract protected String getActionDisplayName(); + + /** + * Template method to allow derived classes to add the indicated tag and + * comment to one or more a SleuthKit data model objects. + */ + abstract protected void addTag(TagName tagName, String comment); + + private void refreshDirectoryTree() { + //TODO instead should send event to node children, which will call its refresh() / refreshKeys() + // RJCTODO: Explain what is going on here and pare to one refreshTree() call. + DirectoryTreeTopComponent viewer = DirectoryTreeTopComponent.findInstance(); + viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE); + viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT); + } + + /** + * Instances of this class implement a context menu user interface for + * creating or selecting a tag name for a tag and specifying an optional tag + * comment. + */ + // @@@ This user interface has some significant usability issues and needs + // to be reworked. + private class TagMenu extends JMenu { + TagMenu() { + super(getActionDisplayName()); + + // Get the current set of tag names. + TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + ArrayList tagNames = new ArrayList<>(); + tagsManager.getTagNames(tagNames); + + // Create a "Quick Tag" sub-menu. + JMenu quickTagMenu = new JMenu("Quick Tag"); + add(quickTagMenu); + + // Each tag name in the current set of tags gets its own menu item in + // the "Quick Tags" sub-menu. Selecting one of these menu items adds + // a tag with the associated tag name. + if (tagNames.isEmpty()) { + for (final TagName tagName : tagNames) { + JMenuItem tagNameItem = new JMenuItem(tagName.getDisplayName()); + tagNameItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + addTag(tagName, NO_COMMENT); + refreshDirectoryTree(); + } + }); + quickTagMenu.add(tagNameItem); + } + } + else { + JMenuItem empty = new JMenuItem("No tags"); + empty.setEnabled(false); + quickTagMenu.add(empty); + } + + quickTagMenu.addSeparator(); + + // The "Quick Tag" menu also gets an "Choose Tag..." menu item. + // Selecting this item initiates a dialog that can be used to create + // or select a tag name and adds a tag with the resulting name. + JMenuItem newTagMenuItem = new JMenuItem("Choose Tag..."); + newTagMenuItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + TagName tagName = GetTagNameDialog.doDialog(); + if (tagName != null) { + addTag(tagName, NO_COMMENT); + refreshDirectoryTree(); + } + } + }); + quickTagMenu.add(newTagMenuItem); + + // Create a "Choose Tag and Comment..." menu item. Selecting this itme initiates + // a dialog that can be used to create or select a tag name with an + // optional comment and adds a tag with the resulting name. + JMenuItem tagAndCommentItem = new JMenuItem("Choose Tag and Comment..."); + tagAndCommentItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog(); + if (null != tagNameAndComment) { + addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment()); + refreshDirectoryTree(); + } + } + }); + add(tagAndCommentItem); + } + } +} \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties index b0c06a74df..1ae4a0f597 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties @@ -1,11 +1,16 @@ +GetTagNameDialog.tagNameField.text= +GetTagNameDialog.cancelButton.text=Cancel +GetTagNameDialog.okButton.text=OK +GetTagNameDialog.preexistingLabel.text=Pre-existing Tags: +GetTagNameDialog.newTagPanel.border.title=New Tag +GetTagNameDialog.tagNameLabel.text=Tag Name: +GetTagNameAndCommentDialog.tagLabel.text=Tag: +GetTagNameAndCommentDialog.okButton.text=OK +GetTagNameAndCommentDialog.tagCombo.toolTipText=Select tag to use # To change this template, choose Tools | Templates # and open the template in the editor. - -TagAndCommentDialog.cancelButton.text=Cancel -TagAndCommentDialog.newTagButton.text=New Tag -TagAndCommentDialog.tagCombo.toolTipText=Select tag to use -TagAndCommentDialog.tagLabel.text=Tag: -TagAndCommentDialog.commentLabel.text=Comment: -TagAndCommentDialog.commentText.toolTipText=Enter an optional tag comment or leave blank -TagAndCommentDialog.commentText.text= -TagAndCommentDialog.okButton.text=OK +GetTagNameAndCommentDialog.cancelButton.text=Cancel +GetTagNameAndCommentDialog.commentText.toolTipText=Enter an optional tag comment or leave blank +GetTagNameAndCommentDialog.commentText.text= +GetTagNameAndCommentDialog.commentLabel.text=Comment: +GetTagNameAndCommentDialog.newTagButton.text=New Tag diff --git a/Core/src/org/sleuthkit/autopsy/actions/TagAndCommentDialog.form b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.form similarity index 87% rename from Core/src/org/sleuthkit/autopsy/actions/TagAndCommentDialog.form rename to Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.form index 268c5b5f77..cbbdaebb26 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/TagAndCommentDialog.form +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.form @@ -78,7 +78,7 @@ - + @@ -91,7 +91,7 @@ - + @@ -104,7 +104,7 @@ - + @@ -114,31 +114,31 @@ - + - + - + - + - + diff --git a/Core/src/org/sleuthkit/autopsy/actions/TagAndCommentDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java similarity index 72% rename from Core/src/org/sleuthkit/autopsy/actions/TagAndCommentDialog.java rename to Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java index 6c390ac720..eef172f209 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/TagAndCommentDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java @@ -20,7 +20,8 @@ package org.sleuthkit.autopsy.actions; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; -import java.util.TreeSet; +import java.util.ArrayList; +import java.util.HashMap; import javax.swing.AbstractAction; import javax.swing.ActionMap; import javax.swing.InputMap; @@ -29,29 +30,26 @@ import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.KeyStroke; import org.openide.windows.WindowManager; -import org.sleuthkit.autopsy.datamodel.Tags; -import org.sleuthkit.autopsy.directorytree.CreateTagDialog; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.services.TagsManager; +import org.sleuthkit.datamodel.TagName; -/** - * Tag dialog for tagging files and results. User enters an optional comment. - */ -public class TagAndCommentDialog extends JDialog { +public class GetTagNameAndCommentDialog extends JDialog { + private static final String NO_TAG_NAMES_MESSAGE = "No Tags"; // RJCTODO: ?? + private final HashMap tagNames = new HashMap<>(); + private TagNameAndComment tagNameAndComment = null; - private static final String NO_TAG_MESSAGE = "No Tags"; - private String tagName = ""; - private String comment = ""; - - public static class CommentedTag { - private String name; + public static class TagNameAndComment { + private TagName tagName; private String comment; - CommentedTag(String name, String comment) { - this.name = name; + private TagNameAndComment(TagName tagName, String comment) { + this.tagName = tagName; this.comment = comment; } - public String getName() { - return name; + public TagName getTagName() { + return tagName; } public String getComment() { @@ -59,25 +57,17 @@ public class TagAndCommentDialog extends JDialog { } } - public static CommentedTag doDialog() { - TagAndCommentDialog dialog = new TagAndCommentDialog(); - if (!dialog.tagName.isEmpty()) { - return new CommentedTag(dialog.tagName, dialog.comment); - } - else { - return null; - } + public static TagNameAndComment doDialog() { + GetTagNameAndCommentDialog dialog = new GetTagNameAndCommentDialog(); + return dialog.tagNameAndComment; } - /** - * Creates new form TagDialog - */ - private TagAndCommentDialog() { - super((JFrame)WindowManager.getDefault().getMainWindow(), "Tag and Comment", true); - + private GetTagNameAndCommentDialog() { + super((JFrame)WindowManager.getDefault().getMainWindow(), "Create Tag", true); initComponents(); - // Close the dialog when Esc is pressed + // Set up the dialog to close when Esc is pressed. + // RJCTODO: Could do this for the other dialog, too. String cancelName = "cancel"; InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName); @@ -88,24 +78,25 @@ public class TagAndCommentDialog extends JDialog { dispose(); } }); - - // get the current list of tag names - TreeSet tags = Tags.getAllTagNames(); - - // if there are no tags, add the NO_TAG_MESSAGE - if (tags.isEmpty()) { - tags.add(NO_TAG_MESSAGE); + + // Populate the combo box with the available tag names. + // Save the tag names to be enable to return the one the user selects. + TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + ArrayList currentTagNames = new ArrayList<>(); + tagsManager.getTagNames(currentTagNames); + if (currentTagNames.isEmpty()) { + tagCombo.addItem(NO_TAG_NAMES_MESSAGE); } - - // add the tags to the combo box - for (String tag : tags) { - tagCombo.addItem(tag); + else { + for (TagName tagName : currentTagNames) { + tagNames.put(tagName.getDisplayName(), tagName); + tagCombo.addItem(tagName.getDisplayName()); + } } - //center it - this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); - - setVisible(true); // blocks + // Center and show the dialog box. + this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); + setVisible(true); } /** @@ -131,30 +122,30 @@ public class TagAndCommentDialog extends JDialog { } }); - org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.okButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.okButton.text")); // NOI18N okButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { okButtonActionPerformed(evt); } }); - org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.cancelButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.cancelButton.text")); // NOI18N cancelButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { cancelButtonActionPerformed(evt); } }); - tagCombo.setToolTipText(org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.tagCombo.toolTipText")); // NOI18N + tagCombo.setToolTipText(org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.tagCombo.toolTipText")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(tagLabel, org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.tagLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(tagLabel, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.tagLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(commentLabel, org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.commentLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(commentLabel, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.commentLabel.text")); // NOI18N - commentText.setText(org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.commentText.text")); // NOI18N - commentText.setToolTipText(org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.commentText.toolTipText")); // NOI18N + commentText.setText(org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.commentText.text")); // NOI18N + commentText.setToolTipText(org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.commentText.toolTipText")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(newTagButton, org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.newTagButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(newTagButton, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.newTagButton.text")); // NOI18N newTagButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { newTagButtonActionPerformed(evt); @@ -213,26 +204,27 @@ public class TagAndCommentDialog extends JDialog { }// //GEN-END:initComponents private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed - tagName = (String)tagCombo.getSelectedItem(); - comment = commentText.getText(); + tagNameAndComment = new TagNameAndComment(tagNames.get((String)tagCombo.getSelectedItem()), commentText.getText()); dispose(); }//GEN-LAST:event_okButtonActionPerformed private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed + tagNameAndComment = null; dispose(); }//GEN-LAST:event_cancelButtonActionPerformed - /** - * Closes the dialog - */ private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog + // RJCTODO: Is this dead code? + tagNameAndComment = null; dispose(); }//GEN-LAST:event_closeDialog private void newTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagButtonActionPerformed - String newTagName = CreateTagDialog.getNewTagNameDialog(null); + // RJCTODO: Make suer this works for dups + TagName newTagName = GetTagNameDialog.doDialog(); if (newTagName != null) { - tagCombo.addItem(newTagName); + tagNames.put(newTagName.getDisplayName(), newTagName); + tagCombo.addItem(newTagName.getDisplayName()); tagCombo.setSelectedItem(newTagName); } }//GEN-LAST:event_newTagButtonActionPerformed diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/CreateTagDialog.form b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.form similarity index 87% rename from Core/src/org/sleuthkit/autopsy/directorytree/CreateTagDialog.form rename to Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.form index 1136325546..a281ea606e 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/CreateTagDialog.form +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.form @@ -72,7 +72,7 @@ - + @@ -82,7 +82,7 @@ - + @@ -124,7 +124,7 @@ - + @@ -133,7 +133,7 @@ - + @@ -168,14 +168,14 @@ - + - + diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/CreateTagDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java similarity index 68% rename from Core/src/org/sleuthkit/autopsy/directorytree/CreateTagDialog.java rename to Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java index 3ab800a2a5..b019c22588 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/CreateTagDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java @@ -16,71 +16,102 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.directorytree; +package org.sleuthkit.autopsy.actions; -import java.awt.Dimension; -import java.awt.Toolkit; import java.awt.event.KeyEvent; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.logging.Level; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.table.AbstractTableModel; import org.openide.util.ImageUtilities; -import org.sleuthkit.autopsy.datamodel.Tags; +import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.casemodule.services.TagsManager; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskCoreException; -public class CreateTagDialog extends JDialog { +public class GetTagNameDialog extends JDialog { private static final String TAG_ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; - private static String newTagName; + private final HashMap tagNames = new HashMap<>(); + private TagName tagName = null; - /** - * Creates new form CreateTagDialog - */ - private CreateTagDialog(JFrame parent) { - super(parent, true); - init(); - } + public static TagName doDialog() { + GetTagNameDialog dialog = new GetTagNameDialog(); + return dialog.tagName; + } - public static String getNewTagNameDialog(JFrame parent) { - new CreateTagDialog(parent); - return newTagName; - } - - private void init() { - setTitle("Create a new tag"); - + private GetTagNameDialog() { + super((JFrame)WindowManager.getDefault().getMainWindow(), "Create Tag", true); + setIconImage(ImageUtilities.loadImage(TAG_ICON_PATH)); initComponents(); - tagsTable.setModel(new TagsTableModel()); + // Get the current set of tag names and hash them for a speedy lookup in + // case the user chooses an existing tag name from the tag names table. + TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); + ArrayList currentTagNames = new ArrayList<>(); + tagsManager.getTagNames(currentTagNames); + for (TagName name : currentTagNames) { + this.tagNames.put(name.getDisplayName(), name); + } + + // Populate the tag names table. + tagsTable.setModel(new TagsTableModel(currentTagNames)); tagsTable.setTableHeader(null); - - //completely disable selections tagsTable.setCellSelectionEnabled(false); tagsTable.setFocusable(false); tagsTable.setRowHeight(tagsTable.getRowHeight() + 5); - - setIconImage(ImageUtilities.loadImage(TAG_ICON_PATH)); - - Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); - // set the popUp window / JFrame - int w = this.getSize().width; - int h = this.getSize().height; - - // set the location of the popUp Window on the center of the screen - setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2); - setVisible(true); //blocks + + // Center and show the dialog box. + this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); + setVisible(true); } private boolean containsIllegalCharacters(String content) { - if ((content.contains("\\") || content.contains(":") || content.contains("*") - || content.contains("?") || content.contains("\"") || content.contains("<") - || content.contains(">") || content.contains("|"))) { - return true; - } - return false; + return (content.contains("\\")|| + content.contains(":") || + content.contains("*") || + content.contains("?") || + content.contains("\"")|| + content.contains("<") || + content.contains(">") || + content.contains("|")); } + private class TagsTableModel extends AbstractTableModel { + private final ArrayList tagNames = new ArrayList<>(); + + TagsTableModel(List tagNames) { + for (TagName tagName : tagNames) { + this.tagNames.add(tagName); + } + } + + @Override + public int getRowCount() { + return tagNames.size(); + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return false; + } + + @Override + public int getColumnCount() { + return 1; + } + + @Override + public String getValueAt(int rowIndex, int columnIndex) { + return tagNames.get(rowIndex).getDisplayName(); + } + } + /** * 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 @@ -106,14 +137,14 @@ public class CreateTagDialog extends JDialog { } }); - org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.cancelButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.cancelButton.text")); // NOI18N cancelButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { cancelButtonActionPerformed(evt); } }); - org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.okButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.okButton.text")); // NOI18N okButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { okButtonActionPerformed(evt); @@ -136,13 +167,13 @@ public class CreateTagDialog extends JDialog { tagsTable.setTableHeader(null); jScrollPane1.setViewportView(tagsTable); - org.openide.awt.Mnemonics.setLocalizedText(preexistingLabel, org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.preexistingLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(preexistingLabel, org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.preexistingLabel.text")); // NOI18N - newTagPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.newTagPanel.border.title"))); // NOI18N + newTagPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.newTagPanel.border.title"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(tagNameLabel, org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.tagNameLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(tagNameLabel, org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.tagNameLabel.text")); // NOI18N - tagNameField.setText(org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.tagNameField.text")); // NOI18N + tagNameField.setText(org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.tagNameField.text")); // NOI18N tagNameField.addKeyListener(new java.awt.event.KeyAdapter() { public void keyReleased(java.awt.event.KeyEvent evt) { tagNameFieldKeyReleased(evt); @@ -210,20 +241,37 @@ public class CreateTagDialog extends JDialog { }// //GEN-END:initComponents private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed - newTagName = null; + tagName = null; dispose(); }//GEN-LAST:event_cancelButtonActionPerformed private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed - String tagName = tagNameField.getText(); - if (tagName.isEmpty()) { + // RJCTODO: Check out this stuff, titles etc. + String tagDisplayName = tagNameField.getText(); + if (tagDisplayName.isEmpty()) { JOptionPane.showMessageDialog(null, "Must supply a tag name to continue.", "Tag Name", JOptionPane.ERROR_MESSAGE); - } else if (containsIllegalCharacters(tagName)) { - JOptionPane.showMessageDialog(null, "The tag name contains illegal characters.\nCannot contain any of the following symbols: \\ : * ? \" < > |", - "Illegal Characters", JOptionPane.ERROR_MESSAGE); - } else { - newTagName = tagName; - dispose(); + } + else if (containsIllegalCharacters(tagDisplayName)) { + JOptionPane.showMessageDialog(null, "The tag name contains illegal characters.\nCannot contain any of the following symbols: \\ : * ? \" < > |", "Illegal Characters", JOptionPane.ERROR_MESSAGE); + } + else { + tagName = tagNames.get(tagDisplayName); + if (tagName == null) { + try { + tagName = Case.getCurrentCase().getServices().getTagsManager().addTagName(tagDisplayName); + dispose(); + } + catch (TskCoreException ex) { + Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex); + JOptionPane.showMessageDialog(null, "Unable to add the " + tagDisplayName + " tag name to the case.", "Tagging Error", JOptionPane.ERROR_MESSAGE); + tagName = null; + } + catch (TagsManager.TagNameAlreadyExistsException ex) { + Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex); + JOptionPane.showMessageDialog(null, "A " + tagDisplayName + " tag name has already been defined.", "Duplicate Tag Error", JOptionPane.ERROR_MESSAGE); + tagName = null; + } + } } }//GEN-LAST:event_okButtonActionPerformed @@ -250,32 +298,5 @@ public class CreateTagDialog extends JDialog { private javax.swing.JTable tagsTable; // End of variables declaration//GEN-END:variables - private class TagsTableModel extends AbstractTableModel { - List tagNames; - - TagsTableModel() { - tagNames = new ArrayList<>(Tags.getAllTagNames()); - } - - @Override - public int getRowCount() { - return tagNames.size(); - } - - @Override - public boolean isCellEditable(int rowIndex, int columnIndex) { - return false; - } - - @Override - public int getColumnCount() { - return 1; - } - - @Override - public String getValueAt(int rowIndex, int columnIndex) { - return tagNames.get(rowIndex); - } - } } diff --git a/Core/src/org/sleuthkit/autopsy/actions/TagAbstractFileAction.java b/Core/src/org/sleuthkit/autopsy/actions/TagAbstractFileAction.java deleted file mode 100755 index b90ebac286..0000000000 --- a/Core/src/org/sleuthkit/autopsy/actions/TagAbstractFileAction.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2013 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.actions; - -import java.util.Collection; -import java.util.logging.Level; -import javax.swing.JMenuItem; -import javax.swing.JOptionPane; -import org.openide.util.Utilities; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.services.TagsManager; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datamodel.Tags; -import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.TagName; -import org.sleuthkit.datamodel.TskCoreException; - -/** - * Instances of this Action allow users to apply tags to content. - */ -public class TagAbstractFileAction extends TagSleuthKitDataModelObjectAction { - // This class is a singleton to support multi-selection of nodes, since - // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every - // node in the array returns a reference to the same action object from Node.getActions(boolean). - private static TagAbstractFileAction instance; - - public static synchronized TagAbstractFileAction getInstance() { - if (null == instance) { - instance = new TagAbstractFileAction(); - } - return instance; - } - - private TagAbstractFileAction() { - } - - @Override - protected JMenuItem getContextMenu() { - return new TagAbstractFileMenu(); - } - - - private class TagAbstractFileMenu extends TagMenu { - public TagAbstractFileMenu() { - super(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class).size() > 1 ? "Tag Files" : "Tag File"); - } - - @Override - protected void applyTag(String tagDisplayName, String comment) { - TagName tagName = getTagName(tagDisplayName, comment); - if (tagName != null) { - TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); - Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); - for (AbstractFile file : selectedFiles) { - Tags.createTag(file, tagDisplayName, comment); - try { - tagsManager.addContentTag(file, tagName); - } - catch (TskCoreException ex) { - Logger.getLogger(TagAbstractFileMenu.class.getName()).log(Level.SEVERE, "Error tagging result", ex); - JOptionPane.showMessageDialog(null, "Unable to tag " + file.getName() + ".", "Tagging Error", JOptionPane.ERROR_MESSAGE); - } - } - } - } - } -} \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/actions/TagBlackboardArtifactAction.java b/Core/src/org/sleuthkit/autopsy/actions/TagBlackboardArtifactAction.java deleted file mode 100755 index ebda9eb87f..0000000000 --- a/Core/src/org/sleuthkit/autopsy/actions/TagBlackboardArtifactAction.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2013 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.actions; - -import java.util.Collection; -import java.util.logging.Level; -import javax.swing.JMenuItem; -import javax.swing.JOptionPane; -import org.openide.util.Utilities; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.services.TagsManager; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datamodel.Tags; -import org.sleuthkit.datamodel.TagName; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.TskCoreException; - -/** - * Instances of this Action allow users to apply tags to blackboard artifacts. - */ -public class TagBlackboardArtifactAction extends TagSleuthKitDataModelObjectAction { - // This class is a singleton to support multi-selection of nodes, since - // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every - // node in the array returns a reference to the same action object from Node.getActions(boolean). - private static TagBlackboardArtifactAction instance; - - public static synchronized TagBlackboardArtifactAction getInstance() { - if (null == instance) { - instance = new TagBlackboardArtifactAction(); - } - return instance; - } - - private TagBlackboardArtifactAction() { - } - - @Override - protected JMenuItem getContextMenu() { - return new TagBlackboardArtifactMenu(); - } - - private class TagBlackboardArtifactMenu extends TagMenu { - public TagBlackboardArtifactMenu() { - super(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class).size() > 1 ? "Tag Results" : "Tag Result"); - } - - @Override - protected void applyTag(String tagDisplayName, String comment) { - TagName tagName = getTagName(tagDisplayName, comment); - if (tagName != null) { - TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); - Collection selectedArtifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class); - for (BlackboardArtifact artifact : selectedArtifacts) { - Tags.createTag(artifact, tagDisplayName, comment); - try { - tagsManager.addBlackboardArtifactTag(artifact, tagName); - } - catch (TskCoreException ex) { - Logger.getLogger(TagBlackboardArtifactMenu.class.getName()).log(Level.SEVERE, "Error tagging result", ex); - JOptionPane.showMessageDialog(null, "Unable to tag " + artifact.getDisplayName() + ".", "Tagging Error", JOptionPane.ERROR_MESSAGE); - } - } - } - } - } -} diff --git a/Core/src/org/sleuthkit/autopsy/actions/TagMenu.java b/Core/src/org/sleuthkit/autopsy/actions/TagMenu.java deleted file mode 100644 index a680e626bc..0000000000 --- a/Core/src/org/sleuthkit/autopsy/actions/TagMenu.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2013 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.actions; - -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.TreeSet; -import javax.swing.JMenu; -import javax.swing.JMenuItem; -import org.sleuthkit.autopsy.datamodel.Tags; -import org.sleuthkit.autopsy.directorytree.CreateTagDialog; -import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; -import org.sleuthkit.datamodel.BlackboardArtifact; - -/** - * The menu that results when one right-clicks on a file or artifact. - */ -public abstract class TagMenu extends JMenu { - public TagMenu(String menuItemText) { - super(menuItemText); - - // Create the 'Quick Tag' sub-menu and add it to the tag menu. - JMenu quickTagMenu = new JMenu("Quick Tag"); - add(quickTagMenu); - - // Get the existing tag names. - TreeSet tagNames = Tags.getAllTagNames(); - if (tagNames.isEmpty()) { - JMenuItem empty = new JMenuItem("No tags"); - empty.setEnabled(false); - quickTagMenu.add(empty); - } - - // Add a menu item for each existing tag name to the 'Quick Tag' menu. - for (final String tagName : tagNames) { - JMenuItem tagNameItem = new JMenuItem(tagName); - tagNameItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - applyTag(tagName, ""); - refreshDirectoryTree(); - } - }); - quickTagMenu.add(tagNameItem); - } - - quickTagMenu.addSeparator(); - - // Create the 'New Tag' menu item and add it to the 'Quick Tag' menu. - JMenuItem newTagMenuItem = new JMenuItem("New Tag"); - newTagMenuItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - String tagName = CreateTagDialog.getNewTagNameDialog(null); - if (tagName != null) { - applyTag(tagName, ""); - refreshDirectoryTree(); - } - } - }); - quickTagMenu.add(newTagMenuItem); - - // Create the 'Tag and Comment' menu item and add it to the tag menu. - JMenuItem tagAndCommentItem = new JMenuItem("Tag and Comment"); - tagAndCommentItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - TagAndCommentDialog.CommentedTag commentedTag = TagAndCommentDialog.doDialog(); - if (null != commentedTag) { - applyTag(commentedTag.getName(), commentedTag.getComment()); - refreshDirectoryTree(); - } - } - }); - add(tagAndCommentItem); - } - - private void refreshDirectoryTree() { - //TODO instead should send event to node children, which will call its refresh() / refreshKeys() - // RJCTODO: Explain what is going on here and pare to one refreshTree() call. - DirectoryTreeTopComponent viewer = DirectoryTreeTopComponent.findInstance(); - viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE); - viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT); - } - - protected abstract void applyTag(String tagName, String comment); -} diff --git a/Core/src/org/sleuthkit/autopsy/actions/TagSleuthKitDataModelObjectAction.java b/Core/src/org/sleuthkit/autopsy/actions/TagSleuthKitDataModelObjectAction.java deleted file mode 100755 index 2796b1ef7c..0000000000 --- a/Core/src/org/sleuthkit/autopsy/actions/TagSleuthKitDataModelObjectAction.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2013 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.actions; - -import java.awt.event.ActionEvent; -import java.util.logging.Level; -import javax.swing.AbstractAction; -import javax.swing.JMenuItem; -import javax.swing.JOptionPane; -import org.openide.util.actions.Presenter; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.services.TagsManager; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.datamodel.TagName; -import org.sleuthkit.datamodel.TskCoreException; - -abstract class TagSleuthKitDataModelObjectAction extends AbstractAction implements Presenter.Popup { - abstract protected JMenuItem getContextMenu(); - - @Override - public JMenuItem getPopupPresenter() { - return getContextMenu(); - } - - @Override - public void actionPerformed(ActionEvent e) { - // Do nothing - this action should never be performed. - // Context actions are invoked instead. - } - - protected TagName getTagName(String tagDisplayName, String comment) { - TagName tagName = null; - try { - TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); - if (tagsManager.tagNameExists(tagDisplayName)) { - tagName = tagsManager.getTagName(tagDisplayName); - } - else { - try { - tagName = tagsManager.addTagName(tagDisplayName); - } - catch (TskCoreException ex) { - Logger.getLogger(TagSleuthKitDataModelObjectAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex); - JOptionPane.showMessageDialog(null, "Unable to add the " + tagDisplayName + " tag name to the case.", "Tagging Error", JOptionPane.ERROR_MESSAGE); - return null; - } - } - } - catch (TagsManager.TagNameAlreadyExistsException ex) { - JOptionPane.showMessageDialog(null, "A " + tagDisplayName + " tag name has already been defined.", "Duplicate Tag Error", JOptionPane.ERROR_MESSAGE); - } - return tagName; - } -} \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ArtifactTypeNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ArtifactTypeNode.java index c5d347ae6e..32367d2d1c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ArtifactTypeNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ArtifactTypeNode.java @@ -128,11 +128,6 @@ public class ArtifactTypeNode extends DisplayableItemNode { return "artifact-icon.png"; } - @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.META; - } - @Override public boolean isLeafTypeNode() { return true; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java index 5879d6f341..c6b98820de 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactNode.java @@ -316,11 +316,6 @@ public class BlackboardArtifactNode extends DisplayableItemNode { return "artifact-icon.png"; } - @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.ARTIFACT; - } - @Override public boolean isLeafTypeNode() { return true; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java index bc9c79c823..65df35b0bf 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java @@ -62,11 +62,6 @@ public class BlackboardArtifactTagNode extends DisplayableItemNode { return v.visit(this); } - @Override - public DisplayableItemNode.TYPE getDisplayableItemNodeType() { - return DisplayableItemNode.TYPE.META; // RJCTODO: Is this right? What is this stuff for? - } - @Override public boolean isLeafTypeNode() { return true; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bookmarks.java b/Core/src/org/sleuthkit/autopsy/datamodel/Bookmarks.java index e9d8036573..e3055f22b7 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bookmarks.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Bookmarks.java @@ -112,6 +112,11 @@ public class Bookmarks implements AutopsyVisitableItem { } + @Override + public boolean isLeafTypeNode() { + return false; + } + @Override public T accept(DisplayableItemNodeVisitor v) { return null; // v.visit(this); @@ -133,11 +138,6 @@ public class Bookmarks implements AutopsyVisitableItem { return s; } - - @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.ARTIFACT; - } } /** @@ -198,20 +198,15 @@ public class Bookmarks implements AutopsyVisitableItem { return s; } + @Override + public boolean isLeafTypeNode() { + return false; + } + @Override public T accept(DisplayableItemNodeVisitor v) { return null; //v.visit(this); } - - @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.ARTIFACT; - } - - @Override - public boolean isLeafTypeNode() { - return true; - } } /** diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java index c583e57d16..628b0b3e35 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java @@ -62,11 +62,6 @@ public class ContentTagNode extends DisplayableItemNode { return v.visit(this); } - @Override - public DisplayableItemNode.TYPE getDisplayableItemNodeType() { - return DisplayableItemNode.TYPE.META; // RJCTODO: Is this right? What is this stuff for? - } - @Override public boolean isLeafTypeNode() { return true; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java index e4a20c80bb..7f3d590765 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java @@ -62,11 +62,6 @@ public class ContentTagTypeNode extends DisplayableItemNode { return v.visit(this); } - @Override - public DisplayableItemNode.TYPE getDisplayableItemNodeType() { - return DisplayableItemNode.TYPE.META; - } - @Override public boolean isLeafTypeNode() { return false; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java index 280563e63a..c8f2e93e29 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataSourcesNode.java @@ -39,10 +39,10 @@ public class DataSourcesNode extends DisplayableItemNode { } @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.CONTENT; + public boolean isLeafTypeNode() { + return false; } - + @Override public T accept(DisplayableItemNodeVisitor v) { return v.visit(this); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java index 66390045ee..bf85dd703a 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DeletedContent.java @@ -109,10 +109,10 @@ public class DeletedContent implements AutopsyVisitableItem { } @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.META; + public boolean isLeafTypeNode() { + return false; } - + @Override public T accept(DisplayableItemNodeVisitor v) { return v.visit(this); @@ -199,11 +199,6 @@ public class DeletedContent implements AutopsyVisitableItem { return s; } - @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.META; - } - @Override public boolean isLeafTypeNode() { return true; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java index 0bf83b433e..279e917abc 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java @@ -23,7 +23,7 @@ import java.util.List; import javax.swing.Action; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.actions.TagAbstractFileAction; +import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Directory; @@ -76,7 +76,7 @@ public class DirectoryNode extends AbstractFsContentNode { actions.add(null); // creates a menu separator actions.add(ExtractAction.getInstance()); actions.add(null); // creates a menu separator - actions.add(TagAbstractFileAction.getInstance()); + actions.add(AddContentTagAction.getInstance()); return actions.toArray(new Action[0]); } @@ -85,13 +85,13 @@ public class DirectoryNode extends AbstractFsContentNode { return v.visit(this); } + @Override + public boolean isLeafTypeNode() { + return false; + } + @Override public T accept(DisplayableItemNodeVisitor v) { return v.visit(this); } - - @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.CONTENT; - } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNode.java index f5c4613bf7..9d150d53ad 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011 - 2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,12 +18,9 @@ */ package org.sleuthkit.autopsy.datamodel; -import java.awt.datatransfer.Transferable; import org.openide.nodes.AbstractNode; import org.openide.nodes.Children; import org.openide.util.Lookup; -import org.openide.util.datatransfer.PasteType; - /** * Interface for all displayable Nodes @@ -37,35 +34,7 @@ public abstract class DisplayableItemNode extends AbstractNode { public DisplayableItemNode(Children children, Lookup lookup) { super(children, lookup); } - - - /** - * Possible sub-implementations - */ - public enum TYPE { - CONTENT, ///< content node, such as file, image - ARTIFACT, ///< artifact data node - META, ///< top-level category node, such as view, filters, etc. - }; - - /** - * Get possible subtype of the displayable item node - * @return - */ - public abstract TYPE getDisplayableItemNodeType(); - - public boolean isLeafTypeNode() { - return false; - } - - /** - * Visitor pattern support. - * - * @param v visitor - * @return visitor's visit return value - */ - public abstract T accept(DisplayableItemNodeVisitor v); - - - + + abstract public boolean isLeafTypeNode(); + public abstract T accept(DisplayableItemNodeVisitor v); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java index a4c3ca1ff2..6b6944a0e5 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/EmailExtracted.java @@ -133,10 +133,10 @@ public class EmailExtracted implements AutopsyVisitableItem { } @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.ARTIFACT; + public boolean isLeafTypeNode() { + return false; } - + @Override public T accept(DisplayableItemNodeVisitor v) { //return v.visit(this); @@ -214,10 +214,10 @@ public class EmailExtracted implements AutopsyVisitableItem { } @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.ARTIFACT; + public boolean isLeafTypeNode() { + return false; } - + @Override public T accept(DisplayableItemNodeVisitor v) { return v.visit(this); @@ -271,11 +271,6 @@ public class EmailExtracted implements AutopsyVisitableItem { this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/account-icon-16.png"); } - @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.ARTIFACT; - } - @Override protected Sheet createSheet() { Sheet s = super.createSheet(); @@ -293,6 +288,11 @@ public class EmailExtracted implements AutopsyVisitableItem { return s; } + @Override + public boolean isLeafTypeNode() { + return false; + } + @Override public T accept(DisplayableItemNodeVisitor v) { return v.visit(this); @@ -336,11 +336,6 @@ public class EmailExtracted implements AutopsyVisitableItem { this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/folder-icon-16.png"); } - @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.ARTIFACT; - } - @Override public boolean isLeafTypeNode() { return true; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContentNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContentNode.java index 6d37c4392a..bd63cdb7e2 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContentNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ExtractedContentNode.java @@ -38,6 +38,11 @@ public class ExtractedContentNode extends DisplayableItemNode { this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/extracted_content.png"); } + @Override + public boolean isLeafTypeNode() { + return false; + } + @Override public T accept(DisplayableItemNodeVisitor v) { return v.visit(this); @@ -58,9 +63,4 @@ public class ExtractedContentNode extends DisplayableItemNode { NAME)); return s; } - - @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.ARTIFACT; - } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java index cb971c64a1..57946ee73f 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java @@ -25,7 +25,7 @@ import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.actions.TagAbstractFileAction; +import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM; @@ -84,7 +84,7 @@ public class FileNode extends AbstractFsContentNode { actionsList.add(ExtractAction.getInstance()); actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this)); actionsList.add(null); // creates a menu separator - actionsList.add(TagAbstractFileAction.getInstance()); + actionsList.add(AddContentTagAction.getInstance()); return actionsList.toArray(new Action[0]); } @@ -168,11 +168,6 @@ public class FileNode extends AbstractFsContentNode { } - @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.CONTENT; - } - @Override public boolean isLeafTypeNode() { return true; //false; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java index cb2b6d0965..2d8b44f8e5 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileSize.java @@ -111,10 +111,10 @@ public class FileSize implements AutopsyVisitableItem { } @Override - public DisplayableItemNode.TYPE getDisplayableItemNodeType() { - return DisplayableItemNode.TYPE.META; + public boolean isLeafTypeNode() { + return false; } - + @Override public T accept(DisplayableItemNodeVisitor v) { return v.visit(this); @@ -201,11 +201,6 @@ public class FileSize implements AutopsyVisitableItem { return s; } - @Override - public DisplayableItemNode.TYPE getDisplayableItemNodeType() { - return DisplayableItemNode.TYPE.META; - } - @Override public boolean isLeafTypeNode() { return true; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeNode.java index 3af3340bac..02c8b89e1c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeNode.java @@ -78,11 +78,6 @@ public class FileTypeNode extends DisplayableItemNode { return s; } - @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.META; - } - @Override public boolean isLeafTypeNode() { return true; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesNode.java index b8198c0d14..98b64f7d9b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesNode.java @@ -52,6 +52,11 @@ public class FileTypesNode extends DisplayableItemNode { this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); } + @Override + public boolean isLeafTypeNode() { + return false; + } + @Override public T accept(DisplayableItemNodeVisitor v) { return v.visit(this); @@ -72,9 +77,4 @@ public class FileTypesNode extends DisplayableItemNode { getName())); return s; } - - @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.META; - } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java index ca15f6d2e7..de62171a6f 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java @@ -113,10 +113,10 @@ public class HashsetHits implements AutopsyVisitableItem { } @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.ARTIFACT; + public boolean isLeafTypeNode() { + return false; } - + @Override public T accept(DisplayableItemNodeVisitor v) { return v.visit(this); @@ -163,11 +163,6 @@ public class HashsetHits implements AutopsyVisitableItem { this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hashset_hits.png"); } - @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.ARTIFACT; - } - @Override public boolean isLeafTypeNode() { return true; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java index 7e02f807a1..bea81eebc7 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ImageNode.java @@ -56,11 +56,6 @@ public class ImageNode extends AbstractContentNode { this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hard-drive-icon.jpg"); } - @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.CONTENT; - } - /** * Right click action for this node * @@ -98,6 +93,11 @@ public class ImageNode extends AbstractContentNode { return v.visit(this); } + @Override + public boolean isLeafTypeNode() { + return false; + } + @Override public T accept(DisplayableItemNodeVisitor v) { return v.visit(this); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java index e11fe6be2c..651fe0ede9 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/KeywordHits.java @@ -169,16 +169,16 @@ public class KeywordHits implements AutopsyVisitableItem { //logger.info("Process took " + (finish-start) + " ms" ); } + @Override + public boolean isLeafTypeNode() { + return false; + } + @Override public T accept(DisplayableItemNodeVisitor v) { return v.visit(this); } - @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.ARTIFACT; - } - @Override protected Sheet createSheet() { Sheet s = super.createSheet(); @@ -229,11 +229,6 @@ public class KeywordHits implements AutopsyVisitableItem { this.children = children; } - @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.ARTIFACT; - } - @Override protected Sheet createSheet() { Sheet s = super.createSheet(); @@ -257,6 +252,11 @@ public class KeywordHits implements AutopsyVisitableItem { return s; } + @Override + public boolean isLeafTypeNode() { + return false; + } + @Override public T accept(DisplayableItemNodeVisitor v) { return v.visit(this); @@ -310,11 +310,6 @@ public class KeywordHits implements AutopsyVisitableItem { return v.visit(this); } - @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.ARTIFACT; - } - @Override protected Sheet createSheet() { Sheet s = super.createSheet(); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java index e1e991a3c7..3becca50d1 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java @@ -27,7 +27,7 @@ import org.openide.nodes.Sheet; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.actions.TagAbstractFileAction; +import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.datamodel.LayoutFile; import org.sleuthkit.datamodel.TskData; @@ -62,11 +62,6 @@ public class LayoutFileNode extends AbstractAbstractFileNode { } } - @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.CONTENT; - } - @Override protected Sheet createSheet() { Sheet s = super.createSheet(); @@ -95,6 +90,11 @@ public class LayoutFileNode extends AbstractAbstractFileNode { return v.visit(this); } + @Override + public boolean isLeafTypeNode() { + return false; + } + @Override public T accept(DisplayableItemNodeVisitor v) { return v.visit(this); @@ -108,7 +108,7 @@ public class LayoutFileNode extends AbstractAbstractFileNode { actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); actionsList.add(null); // creates a menu separator - actionsList.add(TagAbstractFileAction.getInstance()); + actionsList.add(AddContentTagAction.getInstance()); return actionsList.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java index 48f49a60c8..5bd762f85b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java @@ -25,12 +25,11 @@ import java.util.List; import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; -import org.sleuthkit.autopsy.datamodel.DisplayableItemNode.TYPE; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.actions.TagAbstractFileAction; +import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.datamodel.AbstractFile; /** @@ -55,11 +54,6 @@ public class LocalFileNode extends AbstractAbstractFileNode { } - @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.CONTENT; - } - @Override protected Sheet createSheet() { Sheet s = super.createSheet(); @@ -92,7 +86,7 @@ public class LocalFileNode extends AbstractAbstractFileNode { actionsList.add(ExtractAction.getInstance()); actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this)); actionsList.add(null); // creates a menu separator - actionsList.add(TagAbstractFileAction.getInstance()); + actionsList.add(AddContentTagAction.getInstance()); return actionsList.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RecentFilesFilterNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/RecentFilesFilterNode.java index a2b9bf9d46..6646eb24c3 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RecentFilesFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RecentFilesFilterNode.java @@ -79,11 +79,6 @@ public class RecentFilesFilterNode extends DisplayableItemNode { return s; } - @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.META; - } - @Override public boolean isLeafTypeNode() { return true; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RecentFilesNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/RecentFilesNode.java index 91958d0b97..ecacf715e2 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RecentFilesNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RecentFilesNode.java @@ -42,10 +42,10 @@ public class RecentFilesNode extends DisplayableItemNode { } @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.META; + public boolean isLeafTypeNode() { + return false; } - + @Override public T accept(DisplayableItemNodeVisitor v) { return v.visit(this); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java index 065470a7b3..ab5159440b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java @@ -43,6 +43,11 @@ public class ResultsNode extends DisplayableItemNode { this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/results.png"); } + @Override + public boolean isLeafTypeNode() { + return false; + } + @Override public T accept(DisplayableItemNodeVisitor v) { return v.visit(this); @@ -63,9 +68,4 @@ public class ResultsNode extends DisplayableItemNode { NAME)); return s; } - - @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.META; - } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java index 1555b4eca9..a0fc06f539 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java @@ -66,11 +66,6 @@ public class TagNameNode extends DisplayableItemNode { return v.visit(this); } - @Override - public DisplayableItemNode.TYPE getDisplayableItemNodeType() { - return DisplayableItemNode.TYPE.META; // RJCTODO: What do these types mean and how are they used? What is correct? - } - @Override public boolean isLeafTypeNode() { return false; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index 11ad9d6498..74f6fca42b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -155,6 +155,11 @@ public class Tags implements AutopsyVisitableItem { } } + @Override + public boolean isLeafTypeNode() { + return false; + } + @Override public T accept(DisplayableItemNodeVisitor v) { return v.visit(this); @@ -176,11 +181,6 @@ public class Tags implements AutopsyVisitableItem { return s; } - - @Override - public DisplayableItemNode.TYPE getDisplayableItemNodeType() { - return DisplayableItemNode.TYPE.ARTIFACT; - } } /** @@ -246,11 +246,6 @@ public class Tags implements AutopsyVisitableItem { return v.visit(this); } - @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.META; - } - @Override public boolean isLeafTypeNode() { return false; @@ -325,11 +320,6 @@ public class Tags implements AutopsyVisitableItem { return v.visit(this); } - @Override - public DisplayableItemNode.TYPE getDisplayableItemNodeType() { - return DisplayableItemNode.TYPE.ARTIFACT; - } - @Override public boolean isLeafTypeNode() { return true; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java index b630a37600..14533921c1 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java @@ -43,6 +43,11 @@ public class TagsNode extends DisplayableItemNode { this.setIconBaseWithExtension(ICON_PATH); } + @Override + public boolean isLeafTypeNode() { + return false; + } + @Override public T accept(DisplayableItemNodeVisitor v) { return v.visit(this); @@ -61,12 +66,7 @@ public class TagsNode extends DisplayableItemNode { return propertySheet; } - - @Override - public DisplayableItemNode.TYPE getDisplayableItemNodeType() { - return DisplayableItemNode.TYPE.ARTIFACT; - } - + private static class TagsNodeChildFactory extends ChildFactory { @Override protected boolean createKeys(List keys) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/TagsNodeKey.java b/Core/src/org/sleuthkit/autopsy/datamodel/TagsNodeKey.java index 2e98898724..56cd249705 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/TagsNodeKey.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/TagsNodeKey.java @@ -23,8 +23,8 @@ package org.sleuthkit.autopsy.datamodel; * RootContentChildren class. RootContentChildren is a NetBeans child node * factory built on top of the NetBeans Children.Keys class. */ -public class TagsNodeKey implements AutopsyVisitableItem { - // Creation of a TagsNode object corresponding to TagsNodeKey object is done +public class TagsNodeKey implements AutopsyVisitableItem { // RJCTODO: Rename to Tags when old Tags class is deleted (for the sake of consistency). Add comments to similar classes. + // Creation of a TagsNode object corresponding to a TagsNodeKey object is done // by a CreateAutopsyNodeVisitor dispatched from the AbstractContentChildren // override of Children.Keys.createNodes(). @Override diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ViewsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ViewsNode.java index 652ae959a2..1690eb310b 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ViewsNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ViewsNode.java @@ -45,6 +45,11 @@ public class ViewsNode extends DisplayableItemNode { this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/views.png"); } + @Override + public boolean isLeafTypeNode() { + return false; + } + @Override public T accept(DisplayableItemNodeVisitor v) { return v.visit(this); @@ -65,9 +70,4 @@ public class ViewsNode extends DisplayableItemNode { NAME)); return s; } - - @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.META; - } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java index af63757bef..9a234df3c3 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java @@ -27,7 +27,7 @@ import org.openide.nodes.Sheet; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.actions.TagAbstractFileAction; +import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.datamodel.VirtualDirectory; import org.sleuthkit.datamodel.TskData; @@ -81,7 +81,7 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode { return v.visit(this); } + @Override + public boolean isLeafTypeNode() { + return false; + } + @Override public T accept(DisplayableItemNodeVisitor v) { return v.visit(this); } - - @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.CONTENT; - } } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java index 6f5c6d07f8..7eb1e21a4e 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java @@ -66,11 +66,6 @@ public class BlackboardArtifactTagTypeNode extends DisplayableItemNode { return v.visit(this); } - @Override - public DisplayableItemNode.TYPE getDisplayableItemNodeType() { - return DisplayableItemNode.TYPE.META; // RJCTODO: Is this right? - } - @Override public boolean isLeafTypeNode() { return true; diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties index 41d0090399..12abeb5237 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/directorytree/Bundle.properties @@ -47,9 +47,3 @@ ImageDetailsPanel.imgSectorSizeLabel.text=Sector Size: ImageDetailsPanel.imgSectorSizeValue.text=... DirectoryTreeTopComponent.backButton.text= DirectoryTreeTopComponent.forwardButton.text= -CreateTagDialog.cancelButton.text=Cancel -CreateTagDialog.okButton.text=OK -CreateTagDialog.tagNameField.text= -CreateTagDialog.tagNameLabel.text=Tag Name: -CreateTagDialog.preexistingLabel.text=Pre-existing Tags: -CreateTagDialog.newTagPanel.border.title=New Tag diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index 375f848006..7303734772 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -18,8 +18,8 @@ */ package org.sleuthkit.autopsy.directorytree; -import org.sleuthkit.autopsy.actions.TagBlackboardArtifactAction; -import org.sleuthkit.autopsy.actions.TagAbstractFileAction; +import org.sleuthkit.autopsy.actions.AddBlackboardArtifactTagAction; +import org.sleuthkit.autopsy.actions.AddContentTagAction; import java.awt.event.ActionEvent; import java.beans.PropertyVetoException; import java.util.ArrayList; @@ -208,8 +208,8 @@ public class DataResultFilterNode extends FilterNode { if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() && artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { actions.add(null); // creates a menu separator - actions.add(TagAbstractFileAction.getInstance()); - actions.add(TagBlackboardArtifactAction.getInstance()); + actions.add(AddContentTagAction.getInstance()); + actions.add(AddBlackboardArtifactTagAction.getInstance()); } } if ((d = ban.getLookup().lookup(Directory.class)) != null) { @@ -224,8 +224,8 @@ public class DataResultFilterNode extends FilterNode { if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() && artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { actions.add(null); // creates a menu separator - actions.add(TagAbstractFileAction.getInstance()); - actions.add(TagBlackboardArtifactAction.getInstance()); + actions.add(AddContentTagAction.getInstance()); + actions.add(AddBlackboardArtifactTagAction.getInstance()); } } if ((vd = ban.getLookup().lookup(VirtualDirectory.class)) != null) { @@ -240,8 +240,8 @@ public class DataResultFilterNode extends FilterNode { if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() && artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { actions.add(null); // creates a menu separator - actions.add(TagAbstractFileAction.getInstance()); - actions.add(TagBlackboardArtifactAction.getInstance()); + actions.add(AddContentTagAction.getInstance()); + actions.add(AddBlackboardArtifactTagAction.getInstance()); } } else if ((lf = ban.getLookup().lookup(LayoutFile.class)) != null) { LayoutFileNode lfn = new LayoutFileNode(lf); @@ -255,8 +255,8 @@ public class DataResultFilterNode extends FilterNode { if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() && artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { actions.add(null); // creates a menu separator - actions.add(TagAbstractFileAction.getInstance()); - actions.add(TagBlackboardArtifactAction.getInstance()); + actions.add(AddContentTagAction.getInstance()); + actions.add(AddBlackboardArtifactTagAction.getInstance()); } } else if ((locF = ban.getLookup().lookup(LocalFile.class)) != null || (locF = ban.getLookup().lookup(DerivedFile.class)) != null) { @@ -271,8 +271,8 @@ public class DataResultFilterNode extends FilterNode { if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() && artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { actions.add(null); // creates a menu separator - actions.add(TagAbstractFileAction.getInstance()); - actions.add(TagBlackboardArtifactAction.getInstance()); + actions.add(AddContentTagAction.getInstance()); + actions.add(AddBlackboardArtifactTagAction.getInstance()); } } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java b/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java index 80872c0d9f..658444765c 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/ExplorerNodeActionVisitor.java @@ -18,7 +18,7 @@ */ package org.sleuthkit.autopsy.directorytree; -import org.sleuthkit.autopsy.actions.TagAbstractFileAction; +import org.sleuthkit.autopsy.actions.AddContentTagAction; import java.awt.Toolkit; import java.awt.Dimension; import java.awt.Font; @@ -102,7 +102,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default visit(final Directory d) { List actions = new ArrayList(); - actions.add(TagAbstractFileAction.getInstance()); + actions.add(AddContentTagAction.getInstance()); return actions; } @@ -110,7 +110,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default visit(final VirtualDirectory d) { List actions = new ArrayList(); actions.add(ExtractAction.getInstance()); - actions.add(TagAbstractFileAction.getInstance()); + actions.add(AddContentTagAction.getInstance()); return actions; } @@ -118,7 +118,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default visit(final DerivedFile d) { List actions = new ArrayList(); actions.add(ExtractAction.getInstance()); - actions.add(TagAbstractFileAction.getInstance()); + actions.add(AddContentTagAction.getInstance()); return actions; } @@ -126,7 +126,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default visit(final LocalFile d) { List actions = new ArrayList(); actions.add(ExtractAction.getInstance()); - actions.add(TagAbstractFileAction.getInstance()); + actions.add(AddContentTagAction.getInstance()); return actions; } @@ -134,7 +134,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default visit(final org.sleuthkit.datamodel.File d) { List actions = new ArrayList(); actions.add(ExtractAction.getInstance()); - actions.add(TagAbstractFileAction.getInstance()); + actions.add(AddContentTagAction.getInstance()); return actions; } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java index 264e5ae6b1..268bedddcd 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java @@ -30,7 +30,7 @@ import org.openide.util.lookup.Lookups; import org.openide.util.lookup.ProxyLookup; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; -import org.sleuthkit.autopsy.actions.TagAbstractFileAction; +import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.datamodel.Content; @@ -151,7 +151,7 @@ class KeywordSearchFilterNode extends FilterNode { actions.add(ExtractAction.getInstance()); actions.add(new HashSearchAction("Search for files with the same MD5 hash", getOriginal())); actions.add(null); // creates a menu separator - actions.add(TagAbstractFileAction.getInstance()); + actions.add(AddContentTagAction.getInstance()); return actions; } diff --git a/Timeline/src/org/sleuthkit/autopsy/timeline/Timeline.java b/Timeline/src/org/sleuthkit/autopsy/timeline/Timeline.java index 9f027c53ce..e55a35c7d8 100644 --- a/Timeline/src/org/sleuthkit/autopsy/timeline/Timeline.java +++ b/Timeline/src/org/sleuthkit/autopsy/timeline/Timeline.java @@ -885,10 +885,10 @@ public class Timeline extends CallableSystemAction implements Presenter.Toolbar, } @Override - public DisplayableItemNode.TYPE getDisplayableItemNodeType() { - return DisplayableItemNode.TYPE.CONTENT; + public boolean isLeafTypeNode() { + return false; } - + @Override public T accept(DisplayableItemNodeVisitor v) { return null; From 7000ab6865499dd0c72430ee6fc1ac9fb9f5d455 Mon Sep 17 00:00:00 2001 From: raman-bt Date: Tue, 15 Oct 2013 11:31:30 -0400 Subject: [PATCH 008/169] Define DSPProgressMoinitor class. Eliminate dependency on the ProgressControlPanel from DataSourceProcessor. --- .../AddImageWizardAddingProgressPanel.java | 23 ++ .../AddImageWizardIngestConfigPanel.java | 31 ++- .../casemodule/DataSourceProcessor.java | 4 +- .../autopsy/casemodule/ImageDSProcessor.java | 196 +++++++----------- 4 files changed, 118 insertions(+), 136 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java index 7b0faf13f8..3817565c54 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java @@ -50,6 +50,29 @@ class AddImageWizardAddingProgressPanel implements WizardDescriptor.FinishablePa private AddImageWizardAddingProgressVisual component; private final Set listeners = new HashSet<>(1); // or can use ChangeSupport in NB 6.0 + private DSPProgressMonitorImpl dspProgressMonitorImpl = new DSPProgressMonitorImpl(); + + public DSPProgressMonitorImpl getDSPProgressMonitorImpl() { + return dspProgressMonitorImpl; + } + + private class DSPProgressMonitorImpl implements DSPProgressMonitor { + @Override + public void setIndeterminate(boolean indeterminate) { + getComponent().getProgressBar().setIndeterminate(indeterminate); + + } + @Override + public void setProgress(int progress) { + getComponent().getProgressBar().setValue(progress); + } + @Override + public void setText(String text) { + getComponent().setCurrentDirText(text); + + } + + } /** * Get the visual component for the panel. In this template, the component * is kept separate. This can be more efficient: if the wizard is created diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java index dab6bf7318..5a89aa2997 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java @@ -275,8 +275,11 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel errList, List contents) { logger.log(Level.INFO, "RAMAN dataSourceProcessorDone()."); - // RAMAN TBD - // check if there is any new content and kick off ingest.... - - // RAMAN TBD: check the result - - // RAMAN TBD: if errors, display them on the progress panel - - // disbale the cleanup task + // disable the cleanup task cleanupTask.disable(); + + //check the result and display to user + if (result == DSPCallback.DSP_Result.NO_ERRORS) + progressPanel.getComponent().setProgressBarTextAndColor("*Data Source added.", 100, Color.black); + else + progressPanel.getComponent().setProgressBarTextAndColor("*Errors encountered in adding Data Source.", 100, Color.red); + + + //if errors, display them on the progress panel + for ( String err: errList ) { + // TBD: there should be an error level for each error + progressPanel.addErrors(err, false); + } + newContents.clear(); @@ -307,6 +317,9 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel { - - //AddImageWizardIngestConfigPanel.AddImageTask task; - JProgressBar progressBar; - AddImageWizardAddingProgressVisual progressVisual; - SleuthkitJNI.CaseDbHandle.AddImageProcess process; - - CurrentDirectoryFetcher(JProgressBar aProgressBar, AddImageWizardAddingProgressVisual wiz, SleuthkitJNI.CaseDbHandle.AddImageProcess proc) { - this.progressVisual = wiz; - this.process = proc; - this.progressBar = aProgressBar; - } - - /** - * @return the currently processing directory - */ - @Override - protected Integer doInBackground() { - try { - while (progressBar.getValue() < 100 || progressBar.isIndeterminate()) { //TODO Rely on state variable in AddImgTask class - - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - progressVisual.setCurrentDirText(process.currentDirectory()); - } - }); - - Thread.sleep(2 * 1000); - } - return 1; - } catch (InterruptedException ie) { - return -1; - } - } - } - + private class AddImageTask extends SwingWorker { - private JProgressBar progressBar; private Case currentCase; // true if the process was requested to stop private boolean cancelled = false; //true if revert has been invoked. private boolean reverted = false; private boolean hasCritError = false; - private boolean addImagedone = false; + private boolean addImageDone = false; - - //private String errorString = null; private List errorList = new ArrayList(); private WizardDescriptor wizDescriptor; private Logger logger = Logger.getLogger(AddImageTask.class.getName()); - private AddImageWizardAddingProgressPanel progressPanel; + private DSPProgressMonitor progressMonitor; private DSPCallback callbackObj; private final List newContents = Collections.synchronizedList(new ArrayList()); private SleuthkitJNI.CaseDbHandle.AddImageProcess addImageProcess; + private CurrentDirectoryFetcher fetcher; + - protected AddImageTask(WizardDescriptor settings, AddImageWizardAddingProgressPanel aProgressPanel, DSPCallback cbObj ) { - this.progressPanel = aProgressPanel; - this.progressBar = progressPanel.getComponent().getProgressBar(); + + private class CurrentDirectoryFetcher extends SwingWorker { + + DSPProgressMonitor progressMonitor; + SleuthkitJNI.CaseDbHandle.AddImageProcess process; + + CurrentDirectoryFetcher(DSPProgressMonitor aProgressMonitor, SleuthkitJNI.CaseDbHandle.AddImageProcess proc) { + this.progressMonitor = aProgressMonitor; + this.process = proc; + // this.progressBar = aProgressBar; + } + + /** + * @return the currently processing directory + */ + @Override + protected Integer doInBackground() { + try { + while (!(addImageDone)) { + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + progressMonitor.setText(process.currentDirectory()); + } + }); + + Thread.sleep(2 * 1000); + } + return 1; + } catch (InterruptedException ie) { + return -1; + } + } + } + + + protected AddImageTask(WizardDescriptor settings, DSPProgressMonitor aProgressMonitor, DSPCallback cbObj ) { + this.progressMonitor = aProgressMonitor; currentCase = Case.getCurrentCase(); this.callbackObj = cbObj; @@ -223,18 +218,6 @@ public class ImageDSProcessor implements DataSourceProcessor { errorList.clear(); - /**** RAMAN TBD: a higher level caller should set up the cleanup task and then call DataSourceHandler.cancelProcessing() - * - // Add a cleanup task to interrupt the backgroud process if the - // wizard exits while the background process is running. - AddImageAction.CleanupTask cancelledWhileRunning = action.new CleanupTask() { - @Override - void cleanup() throws Exception { - logger.log(Level.INFO, "Add image process interrupted."); - addImageTask.interrupt(); //it might take time to truly interrupt - } - }; - * *************************/ try { @@ -263,27 +246,24 @@ public class ImageDSProcessor implements DataSourceProcessor { addImageProcess = currentCase.makeAddImageProcess(timeZone, true, noFatOrphans); - fetcher = new CurrentDirectoryFetcher(this.progressBar, progressPanel.getComponent(), addImageProcess); - //RAMAN TBD: handle the cleanup task - //cancelledWhileRunning.enable(); + fetcher = new CurrentDirectoryFetcher(progressMonitor, addImageProcess); + try { - progressPanel.setStateStarted(); + progressMonitor.setIndeterminate(true); + progressMonitor.setProgress(0); + fetcher.execute(); addImageProcess.run(new String[]{dataSourcePath}); } catch (TskCoreException ex) { logger.log(Level.WARNING, "Core errors occurred while running add image. ", ex); //critical core/system error and process needs to be interrupted hasCritError = true; - //errorString = ex.getMessage(); errorList.add(ex.getMessage()); } catch (TskDataException ex) { logger.log(Level.WARNING, "Data errors occurred while running add image. ", ex); - //errorString = ex.getMessage(); - errorList.add(ex.getMessage()); + errorList.add(ex.getMessage()); } finally { // process is over, doesn't need to be dealt with if cancel happens - //RAMAN TBD: handle the cleanup task - //cancelledWhileRunning.disable(); } @@ -327,20 +307,19 @@ public class ImageDSProcessor implements DataSourceProcessor { if (verificationErrors.equals("") == false) { //data error (non-critical) errorList.add(verificationErrors); - //progressPanel.addErrors(verificationErrors, false); } - /*** RAMAN TBD: how to handle the newContent notification back to IngestConfigPanel **/ + // newContents.add(newImage); + // RAMAN TBD: imageID should be return via the callback settings.putProperty(AddImageAction.IMAGEID_PROP, imageId); } // Can't bail and revert image add after commit, so disable image cleanup // task - // RAMAN TBD: cleanup task should be handled by the caller - // cleanupImage.disable(); + settings.putProperty(AddImageAction.IMAGECLEANUPTASK_PROP, null); @@ -360,10 +339,11 @@ public class ImageDSProcessor implements DataSourceProcessor { protected void done() { logger.log(Level.INFO, "RAMAN: done()..."); - - //these are required to stop the CurrentDirectoryFetcher - progressBar.setIndeterminate(false); + setProgress(100); + + // cancel + fetcher.cancel(true); addImageDone = true; @@ -372,19 +352,13 @@ public class ImageDSProcessor implements DataSourceProcessor { if (cancelled || hasCritError) { logger.log(Level.INFO, "Handling errors or interruption that occured in add image process"); revert(); - if (hasCritError) { - //core error - // RAMAN TBD: Error reporting needs to be removed from here. All errors are returned to caller directly. - //progressPanel.addErrors(errorString, true); - } // Do not return yet. Callback must be called } if (!errorList.isEmpty()) { - //data error (non-critical) + logger.log(Level.INFO, "Handling non-critical errors that occured in add image process"); - // RAMAN TBD: Error reporting needs to be removed from here. All errors are returned to caller directly. - //progressPanel.addErrors(errorString, false); + // error are returned back to the caller } // When everything happens without an error: @@ -393,28 +367,14 @@ public class ImageDSProcessor implements DataSourceProcessor { try { - /* ***************************** - * RAMAN TBD: the caller needs to handle the cleanup ??? - // the add-image process needs to be reverted if the wizard doesn't finish - cleanupImage = action.new CleanupTask() { - //note, CleanupTask runs inside EWT thread - @Override - void cleanup() throws Exception { - logger.log(Level.INFO, "Running cleanup task after add image process"); - revert(); - } - }; - cleanupImage.enable(); - * ************************/ + - //if (errorString == null) { // complete progress bar - if (errorList.isEmpty() ) { // complete progress bar - progressPanel.getComponent().setProgressBarTextAndColor("*Data Source added.", 100, Color.black); - } + // RAMAN TBD: this should not be happening in here - caller should do this // Get attention for the process finish + /****** java.awt.Toolkit.getDefaultToolkit().beep(); //BEEP! AddImageWizardAddingProgressVisual panel = progressPanel.getComponent(); if (panel != null) { @@ -423,9 +383,10 @@ public class ImageDSProcessor implements DataSourceProcessor { w.toFront(); } } + * *******/ // Tell the panel we're done - progressPanel.setStateFinished(); + progressMonitor.setProgress(100); if (newContents.isEmpty()) { @@ -434,6 +395,7 @@ public class ImageDSProcessor implements DataSourceProcessor { try { commitImage(wizDescriptor); } catch (Exception ex) { + errorList.add(ex.getMessage()); // Log error/display warning logger.log(Level.SEVERE, "Error adding image to case.", ex); } @@ -442,28 +404,19 @@ public class ImageDSProcessor implements DataSourceProcessor { } } - else //already commited? - { + else { //already commited? logger.log(Level.INFO, "Assuming image already committed, will not commit."); - } - - // Start ingest if we can - // RAMAN TBD - remove this from here - //startIngest(); - } catch (Exception ex) { //handle unchecked exceptions post image add + errorList.add(ex.getMessage()); + logger.log(Level.WARNING, "Unexpected errors occurred while running post add image cleanup. ", ex); - - progressPanel.getComponent().setProgressBarTextAndColor("*Failed to add image.", 0, Color.black); // set error message - - // Log error/display warning - + logger.log(Level.SEVERE, "Error adding image to case", ex); } finally { @@ -497,13 +450,6 @@ public class ImageDSProcessor implements DataSourceProcessor { callbackObj.done(result, errorList, newContents); } - /***** - public List getNewContents() { - - return newContents; - - } - * ********/ void cancelTask() { From cf4c996f531e3a60123507f57af54590dd0babf1 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Tue, 15 Oct 2013 13:38:06 -0400 Subject: [PATCH 009/169] New tags api interim work --- .../autopsy/actions/AddTagAction.java | 2 +- .../actions/GetTagNameAndCommentDialog.java | 2 +- .../autopsy/actions/GetTagNameDialog.java | 2 +- .../casemodule/services/TagsManager.java | 20 +++- .../datamodel/BlackboardArtifactTagNode.java | 2 +- .../autopsy/datamodel/ContentTagNode.java | 16 ++- .../autopsy/datamodel/ContentTagTypeNode.java | 4 +- .../sleuthkit/autopsy/datamodel/TagsNode.java | 6 +- nbproject/platform.properties | 108 +----------------- 9 files changed, 39 insertions(+), 123 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java index 9e52cd1ece..a98b94b0c4 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java @@ -81,7 +81,7 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup { // Get the current set of tag names. TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); ArrayList tagNames = new ArrayList<>(); - tagsManager.getTagNames(tagNames); + tagsManager.getAllTagNames(tagNames); // Create a "Quick Tag" sub-menu. JMenu quickTagMenu = new JMenu("Quick Tag"); diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java index eef172f209..2398b59081 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java @@ -83,7 +83,7 @@ public class GetTagNameAndCommentDialog extends JDialog { // Save the tag names to be enable to return the one the user selects. TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); ArrayList currentTagNames = new ArrayList<>(); - tagsManager.getTagNames(currentTagNames); + tagsManager.getAllTagNames(currentTagNames); if (currentTagNames.isEmpty()) { tagCombo.addItem(NO_TAG_NAMES_MESSAGE); } diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java index b019c22588..d576d7c274 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java @@ -54,7 +54,7 @@ public class GetTagNameDialog extends JDialog { // case the user chooses an existing tag name from the tag names table. TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); ArrayList currentTagNames = new ArrayList<>(); - tagsManager.getTagNames(currentTagNames); + tagsManager.getAllTagNames(currentTagNames); for (TagName name : currentTagNames) { this.tagNames.put(name.getDisplayName(), name); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 47675cb5f4..29de1a0e29 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -56,10 +56,10 @@ public class TagsManager implements Closeable { * blackboard artifacts. * @return [out] A list, possibly empty, of TagName data transfer objects (DTOs). */ - public void getTagNames(List tagNames) { + public void getAllTagNames(List tagNames) { try { tagNames.clear(); - tskCase.getTagNames(tagNames); + tskCase.getAllTagNames(tagNames); } catch (TskCoreException ex) { Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names from the current case", ex); @@ -214,7 +214,12 @@ public class TagsManager implements Closeable { * @return */ public void getContentTags(TagName tagName, List tags) { - // RJCTODO: Implement + try { + tskCase.getContentTagsByTagName(tagName, tags); + } + catch (TskCoreException ex) { + Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get content tags from the current case", ex); + } } /** @@ -223,7 +228,12 @@ public class TagsManager implements Closeable { * @return */ public void getBlackboardArtifactTags(TagName tagName, List tags) { - // RJCTODO: Implement + try { + tskCase.getBlackboardArtifactTagsByTagName(tagName, tags); + } + catch (TskCoreException ex) { + Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get blackboard artifact tags from the current case", ex); + } } @Override @@ -235,7 +245,7 @@ public class TagsManager implements Closeable { // Get any tag names already defined for the current case. try { ArrayList currentTagNames = new ArrayList<>(); - tskCase.getTagNames(currentTagNames); + tskCase.getAllTagNames(currentTagNames); for (TagName tagName : currentTagNames) { tagNames.put(tagName.getDisplayName(), tagName); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java index 65df35b0bf..a3eae02719 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java @@ -34,7 +34,7 @@ public class BlackboardArtifactTagNode extends DisplayableItemNode { private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; // RJCTODO: Want better icons? public BlackboardArtifactTagNode(BlackboardArtifactTag tag) { - super(Children.LEAF, Lookups.singleton(tag)); + super(Children.LEAF, Lookups.fixed(tag, tag.getArtifact())); super.setName(tag.getArtifact().getDisplayName()); super.setDisplayName(tag.getArtifact().getDisplayName()); this.setIconBaseWithExtension(ICON_PATH); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java index 628b0b3e35..940fc6ab9d 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java @@ -23,6 +23,7 @@ import org.openide.nodes.Children; import org.openide.nodes.Sheet; import org.openide.util.lookup.Lookups; import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.TskCoreException; /** * Instances of this class wrap ContentTag objects. In the Autopsy @@ -32,12 +33,14 @@ import org.sleuthkit.datamodel.ContentTag; */ public class ContentTagNode extends DisplayableItemNode { private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; + private final ContentTag tag; public ContentTagNode(ContentTag tag) { - super(Children.LEAF, Lookups.singleton(tag)); + super(Children.LEAF, Lookups.fixed(tag, tag.getContent())); super.setName(tag.getContent().getName()); super.setDisplayName(tag.getContent().getName()); this.setIconBaseWithExtension(ICON_PATH); + this.tag = tag; } @Override @@ -50,7 +53,16 @@ public class ContentTagNode extends DisplayableItemNode { propertySheet.put(properties); } - properties.put(new NodeProperty("Name", "Name", "", getName())); + properties.put(new NodeProperty("Source File", "Source File", "", getName())); + String contentPath; + try { + contentPath = tag.getContent().getUniquePath(); + } + catch (TskCoreException ex) { + // RJCTODO: Add to log + contentPath = "Unavailable"; + } + properties.put(new NodeProperty("Source File Path", "Source File Path", "", contentPath)); return propertySheet; } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java index 7f3d590765..123d21944b 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java @@ -33,7 +33,7 @@ import org.sleuthkit.datamodel.TagName; * then by tag name. */ public class ContentTagTypeNode extends DisplayableItemNode { - private static final String DISPLAY_NAME = "Content Tags"; + private static final String DISPLAY_NAME = "File Tags"; private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; public ContentTagTypeNode(TagName tagName) { @@ -64,7 +64,7 @@ public class ContentTagTypeNode extends DisplayableItemNode { @Override public boolean isLeafTypeNode() { - return false; + return true; } private static class ContentTagNodeFactory extends ChildFactory { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java index 14533921c1..e5d121ada6 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java @@ -37,7 +37,7 @@ public class TagsNode extends DisplayableItemNode { private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; public TagsNode() { - super(Children.create(new TagsNodeChildFactory(), true)); + super(Children.create(new TagNameNodeFactory(), true)); super.setName(DISPLAY_NAME); super.setDisplayName(DISPLAY_NAME); this.setIconBaseWithExtension(ICON_PATH); @@ -67,10 +67,10 @@ public class TagsNode extends DisplayableItemNode { return propertySheet; } - private static class TagsNodeChildFactory extends ChildFactory { + private static class TagNameNodeFactory extends ChildFactory { @Override protected boolean createKeys(List keys) { - Case.getCurrentCase().getServices().getTagsManager().getTagNames(keys); + Case.getCurrentCase().getServices().getTagsManager().getAllTagNames(keys); // RJCTODO: Change this call to filtered call return true; } diff --git a/nbproject/platform.properties b/nbproject/platform.properties index e0bdd68b73..9a1e78ae2a 100644 --- a/nbproject/platform.properties +++ b/nbproject/platform.properties @@ -10,111 +10,5 @@ cluster.path=\ ${nbplatform.active.dir}/java:\ ${nbplatform.active.dir}/platform disabled.modules=\ - org.apache.tools.ant.module,\ - org.netbeans.api.debugger.jpda,\ - org.netbeans.api.java,\ - org.netbeans.lib.nbjavac,\ - org.netbeans.libs.cglib,\ - org.netbeans.libs.javacapi,\ - org.netbeans.libs.javacimpl,\ - org.netbeans.libs.springframework,\ - org.netbeans.modules.ant.browsetask,\ - org.netbeans.modules.ant.debugger,\ - org.netbeans.modules.ant.freeform,\ - org.netbeans.modules.ant.grammar,\ - org.netbeans.modules.ant.kit,\ - org.netbeans.modules.beans,\ - org.netbeans.modules.classfile,\ - org.netbeans.modules.dbschema,\ - org.netbeans.modules.debugger.jpda,\ - org.netbeans.modules.debugger.jpda.ant,\ - org.netbeans.modules.debugger.jpda.kit,\ - org.netbeans.modules.debugger.jpda.projects,\ - org.netbeans.modules.debugger.jpda.ui,\ - org.netbeans.modules.debugger.jpda.visual,\ - org.netbeans.modules.findbugs.installer,\ - org.netbeans.modules.form,\ - org.netbeans.modules.form.binding,\ - org.netbeans.modules.form.j2ee,\ - org.netbeans.modules.form.kit,\ - org.netbeans.modules.form.nb,\ - org.netbeans.modules.form.refactoring,\ - org.netbeans.modules.hibernate,\ - org.netbeans.modules.hibernatelib,\ - org.netbeans.modules.hudson.ant,\ - org.netbeans.modules.hudson.maven,\ - org.netbeans.modules.i18n,\ - org.netbeans.modules.i18n.form,\ - org.netbeans.modules.j2ee.core.utilities,\ - org.netbeans.modules.j2ee.eclipselink,\ - org.netbeans.modules.j2ee.eclipselinkmodelgen,\ - org.netbeans.modules.j2ee.jpa.refactoring,\ - org.netbeans.modules.j2ee.jpa.verification,\ - org.netbeans.modules.j2ee.metadata,\ - org.netbeans.modules.j2ee.metadata.model.support,\ - org.netbeans.modules.j2ee.persistence,\ - org.netbeans.modules.j2ee.persistence.kit,\ - org.netbeans.modules.j2ee.persistenceapi,\ - org.netbeans.modules.java.api.common,\ - org.netbeans.modules.java.debug,\ - org.netbeans.modules.java.editor,\ - org.netbeans.modules.java.editor.lib,\ - org.netbeans.modules.java.examples,\ - org.netbeans.modules.java.freeform,\ - org.netbeans.modules.java.guards,\ - org.netbeans.modules.java.helpset,\ - org.netbeans.modules.java.hints,\ - org.netbeans.modules.java.hints.declarative,\ - org.netbeans.modules.java.hints.declarative.test,\ - org.netbeans.modules.java.hints.legacy.spi,\ - org.netbeans.modules.java.hints.test,\ - org.netbeans.modules.java.hints.ui,\ - org.netbeans.modules.java.j2seplatform,\ - org.netbeans.modules.java.j2seproject,\ - org.netbeans.modules.java.kit,\ - org.netbeans.modules.java.lexer,\ - org.netbeans.modules.java.navigation,\ - org.netbeans.modules.java.platform,\ - org.netbeans.modules.java.preprocessorbridge,\ - org.netbeans.modules.java.project,\ - org.netbeans.modules.java.source,\ - org.netbeans.modules.java.source.ant,\ - org.netbeans.modules.java.source.queries,\ - org.netbeans.modules.java.source.queriesimpl,\ - org.netbeans.modules.java.sourceui,\ - org.netbeans.modules.java.testrunner,\ - org.netbeans.modules.javadoc,\ - org.netbeans.modules.javawebstart,\ - org.netbeans.modules.junit,\ - org.netbeans.modules.maven,\ - org.netbeans.modules.maven.checkstyle,\ - org.netbeans.modules.maven.coverage,\ - org.netbeans.modules.maven.embedder,\ - org.netbeans.modules.maven.grammar,\ - org.netbeans.modules.maven.graph,\ - org.netbeans.modules.maven.hints,\ - org.netbeans.modules.maven.indexer,\ - org.netbeans.modules.maven.junit,\ - org.netbeans.modules.maven.kit,\ - org.netbeans.modules.maven.model,\ - org.netbeans.modules.maven.osgi,\ - org.netbeans.modules.maven.persistence,\ - org.netbeans.modules.maven.refactoring,\ - org.netbeans.modules.maven.repository,\ - org.netbeans.modules.maven.search,\ - org.netbeans.modules.maven.spring,\ - org.netbeans.modules.projectimport.eclipse.core,\ - org.netbeans.modules.projectimport.eclipse.j2se,\ - org.netbeans.modules.refactoring.java,\ - org.netbeans.modules.spellchecker.bindings.java,\ - org.netbeans.modules.spring.beans,\ - org.netbeans.modules.testng,\ - org.netbeans.modules.testng.ant,\ - org.netbeans.modules.testng.maven,\ - org.netbeans.modules.websvc.jaxws21,\ - org.netbeans.modules.websvc.jaxws21api,\ - org.netbeans.modules.websvc.saas.codegen.java,\ - org.netbeans.modules.xml.jaxb,\ - org.netbeans.modules.xml.tools.java,\ - org.netbeans.spi.java.hints + org.netbeans.modules.junit From d74fa2e89482dcd54fd6167a30d30ea3880f27a4 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Tue, 15 Oct 2013 16:10:11 -0400 Subject: [PATCH 010/169] New tags API extended to properly handle blackboard artifact and content nodes --- .../casemodule/services/TagsManager.java | 2 +- .../datamodel/BlackboardArtifactTagNode.java | 30 +++++++++++++------ .../autopsy/datamodel/ContentTagNode.java | 9 +++--- 3 files changed, 26 insertions(+), 15 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 29de1a0e29..2f113dec83 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -201,7 +201,7 @@ public class TagsManager implements Closeable { * @throws TskCoreException */ public void addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException { - tskCase.addBlackboardArtifactTag(new BlackboardArtifactTag(artifact, tagName, comment)); + tskCase.addBlackboardArtifactTag(new BlackboardArtifactTag(artifact, tskCase.getContentById(artifact.getObjectID()), tagName, comment)); } void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java index a3eae02719..5a603bbcf5 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java @@ -18,10 +18,13 @@ */ package org.sleuthkit.autopsy.datamodel; +import java.util.logging.Level; +import java.util.logging.Logger; import org.openide.nodes.Children; import org.openide.nodes.Sheet; import org.openide.util.lookup.Lookups; import org.sleuthkit.datamodel.BlackboardArtifactTag; +import org.sleuthkit.datamodel.TskCoreException; /** * Instances of this class wrap BlackboardArtifactTag objects. In the Autopsy @@ -31,18 +34,19 @@ import org.sleuthkit.datamodel.BlackboardArtifactTag; * either content or blackboard artifact tag nodes. */ public class BlackboardArtifactTagNode extends DisplayableItemNode { - private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; // RJCTODO: Want better icons? + private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; + private final BlackboardArtifactTag tag; public BlackboardArtifactTagNode(BlackboardArtifactTag tag) { - super(Children.LEAF, Lookups.fixed(tag, tag.getArtifact())); - super.setName(tag.getArtifact().getDisplayName()); - super.setDisplayName(tag.getArtifact().getDisplayName()); + super(Children.LEAF, Lookups.fixed(tag, tag.getArtifact(), tag.getContent())); + super.setName(tag.getContent().getName()); + super.setDisplayName(tag.getContent().getName()); this.setIconBaseWithExtension(ICON_PATH); + this.tag = tag; } @Override protected Sheet createSheet() { - // RJCTODO: Make additional properties as needed for DataResultViewers Sheet propertySheet = super.createSheet(); Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES); if (properties == null) { @@ -50,15 +54,23 @@ public class BlackboardArtifactTagNode extends DisplayableItemNode { propertySheet.put(properties); } - properties.put(new NodeProperty("Name", "Name", "", getName())); - + properties.put(new NodeProperty("Source File", "Source File", "", tag.getContent().getName())); + String contentPath; + try { + contentPath = tag.getContent().getUniquePath(); + } + catch (TskCoreException ex) { + Logger.getLogger(ContentTagNode.class.getName()).log(Level.SEVERE, "Failed to get path for content (id = " + tag.getContent().getId() + ")", ex); + contentPath = "Unavailable"; + } + properties.put(new NodeProperty("Source File Path", "Source File Path", "", contentPath)); + properties.put(new NodeProperty("Result Type", "Result Type", "", tag.getArtifact().getDisplayName())); + return propertySheet; } @Override public T accept(DisplayableItemNodeVisitor v) { - // See classes derived from DisplayableItemNodeVisitor - // for behavior added using the Visitor pattern. return v.visit(this); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java index 940fc6ab9d..2c893b3fb5 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java @@ -19,6 +19,8 @@ package org.sleuthkit.autopsy.datamodel; +import java.util.logging.Level; +import java.util.logging.Logger; import org.openide.nodes.Children; import org.openide.nodes.Sheet; import org.openide.util.lookup.Lookups; @@ -45,7 +47,6 @@ public class ContentTagNode extends DisplayableItemNode { @Override protected Sheet createSheet() { - // RJCTODO: Make additional properties as needed for DataResultViewers Sheet propertySheet = super.createSheet(); Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES); if (properties == null) { @@ -53,13 +54,13 @@ public class ContentTagNode extends DisplayableItemNode { propertySheet.put(properties); } - properties.put(new NodeProperty("Source File", "Source File", "", getName())); + properties.put(new NodeProperty("Source File", "Source File", "", tag.getContent().getName())); String contentPath; try { contentPath = tag.getContent().getUniquePath(); } catch (TskCoreException ex) { - // RJCTODO: Add to log + Logger.getLogger(ContentTagNode.class.getName()).log(Level.SEVERE, "Failed to get path for content (id = " + tag.getContent().getId() + ")", ex); contentPath = "Unavailable"; } properties.put(new NodeProperty("Source File Path", "Source File Path", "", contentPath)); @@ -69,8 +70,6 @@ public class ContentTagNode extends DisplayableItemNode { @Override public T accept(DisplayableItemNodeVisitor v) { - // See classes derived from DisplayableItemNodeVisitor - // for behavior added using the Visitor pattern. return v.visit(this); } From a3a027eea0bc065918e70f6a3a19d9336c3f251c Mon Sep 17 00:00:00 2001 From: raman-bt Date: Wed, 16 Oct 2013 08:14:17 -0400 Subject: [PATCH 011/169] New file, DSPProgressMonitor.java - that got missed in the the previous commit. --- .../casemodule/DSPProgressMonitor.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/DSPProgressMonitor.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/DSPProgressMonitor.java b/Core/src/org/sleuthkit/autopsy/casemodule/DSPProgressMonitor.java new file mode 100644 index 0000000000..d3acea384c --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/DSPProgressMonitor.java @@ -0,0 +1,19 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.casemodule; + +/* + * An GUI agnostic DSPProgressMonitor interface for DataSorceProcesssors to + * indicate progress. + * It models after a JProgressbar though could use any underlying implementation + */ +public interface DSPProgressMonitor { + + void setIndeterminate(boolean indeterminate); + + void setProgress(int progress); + + void setText(String text); +} From b65a9e6d5a61b2bbd5c46bed886d42d9f6d9807f Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 16 Oct 2013 18:26:32 -0400 Subject: [PATCH 012/169] Added delete tag capability to new tags api --- .../AddBlackboardArtifactTagAction.java | 2 +- .../autopsy/actions/AddContentTagAction.java | 2 +- .../autopsy/actions/AddTagAction.java | 24 +- .../DeleteBlackboardArtifactTagAction.java | 67 +++ .../actions/DeleteContentTagAction.java | 66 +++ .../sleuthkit/autopsy/actions/TagAction.java | 62 +++ .../casemodule/services/TagsManager.java | 336 +++++++------- .../datamodel/AbstractContentChildren.java | 5 - .../autopsy/datamodel/AutopsyItemVisitor.java | 7 - .../datamodel/BlackboardArtifactTagNode.java | 11 + .../autopsy/datamodel/ContentTagNode.java | 11 + .../autopsy/datamodel/ContentTagTypeNode.java | 2 +- .../datamodel/DisplayableItemNodeVisitor.java | 24 - .../autopsy/datamodel/ResultsNode.java | 1 - .../datamodel/RootContentChildren.java | 17 +- .../org/sleuthkit/autopsy/datamodel/Tags.java | 411 +----------------- .../sleuthkit/autopsy/datamodel/TagsNode.java | 6 +- .../BlackboardArtifactTagTypeNode.java | 2 +- .../directorytree/DataResultFilterNode.java | 12 - 19 files changed, 432 insertions(+), 636 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java create mode 100755 Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java create mode 100755 Core/src/org/sleuthkit/autopsy/actions/TagAction.java diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java index 303a773e17..d81e978bc1 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java @@ -46,6 +46,7 @@ public class AddBlackboardArtifactTagAction extends AddTagAction { } private AddBlackboardArtifactTagAction() { + super(""); } @Override @@ -57,7 +58,6 @@ public class AddBlackboardArtifactTagAction extends AddTagAction { protected void addTag(TagName tagName, String comment) { Collection selectedArtifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class); for (BlackboardArtifact artifact : selectedArtifacts) { - Tags.createTag(artifact, tagName.getDisplayName(), comment); //RJCTODO: Jettision this try { Case.getCurrentCase().getServices().getTagsManager().addBlackboardArtifactTag(artifact, tagName, comment); } diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java index 813fde02af..1483ce36c9 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java @@ -46,6 +46,7 @@ public class AddContentTagAction extends AddTagAction { } private AddContentTagAction() { + super(""); } @Override @@ -57,7 +58,6 @@ public class AddContentTagAction extends AddTagAction { protected void addTag(TagName tagName, String comment) { Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); for (AbstractFile file : selectedFiles) { - Tags.createTag(file, tagName.getDisplayName(), comment); //RJCTODO: Jettision this try { Case.getCurrentCase().getServices().getTagsManager().addContentTag(file, tagName, comment); } diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java index a98b94b0c4..1532a573d2 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java @@ -35,16 +35,20 @@ import org.sleuthkit.datamodel.TagName; * An abstract base class for Actions that allow users to tag SleuthKit data * model objects. */ -abstract class AddTagAction extends AbstractAction implements Presenter.Popup { +abstract class AddTagAction extends TagAction implements Presenter.Popup { private static final String NO_COMMENT = ""; + AddTagAction(String menuText) { + super(menuText); + } + @Override public JMenuItem getPopupPresenter() { return new TagMenu(); } @Override - public void actionPerformed(ActionEvent e) { + protected void doAction(ActionEvent event) { } /** @@ -59,14 +63,6 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup { */ abstract protected void addTag(TagName tagName, String comment); - private void refreshDirectoryTree() { - //TODO instead should send event to node children, which will call its refresh() / refreshKeys() - // RJCTODO: Explain what is going on here and pare to one refreshTree() call. - DirectoryTreeTopComponent viewer = DirectoryTreeTopComponent.findInstance(); - viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE); - viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT); - } - /** * Instances of this class implement a context menu user interface for * creating or selecting a tag name for a tag and specifying an optional tag @@ -90,7 +86,7 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup { // Each tag name in the current set of tags gets its own menu item in // the "Quick Tags" sub-menu. Selecting one of these menu items adds // a tag with the associated tag name. - if (tagNames.isEmpty()) { + if (!tagNames.isEmpty()) { for (final TagName tagName : tagNames) { JMenuItem tagNameItem = new JMenuItem(tagName.getDisplayName()); tagNameItem.addActionListener(new ActionListener() { @@ -114,7 +110,7 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup { // The "Quick Tag" menu also gets an "Choose Tag..." menu item. // Selecting this item initiates a dialog that can be used to create // or select a tag name and adds a tag with the resulting name. - JMenuItem newTagMenuItem = new JMenuItem("Choose Tag..."); + JMenuItem newTagMenuItem = new JMenuItem("New Tag..."); newTagMenuItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -127,10 +123,10 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup { }); quickTagMenu.add(newTagMenuItem); - // Create a "Choose Tag and Comment..." menu item. Selecting this itme initiates + // Create a "Choose Tag and Comment..." menu item. Selecting this item initiates // a dialog that can be used to create or select a tag name with an // optional comment and adds a tag with the resulting name. - JMenuItem tagAndCommentItem = new JMenuItem("Choose Tag and Comment..."); + JMenuItem tagAndCommentItem = new JMenuItem("Tag and Comment..."); tagAndCommentItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { diff --git a/Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java new file mode 100755 index 0000000000..67891305da --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/actions/DeleteBlackboardArtifactTagAction.java @@ -0,0 +1,67 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 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.actions; + +import java.awt.event.ActionEvent; +import java.util.Collection; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.JOptionPane; +import org.openide.util.Utilities; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.BlackboardArtifactTag; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Instances of this Action allow users to delete tags applied to blackboard artifacts. + */ +public class DeleteBlackboardArtifactTagAction extends TagAction { + private static final String MENU_TEXT = "Delete Tag(s)"; + + // This class is a singleton to support multi-selection of nodes, since + // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every + // node in the array returns a reference to the same action object from Node.getActions(boolean). + private static DeleteBlackboardArtifactTagAction instance; + + public static synchronized DeleteBlackboardArtifactTagAction getInstance() { + if (null == instance) { + instance = new DeleteBlackboardArtifactTagAction(); + } + return instance; + } + + private DeleteBlackboardArtifactTagAction() { + super(MENU_TEXT); + } + + @Override + protected void doAction(ActionEvent event) { + Collection selectedTags = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifactTag.class); + for (BlackboardArtifactTag tag : selectedTags) { + try { + Case.getCurrentCase().getServices().getTagsManager().deleteBlackboardArtifactTag(tag); + } + catch (TskCoreException ex) { + Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex); + JOptionPane.showMessageDialog(null, "Unable to delete tag " + tag.getName() + ".", "Tag Deletion Error", JOptionPane.ERROR_MESSAGE); + } + } + } +} + diff --git a/Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java new file mode 100755 index 0000000000..fd0f6a41dc --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java @@ -0,0 +1,66 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 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.actions; + +import java.awt.event.ActionEvent; +import java.util.Collection; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.swing.JOptionPane; +import org.openide.util.Utilities; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.datamodel.ContentTag; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Instances of this Action allow users to delete tags applied to content. + */ +public class DeleteContentTagAction extends TagAction { + private static final String MENU_TEXT = "Delete Tag(s)"; + + // This class is a singleton to support multi-selection of nodes, since + // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every + // node in the array returns a reference to the same action object from Node.getActions(boolean). + private static DeleteContentTagAction instance; + + public static synchronized DeleteContentTagAction getInstance() { + if (null == instance) { + instance = new DeleteContentTagAction(); + } + return instance; + } + + private DeleteContentTagAction() { + super(MENU_TEXT); + } + + @Override + protected void doAction(ActionEvent e) { + Collection selectedTags = Utilities.actionsGlobalContext().lookupAll(ContentTag.class); + for (ContentTag tag : selectedTags) { + try { + Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(tag); + } + catch (TskCoreException ex) { + Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex); + JOptionPane.showMessageDialog(null, "Unable to delete tag " + tag.getName() + ".", "Tag Deletion Error", JOptionPane.ERROR_MESSAGE); + } + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/actions/TagAction.java b/Core/src/org/sleuthkit/autopsy/actions/TagAction.java new file mode 100755 index 0000000000..d5d78550f1 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/actions/TagAction.java @@ -0,0 +1,62 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 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.actions; + +import java.awt.event.ActionEvent; +import javax.swing.AbstractAction; +import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; +import org.sleuthkit.datamodel.BlackboardArtifact; + +/** + * Abstract base class for Actions involving tags. + */ +public abstract class TagAction extends AbstractAction { + public TagAction(String menuText) { + super(menuText); + } + + @Override + public void actionPerformed(ActionEvent event) { + doAction(event); + refreshDirectoryTree(); + } + + /** + * Derived classes must implement this Template Method for actionPerformed(). + * @param event ActionEvent object passed to actionPerformed() + */ + abstract protected void doAction(ActionEvent event); + + /** + * Derived classes should call this method any time a tag is created, updated + * or deleted outside of an actionPerformed() call. + */ + protected void refreshDirectoryTree() { + // The way the "directory tree" currently works, a new tags sub-tree + // needs to be made to reflect the results of invoking tag Actions. The + // way to do this is to call DirectoryTreeTopComponent.refreshTree(), + // which calls RootContentChildren.refreshKeys(BlackboardArtifact.ARTIFACT_TYPE... types) + // for the RootContentChildren object that is the child factory for the + // ResultsNode that is the root of the tags sub-tree. There is a switch + // statement in RootContentChildren.refreshKeys() that maps both + // BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE and BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT + // to making a call to refreshKey(TagsNodeKey). + DirectoryTreeTopComponent.findInstance().refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE); + } +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 2f113dec83..afab0a237b 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -37,20 +37,105 @@ import org.sleuthkit.datamodel.TskCoreException; /** * A singleton instance of this class functions as an Autopsy service that - * manages the creation, updating, and deletion of tags applied to Content and - * BlackboardArtifacts objects by users. + * manages the creation, updating, and deletion of tags applied to content and + * blackboard artifacts by users. */ public class TagsManager implements Closeable { - private static final String TAGS_SETTINGS_FILE_NAME = "tags"; - private static final String TAG_NAMES_SETTING_KEY = "tagNames"; + private static final String TAGS_SETTINGS_NAME = "Tags"; + private static final String TAG_NAMES_SETTING_KEY = "TagNames"; + private static final TagName[] predefinedTagNames = new TagName[]{new TagName("Bookmark", "", TagName.HTML_COLOR.NONE)}; private final SleuthkitCase tskCase; private final HashMap tagNames = new HashMap<>(); + private final Object lock = new Object(); + // Use this exception and the member hash map to manage uniqueness of hash + // names. This is deemed more proactive and informative than leaving this to + // the UNIQUE constraint on the display_name field of the tag_names table in + // the case database. + public class TagNameAlreadyExistsException extends Exception { + } + + /** + * Package-scope constructor for use of Services class. An instance of + * TagsManager should be created for each case that is opened. + * @param [in] tskCase The SleuthkitCase object for the current case. + */ TagsManager(SleuthkitCase tskCase) { this.tskCase = tskCase; - loadTagNamesFromTagSettings(); + getExistingTagNames(); + saveTagNamesToTagsSettings(); } - + + private void getExistingTagNames() { + getTagNamesFromCurrentCase(); + getTagNamesFromTagsSettings(); + getPredefinedTagNames(); + } + + private void getTagNamesFromCurrentCase() { + try { + ArrayList currentTagNames = new ArrayList<>(); + tskCase.getAllTagNames(currentTagNames); + for (TagName tagName : currentTagNames) { + tagNames.put(tagName.getDisplayName(), tagName); + } + } + catch (TskCoreException ex) { + Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag types from the current case", ex); + } + } + + private void getTagNamesFromTagsSettings() { + String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); + if (null != setting && !setting.isEmpty()) { + // Read the tag name setting and break it into tag name tuples. + List tagNameTuples = Arrays.asList(setting.split(";")); + + // Parse each tuple and add the tag names to the current case, one + // at a time to gracefully discard any duplicates or corrupt tuples. + for (String tagNameTuple : tagNameTuples) { + String[] tagNameAttributes = tagNameTuple.split(","); + if (!tagNames.containsKey(tagNameAttributes[0])) { + TagName tagName = new TagName(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.getColorByName(tagNameAttributes[2])); + addTagName(tagName, "Failed to add " + tagName.getDisplayName() + " tag name from tag settings to the current case"); + } + } + } + } + + private void getPredefinedTagNames() { + for (TagName tagName : predefinedTagNames) { + if (!tagNames.containsKey(tagName.getDisplayName())) { + addTagName(tagName, "Failed to add predefined " + tagName.getDisplayName() + " tag name to the current case"); + } + } + } + + private void addTagName(TagName tagName, String errorMessage) { + try { + tskCase.addTagName(tagName); + tagNames.put(tagName.getDisplayName(), tagName); + } + catch(TskCoreException ex) { + Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, errorMessage, ex); + } + } + + private void saveTagNamesToTagsSettings() { + if (!tagNames.isEmpty()) { + StringBuilder setting = new StringBuilder(); + for (TagName tagName : tagNames.values()) { + if (setting.length() != 0) { + setting.append(";"); + } + setting.append(tagName.getDisplayName()).append(","); + setting.append(tagName.getDescription()).append(","); + setting.append(tagName.getColor().name()); + } + ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting.toString()); + } + } + /** * Gets a list of all tag names currently available for tagging content or * blackboard artifacts. @@ -67,27 +152,35 @@ public class TagsManager implements Closeable { } /** - * RJCTODO: Discard or properly comment + * Gets a list of all tag names currently used for tagging content or + * blackboard artifacts. + * @return [out] A list, possibly empty, of TagName data transfer objects (DTOs). + */ + public void getTagNamesInUse(List tagNames) { + try { + tagNames.clear(); + tskCase.getTagNamesInUse(tagNames); + } + catch (TskCoreException ex) { + Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names from the current case", ex); + } + } + + /** + * Checks whether a tag name with a given display name exists. + * @param [in] tagDisplayName The display name for which to check. + * @return True if the tag name exists, false otherwise. */ public boolean tagNameExists(String tagDisplayName) { - return tagNames.containsKey(tagDisplayName); + synchronized(lock) { + return tagNames.containsKey(tagDisplayName); + } } - /** - * RJCTODO: Discard or properly comment - */ - public TagName getTagName(String tagDisplayName) { - if (!tagNames.containsKey(tagDisplayName)) { - // RJCTODO: Throw exception - } - - return tagNames.get(tagDisplayName); - } - /** * Adds a new tag name to the current case and to the tags settings file. - * @param displayName The display name for the new tag name. - * @return A TagName object representing the new tag name on success, null on failure. + * @param [in] displayName The display name for the new tag name. + * @return A TagName data transfer object (DTO) representing the new tag name. * @throws TskCoreException */ public TagName addTagName(String displayName) throws TagNameAlreadyExistsException, TskCoreException { @@ -96,9 +189,9 @@ public class TagsManager implements Closeable { /** * Adds a new tag name to the current case and to the tags settings file. - * @param displayName The display name for the new tag name. - * @param description The description for the new tag name. - * @return A TagName object representing the new tag name on success, null on failure. + * @param [in] displayName The display name for the new tag name. + * @param [in] description The description for the new tag name. + * @return A TagName data transfer object (DTO) representing the new tag name. * @throws TskCoreException */ public TagName addTagName(String displayName, String description) throws TagNameAlreadyExistsException, TskCoreException { @@ -107,31 +200,34 @@ public class TagsManager implements Closeable { /** * Adds a new tag name to the current case and to the tags settings file. - * @param displayName The display name for the new tag name. - * @param description The description for the new tag name. - * @param color The HTML color to associate with the new tag name. - * @return A TagName object representing the new tag name. + * @param [in] displayName The display name for the new tag name. + * @param [in] description The description for the new tag name. + * @param [in] color The HTML color to associate with the new tag name. + * @return A TagName data transfer object (DTO) representing the new tag name. * @throws TskCoreException */ public synchronized TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TagNameAlreadyExistsException, TskCoreException { - if (tagNames.containsKey(displayName)) { - throw new TagNameAlreadyExistsException(); - } + synchronized(lock) { + if (tagNames.containsKey(displayName)) { + throw new TagNameAlreadyExistsException(); + } + + // Add the tag name to the case. + TagName newTagName = new TagName(displayName, description, color); + tskCase.addTagName(newTagName); + + // Add the tag name to the tags settings. + tagNames.put(newTagName.getDisplayName(), newTagName); + saveTagNamesToTagsSettings(); + + return newTagName; + } + } - TagName newTagName = new TagName(displayName, description, color); - tskCase.addTagName(newTagName); - tagNames.put(newTagName.getDisplayName(), newTagName); - saveTagNamesToTagsSettings(); - return newTagName; - } - - public class TagNameAlreadyExistsException extends Exception { - } - /** - * Tags a Content object. - * @param content The Content to tag. - * @param tagName The type of tag to add. + * Tags a content object. + * @param [in] content The content to tag. + * @param [in] tagName The name to use for the tag. * @throws TskCoreException */ public void addContentTag(Content content, TagName tagName) throws TskCoreException { @@ -139,10 +235,10 @@ public class TagsManager implements Closeable { } /** - * Tags a Content object. - * @param content The Content to tag. - * @param tagName The name to use for the tag. - * @param comment A comment to store with the tag. + * Tags a content object. + * @param [in] content The content to tag. + * @param [in] tagName The name to use for the tag. + * @param [in] comment A comment to store with the tag. * @throws TskCoreException */ public void addContentTag(Content content, TagName tagName, String comment) throws TskCoreException { @@ -150,12 +246,12 @@ public class TagsManager implements Closeable { } /** - * Tags a Content object or a portion of a content object. - * @param content The Content to tag. - * @param tagName The name to use for the tag. - * @param comment A comment to store with the tag. - * @param beginByteOffset Designates the beginning of a tagged extent. - * @param endByteOffset Designates the end of a tagged extent. + * Tags a content object or a portion of a content object. + * @param [in] content The content to tag. + * @param [in] tagName The name to use for the tag. + * @param [in] comment A comment to store with the tag. + * @param [in] beginByteOffset Designates the beginning of a tagged extent. + * @param [in] endByteOffset Designates the end of a tagged extent. * @throws TskCoreException */ public void addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws IllegalArgumentException, TskCoreException { @@ -176,7 +272,7 @@ public class TagsManager implements Closeable { /** * Deletes a content tag. - * @param tag The tag to delete. + * @param [in] tag The tag to delete. * @throws TskCoreException */ public void deleteContentTag(ContentTag tag) throws TskCoreException { @@ -184,36 +280,11 @@ public class TagsManager implements Closeable { } /** - * Tags a BlackboardArtifact object. - * @param artifact The BlackboardArtifact to tag. - * @param tagName The name to use for the tag. - * @throws TskCoreException + * Gets content tags by tag name. + * @param [in] tagName The tag name of interest. + * @return A list, possibly empty, of the content tags with the specified tag name. */ - public void addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName) throws TskCoreException { - addBlackboardArtifactTag(artifact, tagName, ""); - } - - /** - * Tags a BlackboardArtifact object. - * @param artifact The BlackboardArtifact to tag. - * @param tagName The name to use for the tag. - * @param comment A comment to store with the tag. - * @throws TskCoreException - */ - public void addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException { - tskCase.addBlackboardArtifactTag(new BlackboardArtifactTag(artifact, tskCase.getContentById(artifact.getObjectID()), tagName, comment)); - } - - void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException { - tskCase.deleteBlackboardArtifactTag(tag); - } - - /** - * RJCTODO - * @param tagName - * @return - */ - public void getContentTags(TagName tagName, List tags) { + public void getContentTagsByTagName(TagName tagName, List tags) { try { tskCase.getContentTagsByTagName(tagName, tags); } @@ -221,13 +292,43 @@ public class TagsManager implements Closeable { Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get content tags from the current case", ex); } } - + /** - * RJCTODO - * @param tagName - * @return + * Tags a blackboard artifact object. + * @param [in] artifact The blackboard artifact to tag. + * @param [in] tagName The name to use for the tag. + * @throws TskCoreException */ - public void getBlackboardArtifactTags(TagName tagName, List tags) { + public void addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName) throws TskCoreException { + addBlackboardArtifactTag(artifact, tagName, ""); + } + + /** + * Tags a blackboard artifact object. + * @param [in] artifact The blackboard artifact to tag. + * @param [in] tagName The name to use for the tag. + * @param [in] comment A comment to store with the tag. + * @throws TskCoreException + */ + public void addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException { + tskCase.addBlackboardArtifactTag(new BlackboardArtifactTag(artifact, tskCase.getContentById(artifact.getObjectID()), tagName, comment)); + } + + /** + * Deletes a blackboard artifact tag. + * @param [in] tag The tag to delete. + * @throws TskCoreException + */ + public void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException { + tskCase.deleteBlackboardArtifactTag(tag); + } + + /** + * Gets blackboard artifact tags by tag name. + * @param [in] tagName The tag name of interest. + * @return A list, possibly empty, of the content tags with the specified tag name. + */ + public void getBlackboardArtifactTagsByTagName(TagName tagName, List tags) { try { tskCase.getBlackboardArtifactTagsByTagName(tagName, tags); } @@ -239,62 +340,5 @@ public class TagsManager implements Closeable { @Override public void close() throws IOException { saveTagNamesToTagsSettings(); - } - - private void loadTagNamesFromTagSettings() { - // Get any tag names already defined for the current case. - try { - ArrayList currentTagNames = new ArrayList<>(); - tskCase.getAllTagNames(currentTagNames); - for (TagName tagName : currentTagNames) { - tagNames.put(tagName.getDisplayName(), tagName); - } - } - catch (TskCoreException ex) { - Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag types from the current case", ex); - } - - // Read the saved tag names, if any, from the tags settings file and - // add them to the current case if they haven't already been added, e.g, - // when the case was last opened. - String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_FILE_NAME, TAG_NAMES_SETTING_KEY); - if (null != setting && !setting.isEmpty()) { - // Read the tag types setting and break in into tag type tuples. - List tagNameTuples = Arrays.asList(setting.split(";")); - - // Parse each tuple and add the tag types to the current case, one - // at a time to gracefully discard any duplicates or corrupt tuples. - for (String tagNameTuple : tagNameTuples) { - String[] tagNameAttributes = tagNameTuple.split(","); - if (!tagNames.containsKey(tagNameAttributes[0])) { - TagName tagName = new TagName(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.getColorByName(tagNameAttributes[2])); - try { - tskCase.addTagName(tagName); - tagNames.put(tagName.getDisplayName(),tagName); - } - catch(TskCoreException ex) { - Logger.getLogger(TagsManager.class.getName()).log(Level.WARNING, "Failed to add saved " + tagName.getDisplayName() + " tag name to the current case", ex); - } - } - } - - saveTagNamesToTagsSettings(); - } - } - - private void saveTagNamesToTagsSettings() { - if (!tagNames.isEmpty()) { - StringBuilder setting = new StringBuilder(); - for (TagName tagName : tagNames.values()) { - if (setting.length() != 0) { - setting.append(";"); - } - setting.append(tagName.getDisplayName()).append(","); - setting.append(tagName.getDescription()).append(","); - setting.append(tagName.getColor().name()); - } - - ModuleSettings.setConfigSetting(TAGS_SETTINGS_FILE_NAME, TAG_NAMES_SETTING_KEY, setting.toString()); - } } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java index 5df4ad782e..eaccbc35e2 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractContentChildren.java @@ -155,11 +155,6 @@ abstract class AbstractContentChildren extends Keys { return ee.new EmailExtractedRootNode(); } - @Override - public AbstractNode visit(Tags t) { - return t.new TagsRootNode(); - } - @Override public AbstractNode visit(TagsNodeKey tagsNodeKey) { return new TagsNode(); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java index 0a3133a018..f57388ae65 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AutopsyItemVisitor.java @@ -52,8 +52,6 @@ public interface AutopsyItemVisitor { T visit(EmailExtracted ee); - T visit(Tags t); - T visit(TagsNodeKey tagsNodeKey); T visit(DataSources i); @@ -136,11 +134,6 @@ public interface AutopsyItemVisitor { return defaultVisit(ee); } - @Override - public T visit(Tags t) { - return defaultVisit(t); - } - @Override public T visit(TagsNodeKey tagsNodeKey) { return defaultVisit(tagsNodeKey); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java index 5a603bbcf5..e4e61680b3 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java @@ -18,11 +18,15 @@ */ package org.sleuthkit.autopsy.datamodel; +import java.util.ArrayList; +import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; +import javax.swing.Action; import org.openide.nodes.Children; import org.openide.nodes.Sheet; import org.openide.util.lookup.Lookups; +import org.sleuthkit.autopsy.actions.DeleteBlackboardArtifactTagAction; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.TskCoreException; @@ -69,6 +73,13 @@ public class BlackboardArtifactTagNode extends DisplayableItemNode { return propertySheet; } + @Override + public Action[] getActions(boolean context) { + List actions = new ArrayList<>(); + actions.add(DeleteBlackboardArtifactTagAction.getInstance()); + return actions.toArray(new Action[0]); + } + @Override public T accept(DisplayableItemNodeVisitor v) { return v.visit(this); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java index 2c893b3fb5..b2e5c1d08e 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java @@ -19,11 +19,15 @@ package org.sleuthkit.autopsy.datamodel; +import java.util.ArrayList; +import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; +import javax.swing.Action; import org.openide.nodes.Children; import org.openide.nodes.Sheet; import org.openide.util.lookup.Lookups; +import org.sleuthkit.autopsy.actions.DeleteContentTagAction; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TskCoreException; @@ -68,6 +72,13 @@ public class ContentTagNode extends DisplayableItemNode { return propertySheet; } + @Override + public Action[] getActions(boolean context) { + List actions = new ArrayList<>(); + actions.add(DeleteContentTagAction.getInstance()); + return actions.toArray(new Action[0]); + } + @Override public T accept(DisplayableItemNodeVisitor v) { return v.visit(this); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java index 123d21944b..956ac6d69d 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java @@ -77,7 +77,7 @@ public class ContentTagTypeNode extends DisplayableItemNode { @Override protected boolean createKeys(List keys) { // Use the content tags bearing the specified tag name as the keys. - Case.getCurrentCase().getServices().getTagsManager().getContentTags(tagName, keys); + Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(tagName, keys); return true; } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java index b4d820bec2..e2cef3846e 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DisplayableItemNodeVisitor.java @@ -30,9 +30,6 @@ import org.sleuthkit.autopsy.datamodel.HashsetHits.HashsetHitsSetNode; import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsKeywordNode; import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsListNode; import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode; -import org.sleuthkit.autopsy.datamodel.Tags.TagNodeRoot; -import org.sleuthkit.autopsy.datamodel.Tags.TagsNodeRoot; -import org.sleuthkit.autopsy.datamodel.Tags.TagsRootNode; import org.sleuthkit.autopsy.directorytree.BlackboardArtifactTagTypeNode; /** @@ -86,12 +83,6 @@ public interface DisplayableItemNodeVisitor { T visit(EmailExtractedFolderNode eefn); - T visit(TagsRootNode bksrn); - - T visit(TagsNodeRoot bksrn); - - T visit(TagNodeRoot tnr); - T visit(TagsNode node); T visit(TagNameNode node); @@ -277,21 +268,6 @@ public interface DisplayableItemNodeVisitor { return defaultVisit(ldn); } - @Override - public T visit(TagsRootNode bksrn) { - return defaultVisit(bksrn); - } - - @Override - public T visit(TagsNodeRoot bksnr) { - return defaultVisit(bksnr); - } - - @Override - public T visit(TagNodeRoot tnr) { - return defaultVisit(tnr); - } - @Override public T visit(TagsNode node) { return defaultVisit(node); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java index ab5159440b..d87f1f2670 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ResultsNode.java @@ -35,7 +35,6 @@ public class ResultsNode extends DisplayableItemNode { new KeywordHits(sleuthkitCase), new HashsetHits(sleuthkitCase), new EmailExtracted(sleuthkitCase), - new Tags(sleuthkitCase), //TODO move to the top of the tree new TagsNodeKey() )), Lookups.singleton(NAME)); setName(NAME); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java index 27b1a5ac84..ff91e44112 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java @@ -79,23 +79,12 @@ public class RootContentChildren extends AbstractContentChildren { case TSK_EMAIL_MSG: if (o instanceof EmailExtracted) this.refreshKey(o); - break; - - //TODO check + break; case TSK_TAG_FILE: - if (o instanceof Tags) - this.refreshKey(o); + case TSK_TAG_ARTIFACT: if (o instanceof TagsNodeKey) this.refreshKey(o); - break; - - //TODO check - case TSK_TAG_ARTIFACT: - if (o instanceof Tags) - this.refreshKey(o); - if (o instanceof TagsNodeKey) - this.refreshKey(o); - break; + break; default: if (o instanceof ExtractedContent) this.refreshKey(o); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index 74f6fca42b..dce6ecb3ad 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -18,30 +18,15 @@ */ package org.sleuthkit.autopsy.datamodel; -import java.awt.event.ActionEvent; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; -import java.util.Arrays; -import java.util.EnumMap; -import java.util.HashMap; import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.TreeSet; import java.util.logging.Level; -import javax.swing.AbstractAction; -import javax.swing.Action; -import org.openide.nodes.ChildFactory; -import org.openide.nodes.Children; -import org.openide.nodes.Node; -import org.openide.nodes.Sheet; -import org.openide.util.Lookup; -import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.corecomponentinterfaces.BlackboardResultViewer; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; @@ -50,382 +35,12 @@ import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; -/** - * - * Support for tags in the directory tree. Tag nodes representing file and - * result tags, encapsulate TSK_TAG_FILE and TSK_TAG_ARTIFACT typed artifacts. - * - * The class implements querying of data model and populating node hierarchy - * using child factories. - * - */ -public class Tags implements AutopsyVisitableItem { +public class Tags { private static final Logger logger = Logger.getLogger(Tags.class.getName()); - private static final String FILE_TAG_LABEL_NAME = "File Tags"; - private static final String RESULT_TAG_LABEL_NAME = "Result Tags"; - private SleuthkitCase skCase; - public static final String NAME = "Tags"; - private static final String TAG_ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; - //bookmarks are specializations of tags public static final String BOOKMARK_TAG_NAME = "Bookmark"; - private static final String BOOKMARK_ICON_PATH = "org/sleuthkit/autopsy/images/star-bookmark-icon-16.png"; - private Map>> tags; private static final String EMPTY_COMMENT = ""; - private static final String APP_SETTINGS_FILE_NAME = "app"; // @@@ TODO: Need a general app settings or user preferences file, this will do for now. - private static final String TAG_NAMES_SETTING_KEY = "tag_names"; - private static final HashSet appSettingTagNames = new HashSet<>(); - private static final StringBuilder tagNamesAppSetting = new StringBuilder(); - - // When this class is loaded, either create an new app settings file or - // get the tag names setting from the existing app settings file. - static { - String setting = ModuleSettings.getConfigSetting(APP_SETTINGS_FILE_NAME, TAG_NAMES_SETTING_KEY); - if (null != setting && !setting.isEmpty()) { - // Make a speedy lookup for the tag names in the setting to aid in the - // detection of new tag names. - List tagNamesFromAppSettings = Arrays.asList(setting.split(",")); - for (String tagName : tagNamesFromAppSettings) { - appSettingTagNames.add(tagName); - } - - // Load the raw comma separated values list from the setting into a - // string builder to facilitate adding new tag names to the list and writing - // it back to the app settings file. - tagNamesAppSetting.append(setting); - } - } - Tags(SleuthkitCase skCase) { - this.skCase = skCase; - } - - @Override - public T accept(AutopsyItemVisitor v) { - return v.visit(this); - } - - /** - * Root of all Tag nodes. This node is shown directly under Results in the - * directory tree. - */ - public class TagsRootNode extends DisplayableItemNode { - - public TagsRootNode() { - super(Children.create(new Tags.TagsRootChildren(), true), Lookups.singleton(NAME)); - super.setName(NAME); - super.setDisplayName(NAME); - this.setIconBaseWithExtension(TAG_ICON_PATH); - initData(); - } - - private void initData() { - try { - // Get all file and artifact tags - - //init data - tags = new EnumMap<>(BlackboardArtifact.ARTIFACT_TYPE.class); - tags.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE, new HashMap>()); - tags.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT, new HashMap>()); - - //populate - for (BlackboardArtifact.ARTIFACT_TYPE artType : tags.keySet()) { - final Map> artTags = tags.get(artType); - for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(artType)) { - for (BlackboardAttribute attribute : artifact.getAttributes()) { - if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()) { - String tagName = attribute.getValueString(); - if (artTags.containsKey(tagName)) { - List artifacts = artTags.get(tagName); - artifacts.add(artifact); - } else { - List artifacts = new ArrayList<>(); - artifacts.add(artifact); - artTags.put(tagName, artifacts); - } - break; - } - } - } - } - - - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Count not initialize tag nodes", ex); - } - } - - @Override - public boolean isLeafTypeNode() { - return false; - } - - @Override - public T accept(DisplayableItemNodeVisitor v) { - return v.visit(this); - } - - @Override - protected Sheet createSheet() { - Sheet s = super.createSheet(); - Sheet.Set ss = s.get(Sheet.PROPERTIES); - if (ss == null) { - ss = Sheet.createPropertiesSet(); - s.put(ss); - } - - ss.put(new NodeProperty("Name", - "Name", - "no description", - getName())); - - return s; - } - } - - /** - * bookmarks root child node creating types of bookmarks nodes - */ - private class TagsRootChildren extends ChildFactory { - - @Override - protected boolean createKeys(List list) { - for (BlackboardArtifact.ARTIFACT_TYPE artType : tags.keySet()) { - list.add(artType); - } - - return true; - } - - @Override - protected Node createNodeForKey(BlackboardArtifact.ARTIFACT_TYPE key) { - return new TagsNodeRoot(key, tags.get(key)); - } - } - - /** - * Tag node representation (file or result) - */ - public class TagsNodeRoot extends DisplayableItemNode { - - TagsNodeRoot(BlackboardArtifact.ARTIFACT_TYPE tagType, Map> subTags) { - super(Children.create(new TagRootChildren(tagType, subTags), true), Lookups.singleton(tagType.getDisplayName())); - - String name = null; - if (tagType.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)) { - name = FILE_TAG_LABEL_NAME; - } else if (tagType.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT)) { - name = RESULT_TAG_LABEL_NAME; - } - - super.setName(name); - super.setDisplayName(name + " (" + subTags.values().size() + ")"); - - this.setIconBaseWithExtension(TAG_ICON_PATH); - } - - @Override - protected Sheet createSheet() { - Sheet s = super.createSheet(); - Sheet.Set ss = s.get(Sheet.PROPERTIES); - if (ss == null) { - ss = Sheet.createPropertiesSet(); - s.put(ss); - } - - ss.put(new NodeProperty("Name", - "Name", - "no description", - getName())); - - return s; - } - - @Override - public T accept(DisplayableItemNodeVisitor v) { - return v.visit(this); - } - - @Override - public boolean isLeafTypeNode() { - return false; - } - } - - /** - * Child factory to add all the Tag artifacts to a TagsRootNode with the tag - * name. - */ - private class TagRootChildren extends ChildFactory { - - private Map> subTags; - private BlackboardArtifact.ARTIFACT_TYPE tagType; - - TagRootChildren(BlackboardArtifact.ARTIFACT_TYPE tagType, Map> subTags) { - super(); - this.tagType = tagType; - this.subTags = subTags; - } - - @Override - protected boolean createKeys(List list) { - list.addAll(subTags.keySet()); - - return true; - } - - @Override - protected Node createNodeForKey(String key) { - return new Tags.TagNodeRoot(tagType, key, subTags.get(key)); - } - } - - /** - * Node for each unique tag name. Shown directly under Results > Tags. - */ - public class TagNodeRoot extends DisplayableItemNode { - - TagNodeRoot(BlackboardArtifact.ARTIFACT_TYPE tagType, String tagName, List artifacts) { - super(Children.create(new Tags.TagsChildrenNode(tagType, tagName, artifacts), true), Lookups.singleton(tagName)); - - super.setName(tagName); - super.setDisplayName(tagName + " (" + artifacts.size() + ")"); - - if (tagName.equals(BOOKMARK_TAG_NAME)) { - this.setIconBaseWithExtension(BOOKMARK_ICON_PATH); - } else { - this.setIconBaseWithExtension(TAG_ICON_PATH); - } - } - - @Override - protected Sheet createSheet() { - Sheet s = super.createSheet(); - Sheet.Set ss = s.get(Sheet.PROPERTIES); - if (ss == null) { - ss = Sheet.createPropertiesSet(); - s.put(ss); - } - - ss.put(new NodeProperty("Name", - "Name", - "no description", - getName())); - - return s; - } - - @Override - public T accept(DisplayableItemNodeVisitor v) { - return v.visit(this); - } - - @Override - public boolean isLeafTypeNode() { - return true; - } - } - - /** - * Node representing an individual Tag artifact. For each TagsNodeRoot under - * Results > Tags, this is one of the nodes listed in the result viewer. - */ - private class TagsChildrenNode extends ChildFactory { - - private List artifacts; - private BlackboardArtifact.ARTIFACT_TYPE tagType; - private String tagName; - - private TagsChildrenNode(BlackboardArtifact.ARTIFACT_TYPE tagType, String tagName, List artifacts) { - super(); - this.tagType = tagType; - this.tagName = tagName; - this.artifacts = artifacts; - } - - @Override - protected boolean createKeys(List list) { - list.addAll(artifacts); - return true; - } - - @Override - protected Node createNodeForKey(final BlackboardArtifact artifact) { - //create node with action - BlackboardArtifactNode tagNode = null; - - String iconPath; - if (tagName.equals(BOOKMARK_TAG_NAME)) { - iconPath = BOOKMARK_ICON_PATH; - } else { - iconPath = TAG_ICON_PATH; - } - - //create actions here where Tag logic belongs - //instead of DataResultFilterNode w/visitors, which is much less pluggable and cluttered - if (tagType.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT)) { - //in case of result tag, add a action by sublcassing bb art node - //this action will be merged with other actions set DataResultFIlterNode - //otherwise in case of - tagNode = new BlackboardArtifactNode(artifact, iconPath) { - @Override - public Action[] getActions(boolean bln) { - //Action [] actions = super.getActions(bln); //To change body of generated methods, choose Tools | Templates. - Action[] actions = new Action[1]; - actions[0] = new AbstractAction("View Source Result") { - @Override - public void actionPerformed(ActionEvent e) { - //open the source artifact in dir tree - BlackboardArtifact sourceArt = Tags.getArtifactFromTag(artifact.getArtifactID()); - if (sourceArt != null) { - BlackboardResultViewer v = Lookup.getDefault().lookup(BlackboardResultViewer.class); - v.viewArtifact(sourceArt); - } - } - }; - return actions; - } - }; - } else { - //for file tag, don't subclass to add the additional actions - tagNode = new BlackboardArtifactNode(artifact, iconPath); - } - - //add some additional node properties - int artifactTypeID = artifact.getArtifactTypeID(); - final String NO_DESCR = "no description"; - if (artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { - BlackboardArtifact sourceResult = Tags.getArtifactFromTag(artifact.getArtifactID()); - String resultType = sourceResult.getDisplayName(); - - NodeProperty resultTypeProp = new NodeProperty("Source Result Type", - "Result Type", - NO_DESCR, - resultType); - - - tagNode.addNodeProperty(resultTypeProp); - - } - try { - //add source path property - final AbstractFile sourceFile = skCase.getAbstractFileById(artifact.getObjectID()); - final String sourcePath = sourceFile.getUniquePath(); - NodeProperty sourcePathProp = new NodeProperty("Source File Path", - "Source File Path", - NO_DESCR, - sourcePath); - - - tagNode.addNodeProperty(sourcePathProp); - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error getting a file from artifact to get source file path for a tag, ", ex); - } - - return tagNode; - } - } - /** * Create a tag for a file with TSK_TAG_NAME as tagName. * @@ -448,9 +63,7 @@ public class Tags implements AutopsyVisitableItem { "", comment); attrs.add(attr2); } - bookArt.addAttributes(attrs); - - updateTagNamesAppSetting(tagName); + bookArt.addAttributes(attrs); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Failed to create tag for " + file.getName(), ex); @@ -488,30 +101,13 @@ public class Tags implements AutopsyVisitableItem { attrs.add(attr1); attrs.add(attr3); - bookArt.addAttributes(attrs); - - updateTagNamesAppSetting(tagName); + bookArt.addAttributes(attrs); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Failed to create tag for artifact " + artifact.getArtifactID(), ex); } } - private static void updateTagNamesAppSetting(String tagName) { - // If this tag name is not in the current tag names app setting... - if (!appSettingTagNames.contains(tagName)) { - // Add it to the lookup. - appSettingTagNames.add(tagName); - - // Add it to the setting and write the setting back to the app settings file. - if (tagNamesAppSetting.length() != 0) { - tagNamesAppSetting.append(","); - } - tagNamesAppSetting.append(tagName); - ModuleSettings.setConfigSetting(APP_SETTINGS_FILE_NAME, TAG_NAMES_SETTING_KEY, tagNamesAppSetting.toString()); - } - } - /** * Create a bookmark tag for a file. * @@ -557,7 +153,6 @@ public class Tags implements AutopsyVisitableItem { public static TreeSet getAllTagNames() { // Use a TreeSet<> so the union of the tag names from the two sources will be sorted. TreeSet tagNames = getTagNamesFromCurrentCase(); - tagNames.addAll(appSettingTagNames); // Make sure the book mark tag is always included. tagNames.add(BOOKMARK_TAG_NAME); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java index e5d121ada6..3f1813a647 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java @@ -43,6 +43,10 @@ public class TagsNode extends DisplayableItemNode { this.setIconBaseWithExtension(ICON_PATH); } + public static String getNodeName() { + return DISPLAY_NAME; + } + @Override public boolean isLeafTypeNode() { return false; @@ -70,7 +74,7 @@ public class TagsNode extends DisplayableItemNode { private static class TagNameNodeFactory extends ChildFactory { @Override protected boolean createKeys(List keys) { - Case.getCurrentCase().getServices().getTagsManager().getAllTagNames(keys); // RJCTODO: Change this call to filtered call + Case.getCurrentCase().getServices().getTagsManager().getAllTagNames(keys); return true; } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java index 7eb1e21a4e..b7acf5dd72 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java @@ -81,7 +81,7 @@ public class BlackboardArtifactTagTypeNode extends DisplayableItemNode { @Override protected boolean createKeys(List keys) { // Use the blackboard artifact tags bearing the specified tag name as the keys. - Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTags(tagName, keys); + Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName, keys); return true; } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index 7303734772..1619c18ccf 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -63,8 +63,6 @@ import org.sleuthkit.autopsy.datamodel.LayoutFileNode; import org.sleuthkit.autopsy.datamodel.RecentFilesFilterNode; import org.sleuthkit.autopsy.datamodel.RecentFilesNode; import org.sleuthkit.autopsy.datamodel.FileTypesNode; -import org.sleuthkit.autopsy.datamodel.Tags.TagNodeRoot; -import org.sleuthkit.autopsy.datamodel.Tags.TagsNodeRoot; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -405,16 +403,6 @@ public class DataResultFilterNode extends FilterNode { return openChild(atn); } - @Override - public AbstractAction visit(TagNodeRoot tnr) { - return openChild(tnr); - } - - @Override - public AbstractAction visit(TagsNodeRoot tnr) { - return openChild(tnr); - } - @Override public AbstractAction visit(DirectoryNode dn) { if (dn.getDisplayName().equals(DirectoryNode.DOTDOTDIR)) { From 9ed39d665d84815996159ba1b2d813733c798e09 Mon Sep 17 00:00:00 2001 From: raman-bt Date: Thu, 17 Oct 2013 09:49:18 -0400 Subject: [PATCH 013/169] Eliminate ContentTypePanel. DataSourceProcessor returns a JPanel instead. --- .../AddImageWizardChooseDataSourcePanel.java | 7 +- .../AddImageWizardChooseDataSourceVisual.form | 2 +- .../AddImageWizardChooseDataSourceVisual.java | 190 ++++++------------ .../sleuthkit/autopsy/casemodule/Case.java | 2 + .../autopsy/casemodule/ContentTypePanel.java | 56 +++--- .../casemodule/DataSourceProcessor.java | 10 +- .../autopsy/casemodule/ImageDSProcessor.java | 98 ++++++++- .../autopsy/casemodule/ImageFilePanel.java | 20 +- .../autopsy/casemodule/LocalDiskPanel.java | 16 +- .../autopsy/casemodule/LocalFilesPanel.java | 15 +- .../casemodule/MissingImageDialog.java | 57 +++--- 11 files changed, 244 insertions(+), 229 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java index 7fb2a69b0b..2e103d3272 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java @@ -183,10 +183,12 @@ class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Panel - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java index b20d43e3b2..3595667230 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java @@ -19,6 +19,8 @@ package org.sleuthkit.autopsy.casemodule; import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; @@ -27,6 +29,7 @@ import java.util.Calendar; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.SimpleTimeZone; import java.util.TimeZone; import java.util.logging.Level; @@ -35,8 +38,6 @@ import javax.swing.JPanel; import javax.swing.event.DocumentEvent; import javax.swing.event.ListDataListener; import org.openide.util.Lookup; -import org.sleuthkit.autopsy.casemodule.ContentTypePanel; -//import org.sleuthkit.autopsy.casemodule.ContentTypePanel.ContentType; import org.sleuthkit.autopsy.coreutils.Logger; /** @@ -67,11 +68,10 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { static final String allDesc = "All Supported Types"; static GeneralFilter allFilter = new GeneralFilter(allExt, allDesc); private AddImageWizardChooseDataSourcePanel wizPanel; - private ContentTypeModel model; - private ContentTypePanel currentPanel; + private JPanel currentPanel; - static private Map datasourceProcessorsMap = new HashMap();; - + private Map datasourceProcessorsMap = new HashMap(); + /** @@ -88,60 +88,62 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { private void customInit() { - discoverDataSourceProcessors(); - model = new ContentTypeModel(); - typeComboBox.setModel(model); + // set up the DSP type combobox + typeComboBox.removeAllItems(); + Set dspTypes = datasourceProcessorsMap.keySet(); + for(String dspType:dspTypes){ + typeComboBox.addItem(dspType); + } + + //add actionlistner to listen for change + ActionListener cbActionListener = new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + dspSelectionChanged(); + + } + }; + + typeComboBox.addActionListener(cbActionListener); + typeComboBox.setSelectedIndex(0); typePanel.setLayout(new BorderLayout()); - //updateCurrentPanel(ImageFilePanel.getDefault()); - updateCurrentPanel(model.getElementAt(0)); + updateCurrentPanel(GetCurrentDSProcessor().getPanel()); } private void discoverDataSourceProcessors() { - - //datasourceHandlersMap.clear(); + logger.log(Level.INFO, "RAMAN discoverDataSourceProcessors()..."); - - // RAMAN TBD: hack for now - { - //ContentTypePanel.RegisterPanel(ImageFilePanel.getDefault()); - //ContentTypePanel.RegisterPanel(LocalDiskPanel.getDefault()); - //ContentTypePanel.RegisterPanel(LocalFilesPanel.getDefault()); - } - + for (DataSourceProcessor dsProcessor: Lookup.getDefault().lookupAll(DataSourceProcessor.class)) { - - logger.log(Level.INFO, "RAMAN discoverDataSourceHandlers(): found an instance of DataSourceHandler"); - - - String dsType = dsProcessor.getType(); - JPanel panel = dsProcessor.getPanel(); - String validate = dsProcessor.validatePanel(); - //dshandler.run(null); - //String[] errors = dshandler.getErrors(); - + logger.log(Level.INFO, "RAMAN discoverDataSourceProcessors()L found a DSP for type = " + dsProcessor.getType() ); + if (!datasourceProcessorsMap.containsKey(dsProcessor.getType()) ) { - - // Regsiter the panel for the discovered DS handler here - ContentTypePanel.RegisterPanel(dsProcessor.getPanel()); - - datasourceProcessorsMap.put(dsProcessor.getType(), dsProcessor); - } - + if (!datasourceProcessorsMap.containsKey(dsProcessor.getType()) ) { + datasourceProcessorsMap.put(dsProcessor.getType(), dsProcessor); + } + else { + logger.log(Level.SEVERE, "RAMAN discoverDataSourceProcessors(): A DataSourceProcessor already exisits for type = " + dsProcessor.getType() ); + } + } } - - - } + } + private void dspSelectionChanged() { + // update the current panel to selection + currentPanel = GetCurrentDSProcessor().getPanel(); + updateCurrentPanel(currentPanel); + } + /** * Changes the current panel to the given panel. * * @param panel instance of ImageTypePanel to change to */ - private void updateCurrentPanel(ContentTypePanel panel) { + private void updateCurrentPanel(JPanel panel) { currentPanel = panel; typePanel.removeAll(); typePanel.add((JPanel) currentPanel, BorderLayout.CENTER); @@ -158,8 +160,12 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { } } }); - currentPanel.select(); - if (currentPanel.getContentType().equals("LOCAL")) { + + + /* RAMAN TBD: this should all be ripped from here. the content specific UI elements should all go + * into the corresponding DSP + */ + if (GetCurrentDSProcessor().getType().equals("LOCAL")) { //disable image specific options noFatOrphansCheckbox.setEnabled(false); descLabel.setEnabled(false); @@ -173,18 +179,13 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { } /** - * Returns the currently selected DS handler in the combobox - * - * - * @return name the name of this panel + * Returns the currently selected DS Processor + * @return DataSourceProcessor the DataSourceProcessor corresponding to the data source type selected in the combobox */ public DataSourceProcessor GetCurrentDSProcessor() { - - logger.log(Level.INFO, "RAMAN GetCurrentDSProcessor()..."); // get the type of the currently selected panel and then look up // the correspodning DS Handler in the map - String dsType = currentPanel.getContentType(); - + String dsType = (String) typeComboBox.getSelectedItem(); DataSourceProcessor dsProcessor = datasourceProcessorsMap.get(dsType); return dsProcessor; @@ -202,44 +203,11 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { return "Enter Data Source Information"; } - /** - * Gets the data sources path from the Image Path Text Field. - * - * @return data source path, can be comma separated for multiples - */ - public String getContentPaths() { - return currentPanel.getContentPaths(); - } - - /** - * Gets the data sources type selected - * - * @return data source selected - */ - public String getContentType() { - return currentPanel.getContentType(); - } - - /** - * Reset the data sources panel selected - */ - public void reset() { - currentPanel.reset(); - } - - /** - * Sets the image path of the current panel. - * - * @param s the image path to set - */ - public void setContentPath(String s) { - currentPanel.setContentPath(s); - } - /** * * @return true if no fat orphans processing is selected */ + /***RAMAN TBD: move this into DSP ****/ boolean getNoFatOrphans() { return noFatOrphansCheckbox.isSelected(); } @@ -249,6 +217,7 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { * * @return timeZone the time zone that selected */ + /***RAMAN TBD: move this into the DSP****/ public String getSelectedTimezone() { String tz = timeZoneComboBox.getSelectedItem().toString(); return tz.substring(tz.indexOf(")") + 2).trim(); @@ -259,6 +228,7 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { * Creates the drop down list for the time zones and then makes the local * machine time zones to be selected. */ + /*** RAMAN TBD: move this into the DSP panel ***/ public void createTimeZoneList() { // load and add all timezone String[] ids = SimpleTimeZone.getAvailableIDs(); @@ -309,7 +279,7 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { inputPanel = new javax.swing.JPanel(); typeTabel = new javax.swing.JLabel(); typePanel = new javax.swing.JPanel(); - typeComboBox = new javax.swing.JComboBox(); + typeComboBox = new javax.swing.JComboBox(); imgInfoLabel = new javax.swing.JLabel(); org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.jLabel2.text")); // NOI18N @@ -428,7 +398,7 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { private javax.swing.JCheckBox noFatOrphansCheckbox; private javax.swing.JComboBox timeZoneComboBox; private javax.swing.JLabel timeZoneLabel; - private javax.swing.JComboBox typeComboBox; + private javax.swing.JComboBox typeComboBox; private javax.swing.JPanel typePanel; private javax.swing.JLabel typeTabel; // End of variables declaration//GEN-END:variables @@ -442,44 +412,12 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { * @param e the document event */ public void updateUI(DocumentEvent e) { - this.wizPanel.enableNextButton(currentPanel.enableNext()); + // Enable the Next button if the current DSP panel is valid + String err = GetCurrentDSProcessor().validatePanel(); + if (null == err) + this.wizPanel.enableNextButton(true); + else + this.wizPanel.enableNextButton(false); } - /** - * ComboBoxModel to control typeComboBox and supply ImageTypePanels. - */ - private class ContentTypeModel implements ComboBoxModel { - - private ContentTypePanel selected; - private ContentTypePanel[] types = ContentTypePanel.getPanels(); - - @Override - public void setSelectedItem(Object anItem) { - selected = (ContentTypePanel) anItem; - updateCurrentPanel(selected); - } - - @Override - public Object getSelectedItem() { - return selected; - } - - @Override - public int getSize() { - return types.length; - } - - @Override - public ContentTypePanel getElementAt(int index) { - return types[index]; - } - - @Override - public void addListDataListener(ListDataListener l) { - } - - @Override - public void removeListDataListener(ListDataListener l) { - } - } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 29151bc6ea..caa833e8aa 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -319,7 +319,9 @@ public class Case implements SleuthkitCase.ErrorObserver { + "\nPlease note that you will still be able to browse directories and generate reports\n" + "if you choose No, but you will not be able to view file content or run the ingest process.", "Missing Image", JOptionPane.YES_NO_OPTION); if (ret == JOptionPane.YES_OPTION) { + /***** RAMAN TBD: MissingImageDialog class needs to be refactored to eliminate ContentTypePanel dependency. MissingImageDialog.makeDialog(obj_id, db); + * *****************/ } else { logger.log(Level.WARNING, "Selected image files don't match old files!"); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ContentTypePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/ContentTypePanel.java index 4b2f4aada8..ab144723b1 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ContentTypePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ContentTypePanel.java @@ -23,6 +23,7 @@ import javax.swing.JPanel; import java.util.ArrayList; import java.util.List; +/************ abstract class ContentTypePanel extends JPanel { // Collection of panels that are dynamically discovered and registered @@ -41,10 +42,10 @@ abstract class ContentTypePanel extends JPanel { private String contentType; - /** - * Returns a list off all the panels extending ImageTypePanel. - * @return list of all ImageTypePanels - */ +// +// * Returns a list off all the panels extending ImageTypePanel. +// * @return list of all ImageTypePanels +// public static ContentTypePanel[] getPanels() { //return new ContentTypePanel[] {ImageFilePanel.getDefault(), LocalDiskPanel.getDefault(), LocalFilesPanel.getDefault() }; @@ -55,40 +56,41 @@ abstract class ContentTypePanel extends JPanel { return registeredPanels.toArray(new ContentTypePanel[registeredPanels.size()]); } - /** - * Return the path of the selected content in this panel. - * @return paths to selected content (one or more if multiselect supported) - */ +// +// * Return the path of the selected content in this panel. +// * @return paths to selected content (one or more if multiselect supported) +// abstract public String getContentPaths(); - /** - * Set the selected content in this panel to the provided path. - * This function is optional. - * @param s path to selected content - */ +// +// * Set the selected content in this panel to the provided path. +// * This function is optional. +// * @param s path to selected content +// abstract public void setContentPath(String s); - /** - * Get content type (image, disk, local file) of the source this wizard panel is for - * @return ContentType of the source panel - */ +// +// * Get content type (image, disk, local file) of the source this wizard panel is for +// * @return ContentType of the source panel +// abstract public String getContentType(); - /** - * Returns if the next button should be enabled in the current wizard. - * @return true if the next button should be enabled, false otherwise - */ +// +// * Returns if the next button should be enabled in the current wizard. +// * @return true if the next button should be enabled, false otherwise +// abstract public boolean enableNext(); - /** - * Tells this panel to reset itself - */ +// +// * Tells this panel to reset itself +// abstract public void reset(); - /** - * Tells this panel it has been selected. - */ +// +// * Tells this panel it has been selected. +// abstract public void select(); } +***************/ \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/DataSourceProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/DataSourceProcessor.java index 81b8b21aa0..76f9b89f4e 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/DataSourceProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/DataSourceProcessor.java @@ -22,7 +22,6 @@ import java.util.List; import javax.swing.JPanel; import org.openide.WizardDescriptor; import org.sleuthkit.autopsy.casemodule.DSPProgressMonitor; -import org.sleuthkit.autopsy.casemodule.ContentTypePanel; import org.sleuthkit.datamodel.Content; public interface DataSourceProcessor { @@ -43,7 +42,7 @@ public interface DataSourceProcessor { * Returns the picker panel to be displayed along with any other * runtime options supported by the data source handler. **/ - ContentTypePanel getPanel(); + JPanel getPanel(); /** * Called to validate the input data in the panel. @@ -80,8 +79,11 @@ public interface DataSourceProcessor { **/ void cancel(); - - + /** + * Called to reset/reinit the DSP. + * + **/ + void reset(); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java index 9025379972..696f903f4e 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java @@ -45,6 +45,14 @@ public class ImageDSProcessor implements DataSourceProcessor { DSPCallback callbackObj = null; + // set to TRUE if the image options have been set via API and config Jpanel should be ignored + private boolean imageOptionsSet = false; + private String imagePath; + private String timeZone; + private boolean noFatOrphans; + + + public ImageDSProcessor() { logger.log(Level.INFO, "RAMAN ImageDSHandler()..."); @@ -72,9 +80,11 @@ public class ImageDSProcessor implements DataSourceProcessor { @Override - public ContentTypePanel getPanel() { + public JPanel getPanel() { logger.log(Level.INFO, "RAMAN getPanel()..."); + + // RAMAN TBD: we should preload the panel with any saved settings return imageFilePanel; } @@ -83,9 +93,11 @@ public class ImageDSProcessor implements DataSourceProcessor { public String validatePanel() { logger.log(Level.INFO, "RAMAN validatePanel()..."); - - return null; - + + if (imageFilePanel.validatePanel() ) + return null; + else + return "Error in panel"; } @Override @@ -96,7 +108,26 @@ public class ImageDSProcessor implements DataSourceProcessor { callbackObj = cbObj; cancelled = false; + if (!imageOptionsSet) + { + // get the image options from the panel + imagePath = imageFilePanel.getContentPaths(); + + /*** RAMAN TBD: get the TZ and NoFatOrhpns options from the config panel ******/ + //timeZone = imageFilePanel.getTimeZone(); + //noFatOrphans = imageFilePanel.getNoFatOrphans(); + + + + } + addImageTask = new AddImageTask(settings, progressMonitor, cbObj); + + /**** RAMAN TBD: set other params needed by AddImageTask - such as TZ and NoFatOrhpans **/ + addImageTask.SetImageOptions(imagePath); + + + addImageTask.execute(); return; @@ -130,9 +161,34 @@ public class ImageDSProcessor implements DataSourceProcessor { return addImageTask.getNewContents(); } * *****/ - - + @Override + public void reset() { + + logger.log(Level.INFO, "RAMAN reset()..."); + + // reset the config panel + imageFilePanel.reset(); + + // reset state + imageOptionsSet = false; + imagePath = null; + timeZone = null; + noFatOrphans = false; + + return; + } + + public void SetDataSourceOptions(String imgPath, String tz, boolean noFat) { + + this.imagePath = imgPath; + this.timeZone = tz; + this.noFatOrphans = noFat; + + imageOptionsSet = true; + + } + private class AddImageTask extends SwingWorker { @@ -157,6 +213,20 @@ public class ImageDSProcessor implements DataSourceProcessor { private SleuthkitJNI.CaseDbHandle.AddImageProcess addImageProcess; private CurrentDirectoryFetcher fetcher; + private String imagePath; + private String dataSourcetype; + String timeZone; + boolean noFatOrphans; + + + + public void SetImageOptions(String imgPath) { + this.imagePath = imgPath; + + // RAMAN TBD: also set TZ and noFatOrphans + // this.timeZone = tz; + // this.noFatOrphans = noFatOrphans; + } private class CurrentDirectoryFetcher extends SwingWorker { @@ -239,10 +309,16 @@ public class ImageDSProcessor implements DataSourceProcessor { } - String dataSourcePath = (String) wizDescriptor.getProperty(AddImageAction.DATASOURCEPATH_PROP); - String dataSourceType = (String) wizDescriptor.getProperty(AddImageAction.DATASOURCETYPE_PROP); - String timeZone = wizDescriptor.getProperty(AddImageAction.TIMEZONE_PROP).toString(); - boolean noFatOrphans = ((Boolean) wizDescriptor.getProperty(AddImageAction.NOFATORPHANS_PROP)).booleanValue(); + + + + /*** RAMAN TBD: TZ and NoFatOrpjhans should be moved into the Image panel and then should be set by the DSP + * instead of the settings. + * + */ + timeZone = wizDescriptor.getProperty(AddImageAction.TIMEZONE_PROP).toString(); + noFatOrphans = ((Boolean) wizDescriptor.getProperty(AddImageAction.NOFATORPHANS_PROP)).booleanValue(); + addImageProcess = currentCase.makeAddImageProcess(timeZone, true, noFatOrphans); @@ -253,7 +329,7 @@ public class ImageDSProcessor implements DataSourceProcessor { progressMonitor.setProgress(0); fetcher.execute(); - addImageProcess.run(new String[]{dataSourcePath}); + addImageProcess.run(new String[]{this.imagePath}); } catch (TskCoreException ex) { logger.log(Level.WARNING, "Core errors occurred while running add image. ", ex); //critical core/system error and process needs to be interrupted diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java index 3bc25fe42d..275c3dced8 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java @@ -26,11 +26,12 @@ import java.util.List; import javax.swing.JFileChooser; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; +import javax.swing.JPanel; /** * ImageTypePanel for adding an image file such as .img, .E0x, .00x, etc. */ -public class ImageFilePanel extends ContentTypePanel implements DocumentListener { +public class ImageFilePanel extends JPanel implements DocumentListener { private static ImageFilePanel instance = null; private PropertyChangeSupport pcs = null; private JFileChooser fc = new JFileChooser(); @@ -144,7 +145,6 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener * Get the path of the user selected image. * @return the image path */ - @Override public String getContentPaths() { return pathTextField.getText(); } @@ -152,29 +152,23 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener /** * Set the path of the image file. */ - @Override public void setContentPath(String s) { pathTextField.setText(s); } - @Override public String getContentType() { return "IMAGE"; } - @Override public void reset() { //nothing to reset } - - /** * Should we enable the next button of the wizard? * @return true if a proper image has been selected, false otherwise */ - @Override - public boolean enableNext() { + public boolean validatePanel() { String path = getContentPaths(); if (path == null || path.isEmpty()) { return false; @@ -210,18 +204,10 @@ public class ImageFilePanel extends ContentTypePanel implements DocumentListener /** * Set the focus to the pathTextField. */ - @Override public void select() { pathTextField.requestFocusInWindow(); } - /** - * @return the string form of this panel - */ - @Override - public String toString() { - return "Image File"; - } @Override public synchronized void addPropertyChangeListener(PropertyChangeListener pcl) { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java index f007189683..a0ce4ec323 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java @@ -43,7 +43,7 @@ import org.sleuthkit.autopsy.coreutils.PlatformUtil; /** * ImageTypePanel for adding a local disk or partition such as PhysicalDrive0 or C:. */ -public class LocalDiskPanel extends ContentTypePanel { +public class LocalDiskPanel extends JPanel { private static LocalDiskPanel instance; private PropertyChangeSupport pcs = null; private List disks = new ArrayList(); @@ -129,7 +129,7 @@ public class LocalDiskPanel extends ContentTypePanel { * Return the currently selected disk path. * @return String selected disk path */ - @Override + //@Override public String getContentPaths() { if(disks.size() > 0) { LocalDisk selected = (LocalDisk) diskComboBox.getSelectedItem(); @@ -143,7 +143,7 @@ public class LocalDiskPanel extends ContentTypePanel { /** * Set the selected disk. */ - @Override + // @Override public void setContentPath(String s) { for(int i=0; i currentFiles = new TreeSet(); //keep currents in a set to disallow duplicates per add @@ -57,7 +58,7 @@ public class LocalFilesPanel extends ContentTypePanel { } - @Override + //@Override public String getContentPaths() { //TODO consider interface change to return list of paths instead @@ -72,28 +73,28 @@ public class LocalFilesPanel extends ContentTypePanel { return b.toString(); } - @Override + //@Override public void setContentPath(String s) { //for the local file panel we don't need to restore the last paths used //when the wizard restarts } - @Override + //@Override public String getContentType() { return "LOCAL"; } - @Override + //@Override public boolean enableNext() { return enableNext; } - @Override + //@Override public void select() { reset(); } - @Override + //@Override public void reset() { currentFiles.clear(); selectedPaths.setText(""); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java index 22d9f11a2f..d734444a57 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java @@ -40,6 +40,8 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; +/**** RAMAN TBD: this class needs to be straightened out. It should not duplicate what the ChooseDataSourceWizard does. + public class MissingImageDialog extends javax.swing.JDialog { private static final Logger logger = Logger.getLogger(MissingImageDialog.class.getName()); long obj_id; @@ -55,12 +57,12 @@ public class MissingImageDialog extends javax.swing.JDialog { customInit(); } - /** - * Client call to create a MissingImageDialog. - * - * @param obj_id obj_id of the missing image - * @param db the current SleuthkitCase connected to a db - */ +// +// * Client call to create a MissingImageDialog. +// * +// * @param obj_id obj_id of the missing image +// * @param db the current SleuthkitCase connected to a db +// static void makeDialog(long obj_id, SleuthkitCase db) { final MissingImageDialog dialog = new MissingImageDialog(obj_id, db); dialog.addWindowListener(new WindowAdapter() { @@ -92,10 +94,10 @@ public class MissingImageDialog extends javax.swing.JDialog { this.setVisible(true); } - /** - * Refresh this panel. - * @param panel current typepanel - */ +// +// * Refresh this panel. +// * @param panel current typepanel +// private void updateCurrentPanel(ContentTypePanel panel) { currentPanel = panel; typePanel.removeAll(); @@ -121,25 +123,25 @@ public class MissingImageDialog extends javax.swing.JDialog { updateSelectButton(); } - /** - * Focuses the select button for easy enter-pressing access. - */ +// +// * Focuses the select button for easy enter-pressing access. +// private void moveFocusToSelect() { this.selectButton.requestFocusInWindow(); } - /** - * Enables/disables the select button based off the current panel. - */ +// +// * Enables/disables the select button based off the current panel. +// private void updateSelectButton() { this.selectButton.setEnabled(currentPanel.enableNext()); } - /** - * 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. - */ +// +// * This method is called from within the constructor to initialize the form. +// * WARNING: Do NOT modify this code. The content of this method is always +// * regenerated by the Form Editor. +// @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { @@ -293,9 +295,9 @@ public class MissingImageDialog extends javax.swing.JDialog { private javax.swing.JLabel typeTabel; // End of variables declaration//GEN-END:variables - /** - * Verify the user wants to cancel searching for the image. - */ +// +// * Verify the user wants to cancel searching for the image. +// void cancel() { int ret = JOptionPane.showConfirmDialog(null, "No image file has been selected, are you sure you\n" + @@ -306,9 +308,9 @@ public class MissingImageDialog extends javax.swing.JDialog { } } - /** - * ComboBoxModel to control typeComboBox and supply ImageTypePanels. - */ +// +// * ComboBoxModel to control typeComboBox and supply ImageTypePanels. +// private class ImageTypeModel implements ComboBoxModel { ContentTypePanel selected; ContentTypePanel[] types = ContentTypePanel.getPanels(); @@ -343,3 +345,4 @@ public class MissingImageDialog extends javax.swing.JDialog { } } } +********************************/ \ No newline at end of file From 18d47f3f39ecfdfa050107bb4254ad875270cd65 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 17 Oct 2013 11:45:53 -0400 Subject: [PATCH 014/169] New tags API work --- .../casemodule/services/TagsManager.java | 19 +- .../autopsy/datamodel/Bookmarks.java | 298 ------------------ .../org/sleuthkit/autopsy/datamodel/Tags.java | 226 ------------- .../report/ArtifactSelectionDialog.java | 2 + .../autopsy/report/ReportGenerator.java | 15 +- .../sleuthkit/autopsy/report/ReportHTML.java | 2 +- .../autopsy/report/ReportVisualPanel2.java | 22 +- 7 files changed, 40 insertions(+), 544 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/Bookmarks.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index afab0a237b..4e8d5ec869 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -328,7 +328,7 @@ public class TagsManager implements Closeable { * @param [in] tagName The tag name of interest. * @return A list, possibly empty, of the content tags with the specified tag name. */ - public void getBlackboardArtifactTagsByTagName(TagName tagName, List tags) { + public void getBlackboardArtifactTagsByTagName(TagName tagName, List tags) { try { tskCase.getBlackboardArtifactTagsByTagName(tagName, tags); } @@ -336,7 +336,22 @@ public class TagsManager implements Closeable { Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get blackboard artifact tags from the current case", ex); } } - + + /** + * Gets blackboard artifact tags for a particular blackboard artifact. + * @param [in] artifact The blackboard artifact of interest. + * @param [out] tags A list, possibly empty, of the tags that have been applied to the artifact. + * @throws TskCoreException + */ + public void getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact, List tags) { + try { + tskCase.getBlackboardArtifactTagsByArtifact(artifact, tags); + } + catch (TskCoreException ex) { + Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get blackboard artifact tags from the current case", ex); + } + } + @Override public void close() throws IOException { saveTagNamesToTagsSettings(); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Bookmarks.java b/Core/src/org/sleuthkit/autopsy/datamodel/Bookmarks.java deleted file mode 100644 index e3055f22b7..0000000000 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Bookmarks.java +++ /dev/null @@ -1,298 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2012 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.datamodel; - -import java.awt.event.ActionEvent; -import java.util.EnumMap; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; -import javax.swing.AbstractAction; -import javax.swing.Action; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.openide.nodes.ChildFactory; -import org.openide.nodes.Children; -import org.openide.nodes.Node; -import org.openide.nodes.Sheet; -import org.openide.util.Lookup; -import org.openide.util.lookup.Lookups; -import org.sleuthkit.autopsy.corecomponentinterfaces.BlackboardResultViewer; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; -import org.sleuthkit.datamodel.SleuthkitCase; -import org.sleuthkit.datamodel.TskCoreException; - -/** - * Support for bookmark (file and result/artifact) nodes and displaying - * bookmarks in the directory tree Bookmarks are divided into file and result - * children bookmarks. - * - * Bookmarks are specialized tags - TSK_TAG_NAME starts with File Bookmark or - * Result Bookmark - * - * @deprecated cosolidated under Tags - * - * TODO bookmark hierarchy support (TSK_TAG_NAME with slashes) - */ -@Deprecated -public class Bookmarks implements AutopsyVisitableItem { - - public static final String NAME = "Bookmarks"; - private static final String FILE_BOOKMARKS_LABEL_NAME = "File Bookmarks"; - private static final String RESULT_BOOKMARKS_LABEL_NAME = "Result Bookmarks"; - //bookmarks are specializations of tags - public static final String BOOKMARK_TAG_NAME = "Bookmark"; - private static final String BOOKMARK_ICON_PATH = "org/sleuthkit/autopsy/images/star-bookmark-icon-16.png"; - private static final Logger logger = Logger.getLogger(Bookmarks.class.getName()); - private SleuthkitCase skCase; - private final Map> data = - new EnumMap>(BlackboardArtifact.ARTIFACT_TYPE.class); - - public Bookmarks(SleuthkitCase skCase) { - this.skCase = skCase; - - } - - @Override - public T accept(AutopsyItemVisitor v) { - return null; //v.visit(this); - } - - /** - * bookmarks root node with file/result bookmarks - */ - public class BookmarksRootNode extends DisplayableItemNode { - - public BookmarksRootNode() { - super(Children.create(new BookmarksRootChildren(), true), Lookups.singleton(NAME)); - super.setName(NAME); - super.setDisplayName(NAME); - this.setIconBaseWithExtension(BOOKMARK_ICON_PATH); - initData(); - } - - private void initData() { - data.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE, null); - data.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT, null); - - try { - - //filter out tags that are not bookmarks - //we get bookmarks that have tag names that start with predefined names, preserving the bookmark hierarchy - List tagFiles = skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE, - BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME, - BOOKMARK_TAG_NAME); - List tagArtifacts = skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT, - BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME, - BOOKMARK_TAG_NAME); - - data.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE, tagFiles); - data.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT, tagArtifacts); - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Count not initialize bookmark nodes, ", ex); - } - - - } - - @Override - public boolean isLeafTypeNode() { - return false; - } - - @Override - public T accept(DisplayableItemNodeVisitor v) { - return null; // v.visit(this); - } - - @Override - protected Sheet createSheet() { - Sheet s = super.createSheet(); - Sheet.Set ss = s.get(Sheet.PROPERTIES); - if (ss == null) { - ss = Sheet.createPropertiesSet(); - s.put(ss); - } - - ss.put(new NodeProperty("Name", - "Name", - "no description", - getName())); - - return s; - } - } - - /** - * bookmarks root child node creating types of bookmarks nodes - */ - private class BookmarksRootChildren extends ChildFactory { - - @Override - protected boolean createKeys(List list) { - for (BlackboardArtifact.ARTIFACT_TYPE artType : data.keySet()) { - list.add(artType); - } - - return true; - } - - @Override - protected Node createNodeForKey(BlackboardArtifact.ARTIFACT_TYPE key) { - return new BookmarksNodeRoot(key, data.get(key)); - } - } - - /** - * Bookmarks node representation (file or result) - */ - public class BookmarksNodeRoot extends DisplayableItemNode { - - public BookmarksNodeRoot(BlackboardArtifact.ARTIFACT_TYPE bookType, List bookmarks) { - super(Children.create(new BookmarksChildrenNode(bookmarks), true), Lookups.singleton(bookType.getDisplayName())); - - String name = null; - if (bookType.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)) { - name = FILE_BOOKMARKS_LABEL_NAME; - } else if (bookType.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT)) { - name = RESULT_BOOKMARKS_LABEL_NAME; - } - - super.setName(name); - super.setDisplayName(name + " (" + bookmarks.size() + ")"); - - this.setIconBaseWithExtension(BOOKMARK_ICON_PATH); - } - - @Override - protected Sheet createSheet() { - Sheet s = super.createSheet(); - Sheet.Set ss = s.get(Sheet.PROPERTIES); - if (ss == null) { - ss = Sheet.createPropertiesSet(); - s.put(ss); - } - - ss.put(new NodeProperty("Name", - "Name", - "no description", - getName())); - - return s; - } - - @Override - public boolean isLeafTypeNode() { - return false; - } - - @Override - public T accept(DisplayableItemNodeVisitor v) { - return null; //v.visit(this); - } - } - - /** - * Node representing mail folder content (mail messages) - */ - private class BookmarksChildrenNode extends ChildFactory { - - private List bookmarks; - - private BookmarksChildrenNode(List bookmarks) { - super(); - this.bookmarks = bookmarks; - } - - @Override - protected boolean createKeys(List list) { - list.addAll(bookmarks); - return true; - } - - @Override - protected Node createNodeForKey(BlackboardArtifact artifact) { - BlackboardArtifactNode bookmarkNode = null; - - int artifactTypeID = artifact.getArtifactTypeID(); - if (artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { - final BlackboardArtifact sourceResult = Tags.getArtifactFromTag(artifact.getArtifactID()); - bookmarkNode = new BlackboardArtifactNode(artifact, BOOKMARK_ICON_PATH) { - @Override - public Action[] getActions(boolean bln) { - //Action [] actions = super.getActions(bln); //To change body of generated methods, choose Tools | Templates. - Action[] actions = new Action[1]; - actions[0] = new AbstractAction("View Source Result") { - @Override - public void actionPerformed(ActionEvent e) { - //open the source artifact in dir tree - if (sourceResult != null) { - BlackboardResultViewer v = Lookup.getDefault().lookup(BlackboardResultViewer.class); - v.viewArtifact(sourceResult); - } - } - }; - return actions; - } - }; - - //add custom property - final String NO_DESCR = "no description"; - String resultType = sourceResult.getDisplayName(); - NodeProperty resultTypeProp = new NodeProperty("Source Result Type", - "Result Type", - NO_DESCR, - resultType); - bookmarkNode.addNodeProperty(resultTypeProp); - - } else { - //file bookmark, no additional action - bookmarkNode = new BlackboardArtifactNode(artifact, BOOKMARK_ICON_PATH); - - } - return bookmarkNode; - } - } - - /** - * Links existing blackboard artifact (a tag) to this artifact. Linkage is - * made using TSK_TAGGED_ARTIFACT attribute. - */ - void addArtifactTag(BlackboardArtifact art, BlackboardArtifact tag) throws TskCoreException { - if (art.equals(tag)) { - throw new TskCoreException("Cannot tag the same artifact: id" + art.getArtifactID()); - } - BlackboardAttribute attrLink = new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID(), - "", art.getArtifactID()); - tag.addAttribute(attrLink); - } - - /** - * Get tag artifacts linked to the artifact - * - * @param art artifact to get tags for - * @return list of children artifacts or an empty list - * @throws TskCoreException exception thrown if a critical error occurs - * within tsk core and child artifact could not be queried - */ - List getTagArtifacts(BlackboardArtifact art) throws TskCoreException { - return skCase.getBlackboardArtifacts(ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT, art.getArtifactID()); - } -} \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java index dce6ecb3ad..03a749cfb3 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java @@ -18,249 +18,23 @@ */ package org.sleuthkit.autopsy.datamodel; -import java.sql.ResultSet; -import java.sql.SQLException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; -import java.util.TreeSet; import java.util.logging.Level; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; -import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; public class Tags { private static final Logger logger = Logger.getLogger(Tags.class.getName()); public static final String BOOKMARK_TAG_NAME = "Bookmark"; - private static final String EMPTY_COMMENT = ""; - /** - * Create a tag for a file with TSK_TAG_NAME as tagName. - * - * @param file to create tag for - * @param tagName TSK_TAG_NAME - * @param comment the tag comment, or null if not present - */ - public static void createTag(AbstractFile file, String tagName, String comment) { - try { - final BlackboardArtifact bookArt = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE); - List attrs = new ArrayList<>(); - - - BlackboardAttribute attr1 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID(), - "", tagName); - attrs.add(attr1); - - if (comment != null && !comment.isEmpty()) { - BlackboardAttribute attr2 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID(), - "", comment); - attrs.add(attr2); - } - bookArt.addAttributes(attrs); - } - catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Failed to create tag for " + file.getName(), ex); - } - } - - /** - * Create a tag for an artifact with TSK_TAG_NAME as tagName. - * - * @param artifact to create tag for - * @param tagName TSK_TAG_NAME - * @param comment the tag comment or null if not present - */ - public static void createTag(BlackboardArtifact artifact, String tagName, String comment) { - try { - Case currentCase = Case.getCurrentCase(); - SleuthkitCase skCase = currentCase.getSleuthkitCase(); - - AbstractFile file = skCase.getAbstractFileById(artifact.getObjectID()); - final BlackboardArtifact bookArt = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT); - List attrs = new ArrayList<>(); - - - BlackboardAttribute attr1 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID(), - "", tagName); - - if (comment != null && !comment.isEmpty()) { - BlackboardAttribute attr2 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID(), - "", comment); - attrs.add(attr2); - } - - BlackboardAttribute attr3 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID(), - "", artifact.getArtifactID()); - attrs.add(attr1); - - attrs.add(attr3); - bookArt.addAttributes(attrs); - } - catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Failed to create tag for artifact " + artifact.getArtifactID(), ex); - } - } - - /** - * Create a bookmark tag for a file. - * - * @param file to create bookmark tag for - * @param comment the bookmark comment - */ - public static void createBookmark(AbstractFile file, String comment) { - createTag(file, Tags.BOOKMARK_TAG_NAME, comment); - } - - /** - * Create a bookmark tag for an artifact. - * - * @param artifact to create bookmark tag for - * @param comment the bookmark comment - */ - public static void createBookmark(BlackboardArtifact artifact, String comment) { - createTag(artifact, Tags.BOOKMARK_TAG_NAME, comment); - } - - /** - * Get a list of all the bookmarks. - * - * @return a list of all bookmark artifacts - */ - static List getBookmarks() { - try { - Case currentCase = Case.getCurrentCase(); - SleuthkitCase skCase = currentCase.getSleuthkitCase(); - return skCase.getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME, Tags.BOOKMARK_TAG_NAME); - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Failed to get list of artifacts from the case", ex); - } - return new ArrayList<>(); - } - - /** - * Get a list of all the unique tag names associated with the current case plus any - * tag names stored in the application settings file. - * - * @return A collection of tag names. - */ - public static TreeSet getAllTagNames() { - // Use a TreeSet<> so the union of the tag names from the two sources will be sorted. - TreeSet tagNames = getTagNamesFromCurrentCase(); - - // Make sure the book mark tag is always included. - tagNames.add(BOOKMARK_TAG_NAME); - - return tagNames; - } - - /** - * Get a list of all the unique tag names associated with the current case. - * Uses a custom query for speed when dealing with thousands of tags. - * - * @return A collection of tag names. - */ - @SuppressWarnings("deprecation") - public static TreeSet getTagNamesFromCurrentCase() { - TreeSet tagNames = new TreeSet<>(); - - ResultSet rs = null; - SleuthkitCase skCase = null; - try { - skCase = Case.getCurrentCase().getSleuthkitCase(); - rs = skCase.runQuery("SELECT value_text" - + " FROM blackboard_attributes" - + " WHERE attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID() - + " GROUP BY value_text" - + " ORDER BY value_text"); - while (rs.next()) { - tagNames.add(rs.getString("value_text")); - } - } - catch (IllegalStateException ex) { - // Case.getCurrentCase() throws IllegalStateException if there is no current autopsy case. - } - catch (SQLException ex) { - logger.log(Level.SEVERE, "Failed to query the blackboard for tag names", ex); - } - finally { - if (null != skCase && null != rs) { - try { - skCase.closeRunQuery(rs); - } catch (SQLException ex) { - logger.log(Level.SEVERE, "Failed to close the query for blackboard for tag names", ex); - } - } - } - - // Make sure the book mark tag is always included. - tagNames.add(BOOKMARK_TAG_NAME); - - return tagNames; - } - - /** - * Get the tag comment for a specified tag. - * - * @param tagArtifactId artifact id of the tag - * @return the tag comment - */ - static String getCommentFromTag(long tagArtifactId) { - try { - Case currentCase = Case.getCurrentCase(); - SleuthkitCase skCase = currentCase.getSleuthkitCase(); - - BlackboardArtifact artifact = skCase.getBlackboardArtifact(tagArtifactId); - if (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() - || artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { - List attributes = artifact.getAttributes(); - for (BlackboardAttribute att : attributes) { - if (att.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID()) { - return att.getValueString(); - } - } - } - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Failed to get artifact " + tagArtifactId + " from case", ex); - } - - return EMPTY_COMMENT; - } - - /** - * Get the artifact for a result tag. - * - * @param tagArtifactId artifact id of the tag - * @return the tag's artifact - */ - static BlackboardArtifact getArtifactFromTag(long tagArtifactId) { - try { - Case currentCase = Case.getCurrentCase(); - SleuthkitCase skCase = currentCase.getSleuthkitCase(); - - BlackboardArtifact artifact = skCase.getBlackboardArtifact(tagArtifactId); - if (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() - || artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { - List attributes = artifact.getAttributes(); - for (BlackboardAttribute att : attributes) { - if (att.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID()) { - return skCase.getBlackboardArtifact(att.getValueLong()); - } - } - } - } catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Failed to get artifact " + tagArtifactId + " from case."); - } - - return null; - } - /** * Looks up the tag names associated with either a tagged artifact or a tag artifact. * diff --git a/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.java b/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.java index 24ed36f302..96f417f72b 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.java +++ b/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.java @@ -66,6 +66,8 @@ public class ArtifactSelectionDialog extends javax.swing.JDialog { try { ArrayList doNotReport = new ArrayList(); doNotReport.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO); + doNotReport.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE); // Obsolete artifact type + doNotReport.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT); // Obsolete artifact type artifacts = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifactTypesInUse(); diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java index 889ca07328..9064532933 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java @@ -34,7 +34,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.Iterator; @@ -56,9 +55,9 @@ import org.sleuthkit.autopsy.report.ReportProgressPanel.ReportStatus; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; +import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; -import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; @@ -512,14 +511,18 @@ public class ReportGenerator { private List getFilteredArtifacts(ARTIFACT_TYPE type, HashSet tagNamesFilter) { List artifacts = new ArrayList<>(); try { - // For every artifact of the current type, add it and it's attributes to a list for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(type)) { - HashSet tags = Tags.getUniqueTagNamesForArtifact(artifact); - if(failsTagFilter(tags, tagNamesFilter)) { + ArrayList tags = new ArrayList<>(); + Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact, tags); + HashSet uniqueTagNames = new HashSet<>(); + for (BlackboardArtifactTag tag : tags) { + uniqueTagNames.add(tag.getName().getDisplayName()); + } + if(failsTagFilter(uniqueTagNames, tagNamesFilter)) { continue; } try { - artifacts.add(new ArtifactData(artifact, skCase.getBlackboardAttributes(artifact), tags)); + artifacts.add(new ArtifactData(artifact, skCase.getBlackboardAttributes(artifact), uniqueTagNames)); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "Failed to get Blackboard Attributes when generating report.", ex); } diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index aa48b125f0..4b5492ebec 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -599,7 +599,7 @@ public class ReportHTML implements TableReportModule { // Make a folder for the local file with the same name as the tag. StringBuilder localFilePath = new StringBuilder(); - localFilePath.append(path); + localFilePath.append(path); HashSet tagNames = Tags.getUniqueTagNamesForArtifact(sourceArtifact); if (!tagNames.isEmpty()) { localFilePath.append(tagNames.iterator().next()); diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java index e374135aa9..074892d84c 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java @@ -38,13 +38,12 @@ import javax.swing.ListModel; import javax.swing.event.ListDataListener; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datamodel.Tags; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; +import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; public final class ReportVisualPanel2 extends JPanel { - private static final Logger logger = Logger.getLogger(ReportVisualPanel2.class.getName()); private ReportWizardPanel2 wizPanel; private Map tagStates = new LinkedHashMap<>(); @@ -73,8 +72,11 @@ public final class ReportVisualPanel2 extends JPanel { // Initialize the list of Tags private void initTags() { - for(String tag : Tags.getTagNamesFromCurrentCase()) { - tagStates.put(tag, Boolean.FALSE); + ArrayList tagNamesInUse = new ArrayList<>(); + Case.getCurrentCase().getServices().getTagsManager().getTagNamesInUse(tagNamesInUse); + + for(TagName tagName : tagNamesInUse) { + tagStates.put(tagName.getDisplayName(), Boolean.FALSE); } tags.addAll(tagStates.keySet()); @@ -95,16 +97,17 @@ public final class ReportVisualPanel2 extends JPanel { list.repaint(); updateFinishButton(); } - }); - + }); } // Initialize the list of Artifacts private void initArtifactTypes() { try { - ArrayList doNotReport = new ArrayList(); + ArrayList doNotReport = new ArrayList(); doNotReport.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO); + doNotReport.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE); // Obsolete artifact type + doNotReport.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT); // Obsolete artifact type artifacts = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifactTypesInUse(); @@ -116,7 +119,6 @@ public final class ReportVisualPanel2 extends JPanel { } } catch (TskCoreException ex) { Logger.getLogger(ReportVisualPanel2.class.getName()).log(Level.SEVERE, "Error getting list of artifacts in use: " + ex.getLocalizedMessage(), ex); - return; } } @@ -355,8 +357,6 @@ public final class ReportVisualPanel2 extends JPanel { return this; } return new JLabel(); - } - + } } - } From 09fb5edba59fff5592cff1c87017d132f8893565 Mon Sep 17 00:00:00 2001 From: raman-bt Date: Thu, 17 Oct 2013 14:17:37 -0400 Subject: [PATCH 015/169] Removed passing of WizardDescriptor across the DataSourceProcessor interface. Moved TZ and NoFatOrphans from ChooseDataSourceVisual panel into the specific DSP panel. --- .../AddImageWizardChooseDataSourcePanel.java | 4 +- .../AddImageWizardChooseDataSourceVisual.form | 60 +- .../AddImageWizardChooseDataSourceVisual.java | 112 +--- .../AddImageWizardIngestConfigPanel.java | 516 +----------------- .../autopsy/casemodule/Bundle.properties | 8 +- .../casemodule/DataSourceProcessor.java | 2 +- .../autopsy/casemodule/ImageDSProcessor.java | 104 +--- .../autopsy/casemodule/ImageFilePanel.form | 61 ++- .../autopsy/casemodule/ImageFilePanel.java | 95 +++- .../netbeans/core/startup/Bundle.properties | 2 +- .../core/windows/view/ui/Bundle.properties | 2 +- 11 files changed, 202 insertions(+), 764 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java index 2e103d3272..777b402eb3 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java @@ -228,12 +228,12 @@ class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Panel - - - - - - - - - - @@ -65,16 +55,7 @@ - - - - - - - - - - + @@ -89,41 +70,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -160,7 +106,7 @@ - + @@ -192,7 +138,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java index 3595667230..96440ffd3f 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java @@ -82,7 +82,7 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { AddImageWizardChooseDataSourceVisual(AddImageWizardChooseDataSourcePanel wizPanel) { initComponents(); this.wizPanel = wizPanel; - createTimeZoneList(); + customInit(); } @@ -161,20 +161,6 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { } }); - - /* RAMAN TBD: this should all be ripped from here. the content specific UI elements should all go - * into the corresponding DSP - */ - if (GetCurrentDSProcessor().getType().equals("LOCAL")) { - //disable image specific options - noFatOrphansCheckbox.setEnabled(false); - descLabel.setEnabled(false); - timeZoneComboBox.setEnabled(false); - } else { - noFatOrphansCheckbox.setEnabled(true); - descLabel.setEnabled(true); - timeZoneComboBox.setEnabled(true); - } updateUI(null); } @@ -203,63 +189,6 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { return "Enter Data Source Information"; } - /** - * - * @return true if no fat orphans processing is selected - */ - /***RAMAN TBD: move this into DSP ****/ - boolean getNoFatOrphans() { - return noFatOrphansCheckbox.isSelected(); - } - - /** - * Gets the time zone that selected on the drop down list. - * - * @return timeZone the time zone that selected - */ - /***RAMAN TBD: move this into the DSP****/ - public String getSelectedTimezone() { - String tz = timeZoneComboBox.getSelectedItem().toString(); - return tz.substring(tz.indexOf(")") + 2).trim(); - } - - // add the timeZone list to the timeZoneComboBox - /** - * Creates the drop down list for the time zones and then makes the local - * machine time zones to be selected. - */ - /*** RAMAN TBD: move this into the DSP panel ***/ - public void createTimeZoneList() { - // load and add all timezone - String[] ids = SimpleTimeZone.getAvailableIDs(); - for (String id : ids) { - TimeZone zone = TimeZone.getTimeZone(id); - int offset = zone.getRawOffset() / 1000; - int hour = offset / 3600; - int minutes = (offset % 3600) / 60; - String item = String.format("(GMT%+d:%02d) %s", hour, minutes, id); - - /* - * DateFormat dfm = new SimpleDateFormat("z"); - * dfm.setTimeZone(zone); boolean hasDaylight = - * zone.useDaylightTime(); String first = dfm.format(new Date(2010, - * 1, 1)); String second = dfm.format(new Date(2011, 6, 6)); int mid - * = hour * -1; String result = first + Integer.toString(mid); - * if(hasDaylight){ result = result + second; } - * timeZoneComboBox.addItem(item + " (" + result + ")"); - */ - timeZoneComboBox.addItem(item); - } - // get the current timezone - TimeZone thisTimeZone = Calendar.getInstance().getTimeZone(); - int thisOffset = thisTimeZone.getRawOffset() / 1000; - int thisHour = thisOffset / 3600; - int thisMinutes = (thisOffset % 3600) / 60; - String formatted = String.format("(GMT%+d:%02d) %s", thisHour, thisMinutes, thisTimeZone.getID()); - - // set the selected timezone - timeZoneComboBox.setSelectedItem(formatted); - } /** * This method is called from within the constructor to initialize the form. @@ -272,10 +201,6 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { buttonGroup1 = new javax.swing.ButtonGroup(); jLabel2 = new javax.swing.JLabel(); nextLabel = new javax.swing.JLabel(); - timeZoneLabel = new javax.swing.JLabel(); - timeZoneComboBox = new javax.swing.JComboBox(); - noFatOrphansCheckbox = new javax.swing.JCheckBox(); - descLabel = new javax.swing.JLabel(); inputPanel = new javax.swing.JPanel(); typeTabel = new javax.swing.JLabel(); typePanel = new javax.swing.JPanel(); @@ -288,15 +213,6 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { org.openide.awt.Mnemonics.setLocalizedText(nextLabel, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.nextLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(timeZoneLabel, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.timeZoneLabel.text")); // NOI18N - - timeZoneComboBox.setMaximumRowCount(30); - - org.openide.awt.Mnemonics.setLocalizedText(noFatOrphansCheckbox, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.noFatOrphansCheckbox.text")); // NOI18N - noFatOrphansCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.noFatOrphansCheckbox.toolTipText")); // NOI18N - - org.openide.awt.Mnemonics.setLocalizedText(descLabel, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.descLabel.text")); // NOI18N - inputPanel.setBorder(javax.swing.BorderFactory.createEtchedBorder()); org.openide.awt.Mnemonics.setLocalizedText(typeTabel, org.openide.util.NbBundle.getMessage(AddImageWizardChooseDataSourceVisual.class, "AddImageWizardChooseDataSourceVisual.typeTabel.text")); // NOI18N @@ -312,7 +228,7 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { ); typePanelLayout.setVerticalGroup( typePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 77, Short.MAX_VALUE) + .addGap(0, 173, Short.MAX_VALUE) ); javax.swing.GroupLayout inputPanelLayout = new javax.swing.GroupLayout(inputPanel); @@ -338,7 +254,7 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { .addComponent(typeTabel) .addComponent(typeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(typePanel, javax.swing.GroupLayout.DEFAULT_SIZE, 77, Short.MAX_VALUE) + .addComponent(typePanel, javax.swing.GroupLayout.DEFAULT_SIZE, 173, Short.MAX_VALUE) .addContainerGap()) ); @@ -356,14 +272,6 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(nextLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGroup(layout.createSequentialGroup() - .addComponent(timeZoneLabel) - .addGap(18, 18, 18) - .addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 252, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(noFatOrphansCheckbox) - .addGroup(layout.createSequentialGroup() - .addGap(21, 21, 21) - .addComponent(descLabel)) .addComponent(imgInfoLabel)) .addGap(0, 54, Short.MAX_VALUE))) .addContainerGap()) @@ -375,29 +283,17 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { .addComponent(imgInfoLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(inputPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(timeZoneLabel) - .addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(noFatOrphansCheckbox) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(descLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 64, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 45, Short.MAX_VALUE) .addComponent(nextLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(0, 0, 0)) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup buttonGroup1; - private javax.swing.JLabel descLabel; private javax.swing.JLabel imgInfoLabel; private javax.swing.JPanel inputPanel; private javax.swing.JLabel jLabel2; private javax.swing.JLabel nextLabel; - private javax.swing.JCheckBox noFatOrphansCheckbox; - private javax.swing.JComboBox timeZoneComboBox; - private javax.swing.JLabel timeZoneLabel; private javax.swing.JComboBox typeComboBox; private javax.swing.JPanel typePanel; private javax.swing.JLabel typeTabel; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java index 5a89aa2997..832f93d348 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java @@ -37,7 +37,6 @@ import javax.swing.event.ChangeListener; import org.openide.WizardDescriptor; import org.openide.util.HelpCtx; import org.openide.util.Lookup; -//import org.sleuthkit.autopsy.casemodule.ContentTypePanel.ContentType; import org.sleuthkit.autopsy.casemodule.services.FileManager; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.PlatformUtil; @@ -68,27 +67,21 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel newContents = Collections.synchronizedList(new ArrayList()); private boolean ingested = false; private boolean readyToIngest = false; - // the paths of the image files to be added - private String dataSourcePath; - private String dataSourceType; - // the time zone where the image is added - private String timeZone; - //whether to not process FAT filesystem orphans - private boolean noFatOrphans; + // task that will clean up the created database file if the wizard is cancelled before it finishes - private AddImageAction.CleanupTask cleanupImage; // initialized to null in readSettings() - private CurrentDirectoryFetcher fetcher; - private AddImageProcess process; + private AddImageAction.CleanupTask cleanupTask; + private AddImageAction addImageAction; - private AddImageTask addImageTask; - private AddLocalFilesTask addLocalFilesTask; + private AddImageWizardAddingProgressPanel progressPanel; private AddImageWizardChooseDataSourcePanel dataSourcePanel; + private DataSourceProcessor dsProcessor; - private AddImageAction.CleanupTask cleanupTask; + AddImageWizardIngestConfigPanel(AddImageWizardChooseDataSourcePanel dsPanel, AddImageAction action, AddImageWizardAddingProgressPanel proPanel) { this.addImageAction = action; @@ -188,27 +181,13 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel { - - AddImageTask task; - JProgressBar prog; - AddImageWizardAddingProgressVisual wiz; - AddImageProcess proc; - - CurrentDirectoryFetcher(JProgressBar prog, AddImageWizardAddingProgressVisual wiz, AddImageProcess proc) { - this.wiz = wiz; - this.proc = proc; - this.prog = prog; - } - - /** - * @return the currently processing directory - */ - @Override - protected Integer doInBackground() { - try { - while (prog.getValue() < 100 || prog.isIndeterminate()) { //TODO Rely on state variable in AddImgTask class - - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - wiz.setCurrentDirText(proc.currentDirectory()); - } - }); - - Thread.sleep(2 * 1000); - } - return 1; - } catch (InterruptedException ie) { - return -1; - } - } - } - - /** - * Thread that will add logical files to database, and then kick-off ingest - * modules. Note: the add logical files task cannot currently be reverted as - * the add image task can. This is a separate task from AddImgTask because - * it is much simpler and does not require locks, since the underlying file - * manager methods acquire the locks for each transaction when adding - * logical files. - */ - private class AddLocalFilesTask extends SwingWorker { - - private JProgressBar progressBar; - private Case currentCase; - // true if the process was requested to stop - private boolean interrupted = false; - private boolean hasCritError = false; - private String errorString = null; - private WizardDescriptor settings; - private Logger logger = Logger.getLogger(AddLocalFilesTask.class.getName()); - - protected AddLocalFilesTask(WizardDescriptor settings) { - this.progressBar = progressPanel.getComponent().getProgressBar(); - currentCase = Case.getCurrentCase(); - this.settings = settings; - } - - /** - * Starts the addImage process, but does not commit the results. - * - * @return - * - * @throws Exception - */ - @Override - protected Integer doInBackground() { - this.setProgress(0); - // Add a cleanup task to interupt the backgroud process if the - // wizard exits while the background process is running. - AddImageAction.CleanupTask cancelledWhileRunning = addImageAction.new CleanupTask() { - @Override - void cleanup() throws Exception { - logger.log(Level.INFO, "Add logical files process interrupted."); - //nothing to be cleanedup - } - }; - - cancelledWhileRunning.enable(); - final LocalFilesAddProgressUpdater progUpdater = new LocalFilesAddProgressUpdater(this.progressBar, progressPanel.getComponent()); - try { - final FileManager fileManager = currentCase.getServices().getFileManager(); - progressPanel.setStateStarted(); - String[] paths = dataSourcePath.split(LocalFilesPanel.FILES_SEP); - List absLocalPaths = new ArrayList(); - for (String path : paths) { - absLocalPaths.add(path); - } - newContents.add(fileManager.addLocalFilesDirs(absLocalPaths, progUpdater)); - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Errors occurred while running add logical files. ", ex); - hasCritError = true; - errorString = ex.getMessage(); - } finally { - // process is over, doesn't need to be dealt with if cancel happens - cancelledWhileRunning.disable(); - //enqueue what would be in done() to EDT thread - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - postProcess(); - } - }); - } - return 0; - } - - /** - * - * (called by EventDispatch Thread after doInBackground finishes) - */ - protected void postProcess() { - progressBar.setIndeterminate(false); - setProgress(100); - - //clear updates - // progressPanel.getComponent().setProcessInvis(); - - if (interrupted || hasCritError) { - logger.log(Level.INFO, "Handling errors or interruption that occured in logical files process"); - if (hasCritError) { - //core error - progressPanel.getComponent().showErrors(errorString, true); - } - return; - } else { - if (errorString != null) { - //data error (non-critical) - logger.log(Level.INFO, "Handling non-critical errors that occured in logical files process"); - progressPanel.getComponent().showErrors(errorString, false); - } - } - try { - // When everything happens without an error: - if (errorString == null) { // complete progress bar - progressPanel.getComponent().setProgressBarTextAndColor("*Logical Files added.", 100, Color.black); - } - - // Get attention for the process finish - java.awt.Toolkit.getDefaultToolkit().beep(); //BEEP! - AddImageWizardAddingProgressVisual panel = progressPanel.getComponent(); - if (panel != null) { - Window w = SwingUtilities.getWindowAncestor(panel); - if (w != null) { - w.toFront(); - } - } - - progressPanel.setStateFinished(); - - //notify the case - if (!newContents.isEmpty()) { - Case.getCurrentCase().addLocalDataSource(newContents.get(0)); - } - - // Start ingest if we can - startIngest(); - - } catch (Exception ex) { - //handle unchecked exceptions - logger.log(Level.WARNING, "Unexpected errors occurred while running post add image cleanup. ", ex); - progressPanel.getComponent().setProgressBarTextAndColor("*Failed to add image.", 0, Color.black); // set error message - logger.log(Level.SEVERE, "Error adding image to case", ex); - } - } - - /** - * Updates the wizard status with logical file/folder - */ - private class LocalFilesAddProgressUpdater implements FileManager.FileAddProgressUpdater { - - private int count = 0; - private JProgressBar prog; - private AddImageWizardAddingProgressVisual wiz; - - LocalFilesAddProgressUpdater(JProgressBar prog, AddImageWizardAddingProgressVisual wiz) { - this.wiz = wiz; - this.prog = prog; - } - - @Override - public void fileAdded(final AbstractFile newFile) { - if (count++ % 10 == 0 && (prog.getValue() < 100 || prog.isIndeterminate())) { - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - wiz.setCurrentDirText(newFile.getParentPath() + "/" + newFile.getName()); - } - }); - - } - } - } - } - - /** - * Thread that will make the JNI call to add image to database, and then - * kick-off ingest modules. - */ - private class AddImageTask extends SwingWorker { - - private JProgressBar progressBar; - private Case currentCase; - // true if the process was requested to stop - private boolean interrupted = false; - private boolean hasCritError = false; - private String errorString = null; - private WizardDescriptor wizDescriptor; - private Logger logger = Logger.getLogger(AddImageTask.class.getName()); - - protected AddImageTask(WizardDescriptor settings) { - this.progressBar = progressPanel.getComponent().getProgressBar(); - currentCase = Case.getCurrentCase(); - this.wizDescriptor = settings; - } - - /** - * Starts the addImage process, but does not commit the results. - * - * @return - * - * @throws Exception - */ - @Override - protected Integer doInBackground() { - - this.setProgress(0); - - - // Add a cleanup task to interupt the backgroud process if the - // wizard exits while the background process is running. - AddImageAction.CleanupTask cancelledWhileRunning = addImageAction.new CleanupTask() { - @Override - void cleanup() throws Exception { - logger.log(Level.INFO, "Add image process interrupted."); - addImageTask.interrupt(); //it might take time to truly interrupt - } - }; - - - try { - //lock DB for writes in EWT thread - //wait until lock acquired in EWT - EventQueue.invokeAndWait(new Runnable() { - @Override - public void run() { - SleuthkitCase.dbWriteLock(); - } - }); - } catch (InterruptedException ex) { - logger.log(Level.WARNING, "Errors occurred while running add image, could not acquire lock. ", ex); - return 0; - - } catch (InvocationTargetException ex) { - logger.log(Level.WARNING, "Errors occurred while running add image, could not acquire lock. ", ex); - return 0; - } - - process = currentCase.makeAddImageProcess(timeZone, true, noFatOrphans); - fetcher = new CurrentDirectoryFetcher(this.progressBar, progressPanel.getComponent(), process); - cancelledWhileRunning.enable(); - try { - progressPanel.setStateStarted(); - fetcher.execute(); - process.run(new String[]{dataSourcePath}); - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Core errors occurred while running add image. ", ex); - //critical core/system error and process needs to be interrupted - hasCritError = true; - errorString = ex.getMessage(); - } catch (TskDataException ex) { - logger.log(Level.WARNING, "Data errors occurred while running add image. ", ex); - errorString = ex.getMessage(); - } finally { - // process is over, doesn't need to be dealt with if cancel happens - cancelledWhileRunning.disable(); - - } - - return 0; - } - - /** - * Commit the finished AddImageProcess, and cancel the CleanupTask that - * would have reverted it. - * - * @param settings property set to get AddImageProcess and CleanupTask - * from - * - * @throws Exception if commit or adding the image to the case failed - */ - private void commitImage(WizardDescriptor settings) throws Exception { - - String contentPath = (String) settings.getProperty(AddImageAction.DATASOURCEPATH_PROP); - - String timezone = settings.getProperty(AddImageAction.TIMEZONE_PROP).toString(); - settings.putProperty(AddImageAction.IMAGEID_PROP, ""); - - long imageId = 0; - try { - imageId = process.commit(); - } catch (TskException e) { - logger.log(Level.WARNING, "Errors occured while committing the image", e); - } finally { - //commit done, unlock db write in EWT thread - //before doing anything else - SleuthkitCase.dbWriteUnlock(); - - if (imageId != 0) { - Image newImage = Case.getCurrentCase().addImage(contentPath, imageId, timezone); - - //while we have the image, verify the size of its contents - String verificationErrors = newImage.verifyImageSize(); - if (verificationErrors.equals("") == false) { - //data error (non-critical) - progressPanel.addErrors(verificationErrors, false); - } - - - newContents.add(newImage); - settings.putProperty(AddImageAction.IMAGEID_PROP, imageId); - } - - // Can't bail and revert image add after commit, so disable image cleanup - // task - cleanupImage.disable(); - settings.putProperty(AddImageAction.IMAGECLEANUPTASK_PROP, null); - - logger.log(Level.INFO, "Image committed, imageId: " + imageId); - logger.log(Level.INFO, PlatformUtil.getAllMemUsageInfo()); - - } - } - - /** - * - * (called by EventDispatch Thread after doInBackground finishes) - */ - @Override - protected void done() { - //these are required to stop the CurrentDirectoryFetcher - progressBar.setIndeterminate(false); - setProgress(100); - - // attempt actions that might fail and force the process to stop - - if (interrupted || hasCritError) { - logger.log(Level.INFO, "Handling errors or interruption that occured in add image process"); - revert(); - if (hasCritError) { - //core error - progressPanel.addErrors(errorString, true); - } - return; - } - if (errorString != null) { - //data error (non-critical) - logger.log(Level.INFO, "Handling non-critical errors that occured in add image process"); - progressPanel.addErrors(errorString, false); - } - - - try { - // When everything happens without an error: - - // the add-image process needs to be reverted if the wizard doesn't finish - cleanupImage = addImageAction.new CleanupTask() { - //note, CleanupTask runs inside EWT thread - @Override - void cleanup() throws Exception { - logger.log(Level.INFO, "Running cleanup task after add image process"); - revert(); - } - }; - cleanupImage.enable(); - - if (errorString == null) { // complete progress bar - progressPanel.getComponent().setProgressBarTextAndColor("*Data Source added.", 100, Color.black); - } - - // Get attention for the process finish - java.awt.Toolkit.getDefaultToolkit().beep(); //BEEP! - AddImageWizardAddingProgressVisual panel = progressPanel.getComponent(); - if (panel != null) { - Window w = SwingUtilities.getWindowAncestor(panel); - if (w != null) { - w.toFront(); - } - } - - // Tell the panel we're done - progressPanel.setStateFinished(); - - // Commit the image - if (!newContents.isEmpty()) //already commited - { - logger.log(Level.INFO, "Assuming image already committed, will not commit."); - return; - } - - if (process != null) { // and if we're done configuring ingest - // commit anything - try { - commitImage(wizDescriptor); - } catch (Exception ex) { - // Log error/display warning - logger.log(Level.SEVERE, "Error adding image to case.", ex); - } - } else { - logger.log(Level.SEVERE, "Missing image process object"); - } - - - - - // Start ingest if we can - startIngest(); - - } catch (Exception ex) { - //handle unchecked exceptions post image add - - logger.log(Level.WARNING, "Unexpected errors occurred while running post add image cleanup. ", ex); - - progressPanel.getComponent().setProgressBarTextAndColor("*Failed to add image.", 0, Color.black); // set error message - - // Log error/display warning - - logger.log(Level.SEVERE, "Error adding image to case", ex); - } finally { - } - } - - void interrupt() throws Exception { - interrupted = true; - try { - logger.log(Level.INFO, "interrupt() add image process"); - process.stop(); //it might take time to truly stop processing and writing to db - } catch (TskException ex) { - throw new Exception("Error stopping add-image process.", ex); - } - } - - //runs in EWT - void revert() { - try { - logger.log(Level.INFO, "Revert after add image process"); - try { - process.revert(); - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Error reverting add image process", ex); - } - } finally { - //unlock db write within EWT thread - SleuthkitCase.dbWriteUnlock(); - } - } - } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index ffb3261dd5..6207163194 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -134,12 +134,8 @@ LocalFilesPanel.selectButton.actionCommand=Add AddImageWizardIngestConfigVisual.subtitleLabel.text=Configure the ingest modules you would like to run on this data source. AddImageWizardIngestConfigVisual.titleLabel.text=Configure Ingest Modules AddImageWizardAddingProgressVisual.statusLabel.text=File system has been added to the local database. Files are being analyzed. -AddImageWizardChooseDataSourceVisual.noFatOrphansCheckbox.toolTipText= -AddImageWizardChooseDataSourceVisual.noFatOrphansCheckbox.text=Ignore orphan files in FAT file systems -AddImageWizardChooseDataSourceVisual.descLabel.text=(faster results, although some data will not be searched) AddImageWizardChooseDataSourceVisual.typeTabel.text=Select source type to add: AddImageWizardChooseDataSourceVisual.jLabel2.text=jLabel2 -AddImageWizardChooseDataSourceVisual.timeZoneLabel.text=Please select the input timezone: AddImageWizardChooseDataSourceVisual.nextLabel.text= Press 'Next' to analyze the input data, extract volume and file system data, and populate a local database. AddImageWizardChooseDataSourceVisual.imgInfoLabel.text=Enter Data Source Information: AddImageWizardAddingProgressVisual.progressLabel.text= @@ -148,3 +144,7 @@ AddImageWizardAddingProgressVisual.viewLogButton.text=View Log AddImageWizardAddingProgressVisual.titleLabel.text=Adding Data Source AddImageWizardAddingProgressVisual.subTitle1Label.text=File system information is being added to a local database. File analysis will start when this finishes. AddImageWizardAddingProgressVisual.subTitle2Label.text=Processing Data Source and Adding to Database +ImageFilePanel.timeZoneLabel.text=Please select the input timezone: +ImageFilePanel.noFatOrphansCheckbox.text=Ignore orphan files in FAT file systems +ImageFilePanel.noFatOrphansCheckbox.toolTipText= +ImageFilePanel.descLabel.text=(faster results, although some data will not be searched) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/DataSourceProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/DataSourceProcessor.java index 76f9b89f4e..b934809dea 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/DataSourceProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/DataSourceProcessor.java @@ -58,7 +58,7 @@ public interface DataSourceProcessor { * @param progressPanel progress panel to be updated while processing * **/ - void run(WizardDescriptor settings, DSPProgressMonitor progressPanel, DSPCallback dspCallback); + void run(DSPProgressMonitor progressPanel, DSPCallback dspCallback); /** * Called after run() is done to get the new content added by the handler. diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java index 696f903f4e..eed578d9b0 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java @@ -61,13 +61,6 @@ public class ImageDSProcessor implements DataSourceProcessor { } - /**** - @Override - public ImageDSProcessor createInstance() { - return new ImageDSProcessor(); - } - *****/ - @Override public String getType() { @@ -84,8 +77,10 @@ public class ImageDSProcessor implements DataSourceProcessor { logger.log(Level.INFO, "RAMAN getPanel()..."); - // RAMAN TBD: we should preload the panel with any saved settings + // RAMAN TBD: we should ask the panel to preload with any saved settings + imageFilePanel.select(); + return imageFilePanel; } @@ -101,7 +96,7 @@ public class ImageDSProcessor implements DataSourceProcessor { } @Override - public void run(WizardDescriptor settings, DSPProgressMonitor progressMonitor, DSPCallback cbObj) { + public void run(DSPProgressMonitor progressMonitor, DSPCallback cbObj) { logger.log(Level.INFO, "RAMAN run()..."); @@ -112,38 +107,20 @@ public class ImageDSProcessor implements DataSourceProcessor { { // get the image options from the panel imagePath = imageFilePanel.getContentPaths(); - - /*** RAMAN TBD: get the TZ and NoFatOrhpns options from the config panel ******/ - //timeZone = imageFilePanel.getTimeZone(); - //noFatOrphans = imageFilePanel.getNoFatOrphans(); - - - + timeZone = imageFilePanel.getTimeZone(); + noFatOrphans = imageFilePanel.getNoFatOrphans(); } - addImageTask = new AddImageTask(settings, progressMonitor, cbObj); - - /**** RAMAN TBD: set other params needed by AddImageTask - such as TZ and NoFatOrhpans **/ - addImageTask.SetImageOptions(imagePath); - - + addImageTask = new AddImageTask(progressMonitor, cbObj); + // set the image options needed by AddImageTask - such as TZ and NoFatOrphans **/ + addImageTask.SetImageOptions(imagePath, timeZone, noFatOrphans); + addImageTask.execute(); return; } - /*** - @Override - public String[] getErrors() { - - logger.log(Level.INFO, "RAMAN getErrors()..."); - - // RAMAN TBD - return null; - } - *****/ - @Override public void cancel() { @@ -155,12 +132,6 @@ public class ImageDSProcessor implements DataSourceProcessor { return; } - /***** - @Override - public List getNewContents() { - return addImageTask.getNewContents(); - } - * *****/ @Override public void reset() { @@ -192,6 +163,8 @@ public class ImageDSProcessor implements DataSourceProcessor { private class AddImageTask extends SwingWorker { + private Logger logger = Logger.getLogger(AddImageTask.class.getName()); + private Case currentCase; // true if the process was requested to stop private boolean cancelled = false; @@ -202,9 +175,6 @@ public class ImageDSProcessor implements DataSourceProcessor { private List errorList = new ArrayList(); - private WizardDescriptor wizDescriptor; - - private Logger logger = Logger.getLogger(AddImageTask.class.getName()); private DSPProgressMonitor progressMonitor; private DSPCallback callbackObj; @@ -220,12 +190,10 @@ public class ImageDSProcessor implements DataSourceProcessor { - public void SetImageOptions(String imgPath) { + public void SetImageOptions(String imgPath, String tz, boolean noOrphans) { this.imagePath = imgPath; - - // RAMAN TBD: also set TZ and noFatOrphans - // this.timeZone = tz; - // this.noFatOrphans = noFatOrphans; + this.timeZone = tz; + this.noFatOrphans = noOrphans; } @@ -264,12 +232,11 @@ public class ImageDSProcessor implements DataSourceProcessor { } - protected AddImageTask(WizardDescriptor settings, DSPProgressMonitor aProgressMonitor, DSPCallback cbObj ) { + protected AddImageTask(DSPProgressMonitor aProgressMonitor, DSPCallback cbObj ) { this.progressMonitor = aProgressMonitor; currentCase = Case.getCurrentCase(); this.callbackObj = cbObj; - this.wizDescriptor = settings; } /** @@ -307,19 +274,6 @@ public class ImageDSProcessor implements DataSourceProcessor { logger.log(Level.WARNING, "Errors occurred while running add image, could not acquire lock. ", ex); return 0; } - - - - - - /*** RAMAN TBD: TZ and NoFatOrpjhans should be moved into the Image panel and then should be set by the DSP - * instead of the settings. - * - */ - timeZone = wizDescriptor.getProperty(AddImageAction.TIMEZONE_PROP).toString(); - noFatOrphans = ((Boolean) wizDescriptor.getProperty(AddImageAction.NOFATORPHANS_PROP)).booleanValue(); - - addImageProcess = currentCase.makeAddImageProcess(timeZone, true, noFatOrphans); fetcher = new CurrentDirectoryFetcher(progressMonitor, addImageProcess); @@ -355,14 +309,9 @@ public class ImageDSProcessor implements DataSourceProcessor { * * @throws Exception if commit or adding the image to the case failed */ - private void commitImage(WizardDescriptor settings) throws Exception { + private void commitImage() throws Exception { logger.log(Level.INFO, "RAMAN: commitImage()..."); - - String contentPath = (String) settings.getProperty(AddImageAction.DATASOURCEPATH_PROP); - - String timezone = settings.getProperty(AddImageAction.TIMEZONE_PROP).toString(); - settings.putProperty(AddImageAction.IMAGEID_PROP, ""); long imageId = 0; try { @@ -376,7 +325,7 @@ public class ImageDSProcessor implements DataSourceProcessor { SleuthkitCase.dbWriteUnlock(); if (imageId != 0) { - Image newImage = Case.getCurrentCase().addImage(contentPath, imageId, timezone); + Image newImage = Case.getCurrentCase().addImage(imagePath, imageId, timeZone); //while we have the image, verify the size of its contents String verificationErrors = newImage.verifyImageSize(); @@ -385,23 +334,13 @@ public class ImageDSProcessor implements DataSourceProcessor { errorList.add(verificationErrors); } - // + // Add the image to the list of new content newContents.add(newImage); - - // RAMAN TBD: imageID should be return via the callback - settings.putProperty(AddImageAction.IMAGEID_PROP, imageId); + } - // Can't bail and revert image add after commit, so disable image cleanup - // task - - - - settings.putProperty(AddImageAction.IMAGECLEANUPTASK_PROP, null); - logger.log(Level.INFO, "Image committed, imageId: " + imageId); logger.log(Level.INFO, PlatformUtil.getAllMemUsageInfo()); - } } @@ -424,7 +363,6 @@ public class ImageDSProcessor implements DataSourceProcessor { addImageDone = true; // attempt actions that might fail and force the process to stop - if (cancelled || hasCritError) { logger.log(Level.INFO, "Handling errors or interruption that occured in add image process"); revert(); @@ -469,7 +407,7 @@ public class ImageDSProcessor implements DataSourceProcessor { if (addImageProcess != null) { // and if we're done configuring ingest // commit anything try { - commitImage(wizDescriptor); + commitImage(); } catch (Exception ex) { errorList.add(ex.getMessage()); // Log error/display warning diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form index 313ae952b8..39566f7376 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form @@ -31,8 +31,20 @@ - - + + + + + + + + + + + + + + @@ -45,6 +57,16 @@ + + + + + + + + + + @@ -74,5 +96,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java index 275c3dced8..e7aaa3e987 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java @@ -22,7 +22,10 @@ import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.File; import java.util.ArrayList; +import java.util.Calendar; import java.util.List; +import java.util.SimpleTimeZone; +import java.util.TimeZone; import javax.swing.JFileChooser; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; @@ -47,6 +50,10 @@ public class ImageFilePanel extends JPanel implements DocumentListener { fc.addChoosableFileFilter(AddImageWizardChooseDataSourceVisual.rawFilter); fc.addChoosableFileFilter(AddImageWizardChooseDataSourceVisual.encaseFilter); fc.setFileFilter(AddImageWizardChooseDataSourceVisual.allFilter); + + createTimeZoneList(); + noFatOrphansCheckbox.setEnabled(true); + } /** @@ -80,6 +87,10 @@ public class ImageFilePanel extends JPanel implements DocumentListener { pathLabel = new javax.swing.JLabel(); browseButton = new javax.swing.JButton(); pathTextField = new javax.swing.JTextField(); + timeZoneLabel = new javax.swing.JLabel(); + timeZoneComboBox = new javax.swing.JComboBox(); + noFatOrphansCheckbox = new javax.swing.JCheckBox(); + descLabel = new javax.swing.JLabel(); setMinimumSize(new java.awt.Dimension(0, 65)); setPreferredSize(new java.awt.Dimension(403, 65)); @@ -95,6 +106,15 @@ public class ImageFilePanel extends JPanel implements DocumentListener { pathTextField.setText(org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.pathTextField.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(timeZoneLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.timeZoneLabel.text")); // NOI18N + + timeZoneComboBox.setMaximumRowCount(30); + + org.openide.awt.Mnemonics.setLocalizedText(noFatOrphansCheckbox, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.noFatOrphansCheckbox.text")); // NOI18N + noFatOrphansCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.noFatOrphansCheckbox.toolTipText")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(descLabel, org.openide.util.NbBundle.getMessage(ImageFilePanel.class, "ImageFilePanel.descLabel.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -105,8 +125,17 @@ public class ImageFilePanel extends JPanel implements DocumentListener { .addComponent(browseButton) .addGap(2, 2, 2)) .addGroup(layout.createSequentialGroup() - .addComponent(pathLabel) - .addGap(0, 284, Short.MAX_VALUE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(timeZoneLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 215, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(pathLabel) + .addComponent(noFatOrphansCheckbox) + .addGroup(layout.createSequentialGroup() + .addGap(21, 21, 21) + .addComponent(descLabel))) + .addGap(0, 20, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -115,7 +144,16 @@ public class ImageFilePanel extends JPanel implements DocumentListener { .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))) + .addComponent(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(18, 18, 18) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(timeZoneLabel) + .addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(noFatOrphansCheckbox) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(descLabel) + .addContainerGap(19, Short.MAX_VALUE)) ); }// //GEN-END:initComponents @@ -137,8 +175,12 @@ public class ImageFilePanel extends JPanel implements DocumentListener { // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton browseButton; + private javax.swing.JLabel descLabel; + private javax.swing.JCheckBox noFatOrphansCheckbox; private javax.swing.JLabel pathLabel; private javax.swing.JTextField pathTextField; + private javax.swing.JComboBox timeZoneComboBox; + private javax.swing.JLabel timeZoneLabel; // End of variables declaration//GEN-END:variables /** @@ -156,6 +198,16 @@ public class ImageFilePanel extends JPanel implements DocumentListener { pathTextField.setText(s); } + public String getTimeZone() { + String tz = timeZoneComboBox.getSelectedItem().toString(); + return tz.substring(tz.indexOf(")") + 2).trim(); + + } + + boolean getNoFatOrphans() { + return noFatOrphansCheckbox.isSelected(); + } + public String getContentType() { return "IMAGE"; } @@ -173,6 +225,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener { if (path == null || path.isEmpty()) { return false; } + boolean isExist = Case.pathExists(path); boolean isPhysicalDrive = Case.isPhysicalDrive(path); boolean isPartition = Case.isPartition(path); @@ -180,6 +233,42 @@ public class ImageFilePanel extends JPanel implements DocumentListener { return (isExist || isPhysicalDrive || isPartition); } + + /** + * Creates the drop down list for the time zones and then makes the local + * machine time zone to be selected. + */ + public void createTimeZoneList() { + // load and add all timezone + String[] ids = SimpleTimeZone.getAvailableIDs(); + for (String id : ids) { + TimeZone zone = TimeZone.getTimeZone(id); + int offset = zone.getRawOffset() / 1000; + int hour = offset / 3600; + int minutes = (offset % 3600) / 60; + String item = String.format("(GMT%+d:%02d) %s", hour, minutes, id); + + /* + * DateFormat dfm = new SimpleDateFormat("z"); + * dfm.setTimeZone(zone); boolean hasDaylight = + * zone.useDaylightTime(); String first = dfm.format(new Date(2010, + * 1, 1)); String second = dfm.format(new Date(2011, 6, 6)); int mid + * = hour * -1; String result = first + Integer.toString(mid); + * if(hasDaylight){ result = result + second; } + * timeZoneComboBox.addItem(item + " (" + result + ")"); + */ + timeZoneComboBox.addItem(item); + } + // get the current timezone + TimeZone thisTimeZone = Calendar.getInstance().getTimeZone(); + int thisOffset = thisTimeZone.getRawOffset() / 1000; + int thisHour = thisOffset / 3600; + int thisMinutes = (thisOffset % 3600) / 60; + String formatted = String.format("(GMT%+d:%02d) %s", thisHour, thisMinutes, thisTimeZone.getID()); + + // set the selected timezone + timeZoneComboBox.setSelectedItem(formatted); + } /** * Update functions are called by the pathTextField which has this set * as it's DocumentEventListener. Each update function fires a property change diff --git a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties index 4744f62146..357d499b2f 100644 --- a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties +++ b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties @@ -1,5 +1,5 @@ #Updated by build script -#Wed, 25 Sep 2013 13:55:37 -0400 +#Thu, 17 Oct 2013 13:25:49 -0400 LBL_splash_window_title=Starting Autopsy SPLASH_HEIGHT=288 SPLASH_WIDTH=538 diff --git a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties index 0dbd5e9a00..913a689dc0 100644 --- a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties +++ b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties @@ -1,5 +1,5 @@ #Updated by build script -#Wed, 25 Sep 2013 13:55:37 -0400 +#Thu, 17 Oct 2013 13:25:49 -0400 CTL_MainWindow_Title=Autopsy 3.0.7 CTL_MainWindow_Title_No_Project=Autopsy 3.0.7 From 26fcd4b49ed1fc5ab93e341dbd05282d823a7a22 Mon Sep 17 00:00:00 2001 From: raman-bt Date: Thu, 17 Oct 2013 15:35:26 -0400 Subject: [PATCH 016/169] Sundry cleanup. --- .../AddImageWizardChooseDataSourceVisual.java | 17 ++------- .../AddImageWizardIngestConfigPanel.java | 11 ++++++ .../autopsy/casemodule/ImageDSProcessor.java | 20 +--------- .../autopsy/casemodule/ImageFilePanel.form | 4 +- .../autopsy/casemodule/ImageFilePanel.java | 37 +++++++++++++++---- 5 files changed, 46 insertions(+), 43 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java index 96440ffd3f..ab9746b62c 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java @@ -53,20 +53,7 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { UPDATE_UI, FOCUS_NEXT }; - static final List rawExt = Arrays.asList(new String[]{".img", ".dd", ".001", ".aa", ".raw"}); - static final String rawDesc = "Raw Images (*.img, *.dd, *.001, *.aa, *.raw)"; - static GeneralFilter rawFilter = new GeneralFilter(rawExt, rawDesc); - static final List encaseExt = Arrays.asList(new String[]{".e01"}); - static final String encaseDesc = "Encase Images (*.e01)"; - static GeneralFilter encaseFilter = new GeneralFilter(encaseExt, encaseDesc); - static final List allExt = new ArrayList(); - - static { - allExt.addAll(rawExt); - allExt.addAll(encaseExt); - } - static final String allDesc = "All Supported Types"; - static GeneralFilter allFilter = new GeneralFilter(allExt, allDesc); + private AddImageWizardChooseDataSourcePanel wizPanel; private JPanel currentPanel; @@ -123,6 +110,8 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { if (!datasourceProcessorsMap.containsKey(dsProcessor.getType()) ) { if (!datasourceProcessorsMap.containsKey(dsProcessor.getType()) ) { + + dsProcessor.reset(); datasourceProcessorsMap.put(dsProcessor.getType(), dsProcessor); } else { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java index 832f93d348..4c5b879aa6 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java @@ -273,6 +273,17 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel - + - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java index e7aaa3e987..04a9d78767 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java @@ -22,6 +22,7 @@ import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.File; import java.util.ArrayList; +import java.util.Arrays; import java.util.Calendar; import java.util.List; import java.util.SimpleTimeZone; @@ -35,6 +36,24 @@ import javax.swing.JPanel; * ImageTypePanel for adding an image file such as .img, .E0x, .00x, etc. */ public class ImageFilePanel extends JPanel implements DocumentListener { + + static final List rawExt = Arrays.asList(new String[]{".img", ".dd", ".001", ".aa", ".raw"}); + static final String rawDesc = "Raw Images (*.img, *.dd, *.001, *.aa, *.raw)"; + static GeneralFilter rawFilter = new GeneralFilter(rawExt, rawDesc); + static final List encaseExt = Arrays.asList(new String[]{".e01"}); + static final String encaseDesc = "Encase Images (*.e01)"; + static GeneralFilter encaseFilter = new GeneralFilter(encaseExt, encaseDesc); + static final List allExt = new ArrayList(); + + static { + allExt.addAll(rawExt); + allExt.addAll(encaseExt); + } + static final String allDesc = "All Supported Types"; + static GeneralFilter allFilter = new GeneralFilter(allExt, allDesc); + + + private static ImageFilePanel instance = null; private PropertyChangeSupport pcs = null; private JFileChooser fc = new JFileChooser(); @@ -47,13 +66,11 @@ public class ImageFilePanel extends JPanel implements DocumentListener { fc.setDragEnabled(false); fc.setFileSelectionMode(JFileChooser.FILES_ONLY); fc.setMultiSelectionEnabled(false); - fc.addChoosableFileFilter(AddImageWizardChooseDataSourceVisual.rawFilter); - fc.addChoosableFileFilter(AddImageWizardChooseDataSourceVisual.encaseFilter); - fc.setFileFilter(AddImageWizardChooseDataSourceVisual.allFilter); + fc.addChoosableFileFilter(rawFilter); + fc.addChoosableFileFilter(encaseFilter); + fc.setFileFilter(allFilter); createTimeZoneList(); - noFatOrphansCheckbox.setEnabled(true); - } /** @@ -148,12 +165,12 @@ public class ImageFilePanel extends JPanel implements DocumentListener { .addGap(18, 18, 18) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(timeZoneLabel) - .addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(noFatOrphansCheckbox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(descLabel) - .addContainerGap(19, Short.MAX_VALUE)) + .addContainerGap(13, Short.MAX_VALUE)) ); }// //GEN-END:initComponents @@ -213,7 +230,11 @@ public class ImageFilePanel extends JPanel implements DocumentListener { } public void reset() { - //nothing to reset + //reset the UI elements to default + + pathTextField.setText(null); + + } /** From f67cd305fcf95fb31c150d6ff4a1e26bbe2812fe Mon Sep 17 00:00:00 2001 From: raman-bt Date: Fri, 18 Oct 2013 08:54:40 -0400 Subject: [PATCH 017/169] Move all interfaces to corecomponentinterfaces package. --- .../casemodule/AddImageWizardAddingProgressPanel.java | 2 ++ .../casemodule/AddImageWizardChooseDataSourceVisual.java | 2 ++ .../autopsy/casemodule/AddImageWizardIngestConfigPanel.java | 6 ++++-- .../org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java | 4 ++++ .../DSPCallback.java | 6 +++--- .../DSPProgressMonitor.java | 2 +- .../DataSourceProcessor.java | 3 +-- 7 files changed, 17 insertions(+), 8 deletions(-) rename Core/src/org/sleuthkit/autopsy/{casemodule => corecomponentinterfaces}/DSPCallback.java (78%) rename Core/src/org/sleuthkit/autopsy/{casemodule => corecomponentinterfaces}/DSPProgressMonitor.java (89%) rename Core/src/org/sleuthkit/autopsy/{casemodule => corecomponentinterfaces}/DataSourceProcessor.java (95%) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java index 3817565c54..46592d269e 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.casemodule; + import java.awt.Color; import java.util.HashSet; import java.util.Iterator; @@ -27,6 +28,7 @@ import javax.swing.event.ChangeListener; import org.openide.WizardDescriptor; import org.openide.util.HelpCtx; import org.openide.util.Lookup; +import org.sleuthkit.autopsy.corecomponentinterfaces.DSPProgressMonitor; /** * The final panel of the add image wizard. It displays a progress bar and diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java index ab9746b62c..12fdeceb1f 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.casemodule; + import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -39,6 +40,7 @@ import javax.swing.event.DocumentEvent; import javax.swing.event.ListDataListener; import org.openide.util.Lookup; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; /** * visual component for the first panel of add image wizard. Allows user to pick diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java index 4c5b879aa6..df965f7ea0 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.casemodule; + import org.sleuthkit.autopsy.ingest.IngestConfigurator; import java.awt.Color; import java.awt.Component; @@ -51,7 +52,8 @@ import org.sleuthkit.datamodel.TskDataException; import org.sleuthkit.datamodel.TskException; import org.sleuthkit.datamodel.Volume; import org.sleuthkit.datamodel.VolumeSystem; - +import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; /** * second panel of add image wizard, allows user to configure ingest modules. * @@ -249,7 +251,7 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel errList, List contents) { + public void doneEDT(DSPCallback.DSP_Result result, List errList, List contents) { dataSourceProcessorDone(result, errList, contents ); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java index 5e5b077b6b..dc0c1bf4b2 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java @@ -4,6 +4,7 @@ */ package org.sleuthkit.autopsy.casemodule; + import java.awt.Color; import java.awt.EventQueue; import java.awt.Window; @@ -28,6 +29,9 @@ import org.sleuthkit.datamodel.SleuthkitJNI; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskDataException; import org.sleuthkit.datamodel.TskException; +import org.sleuthkit.autopsy.corecomponentinterfaces.DSPProgressMonitor; +import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; /** * diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/DSPCallback.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DSPCallback.java similarity index 78% rename from Core/src/org/sleuthkit/autopsy/casemodule/DSPCallback.java rename to Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DSPCallback.java index 58ec4d8ce0..553cb71ebe 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/DSPCallback.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DSPCallback.java @@ -2,7 +2,7 @@ * To change this template, choose Tools | Templates * and open the template in the editor. */ -package org.sleuthkit.autopsy.casemodule; +package org.sleuthkit.autopsy.corecomponentinterfaces; import java.awt.EventQueue; import java.util.List; @@ -21,7 +21,7 @@ public abstract class DSPCallback { NONCRITICAL_ERRORS, }; - void done(DSP_Result result, List errList, List newContents) + public void done(DSP_Result result, List errList, List newContents) { final DSP_Result resultf = result; @@ -38,5 +38,5 @@ public abstract class DSPCallback { }); } - abstract void doneEDT(DSP_Result result, List errList, List newContents); + public abstract void doneEDT(DSP_Result result, List errList, List newContents); }; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/DSPProgressMonitor.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DSPProgressMonitor.java similarity index 89% rename from Core/src/org/sleuthkit/autopsy/casemodule/DSPProgressMonitor.java rename to Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DSPProgressMonitor.java index d3acea384c..b375301aed 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/DSPProgressMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DSPProgressMonitor.java @@ -2,7 +2,7 @@ * To change this template, choose Tools | Templates * and open the template in the editor. */ -package org.sleuthkit.autopsy.casemodule; +package org.sleuthkit.autopsy.corecomponentinterfaces; /* * An GUI agnostic DSPProgressMonitor interface for DataSorceProcesssors to diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/DataSourceProcessor.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessor.java similarity index 95% rename from Core/src/org/sleuthkit/autopsy/casemodule/DataSourceProcessor.java rename to Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessor.java index b934809dea..59fc291c6e 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/DataSourceProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessor.java @@ -16,12 +16,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.casemodule; +package org.sleuthkit.autopsy.corecomponentinterfaces; import java.util.List; import javax.swing.JPanel; import org.openide.WizardDescriptor; -import org.sleuthkit.autopsy.casemodule.DSPProgressMonitor; import org.sleuthkit.datamodel.Content; public interface DataSourceProcessor { From aa01261c9a50ad31ff374e55fb8cb6b562e590d6 Mon Sep 17 00:00:00 2001 From: raman-bt Date: Fri, 18 Oct 2013 10:11:47 -0400 Subject: [PATCH 018/169] Cleanup comments, logging, javadocs etc. --- .../AddImageWizardChooseDataSourcePanel.java | 11 +- .../AddImageWizardChooseDataSourceVisual.java | 6 +- .../AddImageWizardIngestConfigPanel.java | 31 ++-- .../autopsy/casemodule/ContentTypePanel.java | 96 ----------- .../autopsy/casemodule/ImageDSProcessor.java | 156 ++++++++++-------- .../corecomponentinterfaces/DSPCallback.java | 9 +- 6 files changed, 115 insertions(+), 194 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/ContentTypePanel.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java index 777b402eb3..1588d865b5 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java @@ -180,10 +180,11 @@ class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Panel errList, List contents) { @@ -264,18 +261,22 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel errList, List contents) { - logger.log(Level.INFO, "RAMAN dataSourceProcessorDone()."); // disable the cleanup task cleanupTask.disable(); - // Get attention for the process finish java.awt.Toolkit.getDefaultToolkit().beep(); //BEEP! AddImageWizardAddingProgressVisual panel = progressPanel.getComponent(); @@ -295,8 +296,8 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel 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.casemodule; - -import java.beans.PropertyChangeListener; -import javax.swing.JPanel; -import java.util.ArrayList; -import java.util.List; - -/************ -abstract class ContentTypePanel extends JPanel { - - // Collection of panels that are dynamically discovered and registered - private static List registeredPanels = new ArrayList();; - - public static void RegisterPanel(ContentTypePanel panel) - { - // RAMAN TBD: check if this panel is already regsitered... - - registeredPanels.add(panel); - - - } - //public enum ContentType{IMAGE, DISK, LOCAL}; - - - private String contentType; - -// -// * Returns a list off all the panels extending ImageTypePanel. -// * @return list of all ImageTypePanels -// - public static ContentTypePanel[] getPanels() { - //return new ContentTypePanel[] {ImageFilePanel.getDefault(), LocalDiskPanel.getDefault(), LocalFilesPanel.getDefault() }; - - - - - - return registeredPanels.toArray(new ContentTypePanel[registeredPanels.size()]); - } - -// -// * Return the path of the selected content in this panel. -// * @return paths to selected content (one or more if multiselect supported) -// - abstract public String getContentPaths(); - -// -// * Set the selected content in this panel to the provided path. -// * This function is optional. -// * @param s path to selected content -// - abstract public void setContentPath(String s); - -// -// * Get content type (image, disk, local file) of the source this wizard panel is for -// * @return ContentType of the source panel -// - abstract public String getContentType(); - -// -// * Returns if the next button should be enabled in the current wizard. -// * @return true if the next button should be enabled, false otherwise -// - abstract public boolean enableNext(); - -// -// * Tells this panel to reset itself -// - abstract public void reset(); - -// -// * Tells this panel it has been selected. -// - abstract public void select(); - - -} -***************/ \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java index dc0c1bf4b2..89098c8f46 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java @@ -34,81 +34,101 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; /** - * - * @author raman + * Image data source processor. + * Handles the addition of "disk images" to Autopsy. + * + * An instance of this class is created via the Netbeans Lookup() method. + * */ @ServiceProvider(service = DataSourceProcessor.class) public class ImageDSProcessor implements DataSourceProcessor { static final Logger logger = Logger.getLogger(ImageDSProcessor.class.getName()); + // The Config UI panel that plugins into the Choose Data Source Wizard private ImageFilePanel imageFilePanel; + + // The Background task that does the actual work of adding the image private AddImageTask addImageTask; + // true of cancelled by the caller private boolean cancelled = false; DSPCallback callbackObj = null; // set to TRUE if the image options have been set via API and config Jpanel should be ignored private boolean imageOptionsSet = false; + + // image options private String imagePath; private String timeZone; private boolean noFatOrphans; - + /* + * A no argument constructor is required for the NM lookup() method to create an object + */ public ImageDSProcessor() { - logger.log(Level.INFO, "RAMAN ImageDSProcessor()..."); // Create the config panel imageFilePanel = ImageFilePanel.getDefault(); } - + /** + * Returns the Data source type (string) handled by this DSP + * + * @return String the data source type + **/ @Override public String getType() { - - logger.log(Level.INFO, "RAMAN getName()..."); - return imageFilePanel.getContentType(); - } - + /** + * Returns the JPanel for collecting the Data source information + * + * @return JPanel the config panel + **/ @Override public JPanel getPanel() { - - logger.log(Level.INFO, "RAMAN getPanel()..."); - + // RAMAN TBD: we should ask the panel to preload with any saved settings imageFilePanel.select(); return imageFilePanel; } - + /** + * Validates the data collected by the JPanel + * + * @return String returns NULL if success, error string if there is any errors + **/ @Override public String validatePanel() { - logger.log(Level.INFO, "RAMAN validatePanel()..."); - if (imageFilePanel.validatePanel() ) return null; else return "Error in panel"; } - + /** + * Runs the data source processor. + * This must kick off processing the data source in background + * + * @param progressMonitor Progress monitor to report progress during processing + * @param cbObj callback to call when processing is done. + **/ @Override public void run(DSPProgressMonitor progressMonitor, DSPCallback cbObj) { - logger.log(Level.INFO, "RAMAN run()..."); - callbackObj = cbObj; cancelled = false; if (!imageOptionsSet) { + // RAMAN TBD: we should ask the panel to save the current settings now + // get the image options from the panel imagePath = imageFilePanel.getContentPaths(); timeZone = imageFilePanel.getTimeZone(); @@ -124,24 +144,25 @@ public class ImageDSProcessor implements DataSourceProcessor { return; } - + + /** + * Cancel the data source processing + **/ @Override public void cancel() { - logger.log(Level.INFO, "RAMAN cancelProcessing()..."); - cancelled = true; addImageTask.cancelTask(); return; } - + /** + * Reset the data source processor + **/ @Override public void reset() { - logger.log(Level.INFO, "RAMAN reset()..."); - // reset the config panel imageFilePanel.reset(); @@ -154,6 +175,15 @@ public class ImageDSProcessor implements DataSourceProcessor { return; } + /** + * Sets the data source options externally. + * To be used by a client that does not have a UI and does not use the JPanel to + * collect this information from a user. + * + * @param imgPath path to thew image or first image + * @param String timeZone + * @param noFat whether to parse FAT orphans + **/ public void SetDataSourceOptions(String imgPath, String tz, boolean noFat) { this.imagePath = imgPath; @@ -164,7 +194,9 @@ public class ImageDSProcessor implements DataSourceProcessor { } - + /* + * Background task that actualy adds the image + */ private class AddImageTask extends SwingWorker { private Logger logger = Logger.getLogger(AddImageTask.class.getName()); @@ -193,14 +225,19 @@ public class ImageDSProcessor implements DataSourceProcessor { boolean noFatOrphans; - + /* + * Sets the name/path and other options for the iimage to be processed + */ public void SetImageOptions(String imgPath, String tz, boolean noOrphans) { this.imagePath = imgPath; this.timeZone = tz; this.noFatOrphans = noOrphans; } - + /* + * A Swingworker that updates the progressMonitor with the name of the + * directory currently being processed by the AddImageTask + */ private class CurrentDirectoryFetcher extends SwingWorker { DSPProgressMonitor progressMonitor; @@ -209,7 +246,6 @@ public class ImageDSProcessor implements DataSourceProcessor { CurrentDirectoryFetcher(DSPProgressMonitor aProgressMonitor, SleuthkitJNI.CaseDbHandle.AddImageProcess proc) { this.progressMonitor = aProgressMonitor; this.process = proc; - // this.progressBar = aProgressBar; } /** @@ -252,15 +288,10 @@ public class ImageDSProcessor implements DataSourceProcessor { */ @Override protected Integer doInBackground() { - - logger.log(Level.INFO, "RAMAN: doInBackground()"); this.setProgress(0); errorList.clear(); - - - try { //lock DB for writes in EWT thread //wait until lock acquired in EWT @@ -315,8 +346,6 @@ public class ImageDSProcessor implements DataSourceProcessor { */ private void commitImage() throws Exception { - logger.log(Level.INFO, "RAMAN: commitImage()..."); - long imageId = 0; try { imageId = addImageProcess.commit(); @@ -352,43 +381,33 @@ public class ImageDSProcessor implements DataSourceProcessor { * * (called by EventDispatch Thread after doInBackground finishes) * - * Must Not return without invoking the callBack. + * Must Not return without invoking the callBack, unless the caller canceled */ @Override protected void done() { - - logger.log(Level.INFO, "RAMAN: done()..."); setProgress(100); - // cancel + // cancel the directory fetcher fetcher.cancel(true); - addImageDone = true; - + addImageDone = true; // attempt actions that might fail and force the process to stop if (cancelled || hasCritError) { logger.log(Level.INFO, "Handling errors or interruption that occured in add image process"); revert(); - // Do not return yet. Callback must be called } if (!errorList.isEmpty()) { - logger.log(Level.INFO, "Handling non-critical errors that occured in add image process"); - - // error are returned back to the caller } // When everything happens without an error: if (!(cancelled || hasCritError)) { try { - - - // Tell the panel we're done + // Tell the progress monitor we're done progressMonitor.setProgress(100); - if (newContents.isEmpty()) { if (addImageProcess != null) { // and if we're done configuring ingest // commit anything @@ -408,8 +427,6 @@ public class ImageDSProcessor implements DataSourceProcessor { logger.log(Level.INFO, "Assuming image already committed, will not commit."); } - - } catch (Exception ex) { //handle unchecked exceptions post image add @@ -428,13 +445,14 @@ public class ImageDSProcessor implements DataSourceProcessor { if (!cancelled) doCallBack(); + return; } - - void doCallBack() - { - logger.log(Level.INFO, "RAMAN In doCallback()"); - + /* + * Call the callback with proper parameters + */ + private void doCallBack() + { DSPCallback.DSP_Result result; if (hasCritError) { @@ -446,14 +464,15 @@ public class ImageDSProcessor implements DataSourceProcessor { else { result = DSPCallback.DSP_Result.NO_ERRORS; } - + + // invoke the callcak, passing it the result, list of new contents, and list of errors callbackObj.done(result, errorList, newContents); } - - void cancelTask() { - - logger.log(Level.INFO, "RAMAN: cancelTask()..."); + /* + * cancel the image addition, if possible + */ + public void cancelTask() { cancelled = true; @@ -474,11 +493,11 @@ public class ImageDSProcessor implements DataSourceProcessor { } } } - void interrupt() throws Exception { + /* + * Interrurp the add image process if it is still running + */ + private void interrupt() throws Exception { - logger.log(Level.INFO, "RAMAN: interrupt()..."); - - //interrupted = true; try { logger.log(Level.INFO, "interrupt() add image process"); addImageProcess.stop(); //it might take time to truly stop processing and writing to db @@ -487,10 +506,11 @@ public class ImageDSProcessor implements DataSourceProcessor { } } - //runs in EWT + /* + * Revert - if image has already been added but not committed yet + */ void revert() { - logger.log(Level.INFO, "RAMAN: revert()..."); if (!reverted) { try { diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DSPCallback.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DSPCallback.java index 553cb71ebe..b5c4b7cba9 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DSPCallback.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DSPCallback.java @@ -9,8 +9,7 @@ import java.util.List; import org.sleuthkit.datamodel.Content; /** - * - * @author raman + * Abstract class for a callback */ public abstract class DSPCallback { @@ -21,6 +20,9 @@ public abstract class DSPCallback { NONCRITICAL_ERRORS, }; + /* + * Invoke the caller supplied callback function on the EDT thread + */ public void done(DSP_Result result, List errList, List newContents) { @@ -38,5 +40,8 @@ public abstract class DSPCallback { }); } + /* + * calling code overrides to provide its own calllback + */ public abstract void doneEDT(DSP_Result result, List errList, List newContents); }; From 1f7e98f28e95d9f79a5b40800cff955207c4173d Mon Sep 17 00:00:00 2001 From: raman-bt Date: Fri, 18 Oct 2013 12:22:57 -0400 Subject: [PATCH 019/169] Move AddImageTask out of ImageDSProcessor so it can be reused. --- .../autopsy/casemodule/AddImageTask.java | 356 ++++++++++++++++++ .../autopsy/casemodule/ImageDSProcessor.java | 334 ---------------- 2 files changed, 356 insertions(+), 334 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java new file mode 100644 index 0000000000..def759ca5b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java @@ -0,0 +1,356 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ +package org.sleuthkit.autopsy.casemodule; + +import java.awt.EventQueue; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import javax.swing.SwingWorker; +import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback; +import org.sleuthkit.autopsy.corecomponentinterfaces.DSPProgressMonitor; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.PlatformUtil; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.Image; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.SleuthkitJNI; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskDataException; +import org.sleuthkit.datamodel.TskException; + +public class AddImageTask extends SwingWorker { + + private Logger logger = Logger.getLogger(AddImageTask.class.getName()); + + private Case currentCase; + // true if the process was requested to stop + private boolean cancelled = false; + //true if revert has been invoked. + private boolean reverted = false; + private boolean hasCritError = false; + private boolean addImageDone = false; + + private List errorList = new ArrayList(); + + private DSPProgressMonitor progressMonitor; + private DSPCallback callbackObj; + + private final List newContents = Collections.synchronizedList(new ArrayList()); + + private SleuthkitJNI.CaseDbHandle.AddImageProcess addImageProcess; + private CurrentDirectoryFetcher fetcher; + + private String imagePath; + private String dataSourcetype; + String timeZone; + boolean noFatOrphans; + + + /* + * Sets the name/path and other options for the iimage to be processed + */ + public void SetImageOptions(String imgPath, String tz, boolean noOrphans) { + this.imagePath = imgPath; + this.timeZone = tz; + this.noFatOrphans = noOrphans; + } + + /* + * A Swingworker that updates the progressMonitor with the name of the + * directory currently being processed by the AddImageTask + */ + private class CurrentDirectoryFetcher extends SwingWorker { + + DSPProgressMonitor progressMonitor; + SleuthkitJNI.CaseDbHandle.AddImageProcess process; + + CurrentDirectoryFetcher(DSPProgressMonitor aProgressMonitor, SleuthkitJNI.CaseDbHandle.AddImageProcess proc) { + this.progressMonitor = aProgressMonitor; + this.process = proc; + } + + /** + * @return the currently processing directory + */ + @Override + protected Integer doInBackground() { + try { + while (!(addImageDone)) { + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + progressMonitor.setText(process.currentDirectory()); + } + }); + + Thread.sleep(2 * 1000); + } + return 1; + } catch (InterruptedException ie) { + return -1; + } + } + } + + + protected AddImageTask(DSPProgressMonitor aProgressMonitor, DSPCallback cbObj ) { + this.progressMonitor = aProgressMonitor; + currentCase = Case.getCurrentCase(); + + this.callbackObj = cbObj; + } + + /** + * Starts the addImage process, but does not commit the results. + * + * @return + * + * @throws Exception + */ + @Override + protected Integer doInBackground() { + + this.setProgress(0); + + errorList.clear(); + try { + //lock DB for writes in EWT thread + //wait until lock acquired in EWT + EventQueue.invokeAndWait(new Runnable() { + @Override + public void run() { + SleuthkitCase.dbWriteLock(); + } + }); + } catch (InterruptedException ex) { + logger.log(Level.WARNING, "Errors occurred while running add image, could not acquire lock. ", ex); + return 0; + + } catch (InvocationTargetException ex) { + logger.log(Level.WARNING, "Errors occurred while running add image, could not acquire lock. ", ex); + return 0; + } + + addImageProcess = currentCase.makeAddImageProcess(timeZone, true, noFatOrphans); + fetcher = new CurrentDirectoryFetcher(progressMonitor, addImageProcess); + + try { + progressMonitor.setIndeterminate(true); + progressMonitor.setProgress(0); + + fetcher.execute(); + addImageProcess.run(new String[]{this.imagePath}); + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Core errors occurred while running add image. ", ex); + //critical core/system error and process needs to be interrupted + hasCritError = true; + errorList.add(ex.getMessage()); + } catch (TskDataException ex) { + logger.log(Level.WARNING, "Data errors occurred while running add image. ", ex); + errorList.add(ex.getMessage()); + } finally { + // process is over, doesn't need to be dealt with if cancel happens + + } + + return 0; + } + + /** + * Commit the finished AddImageProcess, and cancel the CleanupTask that + * would have reverted it. + * + * @param settings property set to get AddImageProcess and CleanupTask + * from + * + * @throws Exception if commit or adding the image to the case failed + */ + private void commitImage() throws Exception { + + long imageId = 0; + try { + imageId = addImageProcess.commit(); + } catch (TskException e) { + logger.log(Level.WARNING, "Errors occured while committing the image", e); + errorList.add(e.getMessage()); + } finally { + //commit done, unlock db write in EWT thread + //before doing anything else + SleuthkitCase.dbWriteUnlock(); + + if (imageId != 0) { + Image newImage = Case.getCurrentCase().addImage(imagePath, imageId, timeZone); + + //while we have the image, verify the size of its contents + String verificationErrors = newImage.verifyImageSize(); + if (verificationErrors.equals("") == false) { + //data error (non-critical) + errorList.add(verificationErrors); + } + + // Add the image to the list of new content + newContents.add(newImage); + + } + + logger.log(Level.INFO, "Image committed, imageId: " + imageId); + logger.log(Level.INFO, PlatformUtil.getAllMemUsageInfo()); + } + } + + /** + * + * (called by EventDispatch Thread after doInBackground finishes) + * + * Must Not return without invoking the callBack, unless the caller canceled + */ + @Override + protected void done() { + + setProgress(100); + + // cancel the directory fetcher + fetcher.cancel(true); + + addImageDone = true; + // attempt actions that might fail and force the process to stop + if (cancelled || hasCritError) { + logger.log(Level.INFO, "Handling errors or interruption that occured in add image process"); + revert(); + } + if (!errorList.isEmpty()) { + logger.log(Level.INFO, "Handling non-critical errors that occured in add image process"); + } + + // When everything happens without an error: + if (!(cancelled || hasCritError)) { + + try { + // Tell the progress monitor we're done + progressMonitor.setProgress(100); + + if (newContents.isEmpty()) { + if (addImageProcess != null) { // and if we're done configuring ingest + // commit anything + try { + commitImage(); + } catch (Exception ex) { + errorList.add(ex.getMessage()); + // Log error/display warning + logger.log(Level.SEVERE, "Error adding image to case.", ex); + } + } else { + logger.log(Level.SEVERE, "Missing image process object"); + } + } + + else { //already commited? + logger.log(Level.INFO, "Assuming image already committed, will not commit."); + } + + } catch (Exception ex) { + //handle unchecked exceptions post image add + + errorList.add(ex.getMessage()); + + logger.log(Level.WARNING, "Unexpected errors occurred while running post add image cleanup. ", ex); + + logger.log(Level.SEVERE, "Error adding image to case", ex); + } finally { + + + } + } + + // invoke the callBack, unless the caller cancelled + if (!cancelled) + doCallBack(); + + return; + } + + /* + * Call the callback with proper parameters + */ + private void doCallBack() + { + DSPCallback.DSP_Result result; + + if (hasCritError) { + result = DSPCallback.DSP_Result.CRITICAL_ERRORS; + } + else if (!errorList.isEmpty()) { + result = DSPCallback.DSP_Result.NONCRITICAL_ERRORS; + } + else { + result = DSPCallback.DSP_Result.NO_ERRORS; + } + + // invoke the callcak, passing it the result, list of new contents, and list of errors + callbackObj.done(result, errorList, newContents); + } + + /* + * cancel the image addition, if possible + */ + public void cancelTask() { + + cancelled = true; + + if (!addImageDone) { + try { + interrupt(); + } + catch (Exception ex) { + logger.log(Level.SEVERE, "Failed to interrup the add image task..."); + } + } + else { + try { + revert(); + } + catch(Exception ex) { + logger.log(Level.SEVERE, "Failed to revert the add image task..."); + } + } + } + /* + * Interrurp the add image process if it is still running + */ + private void interrupt() throws Exception { + + try { + logger.log(Level.INFO, "interrupt() add image process"); + addImageProcess.stop(); //it might take time to truly stop processing and writing to db + } catch (TskException ex) { + throw new Exception("Error stopping add-image process.", ex); + } + } + + /* + * Revert - if image has already been added but not committed yet + */ + void revert() { + + if (!reverted) { + + try { + logger.log(Level.INFO, "Revert after add image process"); + try { + addImageProcess.revert(); + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Error reverting add image process", ex); + } + } finally { + //unlock db write within EWT thread + SleuthkitCase.dbWriteUnlock(); + } + reverted = true; + } + } + } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java index 89098c8f46..773b31f109 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java @@ -194,339 +194,5 @@ public class ImageDSProcessor implements DataSourceProcessor { } - /* - * Background task that actualy adds the image - */ - private class AddImageTask extends SwingWorker { - - private Logger logger = Logger.getLogger(AddImageTask.class.getName()); - - private Case currentCase; - // true if the process was requested to stop - private boolean cancelled = false; - //true if revert has been invoked. - private boolean reverted = false; - private boolean hasCritError = false; - private boolean addImageDone = false; - - private List errorList = new ArrayList(); - - private DSPProgressMonitor progressMonitor; - private DSPCallback callbackObj; - - private final List newContents = Collections.synchronizedList(new ArrayList()); - - private SleuthkitJNI.CaseDbHandle.AddImageProcess addImageProcess; - private CurrentDirectoryFetcher fetcher; - - private String imagePath; - private String dataSourcetype; - String timeZone; - boolean noFatOrphans; - - - /* - * Sets the name/path and other options for the iimage to be processed - */ - public void SetImageOptions(String imgPath, String tz, boolean noOrphans) { - this.imagePath = imgPath; - this.timeZone = tz; - this.noFatOrphans = noOrphans; - } - - /* - * A Swingworker that updates the progressMonitor with the name of the - * directory currently being processed by the AddImageTask - */ - private class CurrentDirectoryFetcher extends SwingWorker { - - DSPProgressMonitor progressMonitor; - SleuthkitJNI.CaseDbHandle.AddImageProcess process; - - CurrentDirectoryFetcher(DSPProgressMonitor aProgressMonitor, SleuthkitJNI.CaseDbHandle.AddImageProcess proc) { - this.progressMonitor = aProgressMonitor; - this.process = proc; - } - - /** - * @return the currently processing directory - */ - @Override - protected Integer doInBackground() { - try { - while (!(addImageDone)) { - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - progressMonitor.setText(process.currentDirectory()); - } - }); - - Thread.sleep(2 * 1000); - } - return 1; - } catch (InterruptedException ie) { - return -1; - } - } - } - - - protected AddImageTask(DSPProgressMonitor aProgressMonitor, DSPCallback cbObj ) { - this.progressMonitor = aProgressMonitor; - currentCase = Case.getCurrentCase(); - - this.callbackObj = cbObj; - } - - /** - * Starts the addImage process, but does not commit the results. - * - * @return - * - * @throws Exception - */ - @Override - protected Integer doInBackground() { - - this.setProgress(0); - - errorList.clear(); - try { - //lock DB for writes in EWT thread - //wait until lock acquired in EWT - EventQueue.invokeAndWait(new Runnable() { - @Override - public void run() { - SleuthkitCase.dbWriteLock(); - } - }); - } catch (InterruptedException ex) { - logger.log(Level.WARNING, "Errors occurred while running add image, could not acquire lock. ", ex); - return 0; - - } catch (InvocationTargetException ex) { - logger.log(Level.WARNING, "Errors occurred while running add image, could not acquire lock. ", ex); - return 0; - } - - addImageProcess = currentCase.makeAddImageProcess(timeZone, true, noFatOrphans); - fetcher = new CurrentDirectoryFetcher(progressMonitor, addImageProcess); - - try { - progressMonitor.setIndeterminate(true); - progressMonitor.setProgress(0); - - fetcher.execute(); - addImageProcess.run(new String[]{this.imagePath}); - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Core errors occurred while running add image. ", ex); - //critical core/system error and process needs to be interrupted - hasCritError = true; - errorList.add(ex.getMessage()); - } catch (TskDataException ex) { - logger.log(Level.WARNING, "Data errors occurred while running add image. ", ex); - errorList.add(ex.getMessage()); - } finally { - // process is over, doesn't need to be dealt with if cancel happens - - } - - return 0; - } - - /** - * Commit the finished AddImageProcess, and cancel the CleanupTask that - * would have reverted it. - * - * @param settings property set to get AddImageProcess and CleanupTask - * from - * - * @throws Exception if commit or adding the image to the case failed - */ - private void commitImage() throws Exception { - - long imageId = 0; - try { - imageId = addImageProcess.commit(); - } catch (TskException e) { - logger.log(Level.WARNING, "Errors occured while committing the image", e); - errorList.add(e.getMessage()); - } finally { - //commit done, unlock db write in EWT thread - //before doing anything else - SleuthkitCase.dbWriteUnlock(); - - if (imageId != 0) { - Image newImage = Case.getCurrentCase().addImage(imagePath, imageId, timeZone); - - //while we have the image, verify the size of its contents - String verificationErrors = newImage.verifyImageSize(); - if (verificationErrors.equals("") == false) { - //data error (non-critical) - errorList.add(verificationErrors); - } - - // Add the image to the list of new content - newContents.add(newImage); - - } - - logger.log(Level.INFO, "Image committed, imageId: " + imageId); - logger.log(Level.INFO, PlatformUtil.getAllMemUsageInfo()); - } - } - - /** - * - * (called by EventDispatch Thread after doInBackground finishes) - * - * Must Not return without invoking the callBack, unless the caller canceled - */ - @Override - protected void done() { - - setProgress(100); - - // cancel the directory fetcher - fetcher.cancel(true); - - addImageDone = true; - // attempt actions that might fail and force the process to stop - if (cancelled || hasCritError) { - logger.log(Level.INFO, "Handling errors or interruption that occured in add image process"); - revert(); - } - if (!errorList.isEmpty()) { - logger.log(Level.INFO, "Handling non-critical errors that occured in add image process"); - } - - // When everything happens without an error: - if (!(cancelled || hasCritError)) { - - try { - // Tell the progress monitor we're done - progressMonitor.setProgress(100); - - if (newContents.isEmpty()) { - if (addImageProcess != null) { // and if we're done configuring ingest - // commit anything - try { - commitImage(); - } catch (Exception ex) { - errorList.add(ex.getMessage()); - // Log error/display warning - logger.log(Level.SEVERE, "Error adding image to case.", ex); - } - } else { - logger.log(Level.SEVERE, "Missing image process object"); - } - } - - else { //already commited? - logger.log(Level.INFO, "Assuming image already committed, will not commit."); - } - - } catch (Exception ex) { - //handle unchecked exceptions post image add - - errorList.add(ex.getMessage()); - - logger.log(Level.WARNING, "Unexpected errors occurred while running post add image cleanup. ", ex); - - logger.log(Level.SEVERE, "Error adding image to case", ex); - } finally { - - - } - } - - // invoke the callBack, unless the caller cancelled - if (!cancelled) - doCallBack(); - - return; - } - - /* - * Call the callback with proper parameters - */ - private void doCallBack() - { - DSPCallback.DSP_Result result; - - if (hasCritError) { - result = DSPCallback.DSP_Result.CRITICAL_ERRORS; - } - else if (!errorList.isEmpty()) { - result = DSPCallback.DSP_Result.NONCRITICAL_ERRORS; - } - else { - result = DSPCallback.DSP_Result.NO_ERRORS; - } - - // invoke the callcak, passing it the result, list of new contents, and list of errors - callbackObj.done(result, errorList, newContents); - } - - /* - * cancel the image addition, if possible - */ - public void cancelTask() { - - cancelled = true; - - if (!addImageDone) { - try { - addImageTask.interrupt(); - } - catch (Exception ex) { - logger.log(Level.SEVERE, "Failed to interrup the add image task..."); - } - } - else { - try { - addImageTask.revert(); - } - catch(Exception ex) { - logger.log(Level.SEVERE, "Failed to revert the add image task..."); - } - } - } - /* - * Interrurp the add image process if it is still running - */ - private void interrupt() throws Exception { - - try { - logger.log(Level.INFO, "interrupt() add image process"); - addImageProcess.stop(); //it might take time to truly stop processing and writing to db - } catch (TskException ex) { - throw new Exception("Error stopping add-image process.", ex); - } - } - - /* - * Revert - if image has already been added but not committed yet - */ - void revert() { - - if (!reverted) { - - try { - logger.log(Level.INFO, "Revert after add image process"); - try { - addImageProcess.revert(); - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Error reverting add image process", ex); - } - } finally { - //unlock db write within EWT thread - SleuthkitCase.dbWriteUnlock(); - } - reverted = true; - } - } - } } From 98913f22ee65555e624372d5c8f6b6ad9a8f3c50 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 18 Oct 2013 14:02:18 -0400 Subject: [PATCH 020/169] Added work around for database writes on EDT to TagsManager --- .../autopsy/actions/AddTagAction.java | 13 +- .../actions/GetTagNameAndCommentDialog.java | 10 +- .../autopsy/actions/GetTagNameDialog.java | 7 +- .../casemodule/services/TagsManager.java | 332 ++++++++++-------- .../autopsy/datamodel/ContentTagTypeNode.java | 10 +- .../sleuthkit/autopsy/datamodel/TagsNode.java | 11 +- .../BlackboardArtifactTagTypeNode.java | 13 +- .../autopsy/report/ReportVisualPanel2.java | 9 +- 8 files changed, 243 insertions(+), 162 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java index 1532a573d2..0224421771 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java @@ -21,15 +21,15 @@ package org.sleuthkit.autopsy.actions; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; -import javax.swing.AbstractAction; +import java.util.logging.Level; import javax.swing.JMenu; import javax.swing.JMenuItem; import org.openide.util.actions.Presenter; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.TagsManager; -import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent; -import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.autopsy.coreutils.Logger; /** * An abstract base class for Actions that allow users to tag SleuthKit data @@ -77,7 +77,12 @@ abstract class AddTagAction extends TagAction implements Presenter.Popup { // Get the current set of tag names. TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); ArrayList tagNames = new ArrayList<>(); - tagsManager.getAllTagNames(tagNames); + try { + tagsManager.getAllTagNames(tagNames); + } + catch (TskCoreException ex) { + Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); + } // Create a "Quick Tag" sub-menu. JMenu quickTagMenu = new JMenu("Quick Tag"); diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java index 2398b59081..34aee2c7df 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java @@ -22,6 +22,7 @@ import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.HashMap; +import java.util.logging.Level; import javax.swing.AbstractAction; import javax.swing.ActionMap; import javax.swing.InputMap; @@ -32,7 +33,9 @@ import javax.swing.KeyStroke; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.services.TagsManager; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskCoreException; public class GetTagNameAndCommentDialog extends JDialog { private static final String NO_TAG_NAMES_MESSAGE = "No Tags"; // RJCTODO: ?? @@ -83,7 +86,12 @@ public class GetTagNameAndCommentDialog extends JDialog { // Save the tag names to be enable to return the one the user selects. TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); ArrayList currentTagNames = new ArrayList<>(); - tagsManager.getAllTagNames(currentTagNames); + try { + tagsManager.getAllTagNames(currentTagNames); + } + catch (TskCoreException ex) { + Logger.getLogger(GetTagNameAndCommentDialog.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); + } if (currentTagNames.isEmpty()) { tagCombo.addItem(NO_TAG_NAMES_MESSAGE); } diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java index d576d7c274..637effab00 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java @@ -54,7 +54,12 @@ public class GetTagNameDialog extends JDialog { // case the user chooses an existing tag name from the tag names table. TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); ArrayList currentTagNames = new ArrayList<>(); - tagsManager.getAllTagNames(currentTagNames); + try { + tagsManager.getAllTagNames(currentTagNames); + } + catch (TskCoreException ex) { + Logger.getLogger(GetTagNameDialog.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); + } for (TagName name : currentTagNames) { this.tagNames.put(name.getDisplayName(), name); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 4e8d5ec869..411d6ec33b 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -36,7 +36,7 @@ import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; /** - * A singleton instance of this class functions as an Autopsy service that + * A per case instance of this class functions as an Autopsy service that * manages the creation, updating, and deletion of tags applied to content and * blackboard artifacts by users. */ @@ -45,8 +45,8 @@ public class TagsManager implements Closeable { private static final String TAG_NAMES_SETTING_KEY = "TagNames"; private static final TagName[] predefinedTagNames = new TagName[]{new TagName("Bookmark", "", TagName.HTML_COLOR.NONE)}; private final SleuthkitCase tskCase; - private final HashMap tagNames = new HashMap<>(); - private final Object lock = new Object(); + private final HashMap uniqueTagNames = new HashMap<>(); + private boolean tagNamesInitialized = false; // @@@ This is part of a work around to be removed when database access on the EDT is correctly synchronized. // Use this exception and the member hash map to manage uniqueness of hash // names. This is deemed more proactive and informative than leaving this to @@ -56,114 +56,46 @@ public class TagsManager implements Closeable { } /** - * Package-scope constructor for use of Services class. An instance of + * Package-scope constructor for use of the Services class. An instance of * TagsManager should be created for each case that is opened. * @param [in] tskCase The SleuthkitCase object for the current case. */ TagsManager(SleuthkitCase tskCase) { this.tskCase = tskCase; - getExistingTagNames(); - saveTagNamesToTagsSettings(); + // @@@ The removal of this call is a work around until database access on the EDT is correctly synchronized. + // getExistingTagNames(); } - private void getExistingTagNames() { - getTagNamesFromCurrentCase(); - getTagNamesFromTagsSettings(); - getPredefinedTagNames(); - } - - private void getTagNamesFromCurrentCase() { - try { - ArrayList currentTagNames = new ArrayList<>(); - tskCase.getAllTagNames(currentTagNames); - for (TagName tagName : currentTagNames) { - tagNames.put(tagName.getDisplayName(), tagName); - } - } - catch (TskCoreException ex) { - Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag types from the current case", ex); - } - } - - private void getTagNamesFromTagsSettings() { - String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); - if (null != setting && !setting.isEmpty()) { - // Read the tag name setting and break it into tag name tuples. - List tagNameTuples = Arrays.asList(setting.split(";")); - - // Parse each tuple and add the tag names to the current case, one - // at a time to gracefully discard any duplicates or corrupt tuples. - for (String tagNameTuple : tagNameTuples) { - String[] tagNameAttributes = tagNameTuple.split(","); - if (!tagNames.containsKey(tagNameAttributes[0])) { - TagName tagName = new TagName(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.getColorByName(tagNameAttributes[2])); - addTagName(tagName, "Failed to add " + tagName.getDisplayName() + " tag name from tag settings to the current case"); - } - } - } - } - - private void getPredefinedTagNames() { - for (TagName tagName : predefinedTagNames) { - if (!tagNames.containsKey(tagName.getDisplayName())) { - addTagName(tagName, "Failed to add predefined " + tagName.getDisplayName() + " tag name to the current case"); - } - } - } - - private void addTagName(TagName tagName, String errorMessage) { - try { - tskCase.addTagName(tagName); - tagNames.put(tagName.getDisplayName(), tagName); - } - catch(TskCoreException ex) { - Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, errorMessage, ex); - } - } - - private void saveTagNamesToTagsSettings() { - if (!tagNames.isEmpty()) { - StringBuilder setting = new StringBuilder(); - for (TagName tagName : tagNames.values()) { - if (setting.length() != 0) { - setting.append(";"); - } - setting.append(tagName.getDisplayName()).append(","); - setting.append(tagName.getDescription()).append(","); - setting.append(tagName.getColor().name()); - } - ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting.toString()); - } - } - /** * Gets a list of all tag names currently available for tagging content or * blackboard artifacts. - * @return [out] A list, possibly empty, of TagName data transfer objects (DTOs). + * @param [out] A list, possibly empty, of TagName data transfer objects (DTOs). + * @throws TskCoreException */ - public void getAllTagNames(List tagNames) { - try { - tagNames.clear(); - tskCase.getAllTagNames(tagNames); - } - catch (TskCoreException ex) { - Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names from the current case", ex); + public synchronized void getAllTagNames(List tagNames) throws TskCoreException { + // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. + if (!tagNamesInitialized) { + getExistingTagNames(); } + + tagNames.clear(); + tskCase.getAllTagNames(tagNames); } /** * Gets a list of all tag names currently used for tagging content or * blackboard artifacts. - * @return [out] A list, possibly empty, of TagName data transfer objects (DTOs). + * @param [out] A list, possibly empty, of TagName data transfer objects (DTOs). + * @throws TskCoreException */ - public void getTagNamesInUse(List tagNames) { - try { - tagNames.clear(); - tskCase.getTagNamesInUse(tagNames); - } - catch (TskCoreException ex) { - Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names from the current case", ex); + public synchronized void getTagNamesInUse(List tagNames) throws TskCoreException { + // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. + if (!tagNamesInitialized) { + getExistingTagNames(); } + + tagNames.clear(); + tskCase.getTagNamesInUse(tagNames); } /** @@ -171,57 +103,63 @@ public class TagsManager implements Closeable { * @param [in] tagDisplayName The display name for which to check. * @return True if the tag name exists, false otherwise. */ - public boolean tagNameExists(String tagDisplayName) { - synchronized(lock) { - return tagNames.containsKey(tagDisplayName); + public synchronized boolean tagNameExists(String tagDisplayName) { + // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. + if (!tagNamesInitialized) { + getExistingTagNames(); } + + return uniqueTagNames.containsKey(tagDisplayName); } /** - * Adds a new tag name to the current case and to the tags settings file. + * Adds a new tag name to the current case and to the tags settings. * @param [in] displayName The display name for the new tag name. * @return A TagName data transfer object (DTO) representing the new tag name. - * @throws TskCoreException + * @throws TagNameAlreadyExistsException, TskCoreException */ public TagName addTagName(String displayName) throws TagNameAlreadyExistsException, TskCoreException { return addTagName(displayName, "", TagName.HTML_COLOR.NONE); } /** - * Adds a new tag name to the current case and to the tags settings file. + * Adds a new tag name to the current case and to the tags settings. * @param [in] displayName The display name for the new tag name. * @param [in] description The description for the new tag name. * @return A TagName data transfer object (DTO) representing the new tag name. - * @throws TskCoreException + * @throws TagNameAlreadyExistsException, TskCoreException */ public TagName addTagName(String displayName, String description) throws TagNameAlreadyExistsException, TskCoreException { return addTagName(displayName, description, TagName.HTML_COLOR.NONE); } /** - * Adds a new tag name to the current case and to the tags settings file. + * Adds a new tag name to the current case and to the tags settings. * @param [in] displayName The display name for the new tag name. * @param [in] description The description for the new tag name. * @param [in] color The HTML color to associate with the new tag name. * @return A TagName data transfer object (DTO) representing the new tag name. - * @throws TskCoreException + * @throws TagNameAlreadyExistsException, TskCoreException */ public synchronized TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TagNameAlreadyExistsException, TskCoreException { - synchronized(lock) { - if (tagNames.containsKey(displayName)) { - throw new TagNameAlreadyExistsException(); - } + // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. + if (!tagNamesInitialized) { + getExistingTagNames(); + } + + if (uniqueTagNames.containsKey(displayName)) { + throw new TagNameAlreadyExistsException(); + } - // Add the tag name to the case. - TagName newTagName = new TagName(displayName, description, color); - tskCase.addTagName(newTagName); + // Add the tag name to the case. + TagName newTagName = new TagName(displayName, description, color); + tskCase.addTagName(newTagName); - // Add the tag name to the tags settings. - tagNames.put(newTagName.getDisplayName(), newTagName); - saveTagNamesToTagsSettings(); - - return newTagName; - } + // Add the tag name to the tags settings. + uniqueTagNames.put(newTagName.getDisplayName(), newTagName); + saveTagNamesToTagsSettings(); + + return newTagName; } /** @@ -246,27 +184,32 @@ public class TagsManager implements Closeable { } /** - * Tags a content object or a portion of a content object. + * Tags a content object or a section of a content object. * @param [in] content The content to tag. * @param [in] tagName The name to use for the tag. * @param [in] comment A comment to store with the tag. - * @param [in] beginByteOffset Designates the beginning of a tagged extent. - * @param [in] endByteOffset Designates the end of a tagged extent. - * @throws TskCoreException + * @param [in] beginByteOffset Designates the beginning of a tagged section. + * @param [in] endByteOffset Designates the end of a tagged section. + * @throws IllegalArgumentException, TskCoreException */ - public void addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws IllegalArgumentException, TskCoreException { - if (beginByteOffset < 0) { - throw new IllegalArgumentException("Content extent incorrect: beginByteOffset < 0"); - } - - if (endByteOffset <= beginByteOffset) { - throw new IllegalArgumentException("Content extent incorrect: endByteOffset <= beginByteOffset"); - } - - if (endByteOffset > content.getSize() - 1) { - throw new IllegalArgumentException("Content extent incorrect: endByteOffset exceeds content size"); + public synchronized void addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws IllegalArgumentException, TskCoreException { + // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. + if (!tagNamesInitialized) { + getExistingTagNames(); } + if (beginByteOffset < 0 || beginByteOffset > content.getSize() - 1) { + throw new IllegalArgumentException("beginByteOffset = " + beginByteOffset + " out of content size range (0 - " + (content.getSize() - 1) + ")"); + } + + if (endByteOffset < 0 || endByteOffset > content.getSize() - 1) { + throw new IllegalArgumentException("endByteOffset = " + endByteOffset + " out of content size range (0 - " + (content.getSize() - 1) + ")"); + } + + if (endByteOffset < beginByteOffset) { + throw new IllegalArgumentException("endByteOffset < beginByteOffset"); + } + tskCase.addContentTag(new ContentTag(content, tagName, comment, beginByteOffset, endByteOffset)); } @@ -275,7 +218,12 @@ public class TagsManager implements Closeable { * @param [in] tag The tag to delete. * @throws TskCoreException */ - public void deleteContentTag(ContentTag tag) throws TskCoreException { + public synchronized void deleteContentTag(ContentTag tag) throws TskCoreException { + // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. + if (!tagNamesInitialized) { + getExistingTagNames(); + } + tskCase.deleteContentTag(tag); } @@ -283,14 +231,15 @@ public class TagsManager implements Closeable { * Gets content tags by tag name. * @param [in] tagName The tag name of interest. * @return A list, possibly empty, of the content tags with the specified tag name. + * @throws TskCoreException */ - public void getContentTagsByTagName(TagName tagName, List tags) { - try { - tskCase.getContentTagsByTagName(tagName, tags); - } - catch (TskCoreException ex) { - Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get content tags from the current case", ex); + public synchronized void getContentTagsByTagName(TagName tagName, List tags) throws TskCoreException { + // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. + if (!tagNamesInitialized) { + getExistingTagNames(); } + + tskCase.getContentTagsByTagName(tagName, tags); } /** @@ -310,7 +259,12 @@ public class TagsManager implements Closeable { * @param [in] comment A comment to store with the tag. * @throws TskCoreException */ - public void addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException { + public synchronized void addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException { + // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. + if (!tagNamesInitialized) { + getExistingTagNames(); + } + tskCase.addBlackboardArtifactTag(new BlackboardArtifactTag(artifact, tskCase.getContentById(artifact.getObjectID()), tagName, comment)); } @@ -319,7 +273,12 @@ public class TagsManager implements Closeable { * @param [in] tag The tag to delete. * @throws TskCoreException */ - public void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException { + public synchronized void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException { + // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. + if (!tagNamesInitialized) { + getExistingTagNames(); + } + tskCase.deleteBlackboardArtifactTag(tag); } @@ -327,14 +286,15 @@ public class TagsManager implements Closeable { * Gets blackboard artifact tags by tag name. * @param [in] tagName The tag name of interest. * @return A list, possibly empty, of the content tags with the specified tag name. + * @throws TskCoreException */ - public void getBlackboardArtifactTagsByTagName(TagName tagName, List tags) { - try { - tskCase.getBlackboardArtifactTagsByTagName(tagName, tags); - } - catch (TskCoreException ex) { - Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get blackboard artifact tags from the current case", ex); + public synchronized void getBlackboardArtifactTagsByTagName(TagName tagName, List tags) throws TskCoreException { + // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. + if (!tagNamesInitialized) { + getExistingTagNames(); } + + tskCase.getBlackboardArtifactTagsByTagName(tagName, tags); } /** @@ -343,17 +303,89 @@ public class TagsManager implements Closeable { * @param [out] tags A list, possibly empty, of the tags that have been applied to the artifact. * @throws TskCoreException */ - public void getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact, List tags) { - try { - tskCase.getBlackboardArtifactTagsByArtifact(artifact, tags); - } - catch (TskCoreException ex) { - Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get blackboard artifact tags from the current case", ex); + public synchronized void getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact, List tags) throws TskCoreException { + // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. + if (!tagNamesInitialized) { + getExistingTagNames(); } + + tskCase.getBlackboardArtifactTagsByArtifact(artifact, tags); } @Override public void close() throws IOException { saveTagNamesToTagsSettings(); } + + private void addTagName(TagName tagName, String errorMessage) { + try { + tskCase.addTagName(tagName); + uniqueTagNames.put(tagName.getDisplayName(), tagName); + } + catch(TskCoreException ex) { + Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, errorMessage, ex); + } + } + + private void getExistingTagNames() { + getTagNamesFromCurrentCase(); + getTagNamesFromTagsSettings(); + getPredefinedTagNames(); + saveTagNamesToTagsSettings(); + tagNamesInitialized = true; // @@@ This is part of a work around to be removed when database access on the EDT is correctly synchronized. + } + + private void getTagNamesFromCurrentCase() { + try { + ArrayList currentTagNames = new ArrayList<>(); + tskCase.getAllTagNames(currentTagNames); + for (TagName tagName : currentTagNames) { + uniqueTagNames.put(tagName.getDisplayName(), tagName); + } + } + catch (TskCoreException ex) { + Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag types from the current case", ex); + } + } + + private void getTagNamesFromTagsSettings() { + String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); + if (null != setting && !setting.isEmpty()) { + // Read the tag name setting and break it into tag name tuples. + List tagNameTuples = Arrays.asList(setting.split(";")); + + // Parse each tuple and add the tag names to the current case, one + // at a time to gracefully discard any duplicates or corrupt tuples. + for (String tagNameTuple : tagNameTuples) { + String[] tagNameAttributes = tagNameTuple.split(","); + if (!uniqueTagNames.containsKey(tagNameAttributes[0])) { + TagName tagName = new TagName(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.getColorByName(tagNameAttributes[2])); + addTagName(tagName, "Failed to add " + tagName.getDisplayName() + " tag name from tag settings to the current case"); + } + } + } + } + + private void getPredefinedTagNames() { + for (TagName tagName : predefinedTagNames) { + if (!uniqueTagNames.containsKey(tagName.getDisplayName())) { + addTagName(tagName, "Failed to add predefined " + tagName.getDisplayName() + " tag name to the current case"); + } + } + } + + private void saveTagNamesToTagsSettings() { + if (!uniqueTagNames.isEmpty()) { + StringBuilder setting = new StringBuilder(); + for (TagName tagName : uniqueTagNames.values()) { + if (setting.length() != 0) { + setting.append(";"); + } + setting.append(tagName.getDisplayName()).append(","); + setting.append(tagName.getDescription()).append(","); + setting.append(tagName.getColor().name()); + } + ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting.toString()); + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java index 956ac6d69d..92dfa50243 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java @@ -19,13 +19,16 @@ package org.sleuthkit.autopsy.datamodel; import java.util.List; +import java.util.logging.Level; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskCoreException; /** * Instances of this class are are elements of a directory tree sub-tree @@ -77,7 +80,12 @@ public class ContentTagTypeNode extends DisplayableItemNode { @Override protected boolean createKeys(List keys) { // Use the content tags bearing the specified tag name as the keys. - Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(tagName, keys); + try { + Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(tagName, keys); + } + catch (TskCoreException ex) { + Logger.getLogger(ContentTagTypeNode.ContentTagNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); + } return true; } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java index 3f1813a647..908252a95f 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java @@ -19,12 +19,16 @@ package org.sleuthkit.autopsy.datamodel; import java.util.List; +import java.util.logging.Level; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; +import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskCoreException; /** * Instances of this class are the root nodes of tree that is a sub-tree of the @@ -74,7 +78,12 @@ public class TagsNode extends DisplayableItemNode { private static class TagNameNodeFactory extends ChildFactory { @Override protected boolean createKeys(List keys) { - Case.getCurrentCase().getServices().getTagsManager().getAllTagNames(keys); + try { + Case.getCurrentCase().getServices().getTagsManager().getAllTagNames(keys); + } + catch (TskCoreException ex) { + Logger.getLogger(TagNameNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); + } return true; } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java index b7acf5dd72..8c2e904aed 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java @@ -19,17 +19,21 @@ package org.sleuthkit.autopsy.directorytree; import java.util.List; +import java.util.logging.Level; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactTagNode; +import org.sleuthkit.autopsy.datamodel.ContentTagTypeNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode; import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor; import org.sleuthkit.autopsy.datamodel.NodeProperty; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskCoreException; /** * Instances of this class are elements in a sub-tree of the Autopsy @@ -80,8 +84,13 @@ public class BlackboardArtifactTagTypeNode extends DisplayableItemNode { @Override protected boolean createKeys(List keys) { - // Use the blackboard artifact tags bearing the specified tag name as the keys. - Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName, keys); + try { + // Use the blackboard artifact tags bearing the specified tag name as the keys. + Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName, keys); + } + catch (TskCoreException ex) { + Logger.getLogger(BlackboardArtifactTagTypeNode.BlackboardArtifactTagNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); + } return true; } diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java index 074892d84c..d63c65f73a 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java @@ -73,8 +73,13 @@ public final class ReportVisualPanel2 extends JPanel { // Initialize the list of Tags private void initTags() { ArrayList tagNamesInUse = new ArrayList<>(); - Case.getCurrentCase().getServices().getTagsManager().getTagNamesInUse(tagNamesInUse); - + try { + Case.getCurrentCase().getServices().getTagsManager().getTagNamesInUse(tagNamesInUse); + } + catch (TskCoreException ex) { + Logger.getLogger(ReportVisualPanel2.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); + } + for(TagName tagName : tagNamesInUse) { tagStates.put(tagName.getDisplayName(), Boolean.FALSE); } From 6627dadd89a0000bffdef1305bcc0c0ba7af26db Mon Sep 17 00:00:00 2001 From: raman-bt Date: Fri, 18 Oct 2013 14:54:35 -0400 Subject: [PATCH 021/169] Added Copyright headers, added/cleaned up comments. --- .../autopsy/casemodule/AddImageTask.java | 28 +++++++++-- .../AddImageWizardIngestConfigPanel.java | 2 +- .../autopsy/casemodule/ImageDSProcessor.java | 38 +++++++-------- .../corecomponentinterfaces/DSPCallback.java | 25 ++++++++-- .../DSPProgressMonitor.java | 22 +++++++-- .../DataSourceProcessor.java | 47 +++++++++---------- 6 files changed, 105 insertions(+), 57 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java index def759ca5b..771d217eaa 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java @@ -1,7 +1,22 @@ /* - * To change this template, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2013 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.casemodule; import java.awt.EventQueue; @@ -23,6 +38,13 @@ import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskDataException; import org.sleuthkit.datamodel.TskException; +/* + * A background task (swingworker) that adds the given image to + * database using the Sleuthkit JNI interface. + * + * It updates the given ProgressMonitor as it works through adding the image, + * and et the end, calls the specified Callback. + */ public class AddImageTask extends SwingWorker { private Logger logger = Logger.getLogger(AddImageTask.class.getName()); @@ -275,7 +297,7 @@ public class AddImageTask extends SwingWorker { } /* - * Call the callback with proper parameters + * Call the callback with results, new content, and errors, if any */ private void doCallBack() { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java index a936b3294c..991e3fef5b 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java @@ -296,7 +296,7 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel 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.casemodule; -import java.awt.Color; -import java.awt.EventQueue; -import java.awt.Window; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; import java.util.logging.Level; import javax.swing.JPanel; -import javax.swing.JProgressBar; -import javax.swing.SwingUtilities; -import javax.swing.SwingWorker; -import org.openide.WizardDescriptor; import org.openide.util.lookup.ServiceProvider; -import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.PlatformUtil; -import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.Image; -import org.sleuthkit.datamodel.SleuthkitCase; -import org.sleuthkit.datamodel.SleuthkitJNI; -import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.datamodel.TskDataException; -import org.sleuthkit.datamodel.TskException; import org.sleuthkit.autopsy.corecomponentinterfaces.DSPProgressMonitor; import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DSPCallback.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DSPCallback.java index b5c4b7cba9..f3bdf028da 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DSPCallback.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DSPCallback.java @@ -1,7 +1,22 @@ /* - * To change this template, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2013 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.corecomponentinterfaces; import java.awt.EventQueue; @@ -9,7 +24,11 @@ import java.util.List; import org.sleuthkit.datamodel.Content; /** - * Abstract class for a callback + * Abstract class for a callback for a DataSourceProcessor. + * + * Ensures that DSP invokes the caller overridden method, doneEDT(), + * in the EDT thread. + * */ public abstract class DSPCallback { diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DSPProgressMonitor.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DSPProgressMonitor.java index b375301aed..c68574eeb2 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DSPProgressMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DSPProgressMonitor.java @@ -1,13 +1,27 @@ /* - * To change this template, choose Tools | Templates - * and open the template in the editor. + * Autopsy Forensic Browser + * + * Copyright 2013 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.corecomponentinterfaces; /* - * An GUI agnostic DSPProgressMonitor interface for DataSorceProcesssors to + * An GUI agnostic DSPProgressMonitor interface for DataSourceProcesssors to * indicate progress. - * It models after a JProgressbar though could use any underlying implementation + * It models after a JProgressbar though it could use any underlying implementation */ public interface DSPProgressMonitor { diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessor.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessor.java index 59fc291c6e..4abce176b7 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessor.java @@ -18,19 +18,31 @@ */ package org.sleuthkit.autopsy.corecomponentinterfaces; -import java.util.List; + import javax.swing.JPanel; -import org.openide.WizardDescriptor; import org.sleuthkit.datamodel.Content; +/* + * Defines an interface used by the Add DataSource wizard to discover different + * Data SourceProcessors. + * A data source for Autopsy may be: + * - Disk Image (Encase, Raw....) + * - Local Disk + * - Logical file(s) + * - Phone Image + * - A CellXML file with content extracted from phone. + * + * Each data source may have its unique attributes and may need to be processed + * differently. + * + * The DataSourceProcessor interface defines a uniform mechanism for thre Autopsy UI + * to: + * - collect details for the data source to be processed. + * - Process the data source in the background + * - Be notified when the processing is complete + */ public interface DataSourceProcessor { - - - - - // public DataSourceProcessor createInstance(); - - + /** * Returns the type of Data Source it handles. * This name gets displayed in the drop-down listbox @@ -59,27 +71,14 @@ public interface DataSourceProcessor { **/ void run(DSPProgressMonitor progressPanel, DSPCallback dspCallback); - /** - * Called after run() is done to get the new content added by the handler. - * Returns a list of content added by the data source handler - **/ - // List getNewContents(); - - - /** - * Called to get the list of errors. - **/ - // String[] getErrors(); /** * Called to cancel the background processing. - * - * TODO look into current use cases to see if this should wait until it has stopped or not. **/ void cancel(); - /** - * Called to reset/reinit the DSP. + /** + * Called to reset/reinitialize the DSP. * **/ void reset(); From d4ac9b3bd4f29443d148efb0a27a9f2ca7b5ee10 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 18 Oct 2013 15:12:01 -0400 Subject: [PATCH 022/169] Added Comment properties to tag nodes --- .../autopsy/datamodel/BlackboardArtifactTagNode.java | 3 ++- .../org/sleuthkit/autopsy/datamodel/ContentTagNode.java | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java index e4e61680b3..8cab0fed87 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java @@ -69,7 +69,8 @@ public class BlackboardArtifactTagNode extends DisplayableItemNode { } properties.put(new NodeProperty("Source File Path", "Source File Path", "", contentPath)); properties.put(new NodeProperty("Result Type", "Result Type", "", tag.getArtifact().getDisplayName())); - + properties.put(new NodeProperty("Comment", "Comment", "", tag.getComment())); + return propertySheet; } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java index b2e5c1d08e..a7c1b487e1 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java @@ -58,7 +58,7 @@ public class ContentTagNode extends DisplayableItemNode { propertySheet.put(properties); } - properties.put(new NodeProperty("Source File", "Source File", "", tag.getContent().getName())); + properties.put(new NodeProperty("File", "File", "", tag.getContent().getName())); String contentPath; try { contentPath = tag.getContent().getUniquePath(); @@ -67,8 +67,9 @@ public class ContentTagNode extends DisplayableItemNode { Logger.getLogger(ContentTagNode.class.getName()).log(Level.SEVERE, "Failed to get path for content (id = " + tag.getContent().getId() + ")", ex); contentPath = "Unavailable"; } - properties.put(new NodeProperty("Source File Path", "Source File Path", "", contentPath)); - + properties.put(new NodeProperty("File Path", "File Path", "", contentPath)); + properties.put(new NodeProperty("Comment", "Comment", "", tag.getComment())); + return propertySheet; } From fd811a49190ed579c234aa84e3a9c647397d22ec Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 18 Oct 2013 15:52:03 -0400 Subject: [PATCH 023/169] Clean up of artifact selection types dialog for reports --- .../report/ArtifactSelectionDialog.form | 1 + .../report/ArtifactSelectionDialog.java | 32 ++----------------- 2 files changed, 4 insertions(+), 29 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.form b/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.form index 4a2908fff3..cd714f81c8 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.form +++ b/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.form @@ -6,6 +6,7 @@ + diff --git a/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.java b/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.java index 96f417f72b..e4dff5c8d2 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.java +++ b/Core/src/org/sleuthkit/autopsy/report/ArtifactSelectionDialog.java @@ -41,8 +41,6 @@ import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.TskCoreException; public class ArtifactSelectionDialog extends javax.swing.JDialog { - private static final Logger logger = Logger.getLogger(ArtifactSelectionDialog.class.getName()); - private static ArtifactSelectionDialog instance; private ArtifactModel model; private ArtifactRenderer renderer; @@ -73,13 +71,12 @@ public class ArtifactSelectionDialog extends javax.swing.JDialog { artifacts.removeAll(doNotReport); - artifactStates = new EnumMap(BlackboardArtifact.ARTIFACT_TYPE.class); + artifactStates = new EnumMap<>(BlackboardArtifact.ARTIFACT_TYPE.class); for (BlackboardArtifact.ARTIFACT_TYPE type : artifacts) { artifactStates.put(type, Boolean.TRUE); } } catch (TskCoreException ex) { Logger.getLogger(ArtifactSelectionDialog.class.getName()).log(Level.SEVERE, "Error getting list of artifacts in use: " + ex.getLocalizedMessage()); - return; } } @@ -101,28 +98,7 @@ public class ArtifactSelectionDialog extends javax.swing.JDialog { } }); } - - /** - * Returns a list of the artifact types we want to report on. - */ - static List getImportantArtifactTypes() { - List types = new ArrayList(); - types.add(ARTIFACT_TYPE.TSK_WEB_BOOKMARK); - types.add(ARTIFACT_TYPE.TSK_WEB_COOKIE); - types.add(ARTIFACT_TYPE.TSK_WEB_HISTORY); - types.add(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD); - types.add(ARTIFACT_TYPE.TSK_RECENT_OBJECT); - types.add(ARTIFACT_TYPE.TSK_INSTALLED_PROG); - types.add(ARTIFACT_TYPE.TSK_KEYWORD_HIT); - types.add(ARTIFACT_TYPE.TSK_HASHSET_HIT); - types.add(ARTIFACT_TYPE.TSK_DEVICE_ATTACHED); - types.add(ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY); - types.add(ARTIFACT_TYPE.TSK_METADATA_EXIF); - types.add(ARTIFACT_TYPE.TSK_TAG_FILE); - types.add(ARTIFACT_TYPE.TSK_TAG_ARTIFACT); - return types; - } - + /** * Display this dialog, and return the selected artifacts. */ @@ -289,8 +265,6 @@ public class ArtifactSelectionDialog extends javax.swing.JDialog { return this; } return new JLabel(); - } - + } } - } From 3ef3ce3da2da35c5fb6c26f5b72e3a2e665fde87 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 18 Oct 2013 15:52:50 -0400 Subject: [PATCH 024/169] Restored use of star icon for bookmark tag name nodes --- Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java index a0fc06f539..3d7783ae98 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java @@ -35,6 +35,7 @@ public class TagNameNode extends DisplayableItemNode { private static final String CONTENT_TAG_TYPE_NODE_KEY = "Content Tags"; private static final String BLACKBOARD_ARTIFACT_TAG_TYPE_NODE_KEY = "Result Tags"; private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; + private static final String BOOKMARK_TAG_ICON_PATH = "org/sleuthkit/autopsy/images/star-bookmark-icon-16.png"; private final TagName tagName; public TagNameNode(TagName tagName) { @@ -42,7 +43,12 @@ public class TagNameNode extends DisplayableItemNode { this.tagName = tagName; super.setName(tagName.getDisplayName()); super.setDisplayName(tagName.getDisplayName()); - this.setIconBaseWithExtension(ICON_PATH); + if (tagName.getDisplayName().equals("Bookmark")) { + setIconBaseWithExtension(BOOKMARK_TAG_ICON_PATH); + } + else { + setIconBaseWithExtension(ICON_PATH); + } } @Override From 4cd68f99a14395a409d03e7f5ae12ea6d56f9a50 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 18 Oct 2013 16:43:45 -0400 Subject: [PATCH 025/169] Added counts to tag sub-tree nodes --- .../casemodule/services/TagsManager.java | 32 ++++++++++++++++++- .../autopsy/datamodel/ContentTagTypeNode.java | 13 ++++++-- .../autopsy/datamodel/TagNameNode.java | 22 ++++++++++--- .../BlackboardArtifactTagTypeNode.java | 15 +++++++-- 4 files changed, 72 insertions(+), 10 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 411d6ec33b..22b2c1b98b 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -226,7 +226,22 @@ public class TagsManager implements Closeable { tskCase.deleteContentTag(tag); } - + + /** + * Gets content tags count by tag name. + * @param [in] tagName The tag name of interest. + * @return A count of the content tags with the specified tag name. + * @throws TskCoreException + */ + public synchronized long getContentTagsCountByTagName(TagName tagName) throws TskCoreException { + // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. + if (!tagNamesInitialized) { + getExistingTagNames(); + } + + return tskCase.getContentTagsCountByTagName(tagName); + } + /** * Gets content tags by tag name. * @param [in] tagName The tag name of interest. @@ -282,6 +297,21 @@ public class TagsManager implements Closeable { tskCase.deleteBlackboardArtifactTag(tag); } + /** + * Gets blackboard artifact tags count by tag name. + * @param [in] tagName The tag name of interest. + * @return A count of the blackboard artifact tags with the specified tag name. + * @throws TskCoreException + */ + public synchronized long getBlackboardArtifactTagsCountByTagName(TagName tagName) throws TskCoreException { + // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. + if (!tagNamesInitialized) { + getExistingTagNames(); + } + + return tskCase.getBlackboardArtifactTagsCountByTagName(tagName); + } + /** * Gets blackboard artifact tags by tag name. * @param [in] tagName The tag name of interest. diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java index 92dfa50243..6c1a454357 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java @@ -41,8 +41,17 @@ public class ContentTagTypeNode extends DisplayableItemNode { public ContentTagTypeNode(TagName tagName) { super(Children.create(new ContentTagNodeFactory(tagName), true)); - super.setName(DISPLAY_NAME); - super.setDisplayName(DISPLAY_NAME); + + long tagsCount = 0; + try { + tagsCount = Case.getCurrentCase().getServices().getTagsManager().getContentTagsCountByTagName(tagName); + } + catch (TskCoreException ex) { + Logger.getLogger(ContentTagTypeNode.class.getName()).log(Level.SEVERE, "Failed to get content tags count for " + tagName.getDisplayName() + " tag name", ex); + } + + super.setName(DISPLAY_NAME + " (" + tagsCount + ")"); + super.setDisplayName(DISPLAY_NAME + " (" + tagsCount + ")"); this.setIconBaseWithExtension(ICON_PATH); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java index 3d7783ae98..05f4a00627 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java @@ -19,12 +19,16 @@ package org.sleuthkit.autopsy.datamodel; import java.util.List; +import java.util.logging.Level; import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.BlackboardArtifactTagTypeNode; import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskCoreException; /** * Instances of this class are elements of Node hierarchies consisting of @@ -32,8 +36,6 @@ import org.sleuthkit.datamodel.TagName; * tag name. */ public class TagNameNode extends DisplayableItemNode { - private static final String CONTENT_TAG_TYPE_NODE_KEY = "Content Tags"; - private static final String BLACKBOARD_ARTIFACT_TAG_TYPE_NODE_KEY = "Result Tags"; private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; private static final String BOOKMARK_TAG_ICON_PATH = "org/sleuthkit/autopsy/images/star-bookmark-icon-16.png"; private final TagName tagName; @@ -41,8 +43,18 @@ public class TagNameNode extends DisplayableItemNode { public TagNameNode(TagName tagName) { super(Children.create(new TagTypeNodeFactory(tagName), true)); this.tagName = tagName; - super.setName(tagName.getDisplayName()); - super.setDisplayName(tagName.getDisplayName()); + + long tagsCount = 0; + try { + tagsCount = Case.getCurrentCase().getServices().getTagsManager().getContentTagsCountByTagName(tagName); + tagsCount += Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName); + } + catch (TskCoreException ex) { + Logger.getLogger(TagNameNode.class.getName()).log(Level.SEVERE, "Failed to get tags count for " + tagName.getDisplayName() + " tag name", ex); + } + + super.setName(tagName.getDisplayName() + " (" + tagsCount + ")"); + super.setDisplayName(tagName.getDisplayName() + " (" + tagsCount + ")"); if (tagName.getDisplayName().equals("Bookmark")) { setIconBaseWithExtension(BOOKMARK_TAG_ICON_PATH); } @@ -78,6 +90,8 @@ public class TagNameNode extends DisplayableItemNode { } private static class TagTypeNodeFactory extends ChildFactory { + private static final String CONTENT_TAG_TYPE_NODE_KEY = "Content Tags"; + private static final String BLACKBOARD_ARTIFACT_TAG_TYPE_NODE_KEY = "Result Tags"; private final TagName tagName; TagTypeNodeFactory(TagName tagName) { diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java index 8c2e904aed..543db96eb0 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java @@ -42,12 +42,21 @@ import org.sleuthkit.datamodel.TskCoreException; */ public class BlackboardArtifactTagTypeNode extends DisplayableItemNode { private static final String DISPLAY_NAME = "Result Tags"; - private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; // RJCTODO: Different icon? + private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; public BlackboardArtifactTagTypeNode(TagName tagName) { super(Children.create(new BlackboardArtifactTagNodeFactory(tagName), true)); - super.setName(DISPLAY_NAME); - super.setDisplayName(DISPLAY_NAME); + + long tagsCount = 0; + try { + tagsCount = Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName); + } + catch (TskCoreException ex) { + Logger.getLogger(BlackboardArtifactTagTypeNode.class.getName()).log(Level.SEVERE, "Failed to get blackboard artifact tags count for " + tagName.getDisplayName() + " tag name", ex); + } + + super.setName(DISPLAY_NAME + " (" + tagsCount + ")"); + super.setDisplayName(DISPLAY_NAME + " (" + tagsCount + ")"); this.setIconBaseWithExtension(ICON_PATH); } From b5095ad802324ccd0e4f9316741e4c64e436989a Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 18 Oct 2013 18:06:53 -0400 Subject: [PATCH 026/169] Additional steps towards removal of old tags code from report package --- .../autopsy/report/ReportGenerator.java | 478 +++++++----------- .../sleuthkit/autopsy/report/ReportHTML.java | 132 ++--- 2 files changed, 252 insertions(+), 358 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java index 9064532933..45a551759d 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java @@ -437,9 +437,9 @@ public class ReportGenerator { boolean msgSent = false; for(ArtifactData artifactData : unsortedArtifacts) { - HashSet tags = artifactData.getTags(); - - String tagsList = makeCommaSeparatedList(tags); +// HashSet tags = artifactData.getTags(); +// +// String tagsList = makeCommaSeparatedList(tags); // Add the row data to all of the reports. for (TableReportModule module : tableModules) { @@ -447,28 +447,22 @@ public class ReportGenerator { // Get the row data for this type of artifact. List rowData; rowData = getArtifactRow(artifactData, module); - if (rowData == null) { + if (rowData.isEmpty()) { if (msgSent == false) { MessageNotifyUtil.Notify.show("Skipping artifact rows for type " + type + " in reports", "Unknown columns to report on", MessageNotifyUtil.MessageType.ERROR); msgSent = true; } continue; } - // Add the list of tag names if the artifact is not itself as tag. - if (artifactData.getArtifact().getArtifactTypeID() != ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID() && - artifactData.getArtifact().getArtifactTypeID() != ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()) - { - rowData.add(tagsList); - } - // This is a temporary workaround to avoid modifying the TableReportModule interface. - if (module instanceof ReportHTML) { - ReportHTML htmlReportModule = (ReportHTML)module; - htmlReportModule.addRow(rowData, artifactData.getArtifact()); - } - else { +// // This is a temporary workaround to avoid modifying the TableReportModule interface. +// if (module instanceof ReportHTML) { +// ReportHTML htmlReportModule = (ReportHTML)module; +// htmlReportModule.addRow(rowData, artifactData.getArtifact()); +// } +// else { module.addRow(rowData); - } +// } } } @@ -618,11 +612,15 @@ public class ReportGenerator { } // Get any tags that associated with this artifact and apply the tag filter. - HashSet tags = Tags.getUniqueTagNamesForArtifact(rs.getLong("artifact_id"), ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()); - if (failsTagFilter(tags, tagNamesFilter)) { - continue; - } - String tagsList = makeCommaSeparatedList(tags); + HashSet uniqueTagNames = new HashSet<>(); + ResultSet tagNameRows = skCase.runQuery("SELECT display_name FROM tag_names WHERE artifact_id = " + rs.getLong("artifact_id")); + while (tagNameRows.next()) { + uniqueTagNames.add(tagNameRows.getString("display_name")); + } + if(failsTagFilter(uniqueTagNames, tagNamesFilter)) { + continue; + } + String tagsList = makeCommaSeparatedList(uniqueTagNames); Long objId = rs.getLong("obj_id"); String keyword = rs.getString("keyword"); @@ -761,12 +759,16 @@ public class ReportGenerator { } } - // Get any tags that associated with this artifact and apply the tag filter. - HashSet tags = Tags.getUniqueTagNamesForArtifact(rs.getLong("artifact_id"), ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()); - if (failsTagFilter(tags, tagNamesFilter)) { + // Get any tags that associated with this artifact and apply the tag filter. + HashSet uniqueTagNames = new HashSet<>(); + ResultSet tagNameRows = skCase.runQuery("SELECT display_name FROM tag_names WHERE artifact_id = " + rs.getLong("artifact_id")); + while (tagNameRows.next()) { + uniqueTagNames.add(tagNameRows.getString("display_name")); + } + if(failsTagFilter(uniqueTagNames, tagNamesFilter)) { continue; } - String tagsList = makeCommaSeparatedList(tags); + String tagsList = makeCommaSeparatedList(uniqueTagNames); Long objId = rs.getLong("obj_id"); String set = rs.getString("setname"); @@ -819,7 +821,7 @@ public class ReportGenerator { } } } - + /** * For a given artifact type ID, return the list of the row titles we're reporting on. * @@ -828,9 +830,8 @@ public class ReportGenerator { */ private List getArtifactTableColumnHeaders(int artifactTypeId) { ArrayList columnHeaders; - - BlackboardArtifact.ARTIFACT_TYPE type = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifactTypeId); - + + BlackboardArtifact.ARTIFACT_TYPE type = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifactTypeId); switch (type) { case TSK_WEB_BOOKMARK: columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"URL", "Title", "Date Accessed", "Program", "Source File"})); @@ -865,12 +866,6 @@ public class ReportGenerator { case TSK_METADATA_EXIF: columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"Date Taken", "Device Manufacturer", "Device Model", "Latitude", "Longitude", "Source File"})); break; - case TSK_TAG_FILE: - columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"File", "Tag", "Comment"})); - break; - case TSK_TAG_ARTIFACT: - columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"Result Type", "Tag", "Comment", "Source File"})); - break; case TSK_CONTACT: columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"Person Name", "Phone Number", "Phone Number (Home)", "Phone Number (Office)", "Phone Number (Mobile)", "Email", "Source File" })); break; @@ -884,25 +879,25 @@ public class ReportGenerator { columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"Calendar Entry Type", "Description", "Start Date/Time", "End Date/Time", "Location", "Source File" })); break; case TSK_SPEED_DIAL_ENTRY: - columnHeaders = new ArrayList(Arrays.asList(new String[] {"Short Cut", "Person Name", "Phone Number", "Source File" })); + columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"Short Cut", "Person Name", "Phone Number", "Source File" })); break; case TSK_BLUETOOTH_PAIRING: - columnHeaders = new ArrayList(Arrays.asList(new String[] {"Device Name", "Device Address", "Date/Time", "Source File" })); + columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"Device Name", "Device Address", "Date/Time", "Source File" })); break; case TSK_GPS_TRACKPOINT: - columnHeaders = new ArrayList(Arrays.asList(new String[] {"Latitude", "Longitude", "Altitude", "Name", "Location Address", "Date/Time", "Source File" })); + columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"Latitude", "Longitude", "Altitude", "Name", "Location Address", "Date/Time", "Source File" })); break; case TSK_GPS_BOOKMARK: - columnHeaders = new ArrayList(Arrays.asList(new String[] {"Latitude", "Longitude", "Altitude", "Name", "Location Address", "Date/Time", "Source File" })); + columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"Latitude", "Longitude", "Altitude", "Name", "Location Address", "Date/Time", "Source File" })); break; case TSK_GPS_LAST_KNOWN_LOCATION: - columnHeaders = new ArrayList(Arrays.asList(new String[] {"Latitude", "Longitude", "Altitude", "Name", "Location Address", "Date/Time", "Source File" })); + columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"Latitude", "Longitude", "Altitude", "Name", "Location Address", "Date/Time", "Source File" })); break; case TSK_GPS_SEARCH: - columnHeaders = new ArrayList(Arrays.asList(new String[] {"Latitude", "Longitude", "Altitude", "Name", "Location Address", "Date/Time", "Source File" })); + columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"Latitude", "Longitude", "Altitude", "Name", "Location Address", "Date/Time", "Source File" })); break; case TSK_SERVICE_ACCOUNT: - columnHeaders = new ArrayList(Arrays.asList(new String[] {"Category", "User ID", "Password", "Person Name", "App Name", "URL", "App Path", "Description", "ReplyTo Address", "Mail Server", "Source File" })); + columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"Category", "User ID", "Password", "Person Name", "App Name", "URL", "App Path", "Description", "ReplyTo Address", "Mail Server", "Source File" })); break; case TSK_TOOL_OUTPUT: columnHeaders = new ArrayList<>(Arrays.asList(new String[] {"Program Name", "Text", "Source File"})); @@ -910,11 +905,7 @@ public class ReportGenerator { default: return null; } - - if (artifactTypeId != ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() && - artifactTypeId != ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { - columnHeaders.add("Tags"); - } + columnHeaders.add("Tags"); return columnHeaders; } @@ -993,227 +984,175 @@ public class ReportGenerator { private List getArtifactRow(ArtifactData artifactData, TableReportModule module) throws TskCoreException { Map attributes = getMappedAttributes(artifactData.getAttributes(), module); - BlackboardArtifact.ARTIFACT_TYPE type = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifactData.getArtifact().getArtifactTypeID()); - + List rowData = new ArrayList<>(); + BlackboardArtifact.ARTIFACT_TYPE type = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifactData.getArtifact().getArtifactTypeID()); switch (type) { case TSK_WEB_BOOKMARK: - List bookmark = new ArrayList<>(); - bookmark.add(attributes.get(ATTRIBUTE_TYPE.TSK_URL.getTypeID())); - bookmark.add(attributes.get(ATTRIBUTE_TYPE.TSK_TITLE.getTypeID())); - bookmark.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID())); - bookmark.add(attributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); - bookmark.add(getFileUniquePath(artifactData.getObjectID())); - return bookmark; + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_URL.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_TITLE.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); + rowData.add(getFileUniquePath(artifactData.getObjectID())); + break; case TSK_WEB_COOKIE: - List cookie = new ArrayList<>(); - cookie.add(attributes.get(ATTRIBUTE_TYPE.TSK_URL.getTypeID())); - cookie.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); - cookie.add(attributes.get(ATTRIBUTE_TYPE.TSK_NAME.getTypeID())); - cookie.add(attributes.get(ATTRIBUTE_TYPE.TSK_VALUE.getTypeID())); - cookie.add(attributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); - cookie.add(getFileUniquePath(artifactData.getObjectID())); - return cookie; + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_URL.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_NAME.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_VALUE.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); + rowData.add(getFileUniquePath(artifactData.getObjectID())); + break; case TSK_WEB_HISTORY: - List history = new ArrayList<>(); - history.add(attributes.get(ATTRIBUTE_TYPE.TSK_URL.getTypeID())); - history.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID())); - history.add(attributes.get(ATTRIBUTE_TYPE.TSK_REFERRER.getTypeID())); - history.add(attributes.get(ATTRIBUTE_TYPE.TSK_NAME.getTypeID())); - history.add(attributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); - history.add(getFileUniquePath(artifactData.getObjectID())); - return history; + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_URL.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_REFERRER.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_NAME.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); + rowData.add(getFileUniquePath(artifactData.getObjectID())); + break; case TSK_WEB_DOWNLOAD: - List download = new ArrayList<>(); - download.add(attributes.get(ATTRIBUTE_TYPE.TSK_PATH.getTypeID())); - download.add(attributes.get(ATTRIBUTE_TYPE.TSK_URL.getTypeID())); - download.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID())); - download.add(attributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); - download.add(getFileUniquePath(artifactData.getObjectID())); - return download; + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_PATH.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_URL.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); + rowData.add(getFileUniquePath(artifactData.getObjectID())); + break; case TSK_RECENT_OBJECT: - List recent = new ArrayList<>(); - recent.add(attributes.get(ATTRIBUTE_TYPE.TSK_PATH.getTypeID())); - recent.add(getFileUniquePath(artifactData.getObjectID())); - return recent; + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_PATH.getTypeID())); + rowData.add(getFileUniquePath(artifactData.getObjectID())); + break; case TSK_INSTALLED_PROG: - List installed = new ArrayList<>(); - installed.add(attributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); - installed.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); - installed.add(getFileUniquePath(artifactData.getObjectID())); - return installed; + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); + rowData.add(getFileUniquePath(artifactData.getObjectID())); + break; case TSK_DEVICE_ATTACHED: - List devices = new ArrayList<>(); - devices.add(attributes.get(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL.getTypeID())); - devices.add(attributes.get(ATTRIBUTE_TYPE.TSK_DEVICE_ID.getTypeID())); - devices.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); - devices.add(getFileUniquePath(artifactData.getObjectID())); - return devices; + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DEVICE_ID.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); + rowData.add(getFileUniquePath(artifactData.getObjectID())); + break; case TSK_WEB_SEARCH_QUERY: - List search = new ArrayList<>(); - search.add(attributes.get(ATTRIBUTE_TYPE.TSK_TEXT.getTypeID())); - search.add(attributes.get(ATTRIBUTE_TYPE.TSK_DOMAIN.getTypeID())); - search.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID())); - search.add(attributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); - search.add(getFileUniquePath(artifactData.getObjectID())); - return search; + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_TEXT.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DOMAIN.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); + rowData.add(getFileUniquePath(artifactData.getObjectID())); + break; case TSK_METADATA_EXIF: - List exif = new ArrayList<>(); - exif.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); - exif.add(attributes.get(ATTRIBUTE_TYPE.TSK_DEVICE_MAKE.getTypeID())); - exif.add(attributes.get(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL.getTypeID())); - exif.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID())); - exif.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID())); - exif.add(getFileUniquePath(artifactData.getObjectID())); - return exif; - case TSK_TAG_FILE: - List taggedFileRow = new ArrayList<>(); - AbstractFile taggedFile = getAbstractFile(artifactData.getObjectID()); - if (taggedFile != null) { - taggedFileRow.add(taggedFile.getUniquePath()); - } else { - taggedFileRow.add(""); - } - taggedFileRow.add(attributes.get(ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID())); - taggedFileRow.add(attributes.get(ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID())); - return taggedFileRow; - case TSK_TAG_ARTIFACT: - List taggedArtifactRow = new ArrayList<>(); - String taggedArtifactType = ""; - for (BlackboardAttribute attr : artifactData.getAttributes()) { - if (attr.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID()) { - BlackboardArtifact taggedArtifact = getArtifact(attr.getValueLong()); - if (taggedArtifact != null) { - taggedArtifactType = taggedArtifact.getDisplayName(); - } - break; - } - } - taggedArtifactRow.add(taggedArtifactType); - taggedArtifactRow.add(attributes.get(ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID())); - taggedArtifactRow.add(attributes.get(ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID())); - AbstractFile sourceFile = getAbstractFile(artifactData.getObjectID()); - if (sourceFile != null) { - taggedArtifactRow.add(sourceFile.getUniquePath()); - } else { - taggedArtifactRow.add(""); - } - return taggedArtifactRow; + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DEVICE_MAKE.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DEVICE_MODEL.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID())); + rowData.add(getFileUniquePath(artifactData.getObjectID())); + break; case TSK_CONTACT: - List contact = new ArrayList<>(); - contact.add(attributes.get(ATTRIBUTE_TYPE.TSK_NAME_PERSON.getTypeID())); - contact.add(attributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER.getTypeID())); - contact.add(attributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_HOME.getTypeID())); - contact.add(attributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_OFFICE.getTypeID())); - contact.add(attributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_MOBILE.getTypeID())); - contact.add(attributes.get(ATTRIBUTE_TYPE.TSK_EMAIL.getTypeID())); - contact.add(getFileUniquePath(artifactData.getObjectID())); - return contact; + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_NAME_PERSON.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_HOME.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_OFFICE.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_MOBILE.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_EMAIL.getTypeID())); + rowData.add(getFileUniquePath(artifactData.getObjectID())); + break; case TSK_MESSAGE: - List message = new ArrayList<>(); - message.add(attributes.get(ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE.getTypeID())); - message.add(attributes.get(ATTRIBUTE_TYPE.TSK_DIRECTION.getTypeID())); - message.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); - message.add(attributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM.getTypeID())); - message.add(attributes.get(ATTRIBUTE_TYPE.TSK_EMAIL_FROM.getTypeID())); - message.add(attributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO.getTypeID())); - message.add(attributes.get(ATTRIBUTE_TYPE.TSK_EMAIL_TO.getTypeID())); - message.add(attributes.get(ATTRIBUTE_TYPE.TSK_SUBJECT.getTypeID())); - message.add(attributes.get(ATTRIBUTE_TYPE.TSK_TEXT.getTypeID())); - message.add(getFileUniquePath(artifactData.getObjectID())); - return message; + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DIRECTION.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_EMAIL_FROM.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_EMAIL_TO.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_SUBJECT.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_TEXT.getTypeID())); + rowData.add(getFileUniquePath(artifactData.getObjectID())); + break; case TSK_CALLLOG: - List call_log = new ArrayList<>(); - call_log.add(attributes.get(ATTRIBUTE_TYPE.TSK_NAME_PERSON.getTypeID())); - call_log.add(attributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER.getTypeID())); - call_log.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); - call_log.add(attributes.get(ATTRIBUTE_TYPE.TSK_DIRECTION.getTypeID())); - call_log.add(getFileUniquePath(artifactData.getObjectID())); - return call_log; + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_NAME_PERSON.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DIRECTION.getTypeID())); + rowData.add(getFileUniquePath(artifactData.getObjectID())); + break; case TSK_CALENDAR_ENTRY: - List calEntry = new ArrayList<>(); - calEntry.add(attributes.get(ATTRIBUTE_TYPE.TSK_CALENDAR_ENTRY_TYPE.getTypeID())); - calEntry.add(attributes.get(ATTRIBUTE_TYPE.TSK_DESCRIPTION.getTypeID())); - calEntry.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME_START.getTypeID())); - calEntry.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME_END.getTypeID())); - calEntry.add(attributes.get(ATTRIBUTE_TYPE.TSK_LOCATION.getTypeID())); - calEntry.add(getFileUniquePath(artifactData.getObjectID())); - return calEntry; + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_CALENDAR_ENTRY_TYPE.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DESCRIPTION.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME_START.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME_END.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_LOCATION.getTypeID())); + rowData.add(getFileUniquePath(artifactData.getObjectID())); + break; case TSK_SPEED_DIAL_ENTRY: - List speedDialEntry = new ArrayList(); - speedDialEntry.add(attributes.get(ATTRIBUTE_TYPE.TSK_SHORTCUT.getTypeID())); - speedDialEntry.add(attributes.get(ATTRIBUTE_TYPE.TSK_NAME_PERSON.getTypeID())); - speedDialEntry.add(attributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER.getTypeID())); - speedDialEntry.add(getFileUniquePath(artifactData.getObjectID())); - return speedDialEntry; + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_SHORTCUT.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_NAME_PERSON.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER.getTypeID())); + rowData.add(getFileUniquePath(artifactData.getObjectID())); + break; case TSK_BLUETOOTH_PAIRING: - List bluetoothEntry = new ArrayList(); - bluetoothEntry.add(attributes.get(ATTRIBUTE_TYPE.TSK_DEVICE_NAME.getTypeID())); - bluetoothEntry.add(attributes.get(ATTRIBUTE_TYPE.TSK_DEVICE_ID.getTypeID())); - bluetoothEntry.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); - bluetoothEntry.add(getFileUniquePath(artifactData.getObjectID())); - return bluetoothEntry; + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DEVICE_NAME.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DEVICE_ID.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); + rowData.add(getFileUniquePath(artifactData.getObjectID())); + break; case TSK_GPS_TRACKPOINT: - List gpsTrackpoint = new ArrayList(); - gpsTrackpoint.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID())); - gpsTrackpoint.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID())); - gpsTrackpoint.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE.getTypeID())); - gpsTrackpoint.add(attributes.get(ATTRIBUTE_TYPE.TSK_NAME.getTypeID())); - gpsTrackpoint.add(attributes.get(ATTRIBUTE_TYPE.TSK_LOCATION.getTypeID())); - gpsTrackpoint.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); - gpsTrackpoint.add(getFileUniquePath(artifactData.getObjectID())); - return gpsTrackpoint; + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_NAME.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_LOCATION.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); + rowData.add(getFileUniquePath(artifactData.getObjectID())); + break; case TSK_GPS_BOOKMARK: - List gpsBookmarkEntry = new ArrayList(); - gpsBookmarkEntry.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID())); - gpsBookmarkEntry.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID())); - gpsBookmarkEntry.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE.getTypeID())); - gpsBookmarkEntry.add(attributes.get(ATTRIBUTE_TYPE.TSK_NAME.getTypeID())); - gpsBookmarkEntry.add(attributes.get(ATTRIBUTE_TYPE.TSK_LOCATION.getTypeID())); - gpsBookmarkEntry.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); - gpsBookmarkEntry.add(getFileUniquePath(artifactData.getObjectID())); - return gpsBookmarkEntry; + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_NAME.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_LOCATION.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); + rowData.add(getFileUniquePath(artifactData.getObjectID())); + break; case TSK_GPS_LAST_KNOWN_LOCATION: - List gpsLastLocation = new ArrayList(); - gpsLastLocation.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID())); - gpsLastLocation.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID())); - gpsLastLocation.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE.getTypeID())); - gpsLastLocation.add(attributes.get(ATTRIBUTE_TYPE.TSK_NAME.getTypeID())); - gpsLastLocation.add(attributes.get(ATTRIBUTE_TYPE.TSK_LOCATION.getTypeID())); - gpsLastLocation.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); - gpsLastLocation.add(getFileUniquePath(artifactData.getObjectID())); - return gpsLastLocation; + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_NAME.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_LOCATION.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); + rowData.add(getFileUniquePath(artifactData.getObjectID())); + break; case TSK_GPS_SEARCH: - List gpsSearch = new ArrayList(); - gpsSearch.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID())); - gpsSearch.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID())); - gpsSearch.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE.getTypeID())); - gpsSearch.add(attributes.get(ATTRIBUTE_TYPE.TSK_NAME.getTypeID())); - gpsSearch.add(attributes.get(ATTRIBUTE_TYPE.TSK_LOCATION.getTypeID())); - gpsSearch.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); - gpsSearch.add(getFileUniquePath(artifactData.getObjectID())); - return gpsSearch; + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_GEO_ALTITUDE.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_NAME.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_LOCATION.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID())); + rowData.add(getFileUniquePath(artifactData.getObjectID())); + break; case TSK_SERVICE_ACCOUNT: - List appAccount = new ArrayList(); - appAccount.add(attributes.get(ATTRIBUTE_TYPE.TSK_CATEGORY.getTypeID())); - appAccount.add(attributes.get(ATTRIBUTE_TYPE.TSK_USER_ID.getTypeID())); - appAccount.add(attributes.get(ATTRIBUTE_TYPE.TSK_PASSWORD.getTypeID())); - appAccount.add(attributes.get(ATTRIBUTE_TYPE.TSK_NAME.getTypeID())); - appAccount.add(attributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); - appAccount.add(attributes.get(ATTRIBUTE_TYPE.TSK_URL.getTypeID())); - appAccount.add(attributes.get(ATTRIBUTE_TYPE.TSK_PATH.getTypeID())); - appAccount.add(attributes.get(ATTRIBUTE_TYPE.TSK_DESCRIPTION.getTypeID())); - appAccount.add(attributes.get(ATTRIBUTE_TYPE.TSK_EMAIL_REPLYTO.getTypeID())); - appAccount.add(attributes.get(ATTRIBUTE_TYPE.TSK_SERVER_NAME.getTypeID())); - appAccount.add(getFileUniquePath(artifactData.getObjectID())); - return appAccount; + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_CATEGORY.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_USER_ID.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_PASSWORD.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_NAME.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_URL.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_PATH.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_DESCRIPTION.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_EMAIL_REPLYTO.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_SERVER_NAME.getTypeID())); + rowData.add(getFileUniquePath(artifactData.getObjectID())); + break; case TSK_TOOL_OUTPUT: - List row = new ArrayList<>(); - row.add(attributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); - row.add(attributes.get(ATTRIBUTE_TYPE.TSK_TEXT.getTypeID())); - row.add(getFileUniquePath(artifactData.getObjectID())); - return row; + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID())); + rowData.add(attributes.get(ATTRIBUTE_TYPE.TSK_TEXT.getTypeID())); + rowData.add(getFileUniquePath(artifactData.getObjectID())); + break; } - return null; + rowData.add(makeCommaSeparatedList(artifactData.getTags())); + + return rowData; // RJCTODO: Is anyone checking for null here? } /** @@ -1230,52 +1169,7 @@ public class ReportGenerator { } return ""; } - - /** - * Given a tsk_file's obj_id, return the name of that file. - * - * @param objId tsk_file obj_id - * @return String name - */ - private String getFileName(long objId) { - try { - return skCase.getAbstractFileById(objId).getName(); - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Failed to get Abstract File by ID.", ex); - } - return ""; - } - - /** - * Return the file associated with a tsk_file obj_id. - * - * @param objId tsk_file obj_id - * @return AbstractFile associated with objId - */ - private AbstractFile getAbstractFile(long objId) { - try { - return skCase.getAbstractFileById(objId); - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Failed to get Abstract File by ID.", ex); - } - return null; - } - - /** - * Get a BlackboardArtifact. - * - * @param long artifactId An artifact id - * @return The BlackboardArtifact associated with the artifact id - */ - private BlackboardArtifact getArtifact(long artifactId) { - try { - return skCase.getBlackboardArtifact(artifactId); - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Failed to get blackboard artifact by ID.", ex); - } - return null; - } - + /** * Container class that holds data about an Artifact to eliminate duplicate * calls to the Sleuthkit database. diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index 4b5492ebec..c3d0466119 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -568,15 +568,15 @@ public class ReportHTML implements TableReportModule { * @param sourceArtifact The artifact associated with the row. */ private void addRowDataForSourceArtifact(List row, BlackboardArtifact sourceArtifact) { - int artifactTypeID = sourceArtifact.getArtifactTypeID(); - BlackboardArtifact.ARTIFACT_TYPE type = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifactTypeID); - switch (type) { - case TSK_TAG_FILE: - addRowDataForFileTagArtifact(row, sourceArtifact); - break; - default: - break; - } +// int artifactTypeID = sourceArtifact.getArtifactTypeID(); +// BlackboardArtifact.ARTIFACT_TYPE type = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifactTypeID); +// switch (type) { +// case TSK_TAG_FILE: +// addRowDataForFileTagArtifact(row, sourceArtifact); +// break; +// default: +// break; +// } } /** @@ -586,63 +586,63 @@ public class ReportHTML implements TableReportModule { * @param sourceArtifact The artifact associated with the row. */ private void addRowDataForFileTagArtifact(List row, BlackboardArtifact sourceArtifact) { - try { - AbstractFile file = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(sourceArtifact.getObjectID()); - - // Don't make a local copy of the file if it is a directory or unallocated space. - if (file.isDir() || - file.getType() == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS || - file.getType() == TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) { - row.add(""); - return; - } - - // Make a folder for the local file with the same name as the tag. - StringBuilder localFilePath = new StringBuilder(); - localFilePath.append(path); - HashSet tagNames = Tags.getUniqueTagNamesForArtifact(sourceArtifact); - if (!tagNames.isEmpty()) { - localFilePath.append(tagNames.iterator().next()); - } - File localFileFolder = new File(localFilePath.toString()); - if (!localFileFolder.exists()) { - localFileFolder.mkdirs(); - } - - // Construct a file name for the local file that incorporates the corresponding object id to ensure uniqueness. - String fileName = file.getName(); - String objectIdSuffix = "_" + sourceArtifact.getObjectID(); - int lastDotIndex = fileName.lastIndexOf("."); - if (lastDotIndex != -1 && lastDotIndex != 0) { - // The file name has a conventional extension. Insert the object id before the '.' of the extension. - fileName = fileName.substring(0, lastDotIndex) + objectIdSuffix + fileName.substring(lastDotIndex, fileName.length()); - } - else { - // The file has no extension or the only '.' in the file is an initial '.', as in a hidden file. - // Add the object id to the end of the file name. - fileName += objectIdSuffix; - } - localFilePath.append(File.separator); - localFilePath.append(fileName); - - // If the local file doesn't already exist, create it now. - // The existence check is necessary because it is possible to apply multiple tags with the same name to a file. - File localFile = new File(localFilePath.toString()); - if (!localFile.exists()) { - ExtractFscContentVisitor.extract(file, localFile, null, null); - } - - // Add the hyperlink to the row. A column header for it was created in startTable(). - StringBuilder localFileLink = new StringBuilder(); - localFileLink.append("View File"); - row.add(localFileLink.toString()); - } - catch (TskCoreException ex) { - logger.log(Level.WARNING, "Failed to get AbstractFile by ID.", ex); - row.add(""); - } +// try { +// AbstractFile file = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(sourceArtifact.getObjectID()); +// +// // Don't make a local copy of the file if it is a directory or unallocated space. +// if (file.isDir() || +// file.getType() == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS || +// file.getType() == TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) { +// row.add(""); +// return; +// } +// +// // Make a folder for the local file with the same name as the tag. +// StringBuilder localFilePath = new StringBuilder(); +// localFilePath.append(path); +// HashSet tagNames = Tags.getUniqueTagNamesForArtifact(sourceArtifact); +// if (!tagNames.isEmpty()) { +// localFilePath.append(tagNames.iterator().next()); +// } +// File localFileFolder = new File(localFilePath.toString()); +// if (!localFileFolder.exists()) { +// localFileFolder.mkdirs(); +// } +// +// // Construct a file name for the local file that incorporates the corresponding object id to ensure uniqueness. +// String fileName = file.getName(); +// String objectIdSuffix = "_" + sourceArtifact.getObjectID(); +// int lastDotIndex = fileName.lastIndexOf("."); +// if (lastDotIndex != -1 && lastDotIndex != 0) { +// // The file name has a conventional extension. Insert the object id before the '.' of the extension. +// fileName = fileName.substring(0, lastDotIndex) + objectIdSuffix + fileName.substring(lastDotIndex, fileName.length()); +// } +// else { +// // The file has no extension or the only '.' in the file is an initial '.', as in a hidden file. +// // Add the object id to the end of the file name. +// fileName += objectIdSuffix; +// } +// localFilePath.append(File.separator); +// localFilePath.append(fileName); +// +// // If the local file doesn't already exist, create it now. +// // The existence check is necessary because it is possible to apply multiple tags with the same name to a file. +// File localFile = new File(localFilePath.toString()); +// if (!localFile.exists()) { +// ExtractFscContentVisitor.extract(file, localFile, null, null); +// } +// +// // Add the hyperlink to the row. A column header for it was created in startTable(). +// StringBuilder localFileLink = new StringBuilder(); +// localFileLink.append("View File"); +// row.add(localFileLink.toString()); +// } +// catch (TskCoreException ex) { +// logger.log(Level.WARNING, "Failed to get AbstractFile by ID.", ex); +// row.add(""); +// } } /** From e91114c77cd793beb81a7ce03475e571f4c57359 Mon Sep 17 00:00:00 2001 From: raman-bt Date: Mon, 21 Oct 2013 11:09:47 -0400 Subject: [PATCH 027/169] i. Changed AddImageTask.CurrentDirFether to be a Runnable instead of Swingworker. ii. Changed the DSPProgressMonitorImpl to update the progress UI on the Swing EDT thread. iii. Added the image related params to AddImageTask constructor, and dropped the SetImageOptions() method. --- .../autopsy/casemodule/AddImageTask.java | 51 +++++++++---------- .../AddImageWizardAddingProgressPanel.java | 37 +++++++++++--- .../autopsy/casemodule/ImageDSProcessor.java | 8 +-- 3 files changed, 54 insertions(+), 42 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java index 771d217eaa..e7b6b05f34 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java @@ -55,7 +55,8 @@ public class AddImageTask extends SwingWorker { //true if revert has been invoked. private boolean reverted = false; private boolean hasCritError = false; - private boolean addImageDone = false; + + private boolean addImageDone = false; private List errorList = new ArrayList(); @@ -65,7 +66,7 @@ public class AddImageTask extends SwingWorker { private final List newContents = Collections.synchronizedList(new ArrayList()); private SleuthkitJNI.CaseDbHandle.AddImageProcess addImageProcess; - private CurrentDirectoryFetcher fetcher; + private Thread dirFetcher; private String imagePath; private String dataSourcetype; @@ -73,20 +74,11 @@ public class AddImageTask extends SwingWorker { boolean noFatOrphans; - /* - * Sets the name/path and other options for the iimage to be processed - */ - public void SetImageOptions(String imgPath, String tz, boolean noOrphans) { - this.imagePath = imgPath; - this.timeZone = tz; - this.noFatOrphans = noOrphans; - } - /* * A Swingworker that updates the progressMonitor with the name of the * directory currently being processed by the AddImageTask */ - private class CurrentDirectoryFetcher extends SwingWorker { + private class CurrentDirectoryFetcher implements Runnable { DSPProgressMonitor progressMonitor; SleuthkitJNI.CaseDbHandle.AddImageProcess process; @@ -100,31 +92,33 @@ public class AddImageTask extends SwingWorker { * @return the currently processing directory */ @Override - protected Integer doInBackground() { + public void run() { try { - while (!(addImageDone)) { - EventQueue.invokeLater(new Runnable() { - @Override - public void run() { - progressMonitor.setText(process.currentDirectory()); - } - }); - + while (!Thread.currentThread().isInterrupted()) { + + progressMonitor.setText(process.currentDirectory()); + Thread.sleep(2 * 1000); } - return 1; + return; } catch (InterruptedException ie) { - return -1; + return; } } } - protected AddImageTask(DSPProgressMonitor aProgressMonitor, DSPCallback cbObj ) { - this.progressMonitor = aProgressMonitor; + protected AddImageTask(String imgPath, String tz, boolean noOrphans, DSPProgressMonitor aProgressMonitor, DSPCallback cbObj ) { + currentCase = Case.getCurrentCase(); + + this.imagePath = imgPath; + this.timeZone = tz; + this.noFatOrphans = noOrphans; + this.callbackObj = cbObj; + this.progressMonitor = aProgressMonitor; } /** @@ -159,13 +153,14 @@ public class AddImageTask extends SwingWorker { } addImageProcess = currentCase.makeAddImageProcess(timeZone, true, noFatOrphans); - fetcher = new CurrentDirectoryFetcher(progressMonitor, addImageProcess); + dirFetcher = new Thread( new CurrentDirectoryFetcher(progressMonitor, addImageProcess)); try { progressMonitor.setIndeterminate(true); progressMonitor.setProgress(0); - fetcher.execute(); + dirFetcher.start(); + addImageProcess.run(new String[]{this.imagePath}); } catch (TskCoreException ex) { logger.log(Level.WARNING, "Core errors occurred while running add image. ", ex); @@ -237,7 +232,7 @@ public class AddImageTask extends SwingWorker { setProgress(100); // cancel the directory fetcher - fetcher.cancel(true); + dirFetcher.interrupt(); addImageDone = true; // attempt actions that might fail and force the process to stop diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java index 46592d269e..7e1bd20464 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.casemodule; import java.awt.Color; +import java.awt.EventQueue; import java.util.HashSet; import java.util.Iterator; import java.util.Set; @@ -60,20 +61,40 @@ class AddImageWizardAddingProgressPanel implements WizardDescriptor.FinishablePa private class DSPProgressMonitorImpl implements DSPProgressMonitor { @Override - public void setIndeterminate(boolean indeterminate) { - getComponent().getProgressBar().setIndeterminate(indeterminate); - + public void setIndeterminate(final boolean indeterminate) { + // update the progress bar asynchronously + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + getComponent().getProgressBar().setIndeterminate(indeterminate); + } + }); } + @Override - public void setProgress(int progress) { - getComponent().getProgressBar().setValue(progress); + public void setProgress(final int progress) { + // update the progress bar asynchronously + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + getComponent().getProgressBar().setValue(progress); + } + }); } + @Override - public void setText(String text) { - getComponent().setCurrentDirText(text); - + public void setText(final String text) { + // update the progress UI asynchronously + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + getComponent().setCurrentDirText(text); + } + }); } + + } /** * Get the visual component for the panel. In this template, the component diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java index 6540961af4..4fe759f3e5 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java @@ -121,7 +121,7 @@ public class ImageDSProcessor implements DataSourceProcessor { if (!imageOptionsSet) { - // RAMAN TBD: we should ask the panel to save the current settings now + // RAMAN TBD: we should ask the panel to save the current settings // get the image options from the panel imagePath = imageFilePanel.getContentPaths(); @@ -129,11 +129,7 @@ public class ImageDSProcessor implements DataSourceProcessor { noFatOrphans = imageFilePanel.getNoFatOrphans(); } - addImageTask = new AddImageTask(progressMonitor, cbObj); - - // set the image options needed by AddImageTask - such as TZ and NoFatOrphans **/ - addImageTask.SetImageOptions(imagePath, timeZone, noFatOrphans); - + addImageTask = new AddImageTask(imagePath, timeZone, noFatOrphans, progressMonitor, cbObj); addImageTask.execute(); return; From bee91a40ce5dfd392129886586b40e1d2097d9ae Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 21 Oct 2013 19:01:25 -0400 Subject: [PATCH 028/169] Updated reporting to work with new tags API --- .../casemodule/services/TagsManager.java | 30 +- .../sleuthkit/autopsy/report/ReportExcel.java | 41 +-- .../autopsy/report/ReportGenerator.java | 329 +++++++++++------- .../sleuthkit/autopsy/report/ReportHTML.java | 224 +++++------- .../autopsy/report/ReportWizardAction.java | 2 +- .../autopsy/report/TableReportModule.java | 3 +- 6 files changed, 321 insertions(+), 308 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 22b2c1b98b..a41743784c 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -97,7 +97,7 @@ public class TagsManager implements Closeable { tagNames.clear(); tskCase.getTagNamesInUse(tagNames); } - + /** * Checks whether a tag name with a given display name exists. * @param [in] tagDisplayName The display name for which to check. @@ -227,6 +227,20 @@ public class TagsManager implements Closeable { tskCase.deleteContentTag(tag); } + /** + * Gets all content tags for the current case. + * @param [out] tags A list, possibly empty, of content tags. + * @throws TskCoreException + */ + public void getAllContentTags(List tags) throws TskCoreException { + // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. + if (!tagNamesInitialized) { + getExistingTagNames(); + } + + tskCase.getAllContentTags(tags); + } + /** * Gets content tags count by tag name. * @param [in] tagName The tag name of interest. @@ -297,6 +311,20 @@ public class TagsManager implements Closeable { tskCase.deleteBlackboardArtifactTag(tag); } + /** + * Gets all blackboard artifact tags for the current case. + * @param [out] tags A list, possibly empty, of blackboard artifact tags. + * @throws TskCoreException + */ + public void getAllBlackboardArtifactTags(List tags) throws TskCoreException { + // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. + if (!tagNamesInitialized) { + getExistingTagNames(); + } + + tskCase.getAllBlackboardArtifactTags(tags); + } + /** * Gets blackboard artifact tags count by tag name. * @param [in] tagName The tag name of interest. diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java b/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java index fbf1ba19f6..5a221e6ef6 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportExcel.java @@ -121,40 +121,6 @@ public class ReportExcel implements TableReportModule { } } - - /** - * Start a new worksheet for the given data type. - * @param name data type name - */ - @Override - public void startDataType(String name) { - // Create a worksheet for the data type (assumed to be an artifact type). - name = escapeForExcel(name); - sheet = wb.createSheet(name); - sheet.setAutobreaks(true); - rowIndex = 0; - artifactsCount = 0; - - // Add a title row to the worksheet. - Row row = sheet.createRow(rowIndex); - row.setRowStyle(setStyle); - row.createCell(0).setCellValue(name); - ++rowIndex; - - // Add an artifacts count row. The actual count will be filled in later. - row = sheet.createRow(rowIndex); - row.setRowStyle(setStyle); - row.createCell(0).setCellValue("Number of artifacts:"); - ++rowIndex; - - // Add an empty row as a separator. - sheet.createRow(rowIndex); - ++rowIndex; - - // There will be at least two columns, one each for the artifacts count and its label. - sheetColCount = 2; - } - /** * Start a new worksheet for the given data type. * Note: This method is a temporary workaround to avoid modifying the TableReportModule interface. @@ -162,7 +128,8 @@ public class ReportExcel implements TableReportModule { * @param name Name of the data type * @param comment Comment on the data type, may be the empty string */ - public void startDataType(String name, String comment) { + @Override + public void startDataType(String name, String description) { // Create a worksheet for the data type (assumed to be an artifact type). name = escapeForExcel(name); sheet = wb.createSheet(name); @@ -183,10 +150,10 @@ public class ReportExcel implements TableReportModule { ++rowIndex; // Add a comment row, if a comment was supplied. - if (!comment.isEmpty()) { + if (!description.isEmpty()) { row = sheet.createRow(rowIndex); row.setRowStyle(setStyle); - row.createCell(0).setCellValue(comment); + row.createCell(0).setCellValue(description); ++rowIndex; } diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java index 45a551759d..792bfa169b 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java @@ -50,7 +50,6 @@ import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.EscapeUtil; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil; -import org.sleuthkit.autopsy.datamodel.Tags; import org.sleuthkit.autopsy.report.ReportProgressPanel.ReportStatus; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; @@ -58,16 +57,15 @@ import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; +import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; /** - * Generates all TableReportModules and GeneralReportModules, given whether each module for both - * types is enabled or disabled, and the base report path to save them at. - * - * After creating an instance of ReportGenerator, one must tell it which reports to run, - * TableReportModules on Tags or Artifacts, and the GeneralReportModules. - * Then, one calls displayProgressPanels() to display the progress to the user. + * Instances of this class use GeneralReportModules, TableReportModules and + * FileReportModules to generate a report. If desired, displayProgressPanels() + * can be called to show report generation progress using ReportProgressPanel + * objects displayed using a dialog box. */ public class ReportGenerator { private static final Logger logger = Logger.getLogger(ReportGenerator.class.getName()); @@ -106,10 +104,11 @@ public class ReportGenerator { } /** - * For every ReportModule which the user enabled, create a ReportProgressPanel for that report. + * Create a ReportProgressPanel for each report generation module selected by the user. * - * @param tableModuleStates the enabled/disabled state of each TableReportModule - * @param generalModuleStates the enabled/disabled state of each GeneralReportModule + * @param tableModuleStates The enabled/disabled state of each TableReportModule + * @param generalModuleStates The enabled/disabled state of each GeneralReportModule + * @param fileListModuleStates The enabled/disabled state of each FileReportModule */ private void setupProgressPanels(Map tableModuleStates, Map generalModuleStates, Map fileListModuleStates) { if (null != tableModuleStates) { @@ -174,28 +173,28 @@ public class ReportGenerator { } /** - * Generate the GeneralReportModule reports in a new SwingWorker. + * Run the GeneralReportModules using a SwingWorker. */ public void generateGeneralReports() { - GeneralWorker worker = new GeneralWorker(); + GeneralReportsWorker worker = new GeneralReportsWorker(); worker.execute(); } /** - * Generate the TableReportModule reports on Blackboard Artifacts in a new SwingWorker. + * Run the TableReportModules using a SwingWorker. * * @param artifactTypeSelections the enabled/disabled state of the artifact types to be included in the report - * @param tagSelections the enabled/disabled state of the tags to be included in the report + * @param tagSelections the enabled/disabled state of the tag names to be included in the report */ - public void generateArtifactTableReports(Map artifactTypeSelections, Map tagSelections) { + public void generateBlackboardArtifactsReports(Map artifactTypeSelections, Map tagNameSelections) { if (!tableProgress.isEmpty() && null != artifactTypeSelections) { - ArtifactsReportsWorker worker = new ArtifactsReportsWorker(artifactTypeSelections, tagSelections); + TableReportsWorker worker = new TableReportsWorker(artifactTypeSelections, tagNameSelections); worker.execute(); } } /** - * Generate the FileReportModule reports in a new SwingWorker. + * Run the FileReportModules using a SwingWorker. * * @param enabledInfo the Information that should be included about each file * in the report. @@ -214,9 +213,9 @@ public class ReportGenerator { } /** - * SwingWorker to generate a report on all GeneralReportModules. + * SwingWorker to run GeneralReportModules. */ - private class GeneralWorker extends SwingWorker { + private class GeneralReportsWorker extends SwingWorker { @Override protected Integer doInBackground() throws Exception { @@ -232,7 +231,7 @@ public class ReportGenerator { } /** - * SwingWorker to generate a FileReport. + * SwingWorker to run FileReportModules. */ private class FileReportsWorker extends SwingWorker { private List enabledInfo = Arrays.asList(FileReportDataTypes.values()); @@ -317,15 +316,15 @@ public class ReportGenerator { } /** - * SwingWorker to generate reports on blackboard artifacts. + * SwingWorker to run TableReportModules to report on blackboard artifacts, + * content tags, and blackboard artifact tags. */ - private class ArtifactsReportsWorker extends SwingWorker { + private class TableReportsWorker extends SwingWorker { private List tableModules = new ArrayList<>(); private List artifactTypes = new ArrayList<>(); private HashSet tagNamesFilter = new HashSet<>(); - // Create an ArtifactWorker with the enabled/disabled state of all Artifacts - ArtifactsReportsWorker(Map artifactTypeSelections, Map tagSelections) { + TableReportsWorker(Map artifactTypeSelections, Map tagNameSelections) { // Get the report modules selected by the user. for (Entry entry : tableProgress.entrySet()) { tableModules.add(entry.getKey()); @@ -338,9 +337,9 @@ public class ReportGenerator { } } - // Get the tags selected by the user. - if (null != tagSelections) { - for (Entry entry : tagSelections.entrySet()) { + // Get the tag names selected by the user and make a tag names filter. + if (null != tagNameSelections) { + for (Entry entry : tagNameSelections.entrySet()) { if (entry.getValue() == true) { tagNamesFilter.add(entry.getKey()); } @@ -350,39 +349,46 @@ public class ReportGenerator { @Override protected Integer doInBackground() throws Exception { - // Start the report + // Start the progress indicators for each active TableReportModule. for (TableReportModule module : tableModules) { ReportProgressPanel progress = tableProgress.get(module); if (progress.getStatus() != ReportStatus.CANCELED) { module.startReport(reportPath); progress.start(); progress.setIndeterminate(false); - progress.setMaximumProgress(ARTIFACT_TYPE.values().length); + progress.setMaximumProgress(ARTIFACT_TYPE.values().length + 2); // +2 for content and blackboard artifact tags } } + + makeBlackboardArtifactTables(); + makeContentTagsTables(); + makeBlackboardArtifactTagsTables(); - // Make a comment on the tags filter. + for (TableReportModule module : tableModules) { + tableProgress.get(module).complete(); + module.endReport(); + } + + return 0; + } + + private void makeBlackboardArtifactTables() { + // Make a comment string describing the tag names filter in effect. StringBuilder comment = new StringBuilder(); if (!tagNamesFilter.isEmpty()) { - comment.append("This report only includes files and artifacts tagged with: "); + comment.append("This report only includes results tagged with: "); comment.append(makeCommaSeparatedList(tagNamesFilter)); } - - // For every enabled artifact type + + // Add a table to the report for every enabled blackboard artifact type. for (ARTIFACT_TYPE type : artifactTypes) { - // Check to see if all the TableReportModules have been canceled + // Check for cancellaton. + removeCancelledTableReportModules(); if (tableModules.isEmpty()) { - break; + return; } - Iterator iter = tableModules.iterator(); - while (iter.hasNext()) { - TableReportModule module = iter.next(); - if (tableProgress.get(module).getStatus() == ReportStatus.CANCELED) { - iter.remove(); - } - } - - // If the type is keyword hit or hashset hit, use the helper + + // Keyword hits and hashset hit artifacts get sepcial handling. if (type.equals(ARTIFACT_TYPE.TSK_KEYWORD_HIT)) { writeKeywordHits(tableModules, comment.toString(), tagNamesFilter); continue; @@ -392,20 +398,19 @@ public class ReportGenerator { } List unsortedArtifacts = getFilteredArtifacts(type, tagNamesFilter); - if (unsortedArtifacts.isEmpty()) { - // Don't report on this artifact type if there are no results continue; } + // The most efficient way to sort all the Artifacts is to add them to a List, and then // sort that List based off a Comparator. Adding to a TreeMap/Set/List sorts the list // each time an element is added, which adds unnecessary overhead if we only need it sorted once. Collections.sort(unsortedArtifacts); // Get the column headers appropriate for the artifact type. - /* @@@ BC: Seems like a better design here woudl be to have a method that - * takes in teh artifact as an argument andreturns the attributes. We then use that - * to make the headers and to make each row afterwards so that we don't ahve artifact-specific + /* @@@ BC: Seems like a better design here would be to have a method that + * takes in the artifact as an argument and returns the attributes. We then use that + * to make the headers and to make each row afterwards so that we don't have artifact-specific * logic in both getArtifactTableCoumnHeaders and getArtifactRow() */ List columnHeaders = getArtifactTableColumnHeaders(type.getTypeID()); @@ -414,37 +419,17 @@ public class ReportGenerator { MessageNotifyUtil.Notify.show("Skipping artifact type " + type + " in reports", "Unknown columns to report on", MessageNotifyUtil.MessageType.ERROR); continue; } - + for (TableReportModule module : tableModules) { tableProgress.get(module).updateStatusLabel("Now processing " + type.getDisplayName() + "..."); - - // This is a temporary workaround to avoid modifying the TableReportModule interface. - if (module instanceof ReportHTML) { - ReportHTML htmlReportModule = (ReportHTML)module; - htmlReportModule.startDataType(type.getDisplayName(), comment.toString()); - htmlReportModule.startTable(columnHeaders, type); - } - else if (module instanceof ReportExcel) { - ReportExcel excelReportModule = (ReportExcel)module; - excelReportModule.startDataType(type.getDisplayName(), comment.toString()); - excelReportModule.startTable(columnHeaders); - } - else { - module.startDataType(type.getDisplayName()); - module.startTable(columnHeaders); - } + module.startDataType(type.getDisplayName(), comment.toString()); + module.startTable(columnHeaders); } - + boolean msgSent = false; - for(ArtifactData artifactData : unsortedArtifacts) { -// HashSet tags = artifactData.getTags(); -// -// String tagsList = makeCommaSeparatedList(tags); - + for(ArtifactData artifactData : unsortedArtifacts) { // Add the row data to all of the reports. - for (TableReportModule module : tableModules) { - - // Get the row data for this type of artifact. + for (TableReportModule module : tableModules) { List rowData; rowData = getArtifactRow(artifactData, module); if (rowData.isEmpty()) { @@ -455,44 +440,160 @@ public class ReportGenerator { continue; } -// // This is a temporary workaround to avoid modifying the TableReportModule interface. -// if (module instanceof ReportHTML) { -// ReportHTML htmlReportModule = (ReportHTML)module; -// htmlReportModule.addRow(rowData, artifactData.getArtifact()); -// } -// else { - module.addRow(rowData); -// } + module.addRow(rowData); } } - + // Finish up this data type for (TableReportModule module : tableModules) { tableProgress.get(module).increment(); module.endTable(); module.endDataType(); } - } - - // End the report - for (TableReportModule module : tableModules) { - tableProgress.get(module).complete(); - module.endReport(); - } - - return 0; + } } + + private void makeContentTagsTables() { + // Check for cancellaton. + removeCancelledTableReportModules(); + if (tableModules.isEmpty()) { + return; + } + + // Get the content tags. + ArrayList tags = new ArrayList<>(); + try { + Case.getCurrentCase().getServices().getTagsManager().getAllContentTags(tags); + } + catch (TskCoreException ex) { + logger.log(Level.SEVERE, "failed to get content tags", ex); + return; + } + + // Tell the modules reporting on content tags is beginning. + for (TableReportModule module : tableModules) { + // @@@ This casting is a tricky little workaround to allow the HTML report module to slip in a content hyperlink. + // @@@ Alos Using the obsolete ARTIFACT_TYPE.TSK_TAG_FILE is also an expedient hack. + tableProgress.get(module).updateStatusLabel("Now processing " + ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName() + "..."); + ArrayList columnHeaders = new ArrayList<>(Arrays.asList("File", "Tag", "Comment")); + StringBuilder comment = new StringBuilder(); + if (!tagNamesFilter.isEmpty()) { + comment.append("This report only includes file tagged with: "); + comment.append(makeCommaSeparatedList(tagNamesFilter)); + } + if (module instanceof ReportHTML) { + ReportHTML htmlReportModule = (ReportHTML)module; + htmlReportModule.startDataType(ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName(), comment.toString()); + htmlReportModule.startContentTagsTable(columnHeaders); + } + else { + module.startDataType(ARTIFACT_TYPE.TSK_TAG_FILE.getDisplayName(), comment.toString()); + module.startTable(columnHeaders); + } + } + + // Give the modules the rows for the content tags. + for (ContentTag tag : tags) { + // Apply the tag names filter. + if (!tagNamesFilter.isEmpty()) { + if (tagNamesFilter.contains(tag.getName().getDisplayName())) { + continue; + } + } + + ArrayList rowData = new ArrayList<>(Arrays.asList(tag.getContent().getName(), tag.getName().getDisplayName(), tag.getComment())); + for (TableReportModule module : tableModules) { + // @@@ This casting is a tricky little workaround to allow the HTML report module to slip in a content hyperlink. + if (module instanceof ReportHTML) { + ReportHTML htmlReportModule = (ReportHTML)module; + htmlReportModule.addRowWithTaggedContentHyperlink(rowData, tag); + } + else { + module.addRow(rowData); + } + } + } + + // The the modules content tags reporting is ended. + for (TableReportModule module : tableModules) { + tableProgress.get(module).increment(); + module.endTable(); + module.endDataType(); + } + } + + private void makeBlackboardArtifactTagsTables() { + // Check for cancellaton. + removeCancelledTableReportModules(); + if (tableModules.isEmpty()) { + return; + } + + ArrayList tags = new ArrayList<>(); + try { + Case.getCurrentCase().getServices().getTagsManager().getAllBlackboardArtifactTags(tags); + } + catch (TskCoreException ex) { + logger.log(Level.SEVERE, "failed to get blackboard artifact tags", ex); + return; + } + + // Tell the modules reporting on blackboard artifact tags data type is beginning. + // @@@ Using the obsolete ARTIFACT_TYPE.TSK_TAG_ARTIFACT is an expedient hack. + for (TableReportModule module : tableModules) { + tableProgress.get(module).updateStatusLabel("Now processing " + ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getDisplayName() + "..."); + StringBuilder comment = new StringBuilder(); + if (!tagNamesFilter.isEmpty()) { + comment.append("This report only includes results tagged with: "); + comment.append(makeCommaSeparatedList(tagNamesFilter)); + } + module.startDataType(ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getDisplayName(), comment.toString()); + module.startTable(new ArrayList<>(Arrays.asList("Result Type", "Tag", "Comment", "Source File"))); + } + + // Give the modules the rows for the content tags. + for (BlackboardArtifactTag tag : tags) { + // Apply the tag names filter. + if (!tagNamesFilter.isEmpty()) { + if (tagNamesFilter.contains(tag.getName().getDisplayName())) { + continue; + } + } + + for (TableReportModule module : tableModules) { + module.addRow(new ArrayList<>(Arrays.asList(tag.getArtifact().getArtifactTypeName(), tag.getName().getDisplayName(), tag.getComment(), tag.getContent().getName()))); + } + } + + // The the modules blackboard artifact tags reporting is ended. + for (TableReportModule module : tableModules) { + tableProgress.get(module).increment(); + module.endTable(); + module.endDataType(); + } + } + + void removeCancelledTableReportModules() { + Iterator iter = tableModules.iterator(); + while (iter.hasNext()) { + TableReportModule module = iter.next(); + if (tableProgress.get(module).getStatus() == ReportStatus.CANCELED) { + iter.remove(); + } + } + } } - - private Boolean failsTagFilter(HashSet tags, HashSet tagsFilter) + + /// @@@ Should move the methods specific to TableReportsWorker into that scope. + private Boolean failsTagFilter(HashSet tagNames, HashSet tagsNamesFilter) { - if (null == tagsFilter || tagsFilter.isEmpty()) { + if (null == tagsNamesFilter || tagsNamesFilter.isEmpty()) { return false; } - HashSet filteredTags = new HashSet<>(tags); - filteredTags.retainAll(tagsFilter); - return filteredTags.isEmpty(); + HashSet filteredTagNames = new HashSet<>(tagNames); + filteredTagNames.retainAll(tagsNamesFilter); + return filteredTagNames.isEmpty(); } /** @@ -554,18 +655,7 @@ public class ReportGenerator { // Make keyword data type and give them set index for (TableReportModule module : tableModules) { - // This is a temporary workaround to avoid modifying the TableReportModule interface. - if (module instanceof ReportHTML) { - ReportHTML htmlReportModule = (ReportHTML)module; - htmlReportModule.startDataType(ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName(), comment); - } - else if (module instanceof ReportExcel) { - ReportExcel excelReportModule = (ReportExcel)module; - excelReportModule.startDataType(ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName(), comment); - } - else { - module.startDataType(ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName()); - } + module.startDataType(ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName(), comment); module.addSetIndex(lists); tableProgress.get(module).updateStatusLabel("Now processing " + ARTIFACT_TYPE.TSK_KEYWORD_HIT.getDisplayName() + "..."); @@ -708,18 +798,7 @@ public class ReportGenerator { } for (TableReportModule module : tableModules) { - // This is a temporary workaround to avoid modifying the TableReportModule interface. - if (module instanceof ReportHTML) { - ReportHTML htmlReportModule = (ReportHTML)module; - htmlReportModule.startDataType(ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName(), comment); - } - else if (module instanceof ReportExcel) { - ReportExcel excelReportModule = (ReportExcel)module; - excelReportModule.startDataType(ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName(), comment); - } - else { - module.startDataType(ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName()); - } + module.startDataType(ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName(), comment); module.addSetIndex(lists); tableProgress.get(module).updateStatusLabel("Now processing " + ARTIFACT_TYPE.TSK_HASHSET_HIT.getDisplayName() + "..."); @@ -981,7 +1060,7 @@ public class ReportGenerator { * @return List row values * @throws TskCoreException */ - private List getArtifactRow(ArtifactData artifactData, TableReportModule module) throws TskCoreException { + private List getArtifactRow(ArtifactData artifactData, TableReportModule module) { Map attributes = getMappedAttributes(artifactData.getAttributes(), module); List rowData = new ArrayList<>(); @@ -1152,7 +1231,7 @@ public class ReportGenerator { } rowData.add(makeCommaSeparatedList(artifactData.getTags())); - return rowData; // RJCTODO: Is anyone checking for null here? + return rowData; } /** diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index c3d0466119..14f47a798b 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -28,7 +28,6 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.io.FileInputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; @@ -45,17 +44,17 @@ import org.openide.filesystems.FileUtil; import org.openide.util.Exceptions; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datamodel.Tags; -import org.sleuthkit.autopsy.datamodel.ContentUtils; import org.sleuthkit.autopsy.datamodel.ContentUtils.ExtractFscContentVisitor; +import org.sleuthkit.autopsy.datamodel.Tags; import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; -import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.TskData; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM; public class ReportHTML implements TableReportModule { @@ -91,7 +90,7 @@ public class ReportHTML implements TableReportModule { currentCase = Case.getCurrentCase(); skCase = currentCase.getSleuthkitCase(); - dataTypes = new TreeMap(); + dataTypes = new TreeMap<>(); path = ""; currentDataType = ""; @@ -129,10 +128,10 @@ public class ReportHTML implements TableReportModule { { String iconFilePath; String iconFileName; - InputStream in = null; + InputStream in; OutputStream output = null; - logger.log(Level.INFO, "useDataTypeIcon: dataType = " + dataType); + logger.log(Level.INFO, "useDataTypeIcon: dataType = {0}", dataType); // find the artifact with matching display name BlackboardArtifact.ARTIFACT_TYPE artifactType = null; @@ -296,39 +295,6 @@ public class ReportHTML implements TableReportModule { } } } - - /** - * Start a new HTML page for the given data type. Update the output stream to this page, - * and setup the web page header. - * @param title title of the data type - */ - @Override - public void startDataType(String title) { - String fTitle = dataTypeToFileName(title); - // Make a new out for this page - try { - //escape out slashes tha that appear in title - - out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path + fTitle + getExtension()), "UTF-8")); - } catch (FileNotFoundException ex) { - logger.log(Level.SEVERE, "File not found: {0}", ex); - } catch (UnsupportedEncodingException ex) { - logger.log(Level.SEVERE, "Unrecognized encoding"); - } - - // Write the beginnings of a page - // Like , header, title, any content divs - try { - StringBuilder page = new StringBuilder(); - page.append("\n\n\t").append(title).append("\n\t\n\n\n\n"); - page.append("
").append(title).append("
\n
\n"); - out.write(page.toString()); - currentDataType = title; - rowCount = 0; - } catch (IOException ex) { - logger.log(Level.SEVERE, "Failed to write page head: {0}", ex); - } - } /** * Start a new HTML page for the given data type. Update the output stream to this page, @@ -338,7 +304,8 @@ public class ReportHTML implements TableReportModule { * @param name Name of the data type * @param comment Comment on the data type, may be the empty string */ - public void startDataType(String name, String comment) { + @Override + public void startDataType(String name, String description) { String title = dataTypeToFileName(name); try { out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path + title + getExtension()), "UTF-8")); @@ -352,9 +319,9 @@ public class ReportHTML implements TableReportModule { StringBuilder page = new StringBuilder(); page.append("\n\n\t").append(name).append("\n\t\n\n\n\n"); page.append("
").append(name).append("
\n
\n"); - if (!comment.isEmpty()) { + if (!description.isEmpty()) { page.append("

"); - page.append(comment); + page.append(description); page.append("

\n"); } out.write(page.toString()); @@ -477,17 +444,17 @@ public class ReportHTML implements TableReportModule { * @param columnHeaders column headers * @param sourceArtifact source blackboard artifact for the table data */ - public void startTable(List columnHeaders, ARTIFACT_TYPE artifactType) { + public void startContentTagsTable(List columnHeaders) { StringBuilder htmlOutput = new StringBuilder(); htmlOutput.append("\n\n\t\n"); + + // Add the specified columns. for(String columnHeader : columnHeaders) { htmlOutput.append("\t\t\n"); } - // For file tag artifacts, add a column for a hyperlink to a local copy of the tagged file. - if (artifactType.equals(ARTIFACT_TYPE.TSK_TAG_FILE)) { - htmlOutput.append("\t\t\n"); - } + // Add a column for a hyperlink to a local copy of the tagged content. + htmlOutput.append("\t\t\n"); htmlOutput.append("\t\n\n"); @@ -527,20 +494,75 @@ public class ReportHTML implements TableReportModule { try { out.write(builder.toString()); } catch (IOException ex) { - logger.log(Level.SEVERE, "Failed to write row to out."); + logger.log(Level.SEVERE, "Failed to write row to out.", ex); } catch (NullPointerException ex) { - logger.log(Level.SEVERE, "Output writer is null. Page was not initialized before writing."); + logger.log(Level.SEVERE, "Output writer is null. Page was not initialized before writing.", ex); } } /** - * Add a row to the current table. + * Saves a local copy of a tagged file and adds a row with a hyper link to + * the file. * - * @param row values for each cell in the row - * @param sourceArtifact source blackboard artifact for the table data + * @param row Values for each data cell in the row. + * @param contentTag A content tag to use to make the hyper link. */ - public void addRow(List row, BlackboardArtifact sourceArtifact) { - addRowDataForSourceArtifact(row, sourceArtifact); + public void addRowWithTaggedContentHyperlink(List row, ContentTag contentTag) { + // Only handling AbstractFiles at present. + AbstractFile file; + if (contentTag.getContent() instanceof AbstractFile) { + file = (AbstractFile)contentTag.getContent(); + } + else { + return; + } + + // Don't make a local copy of the file if it is a directory or unallocated space. + if (file.isDir() || + file.getType() == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS || + file.getType() == TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) { + row.add(""); + return; + } + + // Make a folder for the local file with the same name as the tag. + StringBuilder localFilePath = new StringBuilder(); + localFilePath.append(path); + localFilePath.append(contentTag.getName().getDisplayName()); + File localFileFolder = new File(localFilePath.toString()); + if (!localFileFolder.exists()) { + localFileFolder.mkdirs(); + } + + // Construct a file name for the local file that incorporates the file id to ensure uniqueness. + String fileName = file.getName(); + String objectIdSuffix = "_" + file.getId(); + int lastDotIndex = fileName.lastIndexOf("."); + if (lastDotIndex != -1 && lastDotIndex != 0) { + // The file name has a conventional extension. Insert the object id before the '.' of the extension. + fileName = fileName.substring(0, lastDotIndex) + objectIdSuffix + fileName.substring(lastDotIndex, fileName.length()); + } + else { + // The file has no extension or the only '.' in the file is an initial '.', as in a hidden file. + // Add the object id to the end of the file name. + fileName += objectIdSuffix; + } + localFilePath.append(File.separator); + localFilePath.append(fileName); + + // If the local file doesn't already exist, create it now. + // The existence check is necessary because it is possible to apply multiple tags with the same name to a file. + File localFile = new File(localFilePath.toString()); + if (!localFile.exists()) { + ExtractFscContentVisitor.extract(file, localFile, null, null); + } + + // Add the hyperlink to the row. A column header for it was created in startTable(). + StringBuilder localFileLink = new StringBuilder(); + localFileLink.append("View File"); + row.add(localFileLink.toString()); StringBuilder builder = new StringBuilder(); builder.append("\t\n"); @@ -561,90 +583,6 @@ public class ReportHTML implements TableReportModule { } } - /** - * Add cells particular to a type of artifact associated with the row. Assumes that the overload of startTable() that takes an artifact type was called. - * - * @param row The row. - * @param sourceArtifact The artifact associated with the row. - */ - private void addRowDataForSourceArtifact(List row, BlackboardArtifact sourceArtifact) { -// int artifactTypeID = sourceArtifact.getArtifactTypeID(); -// BlackboardArtifact.ARTIFACT_TYPE type = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifactTypeID); -// switch (type) { -// case TSK_TAG_FILE: -// addRowDataForFileTagArtifact(row, sourceArtifact); -// break; -// default: -// break; -// } - } - - /** - * Saves a local copy of a tagged file and adds a hyper link to the file to the row. - * - * @param row The row. - * @param sourceArtifact The artifact associated with the row. - */ - private void addRowDataForFileTagArtifact(List row, BlackboardArtifact sourceArtifact) { -// try { -// AbstractFile file = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(sourceArtifact.getObjectID()); -// -// // Don't make a local copy of the file if it is a directory or unallocated space. -// if (file.isDir() || -// file.getType() == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS || -// file.getType() == TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) { -// row.add(""); -// return; -// } -// -// // Make a folder for the local file with the same name as the tag. -// StringBuilder localFilePath = new StringBuilder(); -// localFilePath.append(path); -// HashSet tagNames = Tags.getUniqueTagNamesForArtifact(sourceArtifact); -// if (!tagNames.isEmpty()) { -// localFilePath.append(tagNames.iterator().next()); -// } -// File localFileFolder = new File(localFilePath.toString()); -// if (!localFileFolder.exists()) { -// localFileFolder.mkdirs(); -// } -// -// // Construct a file name for the local file that incorporates the corresponding object id to ensure uniqueness. -// String fileName = file.getName(); -// String objectIdSuffix = "_" + sourceArtifact.getObjectID(); -// int lastDotIndex = fileName.lastIndexOf("."); -// if (lastDotIndex != -1 && lastDotIndex != 0) { -// // The file name has a conventional extension. Insert the object id before the '.' of the extension. -// fileName = fileName.substring(0, lastDotIndex) + objectIdSuffix + fileName.substring(lastDotIndex, fileName.length()); -// } -// else { -// // The file has no extension or the only '.' in the file is an initial '.', as in a hidden file. -// // Add the object id to the end of the file name. -// fileName += objectIdSuffix; -// } -// localFilePath.append(File.separator); -// localFilePath.append(fileName); -// -// // If the local file doesn't already exist, create it now. -// // The existence check is necessary because it is possible to apply multiple tags with the same name to a file. -// File localFile = new File(localFilePath.toString()); -// if (!localFile.exists()) { -// ExtractFscContentVisitor.extract(file, localFile, null, null); -// } -// -// // Add the hyperlink to the row. A column header for it was created in startTable(). -// StringBuilder localFileLink = new StringBuilder(); -// localFileLink.append("View File"); -// row.add(localFileLink.toString()); -// } -// catch (TskCoreException ex) { -// logger.log(Level.WARNING, "Failed to get AbstractFile by ID.", ex); -// row.add(""); -// } - } - /** * Return a String date for the long date given. * @param date date as a long @@ -704,11 +642,11 @@ public class ReportHTML implements TableReportModule { "table tr:nth-child(even) td {background: #f3f3f3;}"; cssOut.write(css); } catch (FileNotFoundException ex) { - logger.log(Level.SEVERE, "Could not find index.css file to write to."); + logger.log(Level.SEVERE, "Could not find index.css file to write to.", ex); } catch (UnsupportedEncodingException ex) { - logger.log(Level.SEVERE, "Did not recognize encoding when writing index.css."); + logger.log(Level.SEVERE, "Did not recognize encoding when writing index.css.", ex); } catch (IOException ex) { - logger.log(Level.SEVERE, "Error creating Writer for index.css."); + logger.log(Level.SEVERE, "Error creating Writer for index.css.", ex); } finally { try { if(cssOut != null) { diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java b/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java index 67a91e6521..23d9020de1 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportWizardAction.java @@ -71,7 +71,7 @@ public final class ReportWizardAction extends CallableSystemAction implements P ReportGenerator generator = new ReportGenerator((Map)wiz.getProperty("tableModuleStates"), (Map)wiz.getProperty("generalModuleStates"), (Map)wiz.getProperty("fileModuleStates")); - generator.generateArtifactTableReports((Map)wiz.getProperty("artifactStates"), (Map)wiz.getProperty("tagStates")); + generator.generateBlackboardArtifactsReports((Map)wiz.getProperty("artifactStates"), (Map)wiz.getProperty("tagStates")); generator.generateFileListReports((Map)wiz.getProperty("fileReportOptions")); generator.generateGeneralReports(); generator.displayProgressPanels(); diff --git a/Core/src/org/sleuthkit/autopsy/report/TableReportModule.java b/Core/src/org/sleuthkit/autopsy/report/TableReportModule.java index 13397d4cd5..037b6f16e9 100644 --- a/Core/src/org/sleuthkit/autopsy/report/TableReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/report/TableReportModule.java @@ -51,8 +51,9 @@ public interface TableReportModule extends ReportModule { * It is up to the report how the differentiation is shown. * * @param title String name of the data type + * @param description RJCTODO: fix this header comment */ - public void startDataType(String title); + public void startDataType(String title, String description); /** * End the current data type and prepare for either the end of the report From d992fbe2f754b2105f443c96a4bea37fccdda535 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Tue, 22 Oct 2013 10:42:18 -0400 Subject: [PATCH 029/169] Removed old Tags class from datamodel package --- .../AddBlackboardArtifactTagAction.java | 1 - .../autopsy/actions/AddContentTagAction.java | 1 - .../datamodel/RootContentChildren.java | 2 - .../org/sleuthkit/autopsy/datamodel/Tags.java | 84 ------------------- .../sleuthkit/autopsy/datamodel/TagsNode.java | 1 - .../autopsy/datamodel/TagsNodeKey.java | 2 +- .../sleuthkit/autopsy/report/ReportHTML.java | 3 - 7 files changed, 1 insertion(+), 93 deletions(-) delete mode 100644 Core/src/org/sleuthkit/autopsy/datamodel/Tags.java diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java index d81e978bc1..8a5a0329a4 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java @@ -24,7 +24,6 @@ import javax.swing.JOptionPane; import org.openide.util.Utilities; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datamodel.Tags; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.TskCoreException; diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java index 1483ce36c9..20fdc03a72 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java @@ -24,7 +24,6 @@ import javax.swing.JOptionPane; import org.openide.util.Utilities; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datamodel.Tags; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java index ff91e44112..8b1e2ecc47 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/RootContentChildren.java @@ -98,8 +98,6 @@ public class RootContentChildren extends AbstractContentChildren { this.refreshKey(o); else if (o instanceof EmailExtracted) this.refreshKey(o); - else if (o instanceof Tags) - this.refreshKey(o); else if (o instanceof TagsNodeKey) this.refreshKey(o); else if (o instanceof ExtractedContent) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java b/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java deleted file mode 100644 index 03a749cfb3..0000000000 --- a/Core/src/org/sleuthkit/autopsy/datamodel/Tags.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2013 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.datamodel; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.logging.Level; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; -import org.sleuthkit.datamodel.BlackboardAttribute; -import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; -import org.sleuthkit.datamodel.TskCoreException; - -public class Tags { - - private static final Logger logger = Logger.getLogger(Tags.class.getName()); - public static final String BOOKMARK_TAG_NAME = "Bookmark"; - - /** - * Looks up the tag names associated with either a tagged artifact or a tag artifact. - * - * @param artifact The artifact - * @return A set of unique tag names - */ - public static HashSet getUniqueTagNamesForArtifact(BlackboardArtifact artifact) { - return getUniqueTagNamesForArtifact(artifact.getArtifactID(), artifact.getArtifactTypeID()); - } - - /** - * Looks up the tag names associated with either a tagged artifact or a tag artifact. - * - * @param artifactID The ID of the artifact - * @param artifactTypeID The ID of the artifact type - * @return A set of unique tag names - */ - public static HashSet getUniqueTagNamesForArtifact(long artifactID, int artifactTypeID) { - HashSet tagNames = new HashSet<>(); - - try { - ArrayList tagArtifactIDs = new ArrayList<>(); - if (artifactTypeID == ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() || - artifactTypeID == ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { - tagArtifactIDs.add(artifactID); - } else { - List tags = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifacts(ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT, artifactID); - for (BlackboardArtifact tag : tags) { - tagArtifactIDs.add(tag.getArtifactID()); - } - } - - for (Long tagArtifactID : tagArtifactIDs) { - String whereClause = "WHERE artifact_id = " + tagArtifactID + " AND attribute_type_id = " + ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID(); - List attributes = Case.getCurrentCase().getSleuthkitCase().getMatchingAttributes(whereClause); - for (BlackboardAttribute attr : attributes) { - tagNames.add(attr.getValueString()); - } - } - } - catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Failed to get tags for artifact " + artifactID, ex); - } - - return tagNames; - } -} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java index 908252a95f..76a56f8ab9 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java @@ -24,7 +24,6 @@ import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; -import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.TagName; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/TagsNodeKey.java b/Core/src/org/sleuthkit/autopsy/datamodel/TagsNodeKey.java index 56cd249705..78d0006178 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/TagsNodeKey.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/TagsNodeKey.java @@ -23,7 +23,7 @@ package org.sleuthkit.autopsy.datamodel; * RootContentChildren class. RootContentChildren is a NetBeans child node * factory built on top of the NetBeans Children.Keys class. */ -public class TagsNodeKey implements AutopsyVisitableItem { // RJCTODO: Rename to Tags when old Tags class is deleted (for the sake of consistency). Add comments to similar classes. +public class TagsNodeKey implements AutopsyVisitableItem { // Creation of a TagsNode object corresponding to a TagsNodeKey object is done // by a CreateAutopsyNodeVisitor dispatched from the AbstractContentChildren // override of Children.Keys.createNodes(). diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java index 14f47a798b..85f76bb31f 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java @@ -35,7 +35,6 @@ import java.io.Writer; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.TreeMap; @@ -45,7 +44,6 @@ import org.openide.util.Exceptions; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.ContentUtils.ExtractFscContentVisitor; -import org.sleuthkit.autopsy.datamodel.Tags; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Image; @@ -53,7 +51,6 @@ import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; -import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM; From 4584640ec37d7ac4365b3c443e859c112ab65b05 Mon Sep 17 00:00:00 2001 From: raman-bt Date: Tue, 22 Oct 2013 10:53:11 -0400 Subject: [PATCH 030/169] Changed AddImageTask to be a plain Runnable instead of a SwingWorker. --- .../autopsy/casemodule/AddImageTask.java | 94 ++++++++----------- .../AddImageWizardIngestConfigPanel.java | 15 +-- .../sleuthkit/autopsy/casemodule/Case.java | 13 +++ .../autopsy/casemodule/ImageDSProcessor.java | 8 +- 4 files changed, 66 insertions(+), 64 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java index e7b6b05f34..6b611a6abc 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java @@ -45,18 +45,18 @@ import org.sleuthkit.datamodel.TskException; * It updates the given ProgressMonitor as it works through adding the image, * and et the end, calls the specified Callback. */ -public class AddImageTask extends SwingWorker { +public class AddImageTask implements Runnable { private Logger logger = Logger.getLogger(AddImageTask.class.getName()); private Case currentCase; // true if the process was requested to stop - private boolean cancelled = false; + private volatile boolean cancelled = false; //true if revert has been invoked. private boolean reverted = false; private boolean hasCritError = false; - private boolean addImageDone = false; + private volatile boolean addImageDone = false; private List errorList = new ArrayList(); @@ -112,7 +112,7 @@ public class AddImageTask extends SwingWorker { currentCase = Case.getCurrentCase(); - + this.imagePath = imgPath; this.timeZone = tz; this.noFatOrphans = noOrphans; @@ -129,29 +129,14 @@ public class AddImageTask extends SwingWorker { * @throws Exception */ @Override - protected Integer doInBackground() { + public void run() { - this.setProgress(0); - - errorList.clear(); - try { - //lock DB for writes in EWT thread - //wait until lock acquired in EWT - EventQueue.invokeAndWait(new Runnable() { - @Override - public void run() { - SleuthkitCase.dbWriteLock(); - } - }); - } catch (InterruptedException ex) { - logger.log(Level.WARNING, "Errors occurred while running add image, could not acquire lock. ", ex); - return 0; - - } catch (InvocationTargetException ex) { - logger.log(Level.WARNING, "Errors occurred while running add image, could not acquire lock. ", ex); - return 0; - } + errorList.clear(); + + //lock DB for writes in this thread + SleuthkitCase.dbWriteLock(); + addImageProcess = currentCase.makeAddImageProcess(timeZone, true, noFatOrphans); dirFetcher = new Thread( new CurrentDirectoryFetcher(progressMonitor, addImageProcess)); @@ -162,6 +147,7 @@ public class AddImageTask extends SwingWorker { dirFetcher.start(); addImageProcess.run(new String[]{this.imagePath}); + } catch (TskCoreException ex) { logger.log(Level.WARNING, "Core errors occurred while running add image. ", ex); //critical core/system error and process needs to be interrupted @@ -170,25 +156,28 @@ public class AddImageTask extends SwingWorker { } catch (TskDataException ex) { logger.log(Level.WARNING, "Data errors occurred while running add image. ", ex); errorList.add(ex.getMessage()); - } finally { - // process is over, doesn't need to be dealt with if cancel happens - + } + finally { + } - return 0; + // handle addImage done + postProcess(); + + // unclock the DB + SleuthkitCase.dbWriteUnlock(); + + return; } /** - * Commit the finished AddImageProcess, and cancel the CleanupTask that - * would have reverted it. + * Commit the newly added image to DB * - * @param settings property set to get AddImageProcess and CleanupTask - * from * * @throws Exception if commit or adding the image to the case failed */ private void commitImage() throws Exception { - + long imageId = 0; try { imageId = addImageProcess.commit(); @@ -196,13 +185,11 @@ public class AddImageTask extends SwingWorker { logger.log(Level.WARNING, "Errors occured while committing the image", e); errorList.add(e.getMessage()); } finally { - //commit done, unlock db write in EWT thread - //before doing anything else - SleuthkitCase.dbWriteUnlock(); - + if (imageId != 0) { - Image newImage = Case.getCurrentCase().addImage(imagePath, imageId, timeZone); - + // get the newly added Image so we can return to caller + Image newImage = currentCase.getSleuthkitCase().getImageById(imageId); + //while we have the image, verify the size of its contents String verificationErrors = newImage.verifyImageSize(); if (verificationErrors.equals("") == false) { @@ -212,7 +199,6 @@ public class AddImageTask extends SwingWorker { // Add the image to the list of new content newContents.add(newImage); - } logger.log(Level.INFO, "Image committed, imageId: " + imageId); @@ -221,21 +207,18 @@ public class AddImageTask extends SwingWorker { } /** - * - * (called by EventDispatch Thread after doInBackground finishes) + * Post processing after the addImageProcess is done. * - * Must Not return without invoking the callBack, unless the caller canceled */ - @Override - protected void done() { - - setProgress(100); + private void postProcess() { + // cancel the directory fetcher dirFetcher.interrupt(); - + addImageDone = true; // attempt actions that might fail and force the process to stop + if (cancelled || hasCritError) { logger.log(Level.INFO, "Handling errors or interruption that occured in add image process"); revert(); @@ -272,11 +255,9 @@ public class AddImageTask extends SwingWorker { } catch (Exception ex) { //handle unchecked exceptions post image add - errorList.add(ex.getMessage()); logger.log(Level.WARNING, "Unexpected errors occurred while running post add image cleanup. ", ex); - logger.log(Level.SEVERE, "Error adding image to case", ex); } finally { @@ -285,12 +266,15 @@ public class AddImageTask extends SwingWorker { } // invoke the callBack, unless the caller cancelled - if (!cancelled) + if (!cancelled) { doCallBack(); + } return; } + + /* * Call the callback with results, new content, and errors, if any */ @@ -354,8 +338,7 @@ public class AddImageTask extends SwingWorker { */ void revert() { - if (!reverted) { - + if (!reverted) { try { logger.log(Level.INFO, "Revert after add image process"); try { @@ -364,8 +347,7 @@ public class AddImageTask extends SwingWorker { logger.log(Level.WARNING, "Error reverting add image process", ex); } } finally { - //unlock db write within EWT thread - SleuthkitCase.dbWriteUnlock(); + } reverted = true; } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java index 991e3fef5b..91e265e805 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java @@ -273,7 +273,7 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel errList, List contents) { - + // disable the cleanup task cleanupTask.disable(); @@ -286,7 +286,10 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel Date: Tue, 22 Oct 2013 13:32:49 -0400 Subject: [PATCH 031/169] Fixed DRVT node expansion bug and added selection logic for node deletion --- .../autopsy/datamodel/ContentTagTypeNode.java | 2 +- .../autopsy/datamodel/TagNameNode.java | 2 +- .../sleuthkit/autopsy/datamodel/TagsNode.java | 6 +- .../BlackboardArtifactTagTypeNode.java | 2 +- .../directorytree/DataResultFilterNode.java | 17 +++++ .../DirectoryTreeTopComponent.java | 64 ++++++++++++------- .../autopsy/report/ReportGenerator.java | 42 ++++++------ 7 files changed, 79 insertions(+), 56 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java index 6c1a454357..df7b8aead8 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java @@ -50,7 +50,7 @@ public class ContentTagTypeNode extends DisplayableItemNode { Logger.getLogger(ContentTagTypeNode.class.getName()).log(Level.SEVERE, "Failed to get content tags count for " + tagName.getDisplayName() + " tag name", ex); } - super.setName(DISPLAY_NAME + " (" + tagsCount + ")"); + super.setName(DISPLAY_NAME); super.setDisplayName(DISPLAY_NAME + " (" + tagsCount + ")"); this.setIconBaseWithExtension(ICON_PATH); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java index 05f4a00627..6d41f4911b 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java @@ -53,7 +53,7 @@ public class TagNameNode extends DisplayableItemNode { Logger.getLogger(TagNameNode.class.getName()).log(Level.SEVERE, "Failed to get tags count for " + tagName.getDisplayName() + " tag name", ex); } - super.setName(tagName.getDisplayName() + " (" + tagsCount + ")"); + super.setName(tagName.getDisplayName()); super.setDisplayName(tagName.getDisplayName() + " (" + tagsCount + ")"); if (tagName.getDisplayName().equals("Bookmark")) { setIconBaseWithExtension(BOOKMARK_TAG_ICON_PATH); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java index 76a56f8ab9..3597e34108 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java @@ -46,10 +46,6 @@ public class TagsNode extends DisplayableItemNode { this.setIconBaseWithExtension(ICON_PATH); } - public static String getNodeName() { - return DISPLAY_NAME; - } - @Override public boolean isLeafTypeNode() { return false; @@ -78,7 +74,7 @@ public class TagsNode extends DisplayableItemNode { @Override protected boolean createKeys(List keys) { try { - Case.getCurrentCase().getServices().getTagsManager().getAllTagNames(keys); + Case.getCurrentCase().getServices().getTagsManager().getTagNamesInUse(keys); } catch (TskCoreException ex) { Logger.getLogger(TagNameNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java index 543db96eb0..e8b0cb9fab 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java @@ -55,7 +55,7 @@ public class BlackboardArtifactTagTypeNode extends DisplayableItemNode { Logger.getLogger(BlackboardArtifactTagTypeNode.class.getName()).log(Level.SEVERE, "Failed to get blackboard artifact tags count for " + tagName.getDisplayName() + " tag name", ex); } - super.setName(DISPLAY_NAME + " (" + tagsCount + ")"); + super.setName(DISPLAY_NAME); super.setDisplayName(DISPLAY_NAME + " (" + tagsCount + ")"); this.setIconBaseWithExtension(ICON_PATH); } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index 1619c18ccf..632d7a63ca 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -39,6 +39,7 @@ import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.AbstractFileProp import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode; import org.sleuthkit.autopsy.datamodel.ArtifactTypeNode; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; +import org.sleuthkit.autopsy.datamodel.ContentTagTypeNode; import org.sleuthkit.autopsy.datamodel.LocalFileNode; import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsChildren.DeletedContentNode; import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode; @@ -63,6 +64,7 @@ import org.sleuthkit.autopsy.datamodel.LayoutFileNode; import org.sleuthkit.autopsy.datamodel.RecentFilesFilterNode; import org.sleuthkit.autopsy.datamodel.RecentFilesNode; import org.sleuthkit.autopsy.datamodel.FileTypesNode; +import org.sleuthkit.autopsy.datamodel.TagNameNode; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardAttribute; @@ -403,6 +405,21 @@ public class DataResultFilterNode extends FilterNode { return openChild(atn); } + @Override + public AbstractAction visit(TagNameNode node) { + return openChild(node); + } + + @Override + public AbstractAction visit(ContentTagTypeNode node) { + return openChild(node); + } + + @Override + public AbstractAction visit(BlackboardArtifactTagTypeNode node) { + return openChild(node); + } + @Override public AbstractAction visit(DirectoryNode dn) { if (dn.getDisplayName().equals(DirectoryNode.DOTDOTDIR)) { diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java index d376f06722..b50a5c2122 100644 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DirectoryTreeTopComponent.java @@ -27,6 +27,7 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.ArrayList; +import java.util.Arrays; import java.util.LinkedList; import java.util.List; import java.util.logging.Level; @@ -856,38 +857,53 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat } /** - * Set selected node using the previously saved selection path to the - * selected node + * Set the selected node using a path to a previously selected node. * - * @param path node path with node names - * @param rootNodeName name of the root node to match or null if any + * @param previouslySelectedNodePath Path to a previously selected node. + * @param rootNodeName Name of the root node to match, may be null. */ - private void setSelectedNode(final String[] path, final String rootNodeName) { - if (path == null) { + private void setSelectedNode(final String[] previouslySelectedNodePath, final String rootNodeName) { + if (previouslySelectedNodePath == null) { return; } SwingUtilities.invokeLater(new Runnable() { @Override public void run() { - - if (path.length > 0 && (rootNodeName == null || path[0].equals(rootNodeName))) { - try { - Node newSelection = NodeOp.findPath(em.getRootContext(), path); - - if (newSelection != null) { - if (rootNodeName != null) { - //called from tree auto refresh context - //remove last from backlist, because auto select will result in duplication - backList.pollLast(); - } - em.setExploredContextAndSelection(newSelection, new Node[]{newSelection}); + if (previouslySelectedNodePath.length > 0 && (rootNodeName == null || previouslySelectedNodePath[0].equals(rootNodeName))) { + Node selectedNode = null; + ArrayList selectedNodePath = new ArrayList<>(Arrays.asList(previouslySelectedNodePath)); + while (null == selectedNode && !selectedNodePath.isEmpty()) { + try { + selectedNode = NodeOp.findPath(em.getRootContext(), selectedNodePath.toArray(new String[0])); + } + catch (NodeNotFoundException ex) { + // The selected node may have been deleted (e.g., a deleted tag), so truncate the path and try again. + if (selectedNodePath.size() > 1) { + selectedNodePath.remove(selectedNodePath.size() - 1); + } + else { + StringBuilder nodePath = new StringBuilder(); + for (int i = 0; i < previouslySelectedNodePath.length; ++i) { + nodePath.append(previouslySelectedNodePath[i]).append("/"); + } + logger.log(Level.WARNING, "Failed to find any nodes to select on path " + nodePath.toString(), ex); + break; + } + } + } + + if (null != selectedNode) { + if (rootNodeName != null) { + //called from tree auto refresh context + //remove last from backlist, because auto select will result in duplication + backList.pollLast(); + } + try { + em.setExploredContextAndSelection(selectedNode, new Node[]{selectedNode}); + } + catch (PropertyVetoException ex) { + logger.log(Level.WARNING, "Property veto from ExplorerManager setting selection to " + selectedNode.getName(), ex); } - - // We need to set the selection, which will refresh dataresult and get rid of the oob exception - } catch (NodeNotFoundException ex) { - logger.log(Level.WARNING, "Node not found", ex); - } catch (PropertyVetoException ex) { - logger.log(Level.WARNING, "Property Veto", ex); } } } diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java index 792bfa169b..bf66eb66fe 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java @@ -494,24 +494,19 @@ public class ReportGenerator { // Give the modules the rows for the content tags. for (ContentTag tag : tags) { - // Apply the tag names filter. - if (!tagNamesFilter.isEmpty()) { - if (tagNamesFilter.contains(tag.getName().getDisplayName())) { - continue; + if (passesTagNamesFilter(tag.getName().getDisplayName())) { + ArrayList rowData = new ArrayList<>(Arrays.asList(tag.getContent().getName(), tag.getName().getDisplayName(), tag.getComment())); + for (TableReportModule module : tableModules) { + // @@@ This casting is a tricky little workaround to allow the HTML report module to slip in a content hyperlink. + if (module instanceof ReportHTML) { + ReportHTML htmlReportModule = (ReportHTML)module; + htmlReportModule.addRowWithTaggedContentHyperlink(rowData, tag); + } + else { + module.addRow(rowData); + } } } - - ArrayList rowData = new ArrayList<>(Arrays.asList(tag.getContent().getName(), tag.getName().getDisplayName(), tag.getComment())); - for (TableReportModule module : tableModules) { - // @@@ This casting is a tricky little workaround to allow the HTML report module to slip in a content hyperlink. - if (module instanceof ReportHTML) { - ReportHTML htmlReportModule = (ReportHTML)module; - htmlReportModule.addRowWithTaggedContentHyperlink(rowData, tag); - } - else { - module.addRow(rowData); - } - } } // The the modules content tags reporting is ended. @@ -553,16 +548,11 @@ public class ReportGenerator { // Give the modules the rows for the content tags. for (BlackboardArtifactTag tag : tags) { - // Apply the tag names filter. - if (!tagNamesFilter.isEmpty()) { - if (tagNamesFilter.contains(tag.getName().getDisplayName())) { - continue; + if (passesTagNamesFilter(tag.getName().getDisplayName())) { + for (TableReportModule module : tableModules) { + module.addRow(new ArrayList<>(Arrays.asList(tag.getArtifact().getArtifactTypeName(), tag.getName().getDisplayName(), tag.getComment(), tag.getContent().getName()))); } } - - for (TableReportModule module : tableModules) { - module.addRow(new ArrayList<>(Arrays.asList(tag.getArtifact().getArtifactTypeName(), tag.getName().getDisplayName(), tag.getComment(), tag.getContent().getName()))); - } } // The the modules blackboard artifact tags reporting is ended. @@ -573,6 +563,10 @@ public class ReportGenerator { } } + boolean passesTagNamesFilter(String tagName) { + return tagNamesFilter.isEmpty() || tagNamesFilter.contains(tagName); + } + void removeCancelledTableReportModules() { Iterator iter = tableModules.iterator(); while (iter.hasNext()) { From 8b487ca56da8e7bd369dc660afe1abe1c9bb445c Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Tue, 22 Oct 2013 17:21:44 -0400 Subject: [PATCH 032/169] Removed prematuer merge of some new tags api files --- .../autopsy/casemodule/services/Services.java | 8 - .../casemodule/services/TagsManager.java | 247 ------------------ .../directorytree/TagAbstractFileAction.java | 169 ++++++------ .../TagBlackboardArtifactAction.java | 171 ++++++------ 4 files changed, 151 insertions(+), 444 deletions(-) delete mode 100755 Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java index 069b13ef2e..10663c173b 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java @@ -41,26 +41,18 @@ public class Services implements Closeable { // services private FileManager fileManager; - private TagsManager tagsManager; public Services(SleuthkitCase tskCase) { this.tskCase = tskCase; //create and initialize FileManager as early as possibly in the new/opened Case fileManager = new FileManager(tskCase); services.add(fileManager); - - tagsManager = new TagsManager(tskCase); - services.add(tagsManager); } public FileManager getFileManager() { return fileManager; } - public TagsManager getTagsManager() { - return tagsManager; - } - @Override public void close() throws IOException { // close all services diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java deleted file mode 100755 index 2ae7426655..0000000000 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2013 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.casemodule.services; - -import java.io.Closeable; -import java.io.IOException; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; -import org.sleuthkit.autopsy.coreutils.ModuleSettings; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.BlackboardArtifactTag; -import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.ContentTag; -import org.sleuthkit.datamodel.SleuthkitCase; -import org.sleuthkit.datamodel.TagType; -import org.sleuthkit.datamodel.TskCoreException; - -/** - * A singleton instance of this class functions as an Autopsy service that - * manages the creation, updating, and deletion of tags applied to Content and - * BlackboardArtifacts objects by users. - */ -public class TagsManager implements Closeable { - private static final String TAGS_SETTINGS_FILE_NAME = "tags"; - private static final String TAG_TYPES_SETTING_KEY = "tagTypes"; - private final SleuthkitCase tskCase; - private final HashMap tagTypes = new HashMap<>(); - - TagsManager(SleuthkitCase tskCase) { - this.tskCase = tskCase; - loadTagTypesFromTagSettings(); - } - - private void loadTagTypesFromTagSettings() { - // Get any tag types already added to the current case. - try { - List currentTagTypes = tskCase.getTagTypes(); - for (TagType tagType : currentTagTypes) { - tagTypes.put(tagType.getDisplayName(), tagType); - } - } - catch (TskCoreException ex) { - Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag types from the current case", ex); - } - - // Read the saved tag types, if any, from the tags settings file and - // add them to the current case if they haven't already been added, e.g, - // when the case was last opened. - String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_FILE_NAME, TAG_TYPES_SETTING_KEY); - if (null != setting && !setting.isEmpty()) { - // Read the tag types setting and break in into tag type tuples. - List tagTypeTuples = Arrays.asList(setting.split(";")); - - // Parse each tuple and add the tag types to the current case, one - // at a time to gracefully discard any duplicates or corrupt tuples. - for (String tagTypeTuple : tagTypeTuples) { - String[] tagTypeAttributes = tagTypeTuple.split(","); - if (!tagTypes.containsKey(tagTypeAttributes[0])) { - TagType tagType = new TagType(tagTypeAttributes[0], tagTypeAttributes[1], TagType.HTML_COLOR.getColorByName(tagTypeAttributes[2])); - try { - tskCase.addTagType(tagType); - tagTypes.put(tagType.getDisplayName(),tagType); - } - catch(TskCoreException ex) { - Logger.getLogger(TagsManager.class.getName()).log(Level.WARNING, "Failed to add saved " + tagType.getDisplayName() + " tag type to the current case", ex); - } - } - } - - saveTagTypesToTagsSettings(); - } - } - - private void saveTagTypesToTagsSettings() { - if (!tagTypes.isEmpty()) { - StringBuilder setting = new StringBuilder(); - for (TagType tagType : tagTypes.values()) { - if (setting.length() != 0) { - setting.append(";"); - } - setting.append(tagType.getDisplayName()).append(","); - setting.append(tagType.getDescription()).append(","); - setting.append(tagType.getColor().name()); - } - - ModuleSettings.setConfigSetting(TAGS_SETTINGS_FILE_NAME, TAG_TYPES_SETTING_KEY, setting.toString()); - } - } - - /** - * Gets a list of all tag types currently available for tagging content or - * blackboard artifacts. - * @return A list, possibly empty, of TagType data transfer objects (DTOs). - * @throws TskCoreException - */ - public List getTagTypes() throws TskCoreException { - return tskCase.getTagTypes(); - } - - /** - * Adds a new tag type to the current case and to the tags settings file. - * @param displayName The display name for the new tag type. - * @return A TagType object representing the new type on success, null on failure. - * @throws TskCoreException - */ - public TagType addTagType(String displayName) throws TagTypeAlreadyExistsException, TskCoreException { - return addTagType(displayName, "", TagType.HTML_COLOR.NONE); - } - - /** - * Adds a new tag type to the current case and to the tags settings file. - * @param displayName The display name for the new tag type. - * @param description The description for the new tag type. - * @return A TagType object representing the new type on success, null on failure. - * @throws TskCoreException - */ - public TagType addTagType(String displayName, String description) throws TagTypeAlreadyExistsException, TskCoreException { - return addTagType(displayName, description, TagType.HTML_COLOR.NONE); - } - - /** - * Adds a new tag type to the current case and to the tags settings file. - * @param displayName The display name for the new tag type. - * @param description The description for the new tag type. - * @param color The HTML color to associate with the new tag type. - * @return A TagType object representing the new type. - * @throws TskCoreException - */ - public synchronized TagType addTagType(String displayName, String description, TagType.HTML_COLOR color) throws TagTypeAlreadyExistsException, TskCoreException { - if (tagTypes.containsKey(displayName)) { - throw new TagTypeAlreadyExistsException(); - } - - TagType newTagType = new TagType(displayName, description, color); - tskCase.addTagType(newTagType); - tagTypes.put(newTagType.getDisplayName(), newTagType); - saveTagTypesToTagsSettings(); - return newTagType; - } - - public class TagTypeAlreadyExistsException extends Exception { - } - - /** - * Tags a Content object. - * @param content The Content to tag. - * @param tagType The type of tag to add. - * @throws TskCoreException - */ - public void addContentTag(Content content, TagType tagType) throws TskCoreException { - addContentTag(content, tagType, "", 0, content.getSize() - 1); - } - - /** - * Tags a Content object. - * @param content The Content to tag. - * @param tagType The type of tag to add. - * @param comment A comment to store with the tag. - * @throws TskCoreException - */ - public void addContentTag(Content content, TagType tagType, String comment) throws TskCoreException { - addContentTag(content, tagType, comment, 0, content.getSize() - 1); - } - - /** - * Tags a Content object or a portion of a content object. - * @param content The Content to tag. - * @param tagType The type of tag to add. - * @param comment A comment to store with the tag. - * @param beginByteOffset Designates the beginning of a tagged extent. - * @param endByteOffset Designates the end of a tagged extent. - * @throws TskCoreException - */ - public void addContentTag(Content content, TagType tagType, String comment, long beginByteOffset, long endByteOffset) throws IllegalArgumentException, TskCoreException { - if (beginByteOffset < 0) { - throw new IllegalArgumentException("Content extent incorrect: beginByteOffset < 0"); - } - - if (endByteOffset <= beginByteOffset) { - throw new IllegalArgumentException("Content extent incorrect: endByteOffset <= beginByteOffset"); - } - - if (endByteOffset > content.getSize() - 1) { - throw new IllegalArgumentException("Content extent incorrect: endByteOffset exceeds content size"); - } - - tskCase.addContentTag(new ContentTag(content, tagType, comment, beginByteOffset, endByteOffset)); - } - - /** - * Deletes a content tag. - * @param tag The tag to delete. - * @throws TskCoreException - */ - public void deleteContentTag(ContentTag tag) throws TskCoreException { - tskCase.deleteContentTag(tag); - } - - /** - * Tags a BlackboardArtifact object. - * @param artifact The BlackboardArtifact to tag. - * @param tagType The type of tag to add. - * @throws TskCoreException - */ - public void addBlackboardArtifactTag(BlackboardArtifact artifact, TagType tagType) throws TskCoreException { - addBlackboardArtifactTag(artifact, tagType, ""); - } - - /** - * Tags a BlackboardArtifact object. - * @param artifact The BlackboardArtifact to tag. - * @param tagType The type of tag to add. - * @param comment A comment to store with the tag. - * @throws TskCoreException - */ - public void addBlackboardArtifactTag(BlackboardArtifact artifact, TagType tagType, String comment) throws TskCoreException { - tskCase.addBlackboardArtifactTag(new BlackboardArtifactTag(artifact, tagType, comment)); - } - - void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException { - tskCase.deleteBlackboardArtifactTag(tag); - } - - @Override - public void close() throws IOException { - saveTagTypesToTagsSettings(); - } -} diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java index 5afbf89fef..f174e79121 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/TagAbstractFileAction.java @@ -1,94 +1,75 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2013 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.directorytree; - -import java.awt.event.ActionEvent; -import java.util.Collection; -import java.util.logging.Level; -import javax.swing.AbstractAction; -import javax.swing.JMenuItem; -import javax.swing.JOptionPane; -import org.openide.util.Utilities; -import org.openide.util.actions.Presenter; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.services.TagsManager; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datamodel.Tags; -import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.TagType; -import org.sleuthkit.datamodel.TskCoreException; - -public class TagAbstractFileAction extends AbstractAction implements Presenter.Popup { - // This class is a singleton to support multi-selection of nodes, since - // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every - // node in the array returns a reference to the same action object from Node.getActions(boolean). - private static TagAbstractFileAction instance; - - public static synchronized TagAbstractFileAction getInstance() { - if (null == instance) { - instance = new TagAbstractFileAction(); - } - return instance; - } - - private TagAbstractFileAction() { - } - - @Override - public JMenuItem getPopupPresenter() { - return new TagAbstractFileMenu(); - } - - @Override - public void actionPerformed(ActionEvent e) { - // Do nothing - this action should never be performed. - // Submenu actions are invoked instead. - } - - private static class TagAbstractFileMenu extends TagMenu { - public TagAbstractFileMenu() { - super(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class).size() > 1 ? "Tag Files" : "Tag File"); - } - - @Override - protected void applyTag(String tagDisplayName, String comment) { - try { - TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); - TagType tagType = tagsManager.addTagType(tagDisplayName); - - Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); - for (AbstractFile file : selectedFiles) { - Tags.createTag(file, tagDisplayName, comment); -// try { -// tagsManager.addContentTag(file, tagType); -// } -// catch (TskCoreException ex) { -// Logger.getLogger(TagAbstractFileMenu.class.getName()).log(Level.SEVERE, "Error tagging content", ex); -// } - } - } - catch (TagsManager.TagTypeAlreadyExistsException ex) { - JOptionPane.showMessageDialog(null, "A " + tagDisplayName + " tag type has already been defined.", "Duplicate Tag Type", JOptionPane.ERROR_MESSAGE); - } - catch (TskCoreException ex) { - Logger.getLogger(TagAbstractFileMenu.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag type", ex); - } - } - } -} +/* + * Autopsy Forensic Browser + * + * Copyright 2013 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.directorytree; + +import java.awt.event.ActionEvent; +import java.util.Collection; +import java.util.logging.Level; +import javax.swing.AbstractAction; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import org.openide.util.Utilities; +import org.openide.util.actions.Presenter; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.Tags; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.TskCoreException; + +public class TagAbstractFileAction extends AbstractAction implements Presenter.Popup { + // This class is a singleton to support multi-selection of nodes, since + // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every + // node in the array returns a reference to the same action object from Node.getActions(boolean). + private static TagAbstractFileAction instance; + + public static synchronized TagAbstractFileAction getInstance() { + if (null == instance) { + instance = new TagAbstractFileAction(); + } + return instance; + } + + private TagAbstractFileAction() { + } + + @Override + public JMenuItem getPopupPresenter() { + return new TagAbstractFileMenu(); + } + + @Override + public void actionPerformed(ActionEvent e) { + // Do nothing - this action should never be performed. + // Submenu actions are invoked instead. + } + + private static class TagAbstractFileMenu extends TagMenu { + public TagAbstractFileMenu() { + super(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class).size() > 1 ? "Tag Files" : "Tag File"); + } + + @Override + protected void applyTag(String tagDisplayName, String comment) { + Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); + for (AbstractFile file : selectedFiles) { + Tags.createTag(file, tagDisplayName, comment); + } + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/TagBlackboardArtifactAction.java b/Core/src/org/sleuthkit/autopsy/directorytree/TagBlackboardArtifactAction.java index 3f2c8fd407..460c5b1a90 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/TagBlackboardArtifactAction.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/TagBlackboardArtifactAction.java @@ -1,95 +1,76 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2013 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.directorytree; - -import java.awt.event.ActionEvent; -import java.util.Collection; -import java.util.logging.Level; -import javax.swing.AbstractAction; -import javax.swing.JMenuItem; -import javax.swing.JOptionPane; -import org.openide.util.Utilities; -import org.openide.util.actions.Presenter; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.services.TagsManager; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.datamodel.Tags; -import org.sleuthkit.datamodel.BlackboardArtifact; -import org.sleuthkit.datamodel.TagType; -import org.sleuthkit.datamodel.TskCoreException; - -public class TagBlackboardArtifactAction extends AbstractAction implements Presenter.Popup { - // This class is a singleton to support multi-selection of nodes, since - // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every - // node in the array returns a reference to the same action object from Node.getActions(boolean). - private static TagBlackboardArtifactAction instance; - - public static synchronized TagBlackboardArtifactAction getInstance() { - if (null == instance) { - instance = new TagBlackboardArtifactAction(); - } - return instance; - } - - private TagBlackboardArtifactAction() { - } - - @Override - public JMenuItem getPopupPresenter() { - return new TagBlackboardArtifactMenu(); - } - - @Override - public void actionPerformed(ActionEvent e) { - // Do nothing - this action should never be performed. - // Submenu actions are invoked instead. - } - - - private static class TagBlackboardArtifactMenu extends TagMenu { - public TagBlackboardArtifactMenu() { - super(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class).size() > 1 ? "Tag Results" : "Tag Result"); - } - - @Override - protected void applyTag(String tagDisplayName, String comment) { - try { - TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); - TagType tagType = tagsManager.addTagType(tagDisplayName); - - Collection selectedArtifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class); - for (BlackboardArtifact artifact : selectedArtifacts) { - Tags.createTag(artifact, tagDisplayName, comment); - try { - tagsManager.addBlackboardArtifactTag(artifact, tagType); - } - catch (TskCoreException ex) { - Logger.getLogger(TagBlackboardArtifactMenu.class.getName()).log(Level.SEVERE, "Error tagging result", ex); - } - } - } - catch (TagsManager.TagTypeAlreadyExistsException ex) { - JOptionPane.showMessageDialog(null, "A " + tagDisplayName + " tag type has already been defined.", "Duplicate Tag Type", JOptionPane.ERROR_MESSAGE); - } - catch (TskCoreException ex) { - Logger.getLogger(TagBlackboardArtifactMenu.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag type", ex); - } - } - } -} +/* + * Autopsy Forensic Browser + * + * Copyright 2013 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.directorytree; + +import java.awt.event.ActionEvent; +import java.util.Collection; +import java.util.logging.Level; +import javax.swing.AbstractAction; +import javax.swing.JMenuItem; +import javax.swing.JOptionPane; +import org.openide.util.Utilities; +import org.openide.util.actions.Presenter; +import org.sleuthkit.autopsy.casemodule.Case; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.datamodel.Tags; +import org.sleuthkit.datamodel.BlackboardArtifact; +import org.sleuthkit.datamodel.TskCoreException; + +public class TagBlackboardArtifactAction extends AbstractAction implements Presenter.Popup { + // This class is a singleton to support multi-selection of nodes, since + // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every + // node in the array returns a reference to the same action object from Node.getActions(boolean). + private static TagBlackboardArtifactAction instance; + + public static synchronized TagBlackboardArtifactAction getInstance() { + if (null == instance) { + instance = new TagBlackboardArtifactAction(); + } + return instance; + } + + private TagBlackboardArtifactAction() { + } + + @Override + public JMenuItem getPopupPresenter() { + return new TagBlackboardArtifactMenu(); + } + + @Override + public void actionPerformed(ActionEvent e) { + // Do nothing - this action should never be performed. + // Submenu actions are invoked instead. + } + + + private static class TagBlackboardArtifactMenu extends TagMenu { + public TagBlackboardArtifactMenu() { + super(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class).size() > 1 ? "Tag Results" : "Tag Result"); + } + + @Override + protected void applyTag(String tagDisplayName, String comment) { + Collection selectedArtifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class); + for (BlackboardArtifact artifact : selectedArtifacts) { + Tags.createTag(artifact, tagDisplayName, comment); + } + } + } +} From 407ffb95680d2aac7ec815b58146aaf530407032 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Tue, 22 Oct 2013 19:25:10 -0400 Subject: [PATCH 033/169] Line endings update --- .../autopsy/datamodel/DirectoryNode.java | 194 +++++----- .../sleuthkit/autopsy/datamodel/FileNode.java | 360 +++++++++--------- nbproject/platform.properties | 240 ++++++------ 3 files changed, 397 insertions(+), 397 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java index 3c4d33c253..f859362757 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java @@ -1,97 +1,97 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011 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.datamodel; - -import java.util.ArrayList; -import java.util.List; -import javax.swing.Action; -import org.sleuthkit.autopsy.directorytree.ExtractAction; -import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; -import org.sleuthkit.autopsy.directorytree.ViewContextAction; -import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.Directory; -import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM; - -/** - * This class is used to represent the "Node" for the directory. Its children - * are more directories. - */ -public class DirectoryNode extends AbstractFsContentNode { - - public static final String DOTDOTDIR = "[parent folder]"; - public static final String DOTDIR = "[current folder]"; - - public DirectoryNode(Directory dir) { - this(dir, true); - - setIcon(dir); - } - - public DirectoryNode(AbstractFile dir, boolean directoryBrowseMode) { - super(dir, directoryBrowseMode); - - setIcon(dir); - } - - private void setIcon(AbstractFile dir) { - // set name, display name, and icon - if (dir.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC)) { - this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/folder-icon-deleted.png"); - } else { - this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/Folder-icon.png"); - } - } - - /** - * Right click action for this node - * - * @param popup - * @return - */ - @Override - public Action[] getActions(boolean popup) { - List actions = new ArrayList<>(); - if (!getDirectoryBrowseMode()) { - actions.add(new ViewContextAction("View File in Directory", this)); - actions.add(null); // creates a menu separator - } - actions.add(new NewWindowViewAction("View in New Window", this)); - actions.add(null); // creates a menu separator - actions.add(ExtractAction.getInstance()); - actions.add(null); // creates a menu separator - actions.add(TagAbstractFileAction.getInstance()); - return actions.toArray(new Action[0]); - } - - @Override - public T accept(ContentNodeVisitor v) { - return v.visit(this); - } - - @Override - public T accept(DisplayableItemNodeVisitor v) { - return v.visit(this); - } - - @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.CONTENT; - } -} +/* + * Autopsy Forensic Browser + * + * Copyright 2011 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.datamodel; + +import java.util.ArrayList; +import java.util.List; +import javax.swing.Action; +import org.sleuthkit.autopsy.directorytree.ExtractAction; +import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; +import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; +import org.sleuthkit.autopsy.directorytree.ViewContextAction; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.Directory; +import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM; + +/** + * This class is used to represent the "Node" for the directory. Its children + * are more directories. + */ +public class DirectoryNode extends AbstractFsContentNode { + + public static final String DOTDOTDIR = "[parent folder]"; + public static final String DOTDIR = "[current folder]"; + + public DirectoryNode(Directory dir) { + this(dir, true); + + setIcon(dir); + } + + public DirectoryNode(AbstractFile dir, boolean directoryBrowseMode) { + super(dir, directoryBrowseMode); + + setIcon(dir); + } + + private void setIcon(AbstractFile dir) { + // set name, display name, and icon + if (dir.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC)) { + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/folder-icon-deleted.png"); + } else { + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/Folder-icon.png"); + } + } + + /** + * Right click action for this node + * + * @param popup + * @return + */ + @Override + public Action[] getActions(boolean popup) { + List actions = new ArrayList<>(); + if (!getDirectoryBrowseMode()) { + actions.add(new ViewContextAction("View File in Directory", this)); + actions.add(null); // creates a menu separator + } + actions.add(new NewWindowViewAction("View in New Window", this)); + actions.add(null); // creates a menu separator + actions.add(ExtractAction.getInstance()); + actions.add(null); // creates a menu separator + actions.add(TagAbstractFileAction.getInstance()); + return actions.toArray(new Action[0]); + } + + @Override + public T accept(ContentNodeVisitor v) { + return v.visit(this); + } + + @Override + public T accept(DisplayableItemNodeVisitor v) { + return v.visit(this); + } + + @Override + public TYPE getDisplayableItemNodeType() { + return TYPE.CONTENT; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java index 9ca87fd8a7..628cd145a8 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java @@ -1,180 +1,180 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011 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.datamodel; - -import java.util.ArrayList; -import java.util.List; -import javax.swing.Action; -import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; -import org.sleuthkit.autopsy.directorytree.ExtractAction; -import org.sleuthkit.autopsy.directorytree.HashSearchAction; -import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; -import org.sleuthkit.autopsy.directorytree.ViewContextAction; -import org.sleuthkit.datamodel.AbstractFile; -import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM; -import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM; - -/** - * This class is used to represent the "Node" for the file. It may have derived - * files children. - */ -public class FileNode extends AbstractFsContentNode { - - /** - * @param file underlying Content - */ - public FileNode(AbstractFile file) { - this(file, true); - - setIcon(file); - } - - public FileNode(AbstractFile file, boolean directoryBrowseMode) { - super(file, directoryBrowseMode); - - setIcon(file); - } - - private void setIcon(AbstractFile file) { - // set name, display name, and icon - if (file.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC)) { - if (file.getType().equals(TSK_DB_FILES_TYPE_ENUM.CARVED)) { - this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/carved-file-icon-16.png"); - } else { - this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png"); - } - } else { - this.setIconBaseWithExtension(getIconForFileType(file)); - } - } - - /** - * Right click action for this node - * - * @param popup - * @return - */ - @Override - public Action[] getActions(boolean popup) { - List actionsList = new ArrayList<>(); - if (!this.getDirectoryBrowseMode()) { - actionsList.add(new ViewContextAction("View File in Directory", this)); - actionsList.add(null); // creates a menu separator - } - actionsList.add(new NewWindowViewAction("View in New Window", this)); - actionsList.add(new ExternalViewerAction("Open in External Viewer", this)); - actionsList.add(null); // creates a menu separator - actionsList.add(ExtractAction.getInstance()); - actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this)); - actionsList.add(null); // creates a menu separator - actionsList.add(TagAbstractFileAction.getInstance()); - return actionsList.toArray(new Action[0]); - } - - @Override - public T accept(ContentNodeVisitor< T> v) { - return v.visit(this); - } - - @Override - public T accept(DisplayableItemNodeVisitor< T> v) { - return v.visit(this); - } - - // Given a file, returns the correct icon for said - // file based off it's extension - static String getIconForFileType(AbstractFile file) { - // Get the name, extension - String name = file.getName(); - int dotIndex = name.lastIndexOf("."); - if (dotIndex == -1) { - return "org/sleuthkit/autopsy/images/file-icon.png"; - } - String ext = name.substring(dotIndex).toLowerCase(); - - // Images - for (String s : FileTypeExtensions.getImageExtensions()) { - if (ext.equals(s)) { - return "org/sleuthkit/autopsy/images/image-file.png"; - } - } - // Videos - for (String s : FileTypeExtensions.getVideoExtensions()) { - if (ext.equals(s)) { - return "org/sleuthkit/autopsy/images/video-file.png"; - } - } - // Audio Files - for (String s : FileTypeExtensions.getAudioExtensions()) { - if (ext.equals(s)) { - return "org/sleuthkit/autopsy/images/audio-file.png"; - } - } - // Documents - for (String s : FileTypeExtensions.getDocumentExtensions()) { - if (ext.equals(s)) { - return "org/sleuthkit/autopsy/images/doc-file.png"; - } - } - // Executables / System Files - for (String s : FileTypeExtensions.getExecutableExtensions()) { - if (ext.equals(s)) { - return "org/sleuthkit/autopsy/images/exe-file.png"; - } - } - // Text Files - for (String s : FileTypeExtensions.getTextExtensions()) { - if (ext.equals(s)) { - return "org/sleuthkit/autopsy/images/text-file.png"; - } - } - // Web Files - for (String s : FileTypeExtensions.getWebExtensions()) { - if (ext.equals(s)) { - return "org/sleuthkit/autopsy/images/web-file.png"; - } - } - // PDFs - for (String s : FileTypeExtensions.getPDFExtensions()) { - if (ext.equals(s)) { - return "org/sleuthkit/autopsy/images/pdf-file.png"; - } - } - // Archives - for (String s : FileTypeExtensions.getArchiveExtensions()) { - if (ext.equals(s)) { - return "org/sleuthkit/autopsy/images/archive-file.png"; - } - } - // Else return the default - return "org/sleuthkit/autopsy/images/file-icon.png"; - - } - - @Override - public TYPE getDisplayableItemNodeType() { - return TYPE.CONTENT; - } - - @Override - public boolean isLeafTypeNode() { - return true; //false; - } -} +/* + * Autopsy Forensic Browser + * + * Copyright 2011 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.datamodel; + +import java.util.ArrayList; +import java.util.List; +import javax.swing.Action; +import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; +import org.sleuthkit.autopsy.directorytree.ExtractAction; +import org.sleuthkit.autopsy.directorytree.HashSearchAction; +import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; +import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; +import org.sleuthkit.autopsy.directorytree.ViewContextAction; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM; +import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM; + +/** + * This class is used to represent the "Node" for the file. It may have derived + * files children. + */ +public class FileNode extends AbstractFsContentNode { + + /** + * @param file underlying Content + */ + public FileNode(AbstractFile file) { + this(file, true); + + setIcon(file); + } + + public FileNode(AbstractFile file, boolean directoryBrowseMode) { + super(file, directoryBrowseMode); + + setIcon(file); + } + + private void setIcon(AbstractFile file) { + // set name, display name, and icon + if (file.isDirNameFlagSet(TSK_FS_NAME_FLAG_ENUM.UNALLOC)) { + if (file.getType().equals(TSK_DB_FILES_TYPE_ENUM.CARVED)) { + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/carved-file-icon-16.png"); + } else { + this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png"); + } + } else { + this.setIconBaseWithExtension(getIconForFileType(file)); + } + } + + /** + * Right click action for this node + * + * @param popup + * @return + */ + @Override + public Action[] getActions(boolean popup) { + List actionsList = new ArrayList<>(); + if (!this.getDirectoryBrowseMode()) { + actionsList.add(new ViewContextAction("View File in Directory", this)); + actionsList.add(null); // creates a menu separator + } + actionsList.add(new NewWindowViewAction("View in New Window", this)); + actionsList.add(new ExternalViewerAction("Open in External Viewer", this)); + actionsList.add(null); // creates a menu separator + actionsList.add(ExtractAction.getInstance()); + actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this)); + actionsList.add(null); // creates a menu separator + actionsList.add(TagAbstractFileAction.getInstance()); + return actionsList.toArray(new Action[0]); + } + + @Override + public T accept(ContentNodeVisitor< T> v) { + return v.visit(this); + } + + @Override + public T accept(DisplayableItemNodeVisitor< T> v) { + return v.visit(this); + } + + // Given a file, returns the correct icon for said + // file based off it's extension + static String getIconForFileType(AbstractFile file) { + // Get the name, extension + String name = file.getName(); + int dotIndex = name.lastIndexOf("."); + if (dotIndex == -1) { + return "org/sleuthkit/autopsy/images/file-icon.png"; + } + String ext = name.substring(dotIndex).toLowerCase(); + + // Images + for (String s : FileTypeExtensions.getImageExtensions()) { + if (ext.equals(s)) { + return "org/sleuthkit/autopsy/images/image-file.png"; + } + } + // Videos + for (String s : FileTypeExtensions.getVideoExtensions()) { + if (ext.equals(s)) { + return "org/sleuthkit/autopsy/images/video-file.png"; + } + } + // Audio Files + for (String s : FileTypeExtensions.getAudioExtensions()) { + if (ext.equals(s)) { + return "org/sleuthkit/autopsy/images/audio-file.png"; + } + } + // Documents + for (String s : FileTypeExtensions.getDocumentExtensions()) { + if (ext.equals(s)) { + return "org/sleuthkit/autopsy/images/doc-file.png"; + } + } + // Executables / System Files + for (String s : FileTypeExtensions.getExecutableExtensions()) { + if (ext.equals(s)) { + return "org/sleuthkit/autopsy/images/exe-file.png"; + } + } + // Text Files + for (String s : FileTypeExtensions.getTextExtensions()) { + if (ext.equals(s)) { + return "org/sleuthkit/autopsy/images/text-file.png"; + } + } + // Web Files + for (String s : FileTypeExtensions.getWebExtensions()) { + if (ext.equals(s)) { + return "org/sleuthkit/autopsy/images/web-file.png"; + } + } + // PDFs + for (String s : FileTypeExtensions.getPDFExtensions()) { + if (ext.equals(s)) { + return "org/sleuthkit/autopsy/images/pdf-file.png"; + } + } + // Archives + for (String s : FileTypeExtensions.getArchiveExtensions()) { + if (ext.equals(s)) { + return "org/sleuthkit/autopsy/images/archive-file.png"; + } + } + // Else return the default + return "org/sleuthkit/autopsy/images/file-icon.png"; + + } + + @Override + public TYPE getDisplayableItemNodeType() { + return TYPE.CONTENT; + } + + @Override + public boolean isLeafTypeNode() { + return true; //false; + } +} diff --git a/nbproject/platform.properties b/nbproject/platform.properties index e0bdd68b73..a9fa87f749 100644 --- a/nbproject/platform.properties +++ b/nbproject/platform.properties @@ -1,120 +1,120 @@ -branding.token=autopsy -netbeans-plat-version=7.3.1 -suite.dir=${basedir} -nbplatform.active.dir=${suite.dir}/netbeans-plat/${netbeans-plat-version} -harness.dir=${nbplatform.active.dir}/harness -bootstrap.url=http://deadlock.netbeans.org/hudson/job/nbms-and-javadoc/lastStableBuild/artifact/nbbuild/netbeans/harness/tasks.jar -autoupdate.catalog.url=http://dlc.sun.com.edgesuite.net/netbeans/updates/${netbeans-plat-version}/uc/final/distribution/catalog.xml.gz -cluster.path=\ - ${nbplatform.active.dir}/harness:\ - ${nbplatform.active.dir}/java:\ - ${nbplatform.active.dir}/platform -disabled.modules=\ - org.apache.tools.ant.module,\ - org.netbeans.api.debugger.jpda,\ - org.netbeans.api.java,\ - org.netbeans.lib.nbjavac,\ - org.netbeans.libs.cglib,\ - org.netbeans.libs.javacapi,\ - org.netbeans.libs.javacimpl,\ - org.netbeans.libs.springframework,\ - org.netbeans.modules.ant.browsetask,\ - org.netbeans.modules.ant.debugger,\ - org.netbeans.modules.ant.freeform,\ - org.netbeans.modules.ant.grammar,\ - org.netbeans.modules.ant.kit,\ - org.netbeans.modules.beans,\ - org.netbeans.modules.classfile,\ - org.netbeans.modules.dbschema,\ - org.netbeans.modules.debugger.jpda,\ - org.netbeans.modules.debugger.jpda.ant,\ - org.netbeans.modules.debugger.jpda.kit,\ - org.netbeans.modules.debugger.jpda.projects,\ - org.netbeans.modules.debugger.jpda.ui,\ - org.netbeans.modules.debugger.jpda.visual,\ - org.netbeans.modules.findbugs.installer,\ - org.netbeans.modules.form,\ - org.netbeans.modules.form.binding,\ - org.netbeans.modules.form.j2ee,\ - org.netbeans.modules.form.kit,\ - org.netbeans.modules.form.nb,\ - org.netbeans.modules.form.refactoring,\ - org.netbeans.modules.hibernate,\ - org.netbeans.modules.hibernatelib,\ - org.netbeans.modules.hudson.ant,\ - org.netbeans.modules.hudson.maven,\ - org.netbeans.modules.i18n,\ - org.netbeans.modules.i18n.form,\ - org.netbeans.modules.j2ee.core.utilities,\ - org.netbeans.modules.j2ee.eclipselink,\ - org.netbeans.modules.j2ee.eclipselinkmodelgen,\ - org.netbeans.modules.j2ee.jpa.refactoring,\ - org.netbeans.modules.j2ee.jpa.verification,\ - org.netbeans.modules.j2ee.metadata,\ - org.netbeans.modules.j2ee.metadata.model.support,\ - org.netbeans.modules.j2ee.persistence,\ - org.netbeans.modules.j2ee.persistence.kit,\ - org.netbeans.modules.j2ee.persistenceapi,\ - org.netbeans.modules.java.api.common,\ - org.netbeans.modules.java.debug,\ - org.netbeans.modules.java.editor,\ - org.netbeans.modules.java.editor.lib,\ - org.netbeans.modules.java.examples,\ - org.netbeans.modules.java.freeform,\ - org.netbeans.modules.java.guards,\ - org.netbeans.modules.java.helpset,\ - org.netbeans.modules.java.hints,\ - org.netbeans.modules.java.hints.declarative,\ - org.netbeans.modules.java.hints.declarative.test,\ - org.netbeans.modules.java.hints.legacy.spi,\ - org.netbeans.modules.java.hints.test,\ - org.netbeans.modules.java.hints.ui,\ - org.netbeans.modules.java.j2seplatform,\ - org.netbeans.modules.java.j2seproject,\ - org.netbeans.modules.java.kit,\ - org.netbeans.modules.java.lexer,\ - org.netbeans.modules.java.navigation,\ - org.netbeans.modules.java.platform,\ - org.netbeans.modules.java.preprocessorbridge,\ - org.netbeans.modules.java.project,\ - org.netbeans.modules.java.source,\ - org.netbeans.modules.java.source.ant,\ - org.netbeans.modules.java.source.queries,\ - org.netbeans.modules.java.source.queriesimpl,\ - org.netbeans.modules.java.sourceui,\ - org.netbeans.modules.java.testrunner,\ - org.netbeans.modules.javadoc,\ - org.netbeans.modules.javawebstart,\ - org.netbeans.modules.junit,\ - org.netbeans.modules.maven,\ - org.netbeans.modules.maven.checkstyle,\ - org.netbeans.modules.maven.coverage,\ - org.netbeans.modules.maven.embedder,\ - org.netbeans.modules.maven.grammar,\ - org.netbeans.modules.maven.graph,\ - org.netbeans.modules.maven.hints,\ - org.netbeans.modules.maven.indexer,\ - org.netbeans.modules.maven.junit,\ - org.netbeans.modules.maven.kit,\ - org.netbeans.modules.maven.model,\ - org.netbeans.modules.maven.osgi,\ - org.netbeans.modules.maven.persistence,\ - org.netbeans.modules.maven.refactoring,\ - org.netbeans.modules.maven.repository,\ - org.netbeans.modules.maven.search,\ - org.netbeans.modules.maven.spring,\ - org.netbeans.modules.projectimport.eclipse.core,\ - org.netbeans.modules.projectimport.eclipse.j2se,\ - org.netbeans.modules.refactoring.java,\ - org.netbeans.modules.spellchecker.bindings.java,\ - org.netbeans.modules.spring.beans,\ - org.netbeans.modules.testng,\ - org.netbeans.modules.testng.ant,\ - org.netbeans.modules.testng.maven,\ - org.netbeans.modules.websvc.jaxws21,\ - org.netbeans.modules.websvc.jaxws21api,\ - org.netbeans.modules.websvc.saas.codegen.java,\ - org.netbeans.modules.xml.jaxb,\ - org.netbeans.modules.xml.tools.java,\ - org.netbeans.spi.java.hints - +branding.token=autopsy +netbeans-plat-version=7.3.1 +suite.dir=${basedir} +nbplatform.active.dir=${suite.dir}/netbeans-plat/${netbeans-plat-version} +harness.dir=${nbplatform.active.dir}/harness +bootstrap.url=http://deadlock.netbeans.org/hudson/job/nbms-and-javadoc/lastStableBuild/artifact/nbbuild/netbeans/harness/tasks.jar +autoupdate.catalog.url=http://dlc.sun.com.edgesuite.net/netbeans/updates/${netbeans-plat-version}/uc/final/distribution/catalog.xml.gz +cluster.path=\ + ${nbplatform.active.dir}/harness:\ + ${nbplatform.active.dir}/java:\ + ${nbplatform.active.dir}/platform +disabled.modules=\ + org.apache.tools.ant.module,\ + org.netbeans.api.debugger.jpda,\ + org.netbeans.api.java,\ + org.netbeans.lib.nbjavac,\ + org.netbeans.libs.cglib,\ + org.netbeans.libs.javacapi,\ + org.netbeans.libs.javacimpl,\ + org.netbeans.libs.springframework,\ + org.netbeans.modules.ant.browsetask,\ + org.netbeans.modules.ant.debugger,\ + org.netbeans.modules.ant.freeform,\ + org.netbeans.modules.ant.grammar,\ + org.netbeans.modules.ant.kit,\ + org.netbeans.modules.beans,\ + org.netbeans.modules.classfile,\ + org.netbeans.modules.dbschema,\ + org.netbeans.modules.debugger.jpda,\ + org.netbeans.modules.debugger.jpda.ant,\ + org.netbeans.modules.debugger.jpda.kit,\ + org.netbeans.modules.debugger.jpda.projects,\ + org.netbeans.modules.debugger.jpda.ui,\ + org.netbeans.modules.debugger.jpda.visual,\ + org.netbeans.modules.findbugs.installer,\ + org.netbeans.modules.form,\ + org.netbeans.modules.form.binding,\ + org.netbeans.modules.form.j2ee,\ + org.netbeans.modules.form.kit,\ + org.netbeans.modules.form.nb,\ + org.netbeans.modules.form.refactoring,\ + org.netbeans.modules.hibernate,\ + org.netbeans.modules.hibernatelib,\ + org.netbeans.modules.hudson.ant,\ + org.netbeans.modules.hudson.maven,\ + org.netbeans.modules.i18n,\ + org.netbeans.modules.i18n.form,\ + org.netbeans.modules.j2ee.core.utilities,\ + org.netbeans.modules.j2ee.eclipselink,\ + org.netbeans.modules.j2ee.eclipselinkmodelgen,\ + org.netbeans.modules.j2ee.jpa.refactoring,\ + org.netbeans.modules.j2ee.jpa.verification,\ + org.netbeans.modules.j2ee.metadata,\ + org.netbeans.modules.j2ee.metadata.model.support,\ + org.netbeans.modules.j2ee.persistence,\ + org.netbeans.modules.j2ee.persistence.kit,\ + org.netbeans.modules.j2ee.persistenceapi,\ + org.netbeans.modules.java.api.common,\ + org.netbeans.modules.java.debug,\ + org.netbeans.modules.java.editor,\ + org.netbeans.modules.java.editor.lib,\ + org.netbeans.modules.java.examples,\ + org.netbeans.modules.java.freeform,\ + org.netbeans.modules.java.guards,\ + org.netbeans.modules.java.helpset,\ + org.netbeans.modules.java.hints,\ + org.netbeans.modules.java.hints.declarative,\ + org.netbeans.modules.java.hints.declarative.test,\ + org.netbeans.modules.java.hints.legacy.spi,\ + org.netbeans.modules.java.hints.test,\ + org.netbeans.modules.java.hints.ui,\ + org.netbeans.modules.java.j2seplatform,\ + org.netbeans.modules.java.j2seproject,\ + org.netbeans.modules.java.kit,\ + org.netbeans.modules.java.lexer,\ + org.netbeans.modules.java.navigation,\ + org.netbeans.modules.java.platform,\ + org.netbeans.modules.java.preprocessorbridge,\ + org.netbeans.modules.java.project,\ + org.netbeans.modules.java.source,\ + org.netbeans.modules.java.source.ant,\ + org.netbeans.modules.java.source.queries,\ + org.netbeans.modules.java.source.queriesimpl,\ + org.netbeans.modules.java.sourceui,\ + org.netbeans.modules.java.testrunner,\ + org.netbeans.modules.javadoc,\ + org.netbeans.modules.javawebstart,\ + org.netbeans.modules.junit,\ + org.netbeans.modules.maven,\ + org.netbeans.modules.maven.checkstyle,\ + org.netbeans.modules.maven.coverage,\ + org.netbeans.modules.maven.embedder,\ + org.netbeans.modules.maven.grammar,\ + org.netbeans.modules.maven.graph,\ + org.netbeans.modules.maven.hints,\ + org.netbeans.modules.maven.indexer,\ + org.netbeans.modules.maven.junit,\ + org.netbeans.modules.maven.kit,\ + org.netbeans.modules.maven.model,\ + org.netbeans.modules.maven.osgi,\ + org.netbeans.modules.maven.persistence,\ + org.netbeans.modules.maven.refactoring,\ + org.netbeans.modules.maven.repository,\ + org.netbeans.modules.maven.search,\ + org.netbeans.modules.maven.spring,\ + org.netbeans.modules.projectimport.eclipse.core,\ + org.netbeans.modules.projectimport.eclipse.j2se,\ + org.netbeans.modules.refactoring.java,\ + org.netbeans.modules.spellchecker.bindings.java,\ + org.netbeans.modules.spring.beans,\ + org.netbeans.modules.testng,\ + org.netbeans.modules.testng.ant,\ + org.netbeans.modules.testng.maven,\ + org.netbeans.modules.websvc.jaxws21,\ + org.netbeans.modules.websvc.jaxws21api,\ + org.netbeans.modules.websvc.saas.codegen.java,\ + org.netbeans.modules.xml.jaxb,\ + org.netbeans.modules.xml.tools.java,\ + org.netbeans.spi.java.hints + From e32bc5990ba45044bbee7aaac56f0731474b3886 Mon Sep 17 00:00:00 2001 From: raman-bt Date: Wed, 23 Oct 2013 08:44:21 -0400 Subject: [PATCH 034/169] Addressed review comments from Brian. --- .../AddImageWizardChooseDataSourceVisual.java | 24 +++++++++---------- .../AddImageWizardIngestConfigPanel.java | 2 +- .../autopsy/casemodule/ImageDSProcessor.java | 2 +- .../DataSourceProcessor.java | 6 ----- 4 files changed, 13 insertions(+), 21 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java index 92bb0d08ba..2bcea63a06 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java @@ -100,28 +100,26 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { typeComboBox.setSelectedIndex(0); typePanel.setLayout(new BorderLayout()); - updateCurrentPanel(GetCurrentDSProcessor().getPanel()); + updateCurrentPanel(getCurrentDSProcessor().getPanel()); } private void discoverDataSourceProcessors() { for (DataSourceProcessor dsProcessor: Lookup.getDefault().lookupAll(DataSourceProcessor.class)) { + if (!datasourceProcessorsMap.containsKey(dsProcessor.getType()) ) { - if (!datasourceProcessorsMap.containsKey(dsProcessor.getType()) ) { - - dsProcessor.reset(); - datasourceProcessorsMap.put(dsProcessor.getType(), dsProcessor); - } - else { - logger.log(Level.SEVERE, "discoverDataSourceProcessors(): A DataSourceProcessor already exists for type = " + dsProcessor.getType() ); - } - } + dsProcessor.reset(); + datasourceProcessorsMap.put(dsProcessor.getType(), dsProcessor); + } + else { + logger.log(Level.SEVERE, "discoverDataSourceProcessors(): A DataSourceProcessor already exists for type = " + dsProcessor.getType() ); + } } } private void dspSelectionChanged() { // update the current panel to selection - currentPanel = GetCurrentDSProcessor().getPanel(); + currentPanel = getCurrentDSProcessor().getPanel(); updateCurrentPanel(currentPanel); } @@ -155,7 +153,7 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { * Returns the currently selected DS Processor * @return DataSourceProcessor the DataSourceProcessor corresponding to the data source type selected in the combobox */ - public DataSourceProcessor GetCurrentDSProcessor() { + public DataSourceProcessor getCurrentDSProcessor() { // get the type of the currently selected panel and then look up // the correspodning DS Handler in the map String dsType = (String) typeComboBox.getSelectedItem(); @@ -296,7 +294,7 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { */ public void updateUI(DocumentEvent e) { // Enable the Next button if the current DSP panel is valid - String err = GetCurrentDSProcessor().validatePanel(); + String err = getCurrentDSProcessor().validatePanel(); if (null == err) this.wizPanel.enableNextButton(true); else diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java index 91e265e805..4392cc8498 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java @@ -244,7 +244,7 @@ class AddImageWizardIngestConfigPanel implements WizardDescriptor.Panel Date: Wed, 23 Oct 2013 11:00:08 -0400 Subject: [PATCH 035/169] Second step in merge of new_tags_api branch into master --- .../sleuthkit/autopsy/casemodule/services/Services.java | 8 ++++++++ 1 file changed, 8 insertions(+) mode change 100644 => 100755 Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java old mode 100644 new mode 100755 index 10663c173b..069b13ef2e --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java @@ -41,18 +41,26 @@ public class Services implements Closeable { // services private FileManager fileManager; + private TagsManager tagsManager; public Services(SleuthkitCase tskCase) { this.tskCase = tskCase; //create and initialize FileManager as early as possibly in the new/opened Case fileManager = new FileManager(tskCase); services.add(fileManager); + + tagsManager = new TagsManager(tskCase); + services.add(tagsManager); } public FileManager getFileManager() { return fileManager; } + public TagsManager getTagsManager() { + return tagsManager; + } + @Override public void close() throws IOException { // close all services From 75f8dd47e78e4887b44070662f7cb47d03477388 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 23 Oct 2013 11:04:00 -0400 Subject: [PATCH 036/169] Third step in merge of new_tags_api branch into master --- Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java | 4 ++-- Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java index b3da63790c..278c147917 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java @@ -21,9 +21,9 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; import java.util.List; import javax.swing.Action; +import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Directory; @@ -76,7 +76,7 @@ public class DirectoryNode extends AbstractFsContentNode { actions.add(null); // creates a menu separator actions.add(ExtractAction.getInstance()); actions.add(null); // creates a menu separator - actions.add(TagAbstractFileAction.getInstance()); + actions.add(AddContentTagAction.getInstance()); return actions.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java index 27686787ef..b3312292cf 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; import java.util.List; import javax.swing.Action; +import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; @@ -83,7 +84,7 @@ public class FileNode extends AbstractFsContentNode { actionsList.add(ExtractAction.getInstance()); actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this)); actionsList.add(null); // creates a menu separator - actionsList.add(TagAbstractFileAction.getInstance()); + actionsList.add(AddContentTagAction.getInstance()); return actionsList.toArray(new Action[0]); } From 9c1743ab5a76866e0808492ba7d7b1db5cc80d49 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 23 Oct 2013 15:33:38 -0400 Subject: [PATCH 037/169] Updated for improved lower level tags api, fixed small bug in tag and comment dialog --- .../autopsy/actions/AddTagAction.java | 8 +- .../actions/GetTagNameAndCommentDialog.java | 19 ++- .../autopsy/actions/GetTagNameDialog.java | 36 ++++-- .../casemodule/services/TagsManager.java | 108 +++++++++--------- .../autopsy/datamodel/ContentTagTypeNode.java | 2 +- .../autopsy/datamodel/TagNameNode.java | 3 +- .../sleuthkit/autopsy/datamodel/TagsNode.java | 2 +- .../BlackboardArtifactTagTypeNode.java | 2 +- .../autopsy/report/ReportGenerator.java | 11 +- .../autopsy/report/ReportVisualPanel2.java | 5 +- .../autopsy/report/TableReportModule.java | 4 +- .../sleuthkit/autopsy/timeline/Timeline.java | 6 +- 12 files changed, 112 insertions(+), 94 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java index b6c8feea06..65f6a5e589 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java @@ -20,7 +20,7 @@ package org.sleuthkit.autopsy.actions; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.util.ArrayList; +import java.util.List; import java.util.logging.Level; import javax.swing.JMenu; import javax.swing.JMenuItem; @@ -76,9 +76,9 @@ abstract class AddTagAction extends TagAction implements Presenter.Popup { // Get the current set of tag names. TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); - ArrayList tagNames = new ArrayList<>(); + List tagNames = null; try { - tagsManager.getAllTagNames(tagNames); + tagNames = tagsManager.getAllTagNames(); } catch (TskCoreException ex) { Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); @@ -91,7 +91,7 @@ abstract class AddTagAction extends TagAction implements Presenter.Popup { // Each tag name in the current set of tags gets its own menu item in // the "Quick Tags" sub-menu. Selecting one of these menu items adds // a tag with the associated tag name. - if (!tagNames.isEmpty()) { + if (null != tagNames && !tagNames.isEmpty()) { for (final TagName tagName : tagNames) { JMenuItem tagNameItem = new JMenuItem(tagName.getDisplayName()); tagNameItem.addActionListener(new ActionListener() { diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java index 34aee2c7df..e953694d90 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java @@ -20,8 +20,8 @@ package org.sleuthkit.autopsy.actions; import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; -import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.logging.Level; import javax.swing.AbstractAction; import javax.swing.ActionMap; @@ -38,7 +38,7 @@ import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; public class GetTagNameAndCommentDialog extends JDialog { - private static final String NO_TAG_NAMES_MESSAGE = "No Tags"; // RJCTODO: ?? + private static final String NO_TAG_NAMES_MESSAGE = "No Tags"; private final HashMap tagNames = new HashMap<>(); private TagNameAndComment tagNameAndComment = null; @@ -70,7 +70,6 @@ public class GetTagNameAndCommentDialog extends JDialog { initComponents(); // Set up the dialog to close when Esc is pressed. - // RJCTODO: Could do this for the other dialog, too. String cancelName = "cancel"; InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName); @@ -82,17 +81,17 @@ public class GetTagNameAndCommentDialog extends JDialog { } }); - // Populate the combo box with the available tag names. - // Save the tag names to be enable to return the one the user selects. + // Populate the combo box with the available tag names and save the + // tag name DTOs to be enable to return the one the user selects. TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); - ArrayList currentTagNames = new ArrayList<>(); + List currentTagNames = null; try { - tagsManager.getAllTagNames(currentTagNames); + currentTagNames = tagsManager.getAllTagNames(); } catch (TskCoreException ex) { Logger.getLogger(GetTagNameAndCommentDialog.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); } - if (currentTagNames.isEmpty()) { + if (null != currentTagNames && currentTagNames.isEmpty()) { tagCombo.addItem(NO_TAG_NAMES_MESSAGE); } else { @@ -222,18 +221,16 @@ public class GetTagNameAndCommentDialog extends JDialog { }//GEN-LAST:event_cancelButtonActionPerformed private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog - // RJCTODO: Is this dead code? tagNameAndComment = null; dispose(); }//GEN-LAST:event_closeDialog private void newTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagButtonActionPerformed - // RJCTODO: Make suer this works for dups TagName newTagName = GetTagNameDialog.doDialog(); if (newTagName != null) { tagNames.put(newTagName.getDisplayName(), newTagName); tagCombo.addItem(newTagName.getDisplayName()); - tagCombo.setSelectedItem(newTagName); + tagCombo.setSelectedItem(newTagName.getDisplayName()); } }//GEN-LAST:event_newTagButtonActionPerformed diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java index 637effab00..2100d83ae2 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java @@ -18,14 +18,20 @@ */ package org.sleuthkit.autopsy.actions; +import java.awt.event.ActionEvent; import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.logging.Level; +import javax.swing.AbstractAction; +import javax.swing.ActionMap; +import javax.swing.InputMap; +import javax.swing.JComponent; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JOptionPane; +import javax.swing.KeyStroke; import javax.swing.table.AbstractTableModel; import org.openide.util.ImageUtilities; import org.openide.windows.WindowManager; @@ -50,19 +56,36 @@ public class GetTagNameDialog extends JDialog { setIconImage(ImageUtilities.loadImage(TAG_ICON_PATH)); initComponents(); + // Set up the dialog to close when Esc is pressed. + String cancelName = "cancel"; + InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); + inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName); + ActionMap actionMap = getRootPane().getActionMap(); + actionMap.put(cancelName, new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + dispose(); + } + }); + // Get the current set of tag names and hash them for a speedy lookup in // case the user chooses an existing tag name from the tag names table. TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); - ArrayList currentTagNames = new ArrayList<>(); + List currentTagNames = null; try { - tagsManager.getAllTagNames(currentTagNames); + currentTagNames = tagsManager.getAllTagNames(); } catch (TskCoreException ex) { Logger.getLogger(GetTagNameDialog.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); - } - for (TagName name : currentTagNames) { - this.tagNames.put(name.getDisplayName(), name); - } + } + if (null != currentTagNames) { + for (TagName name : currentTagNames) { + this.tagNames.put(name.getDisplayName(), name); + } + } + else { + currentTagNames = new ArrayList<>(); + } // Populate the tag names table. tagsTable.setModel(new TagsTableModel(currentTagNames)); @@ -251,7 +274,6 @@ public class GetTagNameDialog extends JDialog { }//GEN-LAST:event_cancelButtonActionPerformed private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed - // RJCTODO: Check out this stuff, titles etc. String tagDisplayName = tagNameField.getText(); if (tagDisplayName.isEmpty()) { JOptionPane.showMessageDialog(null, "Must supply a tag name to continue.", "Tag Name", JOptionPane.ERROR_MESSAGE); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 16b3ef58d1..3562887438 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.casemodule.services; import java.io.Closeable; import java.io.IOException; -import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; @@ -43,7 +42,6 @@ import org.sleuthkit.datamodel.TskCoreException; public class TagsManager implements Closeable { private static final String TAGS_SETTINGS_NAME = "Tags"; private static final String TAG_NAMES_SETTING_KEY = "TagNames"; - private static final TagName[] predefinedTagNames = new TagName[]{new TagName("Bookmark", "", TagName.HTML_COLOR.NONE)}; private final SleuthkitCase tskCase; private final HashMap uniqueTagNames = new HashMap<>(); private boolean tagNamesInitialized = false; // @@@ This is part of a work around to be removed when database access on the EDT is correctly synchronized. @@ -69,33 +67,31 @@ public class TagsManager implements Closeable { /** * Gets a list of all tag names currently available for tagging content or * blackboard artifacts. - * @param [out] A list, possibly empty, of TagName data transfer objects (DTOs). + * @return A list, possibly empty, of TagName data transfer objects (DTOs). * @throws TskCoreException */ - public synchronized void getAllTagNames(List tagNames) throws TskCoreException { + public synchronized List getAllTagNames() throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - tagNames.clear(); - tskCase.getAllTagNames(tagNames); + return tskCase.getAllTagNames(); } /** * Gets a list of all tag names currently used for tagging content or * blackboard artifacts. - * @param [out] A list, possibly empty, of TagName data transfer objects (DTOs). + * @return A list, possibly empty, of TagName data transfer objects (DTOs). * @throws TskCoreException */ - public synchronized void getTagNamesInUse(List tagNames) throws TskCoreException { + public synchronized List getTagNamesInUse() throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - tagNames.clear(); - tskCase.getTagNamesInUse(tagNames); + return tskCase.getTagNamesInUse(); } /** @@ -152,8 +148,7 @@ public class TagsManager implements Closeable { } // Add the tag name to the case. - TagName newTagName = new TagName(displayName, description, color); - tskCase.addTagName(newTagName); + TagName newTagName = tskCase.addTagName(displayName, description, color); // Add the tag name to the tags settings. uniqueTagNames.put(newTagName.getDisplayName(), newTagName); @@ -166,10 +161,11 @@ public class TagsManager implements Closeable { * Tags a content object. * @param [in] content The content to tag. * @param [in] tagName The name to use for the tag. + * @return A ContentTag data transfer object (DTO) representing the new tag. * @throws TskCoreException */ - public void addContentTag(Content content, TagName tagName) throws TskCoreException { - addContentTag(content, tagName, "", 0, content.getSize() - 1); + public ContentTag addContentTag(Content content, TagName tagName) throws TskCoreException { + return addContentTag(content, tagName, "", 0, content.getSize() - 1); } /** @@ -177,10 +173,11 @@ public class TagsManager implements Closeable { * @param [in] content The content to tag. * @param [in] tagName The name to use for the tag. * @param [in] comment A comment to store with the tag. + * @return A ContentTag data transfer object (DTO) representing the new tag. * @throws TskCoreException */ - public void addContentTag(Content content, TagName tagName, String comment) throws TskCoreException { - addContentTag(content, tagName, comment, 0, content.getSize() - 1); + public ContentTag addContentTag(Content content, TagName tagName, String comment) throws TskCoreException { + return addContentTag(content, tagName, comment, 0, content.getSize() - 1); } /** @@ -190,9 +187,10 @@ public class TagsManager implements Closeable { * @param [in] comment A comment to store with the tag. * @param [in] beginByteOffset Designates the beginning of a tagged section. * @param [in] endByteOffset Designates the end of a tagged section. + * @return A ContentTag data transfer object (DTO) representing the new tag. * @throws IllegalArgumentException, TskCoreException */ - public synchronized void addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws IllegalArgumentException, TskCoreException { + public synchronized ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws IllegalArgumentException, TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); @@ -210,7 +208,7 @@ public class TagsManager implements Closeable { throw new IllegalArgumentException("endByteOffset < beginByteOffset"); } - tskCase.addContentTag(new ContentTag(content, tagName, comment, beginByteOffset, endByteOffset)); + return tskCase.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset); } /** @@ -229,16 +227,16 @@ public class TagsManager implements Closeable { /** * Gets all content tags for the current case. - * @param [out] tags A list, possibly empty, of content tags. + * @return A list, possibly empty, of content tags. * @throws TskCoreException */ - public void getAllContentTags(List tags) throws TskCoreException { + public List getAllContentTags() throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - tskCase.getAllContentTags(tags); + return tskCase.getAllContentTags(); } /** @@ -262,23 +260,24 @@ public class TagsManager implements Closeable { * @return A list, possibly empty, of the content tags with the specified tag name. * @throws TskCoreException */ - public synchronized void getContentTagsByTagName(TagName tagName, List tags) throws TskCoreException { + public synchronized List getContentTagsByTagName(TagName tagName) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - tskCase.getContentTagsByTagName(tagName, tags); + return tskCase.getContentTagsByTagName(tagName); } /** * Tags a blackboard artifact object. * @param [in] artifact The blackboard artifact to tag. * @param [in] tagName The name to use for the tag. + * @return A BlackboardArtifactTag data transfer object (DTO) representing the new tag. * @throws TskCoreException */ - public void addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName) throws TskCoreException { - addBlackboardArtifactTag(artifact, tagName, ""); + public BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName) throws TskCoreException { + return addBlackboardArtifactTag(artifact, tagName, ""); } /** @@ -286,15 +285,16 @@ public class TagsManager implements Closeable { * @param [in] artifact The blackboard artifact to tag. * @param [in] tagName The name to use for the tag. * @param [in] comment A comment to store with the tag. + * @return A BlackboardArtifactTag data transfer object (DTO) representing the new tag. * @throws TskCoreException */ - public synchronized void addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException { + public synchronized BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - tskCase.addBlackboardArtifactTag(new BlackboardArtifactTag(artifact, tskCase.getContentById(artifact.getObjectID()), tagName, comment)); + return tskCase.addBlackboardArtifactTag(artifact, tagName, comment); } /** @@ -313,16 +313,16 @@ public class TagsManager implements Closeable { /** * Gets all blackboard artifact tags for the current case. - * @param [out] tags A list, possibly empty, of blackboard artifact tags. + * @return A list, possibly empty, of blackboard artifact tags. * @throws TskCoreException */ - public void getAllBlackboardArtifactTags(List tags) throws TskCoreException { + public List getAllBlackboardArtifactTags() throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - tskCase.getAllBlackboardArtifactTags(tags); + return tskCase.getAllBlackboardArtifactTags(); } /** @@ -343,48 +343,38 @@ public class TagsManager implements Closeable { /** * Gets blackboard artifact tags by tag name. * @param [in] tagName The tag name of interest. - * @return A list, possibly empty, of the content tags with the specified tag name. + * @return A list, possibly empty, of the blackboard artifact tags with the specified tag name. * @throws TskCoreException */ - public synchronized void getBlackboardArtifactTagsByTagName(TagName tagName, List tags) throws TskCoreException { + public synchronized List getBlackboardArtifactTagsByTagName(TagName tagName) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - tskCase.getBlackboardArtifactTagsByTagName(tagName, tags); + return tskCase.getBlackboardArtifactTagsByTagName(tagName); } /** * Gets blackboard artifact tags for a particular blackboard artifact. * @param [in] artifact The blackboard artifact of interest. - * @param [out] tags A list, possibly empty, of the tags that have been applied to the artifact. + * @return A list, possibly empty, of the tags that have been applied to the artifact. * @throws TskCoreException */ - public synchronized void getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact, List tags) throws TskCoreException { + public synchronized List getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact) throws TskCoreException { // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. if (!tagNamesInitialized) { getExistingTagNames(); } - tskCase.getBlackboardArtifactTagsByArtifact(artifact, tags); + return tskCase.getBlackboardArtifactTagsByArtifact(artifact); } @Override public void close() throws IOException { saveTagNamesToTagsSettings(); } - - private void addTagName(TagName tagName, String errorMessage) { - try { - tskCase.addTagName(tagName); - uniqueTagNames.put(tagName.getDisplayName(), tagName); - } - catch(TskCoreException ex) { - Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, errorMessage, ex); - } - } - + private void getExistingTagNames() { getTagNamesFromCurrentCase(); getTagNamesFromTagsSettings(); @@ -395,8 +385,7 @@ public class TagsManager implements Closeable { private void getTagNamesFromCurrentCase() { try { - ArrayList currentTagNames = new ArrayList<>(); - tskCase.getAllTagNames(currentTagNames); + List currentTagNames = tskCase.getAllTagNames(); for (TagName tagName : currentTagNames) { uniqueTagNames.put(tagName.getDisplayName(), tagName); } @@ -416,18 +405,27 @@ public class TagsManager implements Closeable { // at a time to gracefully discard any duplicates or corrupt tuples. for (String tagNameTuple : tagNameTuples) { String[] tagNameAttributes = tagNameTuple.split(","); - if (!uniqueTagNames.containsKey(tagNameAttributes[0])) { - TagName tagName = new TagName(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.getColorByName(tagNameAttributes[2])); - addTagName(tagName, "Failed to add " + tagName.getDisplayName() + " tag name from tag settings to the current case"); + if (!uniqueTagNames.containsKey(tagNameAttributes[0])) { + try { + TagName tagName = tskCase.addTagName(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.getColorByName(tagNameAttributes[2])); + uniqueTagNames.put(tagName.getDisplayName(), tagName); + } + catch (TskCoreException ex) { + Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to add saved tag name " + tagNameAttributes[0], ex); + } } } } } private void getPredefinedTagNames() { - for (TagName tagName : predefinedTagNames) { - if (!uniqueTagNames.containsKey(tagName.getDisplayName())) { - addTagName(tagName, "Failed to add predefined " + tagName.getDisplayName() + " tag name to the current case"); + if (!uniqueTagNames.containsKey("Bookmark")) { + try { + TagName tagName = tskCase.addTagName("Bookmark", "", TagName.HTML_COLOR.NONE); + uniqueTagNames.put(tagName.getDisplayName(), tagName); + } + catch (TskCoreException ex) { + Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to add predefined 'Bookmark' tag name", ex); } } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java index ed7f9b655f..37b14bf976 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java @@ -90,7 +90,7 @@ public class ContentTagTypeNode extends DisplayableItemNode { protected boolean createKeys(List keys) { // Use the content tags bearing the specified tag name as the keys. try { - Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(tagName, keys); + keys.addAll(Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(tagName)); } catch (TskCoreException ex) { Logger.getLogger(ContentTagTypeNode.ContentTagNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java index d8d743b92d..74b3f195bf 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java @@ -113,7 +113,8 @@ public class TagNameNode extends DisplayableItemNode { case BLACKBOARD_ARTIFACT_TAG_TYPE_NODE_KEY: return new BlackboardArtifactTagTypeNode(tagName); default: - return null; // RJCTODO: Programming error decide how to handle. + Logger.getLogger(TagNameNode.class.getName()).log(Level.SEVERE, "{0} not a recognized key", key); + return null; } } } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java index 247ffb841a..635416bc1e 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java @@ -74,7 +74,7 @@ public class TagsNode extends DisplayableItemNode { @Override protected boolean createKeys(List keys) { try { - Case.getCurrentCase().getServices().getTagsManager().getTagNamesInUse(keys); + keys.addAll(Case.getCurrentCase().getServices().getTagsManager().getTagNamesInUse()); } catch (TskCoreException ex) { Logger.getLogger(TagNameNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java index e0085e35a7..5cedd82e98 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java @@ -95,7 +95,7 @@ public class BlackboardArtifactTagTypeNode extends DisplayableItemNode { protected boolean createKeys(List keys) { try { // Use the blackboard artifact tags bearing the specified tag name as the keys. - Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName, keys); + keys.addAll(Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName)); } catch (TskCoreException ex) { Logger.getLogger(BlackboardArtifactTagTypeNode.BlackboardArtifactTagNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java index bf66eb66fe..a31be8d299 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java @@ -461,9 +461,9 @@ public class ReportGenerator { } // Get the content tags. - ArrayList tags = new ArrayList<>(); + List tags; try { - Case.getCurrentCase().getServices().getTagsManager().getAllContentTags(tags); + tags = Case.getCurrentCase().getServices().getTagsManager().getAllContentTags(); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "failed to get content tags", ex); @@ -524,9 +524,9 @@ public class ReportGenerator { return; } - ArrayList tags = new ArrayList<>(); + List tags; try { - Case.getCurrentCase().getServices().getTagsManager().getAllBlackboardArtifactTags(tags); + tags = Case.getCurrentCase().getServices().getTagsManager().getAllBlackboardArtifactTags(); } catch (TskCoreException ex) { logger.log(Level.SEVERE, "failed to get blackboard artifact tags", ex); @@ -601,8 +601,7 @@ public class ReportGenerator { List artifacts = new ArrayList<>(); try { for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(type)) { - ArrayList tags = new ArrayList<>(); - Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact, tags); + List tags = Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact); HashSet uniqueTagNames = new HashSet<>(); for (BlackboardArtifactTag tag : tags) { uniqueTagNames.add(tag.getName().getDisplayName()); diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java index d63c65f73a..8ccd2b0770 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java @@ -72,12 +72,13 @@ public final class ReportVisualPanel2 extends JPanel { // Initialize the list of Tags private void initTags() { - ArrayList tagNamesInUse = new ArrayList<>(); + List tagNamesInUse; try { - Case.getCurrentCase().getServices().getTagsManager().getTagNamesInUse(tagNamesInUse); + tagNamesInUse = Case.getCurrentCase().getServices().getTagsManager().getTagNamesInUse(); } catch (TskCoreException ex) { Logger.getLogger(ReportVisualPanel2.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); + return; } for(TagName tagName : tagNamesInUse) { diff --git a/Core/src/org/sleuthkit/autopsy/report/TableReportModule.java b/Core/src/org/sleuthkit/autopsy/report/TableReportModule.java index 037b6f16e9..4a7bc9ac50 100644 --- a/Core/src/org/sleuthkit/autopsy/report/TableReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/report/TableReportModule.java @@ -47,11 +47,11 @@ public interface TableReportModule extends ReportModule { /** * Start a new data type for the report. This is how the report will differentiate between - * the start and end of a certain type of data, such as a Blackboard Artifact Type. + * the start and end of a certain type of data, such as a blackboard artifact Type. * It is up to the report how the differentiation is shown. * * @param title String name of the data type - * @param description RJCTODO: fix this header comment + * @param description Description of the data type */ public void startDataType(String title, String description); diff --git a/Timeline/src/org/sleuthkit/autopsy/timeline/Timeline.java b/Timeline/src/org/sleuthkit/autopsy/timeline/Timeline.java index 3468ab6fef..190aa2a7d5 100644 --- a/Timeline/src/org/sleuthkit/autopsy/timeline/Timeline.java +++ b/Timeline/src/org/sleuthkit/autopsy/timeline/Timeline.java @@ -885,10 +885,10 @@ public class Timeline extends CallableSystemAction implements Presenter.Toolbar, } @Override - public DisplayableItemNode.TYPE getDisplayableItemNodeType() { - return DisplayableItemNode.TYPE.CONTENT; + public boolean isLeafTypeNode() { + return false; } - + @Override public T accept(DisplayableItemNodeVisitor v) { return null; From c45e0d2f782b34fe5b30379211e5aa0bde0060b0 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 23 Oct 2013 16:07:13 -0400 Subject: [PATCH 038/169] Class name adjustments --- .../org/sleuthkit/autopsy/actions/Bundle.properties | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties index 1ae4a0f597..ad0c347ecb 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties @@ -4,13 +4,13 @@ GetTagNameDialog.okButton.text=OK GetTagNameDialog.preexistingLabel.text=Pre-existing Tags: GetTagNameDialog.newTagPanel.border.title=New Tag GetTagNameDialog.tagNameLabel.text=Tag Name: -GetTagNameAndCommentDialog.tagLabel.text=Tag: +GetTagNameAndCommentDialog.newTagButton.text=New Tag GetTagNameAndCommentDialog.okButton.text=OK -GetTagNameAndCommentDialog.tagCombo.toolTipText=Select tag to use -# To change this template, choose Tools | Templates -# and open the template in the editor. -GetTagNameAndCommentDialog.cancelButton.text=Cancel GetTagNameAndCommentDialog.commentText.toolTipText=Enter an optional tag comment or leave blank GetTagNameAndCommentDialog.commentText.text= GetTagNameAndCommentDialog.commentLabel.text=Comment: -GetTagNameAndCommentDialog.newTagButton.text=New Tag +# To change this template, choose Tools | Templates +# and open the template in the editor. +GetTagNameAndCommentDialog.cancelButton.text=Cancel +GetTagNameAndCommentDialog.tagCombo.toolTipText=Select tag to use +GetTagNameAndCommentDialog.tagLabel.text=Tag: From a8263dd7d71ff880bca3df26311e45fafade67f5 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 23 Oct 2013 16:30:13 -0400 Subject: [PATCH 039/169] Fix merge of platform.properties file --- nbproject/platform.properties | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/nbproject/platform.properties b/nbproject/platform.properties index 08baaff2f8..a9fa87f749 100644 --- a/nbproject/platform.properties +++ b/nbproject/platform.properties @@ -1,4 +1,3 @@ -<<<<<<< HEAD branding.token=autopsy netbeans-plat-version=7.3.1 suite.dir=${basedir} @@ -119,19 +118,3 @@ disabled.modules=\ org.netbeans.modules.xml.tools.java,\ org.netbeans.spi.java.hints -======= -branding.token=autopsy -netbeans-plat-version=7.3.1 -suite.dir=${basedir} -nbplatform.active.dir=${suite.dir}/netbeans-plat/${netbeans-plat-version} -harness.dir=${nbplatform.active.dir}/harness -bootstrap.url=http://deadlock.netbeans.org/hudson/job/nbms-and-javadoc/lastStableBuild/artifact/nbbuild/netbeans/harness/tasks.jar -autoupdate.catalog.url=http://dlc.sun.com.edgesuite.net/netbeans/updates/${netbeans-plat-version}/uc/final/distribution/catalog.xml.gz -cluster.path=\ - ${nbplatform.active.dir}/harness:\ - ${nbplatform.active.dir}/java:\ - ${nbplatform.active.dir}/platform -disabled.modules=\ - org.netbeans.modules.junit - ->>>>>>> new_tags_api From 8e06b8e4ff3b0d9650c1dadaf88c877d4c925b65 Mon Sep 17 00:00:00 2001 From: raman-bt Date: Thu, 24 Oct 2013 15:52:39 -0400 Subject: [PATCH 040/169] Added LocalDiskDSProcessor and LocalFilesDSProcessor. Minor bugfixes & cleanup. --- .../autopsy/casemodule/AddImageTask.java | 4 +- .../AddImageWizardChooseDataSourceVisual.java | 6 +- .../autopsy/casemodule/AddLocalFilesTask.java | 186 +++++++++++++++++ .../autopsy/casemodule/Bundle.properties | 4 + .../autopsy/casemodule/ImageFilePanel.form | 2 +- .../autopsy/casemodule/ImageFilePanel.java | 2 +- .../casemodule/LocalDiskDSProcessor.java | 193 ++++++++++++++++++ .../autopsy/casemodule/LocalDiskPanel.form | 59 +++++- .../autopsy/casemodule/LocalDiskPanel.java | 141 +++++++++++-- .../casemodule/LocalFilesDSProcessor.java | 180 ++++++++++++++++ .../autopsy/casemodule/LocalFilesPanel.java | 7 +- 11 files changed, 749 insertions(+), 35 deletions(-) create mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/AddLocalFilesTask.java create mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java create mode 100644 Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java index 6b611a6abc..ff0a90a9c2 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java @@ -19,13 +19,11 @@ package org.sleuthkit.autopsy.casemodule; -import java.awt.EventQueue; -import java.lang.reflect.InvocationTargetException; + import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.logging.Level; -import javax.swing.SwingWorker; import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback; import org.sleuthkit.autopsy.corecomponentinterfaces.DSPProgressMonitor; import org.sleuthkit.autopsy.coreutils.Logger; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java index 2bcea63a06..867d617916 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java @@ -94,13 +94,11 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { } }; - typeComboBox.addActionListener(cbActionListener); - typeComboBox.setSelectedIndex(0); typePanel.setLayout(new BorderLayout()); - - updateCurrentPanel(getCurrentDSProcessor().getPanel()); + + typeComboBox.setSelectedIndex(0); } private void discoverDataSourceProcessors() { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddLocalFilesTask.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddLocalFilesTask.java new file mode 100644 index 0000000000..ea70b783e3 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddLocalFilesTask.java @@ -0,0 +1,186 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 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.casemodule; + + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.logging.Level; +import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback; +import org.sleuthkit.autopsy.corecomponentinterfaces.DSPProgressMonitor; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.Content; +import org.sleuthkit.autopsy.casemodule.services.FileManager; +import org.sleuthkit.datamodel.TskCoreException; + + +/** + * Thread that will add logical files to database, and then kick-off ingest + * modules. Note: the add logical files task cannot currently be reverted as + * the add image task can. This is a separate task from AddImgTask because + * it is much simpler and does not require locks, since the underlying file + * manager methods acquire the locks for each transaction when adding + * logical files. + */ +public class AddLocalFilesTask implements Runnable { + + private Logger logger = Logger.getLogger(AddLocalFilesTask.class.getName()); + + private String dataSourcePath; + private DSPProgressMonitor progressMonitor; + private DSPCallback callbackObj; + + private Case currentCase; + // true if the process was requested to stop + private volatile boolean cancelled = false; + private boolean hasCritError = false; + + private List errorList = new ArrayList(); + private final List newContents = Collections.synchronizedList(new ArrayList()); + + + protected AddLocalFilesTask(String dataSourcePath, DSPProgressMonitor aProgressMonitor, DSPCallback cbObj) { + + currentCase = Case.getCurrentCase(); + + this.dataSourcePath = dataSourcePath; + this.callbackObj = cbObj; + this.progressMonitor = aProgressMonitor; + } + + /** + * Starts the addImage process, but does not commit the results. + * + * @return + * + * @throws Exception + */ + @Override + public void run() { + errorList.clear(); + + // RAMAN TBD: dont we need to lock the DB ???? + + final LocalFilesAddProgressUpdater progUpdater = new LocalFilesAddProgressUpdater(progressMonitor); + try { + + progressMonitor.setIndeterminate(true); + progressMonitor.setProgress(0); + + final FileManager fileManager = currentCase.getServices().getFileManager(); + String[] paths = dataSourcePath.split(LocalFilesPanel.FILES_SEP); + List absLocalPaths = new ArrayList(); + for (String path : paths) { + absLocalPaths.add(path); + } + newContents.add(fileManager.addLocalFilesDirs(absLocalPaths, progUpdater)); + } catch (TskCoreException ex) { + logger.log(Level.WARNING, "Errors occurred while running add logical files. ", ex); + hasCritError = true; + errorList.add(ex.getMessage()); + } finally { + + } + + // handle done + postProcess(); + + return; + } + + /** + * + * (called by EventDispatch Thread after doInBackground finishes) + */ + protected void postProcess() { + + if (cancelled || hasCritError) { + logger.log(Level.WARNING, "Handling errors or interruption that occured in logical files process"); + + } + if (!errorList.isEmpty()) { + //data error (non-critical) + logger.log(Level.WARNING, "Handling non-critical errors that occured in logical files process"); + } + + if (!(cancelled || hasCritError)) { + progressMonitor.setProgress(100); + progressMonitor.setIndeterminate(false); + } + + // invoke the callBack, unless the caller cancelled + if (!cancelled) { + doCallBack(); + } + + } + + /* + * Call the callback with results, new content, and errors, if any + */ + private void doCallBack() + { + DSPCallback.DSP_Result result; + + if (hasCritError) { + result = DSPCallback.DSP_Result.CRITICAL_ERRORS; + } + else if (!errorList.isEmpty()) { + result = DSPCallback.DSP_Result.NONCRITICAL_ERRORS; + } + else { + result = DSPCallback.DSP_Result.NO_ERRORS; + } + + // invoke the callback, passing it the result, list of new contents, and list of errors + callbackObj.done(result, errorList, newContents); + } + + /* + * cancel the files addition, if possible + */ + public void cancelTask() { + cancelled = true; + + } + + /** + * Updates the wizard status with logical file/folder + */ + private class LocalFilesAddProgressUpdater implements FileManager.FileAddProgressUpdater { + + private int count = 0; + private DSPProgressMonitor progressMonitor; + + + LocalFilesAddProgressUpdater(DSPProgressMonitor progressMonitor) { + + this.progressMonitor = progressMonitor; + } + + @Override + public void fileAdded(final AbstractFile newFile) { + if (count++ % 10 == 0) { + progressMonitor.setText(newFile.getParentPath() + "/" + newFile.getName()); + } + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index 6207163194..f7b76e175a 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -148,3 +148,7 @@ ImageFilePanel.timeZoneLabel.text=Please select the input timezone: ImageFilePanel.noFatOrphansCheckbox.text=Ignore orphan files in FAT file systems ImageFilePanel.noFatOrphansCheckbox.toolTipText= ImageFilePanel.descLabel.text=(faster results, although some data will not be searched) +LocalDiskPanel.timeZoneLabel.text=Please select the input timezone: +LocalDiskPanel.noFatOrphansCheckbox.toolTipText= +LocalDiskPanel.noFatOrphansCheckbox.text=Ignore orphan files in FAT file systems +LocalDiskPanel.descLabel.text=(faster results, although some data will not be searched) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form index b4dbaafd63..5d919e225a 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form @@ -66,7 +66,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java index 04a9d78767..c379f74f74 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java @@ -170,7 +170,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener { .addComponent(noFatOrphansCheckbox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(descLabel) - .addContainerGap(13, Short.MAX_VALUE)) + .addContainerGap(73, Short.MAX_VALUE)) ); }// //GEN-END:initComponents diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java new file mode 100644 index 0000000000..f268ef2b98 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java @@ -0,0 +1,193 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 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.casemodule; + +import javax.swing.JPanel; +import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback; +import org.sleuthkit.autopsy.corecomponentinterfaces.DSPProgressMonitor; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; +import org.sleuthkit.autopsy.coreutils.Logger; + + +@ServiceProvider(service = DataSourceProcessor.class) +public class LocalDiskDSProcessor implements DataSourceProcessor { + + static final Logger logger = Logger.getLogger(ImageDSProcessor.class.getName()); + + // Data source type handled by this processor + private final String dsType = "Local Disk"; + + // The Config UI panel that plugins into the Choose Data Source Wizard + private LocalDiskPanel localDiskPanel; + + // The Background task that does the actual work of adding the local Disk + // Adding a local disk is exactly same as adding an Image. + private AddImageTask addDiskTask; + + // true if cancelled by the caller + private boolean cancelled = false; + + DSPCallback callbackObj = null; + + // set to TRUE if the image options have been set via API and config Jpanel should be ignored + private boolean localDiskOptionsSet = false; + + // data source options + private String localDiskPath; + private String timeZone; + private boolean noFatOrphans; + + + + /* + * A no argument constructor is required for the NM lookup() method to create an object + */ + public LocalDiskDSProcessor() { + + // Create the config panel + localDiskPanel = LocalDiskPanel.getDefault(); + + } + + /** + * Returns the Data source type (string) handled by this DSP + * + * @return String the data source type + **/ + @Override + public String getType() { + return dsType; + } + + /** + * Returns the JPanel for collecting the Data source information + * + * @return JPanel the config panel + **/ + @Override + public JPanel getPanel() { + + // RAMAN TBD: we should ask the panel to preload with any saved settings + + localDiskPanel.select(); + return localDiskPanel; + } + /** + * Validates the data collected by the JPanel + * + * @return String returns NULL if success, error string if there is any errors + **/ + @Override + public String validatePanel() { + + if (localDiskPanel.validatePanel() ) + return null; + else + return "Error in panel"; + } + + + + /** + * Runs the data source processor. + * This must kick off processing the data source in background + * + * @param progressMonitor Progress monitor to report progress during processing + * @param cbObj callback to call when processing is done. + **/ + @Override + public void run(DSPProgressMonitor progressMonitor, DSPCallback cbObj) { + + callbackObj = cbObj; + cancelled = false; + + if (!localDiskOptionsSet) + { + // RAMAN TBD: we should ask the panel to save the current settings + + // get the image options from the panel + localDiskPath = localDiskPanel.getContentPaths(); + timeZone = localDiskPanel.getTimeZone(); + noFatOrphans = localDiskPanel.getNoFatOrphans(); + } + + addDiskTask = new AddImageTask(localDiskPath, timeZone, noFatOrphans, progressMonitor, cbObj); + new Thread(addDiskTask).start(); + + return; + } + + + + + + + + /** + * Cancel the data source processing + **/ + @Override + public void cancel() { + + cancelled = true; + + addDiskTask.cancelTask(); + + return; + } + + /** + * Reset the data source processor + **/ + @Override + public void reset() { + + // reset the config panel + localDiskPanel.reset(); + + // reset state + localDiskOptionsSet = false; + localDiskPath = null; + timeZone = null; + noFatOrphans = false; + + return; + } + + /** + * Sets the data source options externally. + * To be used by a client that does not have a UI and does not use the JPanel to + * collect this information from a user. + * + * @param diskPath path to the local disk + * @param String timeZone + * @param noFat whether to parse FAT orphans + **/ + public void setDataSourceOptions(String diskPath, String tz, boolean noFat) { + + this.localDiskPath = diskPath; + this.timeZone = tz; + this.noFatOrphans = noFat; + + localDiskOptionsSet = true; + + } +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.form index a0b5f3f431..2b1062c834 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.form @@ -29,8 +29,18 @@ + + + + + + + + + + - + @@ -40,8 +50,18 @@ - + + + + + + + + + + + @@ -71,5 +91,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java index a0ce4ec323..671622fdc7 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java @@ -25,7 +25,10 @@ import java.awt.Font; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.ArrayList; +import java.util.Calendar; import java.util.List; +import java.util.SimpleTimeZone; +import java.util.TimeZone; import java.util.concurrent.CancellationException; import java.util.logging.Level; import javax.swing.ComboBoxModel; @@ -43,7 +46,9 @@ import org.sleuthkit.autopsy.coreutils.PlatformUtil; /** * ImageTypePanel for adding a local disk or partition such as PhysicalDrive0 or C:. */ -public class LocalDiskPanel extends JPanel { +public class LocalDiskPanel extends JPanel { + private static final Logger logger = Logger.getLogger(LocalDiskPanel.class.getName()); + private static LocalDiskPanel instance; private PropertyChangeSupport pcs = null; private List disks = new ArrayList(); @@ -56,6 +61,9 @@ public class LocalDiskPanel extends JPanel { public LocalDiskPanel() { initComponents(); customInit(); + + createTimeZoneList(); + } /** @@ -73,8 +81,10 @@ public class LocalDiskPanel extends JPanel { model = new LocalDiskModel(); diskComboBox.setModel(model); diskComboBox.setRenderer(model); + errorLabel.setText(""); diskComboBox.setEnabled(false); + } /** @@ -89,6 +99,10 @@ public class LocalDiskPanel extends JPanel { diskLabel = new javax.swing.JLabel(); diskComboBox = new javax.swing.JComboBox(); errorLabel = new javax.swing.JLabel(); + timeZoneLabel = new javax.swing.JLabel(); + timeZoneComboBox = new javax.swing.JComboBox(); + noFatOrphansCheckbox = new javax.swing.JCheckBox(); + descLabel = new javax.swing.JLabel(); setMinimumSize(new java.awt.Dimension(0, 65)); setPreferredSize(new java.awt.Dimension(485, 65)); @@ -98,6 +112,15 @@ public class LocalDiskPanel extends JPanel { errorLabel.setForeground(new java.awt.Color(255, 0, 0)); org.openide.awt.Mnemonics.setLocalizedText(errorLabel, org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.errorLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(timeZoneLabel, org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.timeZoneLabel.text")); // NOI18N + + timeZoneComboBox.setMaximumRowCount(30); + + org.openide.awt.Mnemonics.setLocalizedText(noFatOrphansCheckbox, org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.noFatOrphansCheckbox.text")); // NOI18N + noFatOrphansCheckbox.setToolTipText(org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.noFatOrphansCheckbox.toolTipText")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(descLabel, org.openide.util.NbBundle.getMessage(LocalDiskPanel.class, "LocalDiskPanel.descLabel.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -106,8 +129,16 @@ public class LocalDiskPanel extends JPanel { .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(diskLabel) .addComponent(diskComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 345, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(errorLabel)) - .addGap(0, 140, Short.MAX_VALUE)) + .addComponent(errorLabel) + .addGroup(layout.createSequentialGroup() + .addComponent(timeZoneLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 215, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(noFatOrphansCheckbox) + .addGroup(layout.createSequentialGroup() + .addGap(21, 21, 21) + .addComponent(descLabel))) + .addGap(0, 102, Short.MAX_VALUE)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -115,14 +146,27 @@ public class LocalDiskPanel extends JPanel { .addComponent(diskLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(diskComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(13, 13, 13) + .addComponent(errorLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(timeZoneLabel) + .addComponent(timeZoneComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(18, 18, 18) + .addComponent(noFatOrphansCheckbox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(errorLabel)) + .addComponent(descLabel) + .addContainerGap(27, Short.MAX_VALUE)) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JLabel descLabel; private javax.swing.JComboBox diskComboBox; private javax.swing.JLabel diskLabel; private javax.swing.JLabel errorLabel; + private javax.swing.JCheckBox noFatOrphansCheckbox; + private javax.swing.JComboBox timeZoneComboBox; + private javax.swing.JLabel timeZoneLabel; // End of variables declaration//GEN-END:variables /** @@ -152,9 +196,14 @@ public class LocalDiskPanel extends JPanel { } } - //@Override - public String getContentType() { - return "DISK"; + public String getTimeZone() { + String tz = timeZoneComboBox.getSelectedItem().toString(); + return tz.substring(tz.indexOf(")") + 2).trim(); + + } + + boolean getNoFatOrphans() { + return noFatOrphansCheckbox.isSelected(); } /** @@ -163,22 +212,19 @@ public class LocalDiskPanel extends JPanel { * @return true */ //@Override - public boolean enableNext() { + public boolean validatePanel() { return enableNext; } //@Override public void reset() { //nothing to reset + + // RAMAN TBD this should reset the UI elements? + } - /** - * @return the representation of this panel as a String. - */ - //@Override - public String toString() { - return "Local Disk"; - } + /** * Set the focus to the diskComboBox and refreshes the list of disks. @@ -186,7 +232,8 @@ public class LocalDiskPanel extends JPanel { // @Override public void select() { diskComboBox.requestFocusInWindow(); - model.loadDisks(); + model.loadDisks(); + } @Override @@ -207,16 +254,61 @@ public class LocalDiskPanel extends JPanel { pcs.removePropertyChangeListener(pcl); } + /** + * Creates the drop down list for the time zones and then makes the local + * machine time zone to be selected. + */ + public void createTimeZoneList() { + // load and add all timezone + String[] ids = SimpleTimeZone.getAvailableIDs(); + for (String id : ids) { + TimeZone zone = TimeZone.getTimeZone(id); + int offset = zone.getRawOffset() / 1000; + int hour = offset / 3600; + int minutes = (offset % 3600) / 60; + String item = String.format("(GMT%+d:%02d) %s", hour, minutes, id); + + /* + * DateFormat dfm = new SimpleDateFormat("z"); + * dfm.setTimeZone(zone); boolean hasDaylight = + * zone.useDaylightTime(); String first = dfm.format(new Date(2010, + * 1, 1)); String second = dfm.format(new Date(2011, 6, 6)); int mid + * = hour * -1; String result = first + Integer.toString(mid); + * if(hasDaylight){ result = result + second; } + * timeZoneComboBox.addItem(item + " (" + result + ")"); + */ + timeZoneComboBox.addItem(item); + } + // get the current timezone + TimeZone thisTimeZone = Calendar.getInstance().getTimeZone(); + int thisOffset = thisTimeZone.getRawOffset() / 1000; + int thisHour = thisOffset / 3600; + int thisMinutes = (thisOffset % 3600) / 60; + String formatted = String.format("(GMT%+d:%02d) %s", thisHour, thisMinutes, thisTimeZone.getID()); + + // set the selected timezone + timeZoneComboBox.setSelectedItem(formatted); + } + private class LocalDiskModel implements ComboBoxModel, ListCellRenderer { private Object selected; private boolean ready = false; + private volatile boolean loadingDisks = false; List physical = new ArrayList(); List partitions = new ArrayList(); //private String SELECT = "Select a local disk:"; private String LOADING = "Loading local disks..."; + LocalDiskThread worker = null; + private void loadDisks() { + + // if there is a worker already building the lists, then cancel it first. + if (loadingDisks && worker != null) { + worker.cancel(false); + } + // Clear the lists errorLabel.setText(""); disks = new ArrayList(); @@ -224,9 +316,13 @@ public class LocalDiskPanel extends JPanel { partitions = new ArrayList(); diskComboBox.setEnabled(false); ready = false; - - LocalDiskThread worker = new LocalDiskThread(); + enableNext = false; + loadingDisks = true; + + worker = new LocalDiskThread(); worker.execute(); + + } @Override @@ -260,7 +356,7 @@ public class LocalDiskPanel extends JPanel { @Override public void removeListDataListener(ListDataListener l) { } - + @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { JPanel panel = new JPanel(new BorderLayout()); @@ -300,8 +396,6 @@ public class LocalDiskPanel extends JPanel { // Populate the lists physical = PlatformUtil.getPhysicalDrives(); partitions = PlatformUtil.getPartitions(); - disks.addAll(physical); - disks.addAll(partitions); return null; } @@ -337,6 +431,11 @@ public class LocalDiskPanel extends JPanel { enableNext = false; displayErrors(); ready = true; + worker = null; + loadingDisks = false; + + disks.addAll(physical); + disks.addAll(partitions); if(disks.size() > 0) { diskComboBox.setEnabled(true); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java new file mode 100644 index 0000000000..023b21259f --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java @@ -0,0 +1,180 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 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.casemodule; + +import javax.swing.JPanel; +import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback; +import org.sleuthkit.autopsy.corecomponentinterfaces.DSPProgressMonitor; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; +import org.sleuthkit.autopsy.coreutils.Logger; + +@ServiceProvider(service = DataSourceProcessor.class) +public class LocalFilesDSProcessor implements DataSourceProcessor { + + static final Logger logger = Logger.getLogger(LocalFilesDSProcessor.class.getName()); + + // Data source type handled by this processor + private final String dsType = "Logical Files"; + + // The Config UI panel that plugins into the Choose Data Source Wizard + private LocalFilesPanel localFilesPanel; + + // The Background task that does the actual work of adding the local Disk + // Adding a local disk is exactly same as adding an Image. + private AddLocalFilesTask addFilesTask; + + // true if cancelled by the caller + private boolean cancelled = false; + + DSPCallback callbackObj = null; + + // set to TRUE if the image options have been set via API and config Jpanel should be ignored + private boolean localFilesOptionsSet = false; + + // data source options + private String localFilesPath; + + + + /* + * A no argument constructor is required for the NM lookup() method to create an object + */ + public LocalFilesDSProcessor() { + + // Create the config panel + localFilesPanel = LocalFilesPanel.getDefault(); + + } + + /** + * Returns the Data source type (string) handled by this DSP + * + * @return String the data source type + **/ + @Override + public String getType() { + return dsType; + } + + /** + * Returns the JPanel for collecting the Data source information + * + * @return JPanel the config panel + **/ + @Override + public JPanel getPanel() { + + // RAMAN TBD: we should ask the panel to preload with any saved settings + + localFilesPanel.select(); + + return localFilesPanel; + } + /** + * Validates the data collected by the JPanel + * + * @return String returns NULL if success, error string if there is any errors + **/ + @Override + public String validatePanel() { + + if (localFilesPanel.validatePanel() ) + return null; + else + return "Error in panel"; + } + + + + /** + * Runs the data source processor. + * This must kick off processing the data source in background + * + * @param progressMonitor Progress monitor to report progress during processing + * @param cbObj callback to call when processing is done. + **/ + @Override + public void run(DSPProgressMonitor progressMonitor, DSPCallback cbObj) { + + callbackObj = cbObj; + cancelled = false; + + if (!localFilesOptionsSet) + { + // RAMAN TBD: we should ask the panel to save the current settings + + // get the image options from the panel + localFilesPath = localFilesPanel.getContentPaths(); + } + + addFilesTask = new AddLocalFilesTask(localFilesPath, progressMonitor, cbObj); + new Thread(addFilesTask).start(); + + return; + } + + /** + * Cancel the data source processing + **/ + @Override + public void cancel() { + + cancelled = true; + addFilesTask.cancelTask(); + + return; + } + + /** + * Reset the data source processor + **/ + @Override + public void reset() { + + // reset the config panel + localFilesPanel.reset(); + + // reset state + localFilesOptionsSet = false; + localFilesPath = null; + + + return; + } + + /** + * Sets the data source options externally. + * To be used by a client that does not have a UI and does not use the JPanel to + * collect this information from a user. + * + * @param filesPath PATH_SEP list of paths to local files + * + **/ + public void setDataSourceOptions(String filesPath) { + + this.localFilesPath = filesPath; + + localFilesOptionsSet = true; + + } + + +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java index 31b4877ff4..557f41fc87 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java @@ -85,7 +85,7 @@ public class LocalFilesPanel extends JPanel { } //@Override - public boolean enableNext() { + public boolean validatePanel() { return enableNext; } @@ -99,10 +99,11 @@ public class LocalFilesPanel extends JPanel { currentFiles.clear(); selectedPaths.setText(""); enableNext = false; - pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true); + + //pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true); } - @Override + @Override public synchronized void addPropertyChangeListener(PropertyChangeListener pcl) { super.addPropertyChangeListener(pcl); From 5e118737da5cd5443e5103d7d7b91366641250a5 Mon Sep 17 00:00:00 2001 From: raman-bt Date: Thu, 24 Oct 2013 17:01:56 -0400 Subject: [PATCH 041/169] i. Changed validatePanel() to return a boolean instead of string ii. Moved the UI Event/Property names into DataSourceProcessor to eliminate dependency on AddImageWizardChooseDataSourceVisual --- .../AddImageWizardChooseDataSourceVisual.java | 17 ++++----------- .../autopsy/casemodule/ImageDSProcessor.java | 7 ++----- .../autopsy/casemodule/ImageFilePanel.java | 9 ++++---- .../casemodule/LocalDiskDSProcessor.java | 8 ++----- .../autopsy/casemodule/LocalDiskPanel.java | 3 ++- .../casemodule/LocalFilesDSProcessor.java | 16 +++++--------- .../autopsy/casemodule/LocalFilesPanel.java | 3 ++- .../DataSourceProcessor.java | 21 ++++++++++++++----- 8 files changed, 38 insertions(+), 46 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java index 867d617916..42a49daf56 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java @@ -51,14 +51,9 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { static final Logger logger = Logger.getLogger(AddImageWizardChooseDataSourceVisual.class.getName()); - enum EVENT { - - UPDATE_UI, FOCUS_NEXT - }; - private AddImageWizardChooseDataSourcePanel wizPanel; - private JPanel currentPanel; + private JPanel currentPanel; private Map datasourceProcessorsMap = new HashMap(); @@ -135,10 +130,10 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { currentPanel.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString())) { + if (evt.getPropertyName().equals(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString())) { updateUI(null); } - if (evt.getPropertyName().equals(AddImageWizardChooseDataSourceVisual.EVENT.FOCUS_NEXT.toString())) { + if (evt.getPropertyName().equals(DataSourceProcessor.DSP_PANEL_EVENT.FOCUS_NEXT.toString())) { wizPanel.moveFocusToNext(); } } @@ -292,11 +287,7 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { */ public void updateUI(DocumentEvent e) { // Enable the Next button if the current DSP panel is valid - String err = getCurrentDSProcessor().validatePanel(); - if (null == err) - this.wizPanel.enableNextButton(true); - else - this.wizPanel.enableNextButton(false); + this.wizPanel.enableNextButton(getCurrentDSProcessor().validatePanel()); } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java index cb9f768ecc..fee952c05f 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java @@ -102,12 +102,9 @@ public class ImageDSProcessor implements DataSourceProcessor { * @return String returns NULL if success, error string if there is any errors **/ @Override - public String validatePanel() { + public boolean validatePanel() { - if (imageFilePanel.validatePanel() ) - return null; - else - return "Error in panel"; + return imageFilePanel.validatePanel(); } /** * Runs the data source processor. diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java index c379f74f74..4be2a44483 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java @@ -31,6 +31,7 @@ import javax.swing.JFileChooser; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.JPanel; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; /** * ImageTypePanel for adding an image file such as .img, .E0x, .00x, etc. @@ -187,7 +188,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener { String path = fc.getSelectedFile().getPath(); pathTextField.setText(path); } - pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.FOCUS_NEXT.toString(), false, true); + pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.FOCUS_NEXT.toString(), false, true); }//GEN-LAST:event_browseButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables @@ -298,17 +299,17 @@ public class ImageFilePanel extends JPanel implements DocumentListener { */ @Override public void insertUpdate(DocumentEvent e) { - pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true); + pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true); } @Override public void removeUpdate(DocumentEvent e) { - pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true); + pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true); } @Override public void changedUpdate(DocumentEvent e) { - pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true); + pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true); } /** diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java index f268ef2b98..d6b8007fdb 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java @@ -96,12 +96,8 @@ public class LocalDiskDSProcessor implements DataSourceProcessor { * @return String returns NULL if success, error string if there is any errors **/ @Override - public String validatePanel() { - - if (localDiskPanel.validatePanel() ) - return null; - else - return "Error in panel"; + public boolean validatePanel() { + return localDiskPanel.validatePanel(); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java index 671622fdc7..5b2e95ce04 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java @@ -40,6 +40,7 @@ import javax.swing.ListCellRenderer; import javax.swing.SwingWorker; import javax.swing.border.EmptyBorder; import javax.swing.event.ListDataListener; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.PlatformUtil; @@ -330,7 +331,7 @@ public class LocalDiskPanel extends JPanel { if(ready) { selected = anItem; enableNext = true; - pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true); + pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true); } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java index 023b21259f..085c0b65c1 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java @@ -29,7 +29,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; @ServiceProvider(service = DataSourceProcessor.class) public class LocalFilesDSProcessor implements DataSourceProcessor { - static final Logger logger = Logger.getLogger(LocalFilesDSProcessor.class.getName()); + static final Logger logger = Logger.getLogger(LocalFilesDSProcessor.class.getName()); // Data source type handled by this processor private final String dsType = "Logical Files"; @@ -37,8 +37,7 @@ public class LocalFilesDSProcessor implements DataSourceProcessor { // The Config UI panel that plugins into the Choose Data Source Wizard private LocalFilesPanel localFilesPanel; - // The Background task that does the actual work of adding the local Disk - // Adding a local disk is exactly same as adding an Image. + // The Background task that does the actual work of adding the files private AddLocalFilesTask addFilesTask; // true if cancelled by the caller @@ -60,8 +59,7 @@ public class LocalFilesDSProcessor implements DataSourceProcessor { public LocalFilesDSProcessor() { // Create the config panel - localFilesPanel = LocalFilesPanel.getDefault(); - + localFilesPanel = LocalFilesPanel.getDefault(); } /** @@ -94,12 +92,8 @@ public class LocalFilesDSProcessor implements DataSourceProcessor { * @return String returns NULL if success, error string if there is any errors **/ @Override - public String validatePanel() { - - if (localFilesPanel.validatePanel() ) - return null; - else - return "Error in panel"; + public boolean validatePanel() { + return localFilesPanel.validatePanel(); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java index 557f41fc87..c9cff7b1d0 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesPanel.java @@ -25,6 +25,7 @@ import java.util.Set; import java.util.TreeSet; import javax.swing.JFileChooser; import javax.swing.JPanel; +import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; /** * Add input wizard subpanel for adding local files / dirs to the case @@ -233,7 +234,7 @@ public class LocalFilesPanel extends JPanel { else { enableNext = false; } - pcs.firePropertyChange(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString(), false, true); + pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.UPDATE_UI.toString(), false, true); }//GEN-LAST:event_selectButtonActionPerformed private void clearButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_clearButtonActionPerformed diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessor.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessor.java index 581cd87b61..af67e78b68 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DataSourceProcessor.java @@ -20,7 +20,6 @@ package org.sleuthkit.autopsy.corecomponentinterfaces; import javax.swing.JPanel; -import org.sleuthkit.datamodel.Content; /* * Defines an interface used by the Add DataSource wizard to discover different @@ -29,7 +28,7 @@ import org.sleuthkit.datamodel.Content; * Each data source may have its unique attributes and may need to be processed * differently. * - * The DataSourceProcessor interface defines a uniform mechanism for thre Autopsy UI + * The DataSourceProcessor interface defines a uniform mechanism for the Autopsy UI * to: * - collect details for the data source to be processed. * - Process the data source in the background @@ -37,6 +36,18 @@ import org.sleuthkit.datamodel.Content; */ public interface DataSourceProcessor { + /* + * The DSP Panel may fire Property change events + * The caller must enure to add itself as a listener and + * then react appropriately to the events + */ + enum DSP_PANEL_EVENT { + + UPDATE_UI, // the content of JPanel has changed that MAY warrant updates to the caller UI + FOCUS_NEXT // the caller UI may move focus the the next UI element, floowing the panel. + }; + + /** * Returns the type of Data Source it handles. * This name gets displayed in the drop-down listbox @@ -51,10 +62,10 @@ public interface DataSourceProcessor { /** * Called to validate the input data in the panel. - * Returns null if no errors, or - * Returns a string describing the error if there are errors. + * Returns true if no errors, or + * Returns false if there is an error. **/ - String validatePanel(); + boolean validatePanel(); /** * Called to invoke the handling of Data source in the background. From f3635ca754fc6c7cf44e13f43d6f913d6f05764a Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Fri, 25 Oct 2013 14:50:24 -0400 Subject: [PATCH 042/169] Adjust label text for hash import dialog. --- .../src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties | 4 ++-- .../autopsy/hashdatabase/HashDbAddDatabaseDialog.form | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties index a9aead73cb..3c63f386fb 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties @@ -15,9 +15,9 @@ HashDbAddDatabaseDialog.nsrlRadioButton.text=NSRL HashDbAddDatabaseDialog.knownBadRadioButton.text=Known Bad HashDbAddDatabaseDialog.databasePathTextField.text= HashDbAddDatabaseDialog.browseButton.text=Browse -HashDbAddDatabaseDialog.jLabel1.text=Enter the name of the database: +HashDbAddDatabaseDialog.jLabel1.text=Display name of database: HashDbAddDatabaseDialog.databaseNameTextField.text= -HashDbAddDatabaseDialog.jLabel2.text=Select the type of database: +HashDbAddDatabaseDialog.jLabel2.text=Type of database: HashDbAddDatabaseDialog.useForIngestCheckbox.text=Enable for ingest HashDbAddDatabaseDialog.sendInboxMessagesCheckbox.text=Enable sending messages to inbox during ingest HashDbSearchPanel.hashTable.columnModel.title0=MD5 Hashes diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.form index f336266aed..52051b0957 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.form @@ -10,6 +10,7 @@ + From a1c6352559ee707f3dec6b474ae247c7af779a04 Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Fri, 25 Oct 2013 14:58:09 -0400 Subject: [PATCH 043/169] HashDbAddDatabaseDialog class renamed to HashDbImportDatabaseDialog --- .../autopsy/hashdatabase/Bundle.properties | 22 ++++++------- ...g.form => HashDbImportDatabaseDialog.form} | 22 ++++++------- ...g.java => HashDbImportDatabaseDialog.java} | 32 +++++++++---------- .../hashdatabase/HashDbManagementPanel.java | 2 +- 4 files changed, 39 insertions(+), 39 deletions(-) rename HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/{HashDbAddDatabaseDialog.form => HashDbImportDatabaseDialog.form} (86%) rename HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/{HashDbAddDatabaseDialog.java => HashDbImportDatabaseDialog.java} (90%) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties index 3c63f386fb..4841f13887 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties @@ -9,17 +9,6 @@ HashDbSimplePanel.notableLabel.text=Known Bad Database(s): HashDbSimplePanel.knownValLabel.text=- HashDbSimplePanel.notableValLabel.text=- HashDbSimplePanel.jLabel1.text=Enable known bad databases for ingest: -HashDbAddDatabaseDialog.cancelButton.text=Cancel -HashDbAddDatabaseDialog.okButton.text=OK -HashDbAddDatabaseDialog.nsrlRadioButton.text=NSRL -HashDbAddDatabaseDialog.knownBadRadioButton.text=Known Bad -HashDbAddDatabaseDialog.databasePathTextField.text= -HashDbAddDatabaseDialog.browseButton.text=Browse -HashDbAddDatabaseDialog.jLabel1.text=Display name of database: -HashDbAddDatabaseDialog.databaseNameTextField.text= -HashDbAddDatabaseDialog.jLabel2.text=Type of database: -HashDbAddDatabaseDialog.useForIngestCheckbox.text=Enable for ingest -HashDbAddDatabaseDialog.sendInboxMessagesCheckbox.text=Enable sending messages to inbox during ingest HashDbSearchPanel.hashTable.columnModel.title0=MD5 Hashes HashDbSearchPanel.hashTable.columnModel.title3=Title 4 HashDbSearchPanel.hashTable.columnModel.title2=Title 3 @@ -62,3 +51,14 @@ ModalNoButtons.CURRENTLYON_LABEL.text=Currently Indexing x of y ModalNoButtons.GO_GET_COFFEE_LABEL.text=Hash databases are currently being indexed, this may take some time. ModalNoButtons.CURRENTDB_LABEL.text=(CurrentDb) ModalNoButtons.CANCEL_BUTTON.text=Cancel +HashDbImportDatabaseDialog.sendInboxMessagesCheckbox.text=Enable sending messages to inbox during ingest +HashDbImportDatabaseDialog.useForIngestCheckbox.text=Enable for ingest +HashDbImportDatabaseDialog.jLabel1.text=Display name of database: +HashDbImportDatabaseDialog.databaseNameTextField.text= +HashDbImportDatabaseDialog.databasePathTextField.text= +HashDbImportDatabaseDialog.browseButton.text=Browse +HashDbImportDatabaseDialog.nsrlRadioButton.text=NSRL +HashDbImportDatabaseDialog.knownBadRadioButton.text=Known Bad +HashDbImportDatabaseDialog.jLabel2.text=Type of database: +HashDbImportDatabaseDialog.okButton.text=OK +HashDbImportDatabaseDialog.cancelButton.text=Cancel diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.form similarity index 86% rename from HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.form rename to HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.form index 52051b0957..e6473a9688 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.form @@ -111,7 +111,7 @@ - + @@ -121,7 +121,7 @@ - + @@ -131,14 +131,14 @@ - + - + @@ -151,7 +151,7 @@ - + @@ -165,7 +165,7 @@ - + @@ -175,21 +175,21 @@ - + - + - + @@ -197,7 +197,7 @@ - + @@ -208,7 +208,7 @@ - + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java similarity index 90% rename from HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.java rename to HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java index 56e5427355..71d0334eb1 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java @@ -37,16 +37,16 @@ import org.sleuthkit.datamodel.TskException; * * @author dfickling */ -final class HashDbAddDatabaseDialog extends javax.swing.JDialog { +final class HashDbImportDatabaseDialog extends javax.swing.JDialog { private JFileChooser fc = new JFileChooser(); private String databaseName; - private static final Logger logger = Logger.getLogger(HashDbAddDatabaseDialog.class.getName()); + private static final Logger logger = Logger.getLogger(HashDbImportDatabaseDialog.class.getName()); /** - * Creates new form HashDbAddDatabaseDialog + * Creates new form HashDbImportDatabaseDialog */ - HashDbAddDatabaseDialog() { - super(new javax.swing.JFrame(), "Add Hash Database", true); + HashDbImportDatabaseDialog() { + super(new javax.swing.JFrame(), "Import Hash Database", true); setResizable(false); initComponents(); customizeComponents(); @@ -100,23 +100,23 @@ final class HashDbAddDatabaseDialog extends javax.swing.JDialog { setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); - org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(HashDbAddDatabaseDialog.class, "HashDbAddDatabaseDialog.okButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.okButton.text")); // NOI18N okButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { okButtonActionPerformed(evt); } }); - org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(HashDbAddDatabaseDialog.class, "HashDbAddDatabaseDialog.cancelButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.cancelButton.text")); // NOI18N cancelButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { cancelButtonActionPerformed(evt); } }); - databasePathTextField.setText(org.openide.util.NbBundle.getMessage(HashDbAddDatabaseDialog.class, "HashDbAddDatabaseDialog.databasePathTextField.text")); // NOI18N + databasePathTextField.setText(org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.databasePathTextField.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(HashDbAddDatabaseDialog.class, "HashDbAddDatabaseDialog.browseButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.browseButton.text")); // NOI18N browseButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { browseButtonActionPerformed(evt); @@ -124,7 +124,7 @@ final class HashDbAddDatabaseDialog extends javax.swing.JDialog { }); buttonGroup1.add(nsrlRadioButton); - org.openide.awt.Mnemonics.setLocalizedText(nsrlRadioButton, org.openide.util.NbBundle.getMessage(HashDbAddDatabaseDialog.class, "HashDbAddDatabaseDialog.nsrlRadioButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(nsrlRadioButton, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.nsrlRadioButton.text")); // NOI18N nsrlRadioButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { nsrlRadioButtonActionPerformed(evt); @@ -133,21 +133,21 @@ final class HashDbAddDatabaseDialog extends javax.swing.JDialog { buttonGroup1.add(knownBadRadioButton); knownBadRadioButton.setSelected(true); - org.openide.awt.Mnemonics.setLocalizedText(knownBadRadioButton, org.openide.util.NbBundle.getMessage(HashDbAddDatabaseDialog.class, "HashDbAddDatabaseDialog.knownBadRadioButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(knownBadRadioButton, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.knownBadRadioButton.text")); // NOI18N knownBadRadioButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { knownBadRadioButtonActionPerformed(evt); } }); - org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(HashDbAddDatabaseDialog.class, "HashDbAddDatabaseDialog.jLabel1.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.jLabel1.text")); // NOI18N - databaseNameTextField.setText(org.openide.util.NbBundle.getMessage(HashDbAddDatabaseDialog.class, "HashDbAddDatabaseDialog.databaseNameTextField.text")); // NOI18N + databaseNameTextField.setText(org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.databaseNameTextField.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(HashDbAddDatabaseDialog.class, "HashDbAddDatabaseDialog.jLabel2.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.jLabel2.text")); // NOI18N useForIngestCheckbox.setSelected(true); - org.openide.awt.Mnemonics.setLocalizedText(useForIngestCheckbox, org.openide.util.NbBundle.getMessage(HashDbAddDatabaseDialog.class, "HashDbAddDatabaseDialog.useForIngestCheckbox.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(useForIngestCheckbox, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.useForIngestCheckbox.text")); // NOI18N useForIngestCheckbox.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { useForIngestCheckboxActionPerformed(evt); @@ -155,7 +155,7 @@ final class HashDbAddDatabaseDialog extends javax.swing.JDialog { }); sendInboxMessagesCheckbox.setSelected(true); - org.openide.awt.Mnemonics.setLocalizedText(sendInboxMessagesCheckbox, org.openide.util.NbBundle.getMessage(HashDbAddDatabaseDialog.class, "HashDbAddDatabaseDialog.sendInboxMessagesCheckbox.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(sendInboxMessagesCheckbox, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.sendInboxMessagesCheckbox.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java index d64b93ec92..f517867898 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java @@ -613,7 +613,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP private javax.swing.JCheckBox useForIngestCheckbox; // End of variables declaration//GEN-END:variables private void importHashSet(java.awt.event.ActionEvent evt) { - String name = new HashDbAddDatabaseDialog().display(); + String name = new HashDbImportDatabaseDialog().display(); if(name != null) { hashSetTableModel.selectRowByName(name); } From 2256e737a4ff6b84b615af134d35c2b82e625cc2 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 25 Oct 2013 15:12:31 -0400 Subject: [PATCH 044/169] Added stub implementation of new AddContentToHashDbAction class --- .../AddContentToHashDbAction.java | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100755 HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java new file mode 100755 index 0000000000..64dec2f494 --- /dev/null +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java @@ -0,0 +1,101 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 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.hashdatabase; + +import java.awt.event.ActionEvent; +import java.util.Collection; +import java.util.logging.Level; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.JOptionPane; +import org.openide.util.Utilities; +import org.openide.util.Lookup; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.ingest.IngestConfigurator; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Instances of this Action allow users to content to a hash database. + */ +public class AddContentToHashDbAction extends AbstractAction { + // This class is a singleton to support multi-selection of nodes, since + // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every + // node in the array returns a reference to the same action object from Node.getActions(boolean). + private static AddContentToHashDbAction instance; + private static String SINGLE_SELECTION_NAME = "Add file to hash database"; + private static String MULTIPLE_SELECTION_NAME = "Add file) to hash database"; + + public static synchronized AddContentToHashDbAction getInstance() { + if (null == instance) { + instance = new AddContentToHashDbAction(); + } + + instance.setEnabled(true); + instance.putValue(Action.NAME, SINGLE_SELECTION_NAME); + + // Disable the action if file ingest is in progress. + IngestConfigurator ingestConfigurator = Lookup.getDefault().lookup(IngestConfigurator.class); + if (null != ingestConfigurator && ingestConfigurator.isIngestRunning()) { + instance.setEnabled(false); + } + + // Set the name of the action based on the selected content and disable the action if there is + // selected content without an MD5 hash. + Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); + if (selectedFiles.size() > 1) { + instance.putValue(Action.NAME, MULTIPLE_SELECTION_NAME); + } + if (selectedFiles.isEmpty()) { + instance.setEnabled(false); + } + else { + for (AbstractFile file : selectedFiles) { + if (null == file.getMd5Hash()) { + instance.setEnabled(false); + break; + } + } + } + + return instance; + } + + private AddContentToHashDbAction() { + super(SINGLE_SELECTION_NAME); + } + + @Override + public void actionPerformed(ActionEvent event) { + Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); + for (AbstractFile file : selectedFiles) { + try { + // RJCTODO: Complete this method. + String md5Hash = file.getMd5Hash(); + if (null != md5Hash) { + throw new TskCoreException("RJCTODO"); + } + } + catch (TskCoreException ex) { + Logger.getLogger(AddContentToHashDbAction.class.getName()).log(Level.SEVERE, "Error tagging result", ex); + JOptionPane.showMessageDialog(null, "Unable to add " + file.getName() + "to hash database.", "Add to Hash Database Error", JOptionPane.ERROR_MESSAGE); + } + } + } +} From 6aec5f35d5393422f92959cece069dd10a20aa34 Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Fri, 25 Oct 2013 15:25:44 -0400 Subject: [PATCH 045/169] Add skeleton of new Create Hash Database GUI. --- .../autopsy/hashdatabase/Bundle.properties | 12 + .../HashDbCreateDatabaseDialog.form | 217 ++++++++++++ .../HashDbCreateDatabaseDialog.java | 322 ++++++++++++++++++ .../hashdatabase/HashDbManagementPanel.form | 27 +- .../hashdatabase/HashDbManagementPanel.java | 32 +- 5 files changed, 607 insertions(+), 3 deletions(-) create mode 100644 HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.form create mode 100644 HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties index 4841f13887..e02678bfe5 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties @@ -62,3 +62,15 @@ HashDbImportDatabaseDialog.knownBadRadioButton.text=Known Bad HashDbImportDatabaseDialog.jLabel2.text=Type of database: HashDbImportDatabaseDialog.okButton.text=OK HashDbImportDatabaseDialog.cancelButton.text=Cancel +HashDbCreateDatabaseDialog.jLabel2.text=Type of database: +HashDbCreateDatabaseDialog.knownBadRadioButton.text=Known Bad +HashDbCreateDatabaseDialog.nsrlRadioButton.text=NSRL +HashDbCreateDatabaseDialog.browseButton.text=Browse +HashDbCreateDatabaseDialog.databasePathTextField.text= +HashDbCreateDatabaseDialog.cancelButton.text=Cancel +HashDbCreateDatabaseDialog.sendInboxMessagesCheckbox.text=Enable sending messages to inbox during ingest +HashDbCreateDatabaseDialog.okButton.text=OK +HashDbCreateDatabaseDialog.useForIngestCheckbox.text=Enable for ingest +HashDbCreateDatabaseDialog.jLabel1.text=Display name of database: +HashDbCreateDatabaseDialog.databaseNameTextField.text= +HashDbManagementPanel.importButton1.text=Create Database diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.form new file mode 100644 index 0000000000..1342083256 --- /dev/null +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.form @@ -0,0 +1,217 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java new file mode 100644 index 0000000000..780f727412 --- /dev/null +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java @@ -0,0 +1,322 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 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.hashdatabase; + +import java.awt.Dimension; +import java.awt.Toolkit; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.logging.Level; +import org.sleuthkit.autopsy.coreutils.Logger; +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; +import javax.swing.filechooser.FileNameExtensionFilter; +import org.sleuthkit.autopsy.hashdatabase.HashDb.DBType; +import org.sleuthkit.datamodel.SleuthkitJNI; +import org.sleuthkit.datamodel.TskException; + +/** + * Creation is a different GUI class than importing + */ +final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { + + private JFileChooser fc = new JFileChooser(); + private String databaseName; + private static final Logger logger = Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()); + /** + * Creates new form HashDbCreateDatabaseDialog + */ + HashDbCreateDatabaseDialog() { + super(new javax.swing.JFrame(), "Create Hash Database", true); + setResizable(false); + initComponents(); + customizeComponents(); + } + + void customizeComponents() { + fc.setDragEnabled(false); + fc.setFileSelectionMode(JFileChooser.FILES_ONLY); + String[] EXTENSION = new String[] { "txt", "kdb", "idx", "hash", "Hash", "hsh"}; + FileNameExtensionFilter filter = new FileNameExtensionFilter( + "Hash Database File", EXTENSION); + fc.setFileFilter(filter); + fc.setMultiSelectionEnabled(false); + } + + String display() { + Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); + + // set the popUp window / JFrame + int w = this.getSize().width; + int h = this.getSize().height; + + // set the location of the popUp Window on the center of the screen + setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2); + + this.setVisible(true); + return databaseName; + } + + /** + * This method is called from within the constructor to initialize the form. + * WARNING: Do NOT modify this code. The content of this method is always + * regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + buttonGroup1 = new javax.swing.ButtonGroup(); + okButton = new javax.swing.JButton(); + cancelButton = new javax.swing.JButton(); + databasePathTextField = new javax.swing.JTextField(); + browseButton = new javax.swing.JButton(); + nsrlRadioButton = new javax.swing.JRadioButton(); + knownBadRadioButton = new javax.swing.JRadioButton(); + jLabel1 = new javax.swing.JLabel(); + databaseNameTextField = new javax.swing.JTextField(); + jLabel2 = new javax.swing.JLabel(); + useForIngestCheckbox = new javax.swing.JCheckBox(); + sendInboxMessagesCheckbox = new javax.swing.JCheckBox(); + + setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); + + org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.okButton.text")); // NOI18N + okButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + okButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.cancelButton.text")); // NOI18N + cancelButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + cancelButtonActionPerformed(evt); + } + }); + + databasePathTextField.setText(org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.databasePathTextField.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.browseButton.text")); // NOI18N + browseButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + browseButtonActionPerformed(evt); + } + }); + + buttonGroup1.add(nsrlRadioButton); + org.openide.awt.Mnemonics.setLocalizedText(nsrlRadioButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.nsrlRadioButton.text")); // NOI18N + nsrlRadioButton.setEnabled(false); + nsrlRadioButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + nsrlRadioButtonActionPerformed(evt); + } + }); + + buttonGroup1.add(knownBadRadioButton); + knownBadRadioButton.setSelected(true); + org.openide.awt.Mnemonics.setLocalizedText(knownBadRadioButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.knownBadRadioButton.text")); // NOI18N + knownBadRadioButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + knownBadRadioButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.jLabel1.text")); // NOI18N + + databaseNameTextField.setText(org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.databaseNameTextField.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.jLabel2.text")); // NOI18N + + useForIngestCheckbox.setSelected(true); + org.openide.awt.Mnemonics.setLocalizedText(useForIngestCheckbox, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.useForIngestCheckbox.text")); // NOI18N + useForIngestCheckbox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + useForIngestCheckboxActionPerformed(evt); + } + }); + + sendInboxMessagesCheckbox.setSelected(true); + org.openide.awt.Mnemonics.setLocalizedText(sendInboxMessagesCheckbox, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.sendInboxMessagesCheckbox.text")); // NOI18N + + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); + getContentPane().setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addComponent(okButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cancelButton)) + .addGroup(layout.createSequentialGroup() + .addComponent(databasePathTextField) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(browseButton)) + .addGroup(layout.createSequentialGroup() + .addComponent(jLabel1) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(databaseNameTextField)) + .addGroup(layout.createSequentialGroup() + .addComponent(jLabel2) + .addGap(0, 0, Short.MAX_VALUE))) + .addContainerGap()) + .addGroup(layout.createSequentialGroup() + .addGap(10, 10, 10) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(knownBadRadioButton) + .addComponent(nsrlRadioButton)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(useForIngestCheckbox) + .addComponent(sendInboxMessagesCheckbox)) + .addGap(0, 135, Short.MAX_VALUE)))) + ); + layout.setVerticalGroup( + layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(databasePathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(browseButton)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel1) + .addComponent(databaseNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jLabel2) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(nsrlRadioButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(knownBadRadioButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(useForIngestCheckbox) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(sendInboxMessagesCheckbox) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(okButton) + .addComponent(cancelButton)) + .addContainerGap()) + ); + + pack(); + }// //GEN-END:initComponents + + private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed + String oldText = databasePathTextField.getText(); + // set the current directory of the FileChooser if the databasePath Field is valid + File currentDir = new File(oldText); + if (currentDir.exists()) { + fc.setCurrentDirectory(currentDir); + } + int retval = fc.showSaveDialog(this); + if (retval == JFileChooser.APPROVE_OPTION) { + File f = fc.getSelectedFile(); + try { + String filePath = f.getCanonicalPath(); + if (HashDb.isIndexPath(filePath)) { + filePath = HashDb.toDatabasePath(filePath); + } + String derivedName = f.getName(); + databasePathTextField.setText(filePath); + databaseNameTextField.setText(derivedName); + if (derivedName.toLowerCase().contains("nsrl")) { + nsrlRadioButton.setSelected(true); + nsrlRadioButtonActionPerformed(null); + } + } catch (IOException ex) { + logger.log(Level.WARNING, "Couldn't get selected file path.", ex); + } + } + }//GEN-LAST:event_browseButtonActionPerformed + + private void nsrlRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nsrlRadioButtonActionPerformed + sendInboxMessagesCheckbox.setSelected(false); + sendInboxMessagesCheckbox.setEnabled(false); + }//GEN-LAST:event_nsrlRadioButtonActionPerformed + + private void knownBadRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_knownBadRadioButtonActionPerformed + sendInboxMessagesCheckbox.setSelected(true); + sendInboxMessagesCheckbox.setEnabled(true); + }//GEN-LAST:event_knownBadRadioButtonActionPerformed + + private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed + this.dispose(); + }//GEN-LAST:event_cancelButtonActionPerformed + + private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed + if(databasePathTextField.getText().isEmpty()) { + JOptionPane.showMessageDialog(this, "Database path cannot be empty"); + return; + } + if(databaseNameTextField.getText().isEmpty()) { + JOptionPane.showMessageDialog(this, "Database name cannot be empty"); + return; + } + + DBType type; + if(nsrlRadioButton.isSelected()) { + type = DBType.NSRL; + } else { + type = DBType.KNOWN_BAD; + } + + /// @todo Call the HashDb create factory method here +// HashDb db = HashDb.create(databaseNameTextField.getText(), +// Arrays.asList(new String[] {databasePathTextField.getText()}), +// useForIngestCheckbox.isSelected(), +// sendInboxMessagesCheckbox.isSelected(), +// type); + +// if(type == DBType.KNOWN_BAD) { +// HashDbXML.getCurrent().addKnownBadSet(db); +// } else if(type == DBType.NSRL) { +// HashDbXML.getCurrent().setNSRLSet(db); +// } + databaseName = databaseNameTextField.getText(); + this.dispose(); + }//GEN-LAST:event_okButtonActionPerformed + + private void useForIngestCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useForIngestCheckboxActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_useForIngestCheckboxActionPerformed + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton browseButton; + private javax.swing.ButtonGroup buttonGroup1; + private javax.swing.JButton cancelButton; + private javax.swing.JTextField databaseNameTextField; + private javax.swing.JTextField databasePathTextField; + private javax.swing.JLabel jLabel1; + private javax.swing.JLabel jLabel2; + private javax.swing.JRadioButton knownBadRadioButton; + private javax.swing.JRadioButton nsrlRadioButton; + private javax.swing.JButton okButton; + private javax.swing.JCheckBox sendInboxMessagesCheckbox; + private javax.swing.JCheckBox useForIngestCheckbox; + // End of variables declaration//GEN-END:variables +} diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form index ab3578fe41..a59153fa65 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form @@ -115,6 +115,7 @@ + @@ -170,7 +171,7 @@ - + @@ -178,6 +179,8 @@ + + @@ -379,5 +382,27 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java index f517867898..442c220df5 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java @@ -179,6 +179,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP optionsLabel = new javax.swing.JLabel(); informationSeparator = new javax.swing.JSeparator(); optionsSeparator = new javax.swing.JSeparator(); + importButton1 = new javax.swing.JButton(); org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.jLabel2.text")); // NOI18N @@ -278,6 +279,17 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP org.openide.awt.Mnemonics.setLocalizedText(optionsLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.optionsLabel.text")); // NOI18N + importButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/import16.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(importButton1, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.importButton1.text")); // NOI18N + importButton1.setMaximumSize(new java.awt.Dimension(140, 25)); + importButton1.setMinimumSize(new java.awt.Dimension(140, 25)); + importButton1.setPreferredSize(new java.awt.Dimension(140, 25)); + importButton1.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + importButton1ActionPerformed(evt); + } + }); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -325,7 +337,8 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP .addComponent(hashDbNameLabel))) .addComponent(useForIngestCheckbox) .addComponent(showInboxMessagesCheckBox) - .addComponent(indexButton, javax.swing.GroupLayout.PREFERRED_SIZE, 75, javax.swing.GroupLayout.PREFERRED_SIZE)))))) + .addComponent(indexButton, javax.swing.GroupLayout.PREFERRED_SIZE, 75, javax.swing.GroupLayout.PREFERRED_SIZE))))) + .addComponent(importButton1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap(40, Short.MAX_VALUE)) ); layout.setVerticalGroup( @@ -370,11 +383,13 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP .addGap(18, 18, 18) .addComponent(ingestWarningLabel) .addGap(0, 0, Short.MAX_VALUE)) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 422, Short.MAX_VALUE)) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 391, Short.MAX_VALUE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(importButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(deleteButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(importButton1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addContainerGap()) ); }// //GEN-END:initComponents @@ -489,6 +504,10 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP importHashSet(evt); }//GEN-LAST:event_importButtonActionPerformed + private void importButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importButton1ActionPerformed + createHashSet(evt); + }//GEN-LAST:event_importButton1ActionPerformed + @Override public void load() { hashSetTable.clearSelection(); // Deselect all rows @@ -594,6 +613,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP private javax.swing.JLabel hashDbTypeLabel; private javax.swing.JTable hashSetTable; private javax.swing.JButton importButton; + private javax.swing.JButton importButton1; private javax.swing.JButton indexButton; private javax.swing.JLabel indexLabel; private javax.swing.JLabel informationLabel; @@ -620,6 +640,14 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP resync(); } + private void createHashSet(java.awt.event.ActionEvent evt) { + String name = new HashDbCreateDatabaseDialog().display(); + if(name != null) { + hashSetTableModel.selectRowByName(name); + } + resync(); + } + /** * The visual display of hash databases loaded. */ From 66babd6068b208f91933e5e756c1a4a4a643aa08 Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Fri, 25 Oct 2013 15:53:53 -0400 Subject: [PATCH 046/169] Prevent overwriting existing files from create database dialog. --- .../HashDbCreateDatabaseDialog.java | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java index 780f727412..a60a1232fd 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java @@ -38,7 +38,8 @@ import org.sleuthkit.datamodel.TskException; */ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { - private JFileChooser fc = new JFileChooser(); + private JFileChooser fc; + private String databaseName; private static final Logger logger = Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()); /** @@ -47,6 +48,22 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { HashDbCreateDatabaseDialog() { super(new javax.swing.JFrame(), "Create Hash Database", true); setResizable(false); + + fc = new JFileChooser() { + @Override + public void approveSelection() { + File ftemp = getSelectedFile(); + if (ftemp.exists()) { + int r = JOptionPane.showConfirmDialog(this, "A file with this name already exists. Please enter a new filename.", "Existing File", JOptionPane.OK_CANCEL_OPTION); + if (r == JOptionPane.CANCEL_OPTION) { + cancelSelection(); + } + return; + } + super.approveSelection(); + } + }; + initComponents(); customizeComponents(); } @@ -236,6 +253,9 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { int retval = fc.showSaveDialog(this); if (retval == JFileChooser.APPROVE_OPTION) { File f = fc.getSelectedFile(); + + ///@todo check if file already exists + try { String filePath = f.getCanonicalPath(); if (HashDb.isIndexPath(filePath)) { From f2591c721244173307fa305464ccee84ad6a27d5 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 25 Oct 2013 16:08:16 -0400 Subject: [PATCH 047/169] Wired up new AddContentToHashDbAction stub --- .../autopsy/datamodel/DirectoryNode.java | 4 +++- .../org/sleuthkit/autopsy/datamodel/FileNode.java | 4 +++- .../autopsy/datamodel/LayoutFileNode.java | 6 ++++-- .../autopsy/datamodel/LocalFileNode.java | 4 +++- .../autopsy/datamodel/VirtualDirectoryNode.java | 4 +++- .../directorytree}/AddContentToHashDbAction.java | 4 ++-- .../directorytree/DataResultFilterNode.java | 7 ++++++- .../directorytree/ExplorerNodeActionVisitor.java | 15 ++++++++++----- .../keywordsearch/KeywordSearchFilterNode.java | 2 ++ 9 files changed, 36 insertions(+), 14 deletions(-) rename {HashDatabase/src/org/sleuthkit/autopsy/hashdatabase => Core/src/org/sleuthkit/autopsy/directorytree}/AddContentToHashDbAction.java (95%) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java index 3c4d33c253..a2828140ab 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011 - 2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; import java.util.List; import javax.swing.Action; +import org.sleuthkit.autopsy.directorytree.AddContentToHashDbAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; @@ -77,6 +78,7 @@ public class DirectoryNode extends AbstractFsContentNode { actions.add(ExtractAction.getInstance()); actions.add(null); // creates a menu separator actions.add(TagAbstractFileAction.getInstance()); + actions.add(AddContentToHashDbAction.getInstance()); return actions.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java index 9ca87fd8a7..614b34daff 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011 - 2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; import java.util.List; import javax.swing.Action; +import org.sleuthkit.autopsy.directorytree.AddContentToHashDbAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; @@ -85,6 +86,7 @@ public class FileNode extends AbstractFsContentNode { actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this)); actionsList.add(null); // creates a menu separator actionsList.add(TagAbstractFileAction.getInstance()); + actionsList.add(AddContentToHashDbAction.getInstance()); return actionsList.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java index 9224131ad6..d7384b05d8 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011 - 2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,6 +24,7 @@ import java.util.List; import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; +import org.sleuthkit.autopsy.directorytree.AddContentToHashDbAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; @@ -102,13 +103,14 @@ public class LayoutFileNode extends AbstractAbstractFileNode { @Override public Action[] getActions(boolean context) { - List actionsList = new ArrayList(); + List actionsList = new ArrayList<>(); actionsList.add(new NewWindowViewAction("View in New Window", this)); actionsList.add(new ExternalViewerAction("Open in External Viewer", this)); actionsList.add(null); // creates a menu separator actionsList.add(ExtractAction.getInstance()); actionsList.add(null); // creates a menu separator actionsList.add(TagAbstractFileAction.getInstance()); + actionsList.add(AddContentToHashDbAction.getInstance()); return actionsList.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java index 78711736b9..be3a93f602 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java @@ -26,6 +26,7 @@ import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode.TYPE; +import org.sleuthkit.autopsy.directorytree.AddContentToHashDbAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; @@ -92,7 +93,8 @@ public class LocalFileNode extends AbstractAbstractFileNode { actionsList.add(ExtractAction.getInstance()); actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this)); actionsList.add(null); // creates a menu separator - actionsList.add(TagAbstractFileAction.getInstance()); + actionsList.add(TagAbstractFileAction.getInstance()); + actionsList.add(AddContentToHashDbAction.getInstance()); return actionsList.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java index 756a376d11..c0b9a6a841 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011 - 2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,6 +25,7 @@ import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.directorytree.AddContentToHashDbAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; @@ -82,6 +83,7 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode visit(final Directory d) { - List actions = new ArrayList(); + List actions = new ArrayList<>(); actions.add(TagAbstractFileAction.getInstance()); + actions.add(AddContentToHashDbAction.getInstance()); return actions; } @Override public List visit(final VirtualDirectory d) { - List actions = new ArrayList(); + List actions = new ArrayList<>(); actions.add(ExtractAction.getInstance()); actions.add(TagAbstractFileAction.getInstance()); + actions.add(AddContentToHashDbAction.getInstance()); return actions; } @Override public List visit(final DerivedFile d) { - List actions = new ArrayList(); + List actions = new ArrayList<>(); actions.add(ExtractAction.getInstance()); actions.add(TagAbstractFileAction.getInstance()); + actions.add(AddContentToHashDbAction.getInstance()); return actions; } @Override public List visit(final LocalFile d) { - List actions = new ArrayList(); + List actions = new ArrayList<>(); actions.add(ExtractAction.getInstance()); actions.add(TagAbstractFileAction.getInstance()); + actions.add(AddContentToHashDbAction.getInstance()); return actions; } @Override public List visit(final org.sleuthkit.datamodel.File d) { - List actions = new ArrayList(); + List actions = new ArrayList<>(); actions.add(ExtractAction.getInstance()); actions.add(TagAbstractFileAction.getInstance()); + actions.add(AddContentToHashDbAction.getInstance()); return actions; } diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java index 968631e27a..006839fcc5 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java @@ -33,6 +33,7 @@ import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; +import org.sleuthkit.autopsy.directorytree.AddContentToHashDbAction; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentVisitor; import org.sleuthkit.datamodel.DerivedFile; @@ -152,6 +153,7 @@ class KeywordSearchFilterNode extends FilterNode { actions.add(new HashSearchAction("Search for files with the same MD5 hash", getOriginal())); actions.add(null); // creates a menu separator actions.add(TagAbstractFileAction.getInstance()); + actions.add(AddContentToHashDbAction.getInstance()); return actions; } From bd083e7b8d3338ebf8330b96929ea0ca2d23648d Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Fri, 25 Oct 2013 16:19:41 -0400 Subject: [PATCH 048/169] Update the create button. The new icon can be improved later. --- .../hashdatabase/HashDbCreateDatabaseDialog.java | 4 +--- .../hashdatabase/HashDbManagementPanel.form | 7 +++++-- .../hashdatabase/HashDbManagementPanel.java | 5 +++-- .../hashdatabase/btn_icon_create_new_16.png | Bin 0 -> 744 bytes 4 files changed, 9 insertions(+), 7 deletions(-) create mode 100644 HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/btn_icon_create_new_16.png diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java index a60a1232fd..90b852310d 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java @@ -252,9 +252,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { } int retval = fc.showSaveDialog(this); if (retval == JFileChooser.APPROVE_OPTION) { - File f = fc.getSelectedFile(); - - ///@todo check if file already exists + File f = fc.getSelectedFile(); try { String filePath = f.getCanonicalPath(); diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form index a59153fa65..6a5753371f 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form @@ -115,7 +115,7 @@ - + @@ -385,11 +385,14 @@ - + + + + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java index 442c220df5..76ad80bbd9 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java @@ -279,8 +279,9 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP org.openide.awt.Mnemonics.setLocalizedText(optionsLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.optionsLabel.text")); // NOI18N - importButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/import16.png"))); // NOI18N + importButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/btn_icon_create_new_16.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(importButton1, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.importButton1.text")); // NOI18N + importButton1.setMargin(new java.awt.Insets(2, 11, 2, 14)); importButton1.setMaximumSize(new java.awt.Dimension(140, 25)); importButton1.setMinimumSize(new java.awt.Dimension(140, 25)); importButton1.setPreferredSize(new java.awt.Dimension(140, 25)); @@ -338,7 +339,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP .addComponent(useForIngestCheckbox) .addComponent(showInboxMessagesCheckBox) .addComponent(indexButton, javax.swing.GroupLayout.PREFERRED_SIZE, 75, javax.swing.GroupLayout.PREFERRED_SIZE))))) - .addComponent(importButton1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(importButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap(40, Short.MAX_VALUE)) ); layout.setVerticalGroup( diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/btn_icon_create_new_16.png b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/btn_icon_create_new_16.png new file mode 100644 index 0000000000000000000000000000000000000000..86c1018f3912e1e39fdb52a275fc979c55224da4 GIT binary patch literal 744 zcmVP)ikZ z^;)fllQn6r|0mAgLZLuDpGQOx5r&6{uK`pl74+%9I8Xc*p2JE)YGZ_yT+WgHbmyHd z6N?B+Db^bgQ95OyP$V`XoldAf2sjP;tNtg&;TYwd;M+q62FDmJUEsmv?{?jzqbdEq z>wnIg7h8`|r9(PtgX3e0+T3D}7p&B|xti5m}dxye2deeh{$s zqCuSWh1fA$74Und(%689INYaEazxY<%zsvaDfY?Tu(GB9BC5$8X zc8=Dz*Z-YYD=RB`;HpyUYo*jEP=1#HrPL;Br@1`cie60wX^TNU&c(qiOC!0@zW?~6 a>5VtgY;za!XkOX?0000 Date: Fri, 25 Oct 2013 17:15:59 -0400 Subject: [PATCH 049/169] Added new API to HashDb class (start of SleuthkitKNI hash db facade) --- .../autopsy/hashdatabase/HashDb.java | 47 +++++++++++++++++-- .../hashdatabase/HashDbAddDatabaseDialog.java | 21 +++++---- .../autopsy/hashdatabase/HashDbXML.java | 30 +++++++----- 3 files changed, 73 insertions(+), 25 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index 6f623157a6..c1b68d8ade 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011 - 2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,14 +21,17 @@ package org.sleuthkit.autopsy.hashdatabase; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.File; +import java.util.Collections; import java.util.List; import java.util.logging.Level; import javax.swing.SwingWorker; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; -import org.openide.util.Cancellable; import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SleuthkitJNI; +import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskException; /** @@ -66,8 +69,31 @@ public class HashDb implements Comparable { private boolean showInboxMessages; private boolean indexing; private DBType type; + private int handle; - public HashDb(String name, List databasePaths, boolean useForIngest, boolean showInboxMessages, DBType type) { + static public HashDb openHashDatabase(String name, String databasePath, boolean useForIngest, boolean showInboxMessages, DBType type) throws TskCoreException { + HashDb database = new HashDb(SleuthkitJNI.openHashDatabase(databasePath), name, Collections.singletonList(databasePath), useForIngest, showInboxMessages, type); + addToXMLFile(database); + return database; + } + + static public HashDb createHashDatabase(String name, String databasePath, boolean useForIngest, boolean showInboxMessages, DBType type) throws TskCoreException { + HashDb database = new HashDb(SleuthkitJNI.newHashDatabase(databasePath), name, Collections.singletonList(databasePath), useForIngest, showInboxMessages, type); + addToXMLFile(database); + return database; + } + + static private void addToXMLFile(HashDb database) { + if (database.getDbType() == HashDb.DBType.NSRL) { + HashDbXML.getCurrent().setNSRLSet(database); + } + else { + HashDbXML.getCurrent().addKnownBadSet(database); + } + } + + private HashDb(int handle, String name, List databasePaths, boolean useForIngest, boolean showInboxMessages, DBType type) { + this.handle = handle; this.name = name; this.databasePaths = databasePaths; this.useForIngest = useForIngest; @@ -76,6 +102,21 @@ public class HashDb implements Comparable { this.indexing = false; } + public boolean isUpdateable() { + // RJCTODO: Complete this + return true; + } + + public void addContent(Content content) throws TskCoreException { + // @@@ This only works for AbstractFiles at present. + if (content instanceof AbstractFile) { + AbstractFile file = (AbstractFile)content; + if (null != file.getMd5Hash()) { + SleuthkitJNI.addToHashDatabase(file.getName(), file.getMd5Hash(), "", "", handle); + } + } + } + void addPropertyChangeListener(PropertyChangeListener pcl) { pcs.addPropertyChangeListener(pcl); } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.java index 56e5427355..1b34ad620f 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbAddDatabaseDialog.java @@ -303,16 +303,17 @@ final class HashDbAddDatabaseDialog extends javax.swing.JDialog { } else { type = DBType.KNOWN_BAD; } - HashDb db = new HashDb(databaseNameTextField.getText(), - Arrays.asList(new String[] {databasePathTextField.getText()}), - useForIngestCheckbox.isSelected(), - sendInboxMessagesCheckbox.isSelected(), - type); - if(type == DBType.KNOWN_BAD) { - HashDbXML.getCurrent().addKnownBadSet(db); - } else if(type == DBType.NSRL) { - HashDbXML.getCurrent().setNSRLSet(db); - } + // RJCTODO: Sam is replacing this class. +// HashDb db = new HashDb(databaseNameTextField.getText(), +// Arrays.asList(new String[] {databasePathTextField.getText()}), +// useForIngestCheckbox.isSelected(), +// sendInboxMessagesCheckbox.isSelected(), +// type); +// if(type == DBType.KNOWN_BAD) { +// HashDbXML.getCurrent().addKnownBadSet(db); +// } else if(type == DBType.NSRL) { +// HashDbXML.getCurrent().setNSRLSet(db); +// } databaseName = databaseNameTextField.getText(); this.dispose(); }//GEN-LAST:event_okButtonActionPerformed diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java index 9ddc638b9e..0ac5f8b31c 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011 - 2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,6 +32,7 @@ import javax.xml.parsers.ParserConfigurationException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.XMLUtil; +import org.sleuthkit.autopsy.directorytree.AddContentToHashDbAction; import org.sleuthkit.autopsy.hashdatabase.HashDb.DBType; import org.sleuthkit.datamodel.SleuthkitJNI; import org.sleuthkit.datamodel.TskCoreException; @@ -63,7 +64,7 @@ public class HashDbXML { private boolean calculate; private HashDbXML(String xmlFile) { - knownBadSets = new ArrayList(); + knownBadSets = new ArrayList<>(); this.xmlFile = xmlFile; } @@ -82,7 +83,7 @@ public class HashDbXML { * Get the hash sets */ public List getAllSets() { - List ret = new ArrayList(); + List ret = new ArrayList<>(); if(nsrlSet != null) { ret.add(nsrlSet); } @@ -285,9 +286,10 @@ public class HashDbXML { final String showInboxMessages = setEl.getAttribute(SET_SHOW_INBOX_MESSAGES); Boolean useForIngestBool = Boolean.parseBoolean(useForIngest); Boolean showInboxMessagesBool = Boolean.parseBoolean(showInboxMessages); - List paths = new ArrayList(); + List paths = new ArrayList<>(); // Parse all paths + // @@@ TODO: There is no need for more than one path. NodeList pathsNList = setEl.getElementsByTagName(PATH_EL); final int numPaths = pathsNList.getLength(); for (int j = 0; j < numPaths; ++j) { @@ -330,16 +332,20 @@ public class HashDbXML { } if(paths.isEmpty()) { - logger.log(Level.WARNING, "No paths were set for hash_set at index {0}. Removing the database.", i); - } else { // No paths for this entry, the user most likely declined to search for them + logger.log(Level.WARNING, "No paths were set for hash_set at index {0}. Removing the database.", i); + } + else { DBType typeDBType = DBType.valueOf(type); - HashDb set = new HashDb(name, paths, useForIngestBool, showInboxMessagesBool, typeDBType); - - if(typeDBType == DBType.KNOWN_BAD) { - knownBadSets.add(set); - } else if(typeDBType == DBType.NSRL) { - this.nsrlSet = set; + try { + // @@@ Note that this method calls back to addKnownBadSet() or setNSRLSet(). + // In the future, this class will become an inner class of HashDb and will only handle reading and + // writing the XML file. + HashDb.openHashDatabase(name, paths.get(0), useForIngestBool, showInboxMessagesBool, typeDBType); + } + catch (TskCoreException ex) { + Logger.getLogger(HashDbXML.class.getName()).log(Level.SEVERE, "Error opening hash database", ex); + JOptionPane.showMessageDialog(null, "Unable to open " + paths.get(0) + " hash database.", "Open Hash Database Error", JOptionPane.ERROR_MESSAGE); } } } From cd8b25745876dba5d12ac05ad4590f18fc7faa2e Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 25 Oct 2013 17:33:06 -0400 Subject: [PATCH 050/169] Extended the HasdDb API --- .../org/sleuthkit/autopsy/hashdatabase/HashDb.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index c1b68d8ade..e9f87f158b 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.hashdatabase; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.File; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.logging.Level; @@ -92,6 +93,17 @@ public class HashDb implements Comparable { } } + static public List getUpdateableHashDatabases() { + ArrayList updateableDbs = new ArrayList<>(); + List candidateDbs = HashDbXML.getCurrent().getKnownBadSets(); + for (HashDb db : candidateDbs) { + if (db.isUpdateable()) { + updateableDbs.add(db); + } + } + return updateableDbs; + } + private HashDb(int handle, String name, List databasePaths, boolean useForIngest, boolean showInboxMessages, DBType type) { this.handle = handle; this.name = name; From 136f93d38c0e877a288664c68fecdf517ec5baa5 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 25 Oct 2013 17:53:45 -0400 Subject: [PATCH 051/169] Changed HashDb method name and updated comments --- .../src/org/sleuthkit/autopsy/hashdatabase/HashDb.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index e9f87f158b..e86dcc2492 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -65,7 +65,7 @@ public class HashDb implements Comparable { private static final String INDEX_SUFFIX_OLD = "-md5.idx"; private String name; - private List databasePaths; // TODO: Length limited to one for now... + private List databasePaths; // TODO: Only need a single path, may only need to store handle private boolean useForIngest; private boolean showInboxMessages; private boolean indexing; @@ -119,7 +119,7 @@ public class HashDb implements Comparable { return true; } - public void addContent(Content content) throws TskCoreException { + public void addContentHash(Content content) throws TskCoreException { // @@@ This only works for AbstractFiles at present. if (content instanceof AbstractFile) { AbstractFile file = (AbstractFile)content; @@ -203,7 +203,7 @@ public class HashDb implements Comparable { * @return a File initialized with the database path */ File databaseFile() { - return new File(databasePaths.get(0)); // TODO: support multiple paths + return new File(databasePaths.get(0)); // TODO: don't support multiple paths } /** @@ -212,7 +212,7 @@ public class HashDb implements Comparable { * path */ File indexFile() { - return new File(toIndexPath(databasePaths.get(0))); // TODO: support multiple paths + return new File(toIndexPath(databasePaths.get(0))); // TODO: don't support multiple paths } /** From 6cb5b47af495a2834d234f39f430b5008564cf5d Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Fri, 25 Oct 2013 18:01:18 -0400 Subject: [PATCH 052/169] Update create and import dialogs for the new HashDB interface. --- .../HashDbCreateDatabaseDialog.java | 21 ++++++++----------- .../HashDbImportDatabaseDialog.java | 21 +++++++++---------- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java index 90b852310d..f17eabd0bd 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java @@ -302,19 +302,16 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { } else { type = DBType.KNOWN_BAD; } + + try + { + HashDb db = HashDb.createHashDatabase(databaseNameTextField.getText(), databasePathTextField.getText(), useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); + } catch (TskException ex) { + logger.log(Level.WARNING, "Database creation error: ", ex); + JOptionPane.showMessageDialog(this, "Database file cannot be created.\n"); + return; + } - /// @todo Call the HashDb create factory method here -// HashDb db = HashDb.create(databaseNameTextField.getText(), -// Arrays.asList(new String[] {databasePathTextField.getText()}), -// useForIngestCheckbox.isSelected(), -// sendInboxMessagesCheckbox.isSelected(), -// type); - -// if(type == DBType.KNOWN_BAD) { -// HashDbXML.getCurrent().addKnownBadSet(db); -// } else if(type == DBType.NSRL) { -// HashDbXML.getCurrent().setNSRLSet(db); -// } databaseName = databaseNameTextField.getText(); this.dispose(); }//GEN-LAST:event_okButtonActionPerformed diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java index d62c764b9c..71d769f8df 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java @@ -303,17 +303,16 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { } else { type = DBType.KNOWN_BAD; } - // RJCTODO: Sam is replacing this class. -// HashDb db = new HashDb(databaseNameTextField.getText(), -// Arrays.asList(new String[] {databasePathTextField.getText()}), -// useForIngestCheckbox.isSelected(), -// sendInboxMessagesCheckbox.isSelected(), -// type); -// if(type == DBType.KNOWN_BAD) { -// HashDbXML.getCurrent().addKnownBadSet(db); -// } else if(type == DBType.NSRL) { -// HashDbXML.getCurrent().setNSRLSet(db); -// } + + try + { + HashDb db = HashDb.openHashDatabase(databaseNameTextField.getText(), databasePathTextField.getText(), useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); + } catch (TskException ex) { + logger.log(Level.WARNING, "Invalid database: ", ex); + JOptionPane.showMessageDialog(this, "Database file you chose cannot be opened.\n" + "If it was just an index, please try to recreate it from the database"); + return; + } + databaseName = databaseNameTextField.getText(); this.dispose(); }//GEN-LAST:event_okButtonActionPerformed From de7eb6b519ee7de788a8e7c5fbd9ecd3e7eee5a0 Mon Sep 17 00:00:00 2001 From: raman-bt Date: Mon, 28 Oct 2013 11:03:14 -0400 Subject: [PATCH 053/169] Straightened out the MissingImageDialog class w.r.t. DataSourceProcessor interface. MissingImageDialog allows the user to directly pick an image/local-disk if its is found to be missing. --- .../autopsy/casemodule/Bundle.properties | 3 +- .../sleuthkit/autopsy/casemodule/Case.java | 4 +- .../casemodule/MissingImageDialog.form | 64 +++--- .../casemodule/MissingImageDialog.java | 203 ++++++++---------- 4 files changed, 114 insertions(+), 160 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index f7b76e175a..53aba1d053 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -115,7 +115,6 @@ ImageFilePanel.browseButton.text=Browse ImageFilePanel.pathTextField.text= LocalDiskPanel.diskLabel.text=Select a local disk: MissingImageDialog.selectButton.text=Select Image -MissingImageDialog.typeTabel.text=Select input type to add: MissingImageDialog.titleLabel.text=Search for missing image MissingImageDialog.cancelButton.text=Cancel LocalDiskPanel.errorLabel.text=Error Label @@ -152,3 +151,5 @@ LocalDiskPanel.timeZoneLabel.text=Please select the input timezone: LocalDiskPanel.noFatOrphansCheckbox.toolTipText= LocalDiskPanel.noFatOrphansCheckbox.text=Ignore orphan files in FAT file systems LocalDiskPanel.descLabel.text=(faster results, although some data will not be searched) +MissingImageDialog.browseButton.text=Browse +MissingImageDialog.pathNameTextField.text= diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java index 63cfd6494d..1aedbc3124 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java @@ -319,9 +319,9 @@ public class Case implements SleuthkitCase.ErrorObserver { + "\nPlease note that you will still be able to browse directories and generate reports\n" + "if you choose No, but you will not be able to view file content or run the ingest process.", "Missing Image", JOptionPane.YES_NO_OPTION); if (ret == JOptionPane.YES_OPTION) { - /***** RAMAN TBD: MissingImageDialog class needs to be refactored to eliminate ContentTypePanel dependency. + MissingImageDialog.makeDialog(obj_id, db); - * *****************/ + } else { logger.log(Level.WARNING, "Selected image files don't match old files!"); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.form b/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.form index 24dd272951..d730da08dc 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.form @@ -110,65 +110,49 @@ - - - - - - - - - - + + + + + - + - - + + - - - + - - - - - - - - + - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java index d734444a57..deec62e813 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java @@ -18,42 +18,51 @@ */ package org.sleuthkit.autopsy.casemodule; -import java.awt.BorderLayout; -import java.awt.Color; -import java.awt.Component; + import java.awt.Dimension; import java.awt.Toolkit; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; import java.util.Arrays; import java.util.logging.Level; -import javax.swing.ComboBoxModel; -import javax.swing.JDialog; +import java.io.File; +import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.event.ListDataListener; -import org.openide.util.Exceptions; +import org.sleuthkit.autopsy.casemodule.ImageFilePanel; + import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TskCoreException; -/**** RAMAN TBD: this class needs to be straightened out. It should not duplicate what the ChooseDataSourceWizard does. + public class MissingImageDialog extends javax.swing.JDialog { private static final Logger logger = Logger.getLogger(MissingImageDialog.class.getName()); long obj_id; SleuthkitCase db; - ContentTypePanel currentPanel; - ImageTypeModel model; + + + + + private JFileChooser fc = new JFileChooser(); private MissingImageDialog(long obj_id, SleuthkitCase db) { super(new JFrame(), true); this.obj_id = obj_id; this.db = db; initComponents(); + + fc.setDragEnabled(false); + fc.setFileSelectionMode(JFileChooser.FILES_ONLY); + fc.setMultiSelectionEnabled(false); + + // borrow the filters from ImageFilePanel + fc.addChoosableFileFilter(ImageFilePanel.rawFilter); + fc.addChoosableFileFilter(ImageFilePanel.encaseFilter); + fc.setFileFilter(ImageFilePanel.allFilter); + + customInit(); } @@ -75,11 +84,8 @@ public class MissingImageDialog extends javax.swing.JDialog { } private void customInit() { - model = new ImageTypeModel(); - typeComboBox.setModel(model); - typeComboBox.setSelectedIndex(0); - typePanel.setLayout(new BorderLayout()); - updateCurrentPanel(ImageFilePanel.getDefault()); + + selectButton.setEnabled(false); } private void display() { @@ -94,35 +100,6 @@ public class MissingImageDialog extends javax.swing.JDialog { this.setVisible(true); } -// -// * Refresh this panel. -// * @param panel current typepanel -// - private void updateCurrentPanel(ContentTypePanel panel) { - currentPanel = panel; - typePanel.removeAll(); - typePanel.add((JPanel) currentPanel, BorderLayout.CENTER); - typePanel.validate(); - typePanel.repaint(); - this.validate(); - this.repaint(); - currentPanel.addPropertyChangeListener(new PropertyChangeListener() { - - @Override - public void propertyChange(PropertyChangeEvent evt) { - if(evt.getPropertyName().equals(AddImageWizardChooseDataSourceVisual.EVENT.UPDATE_UI.toString())) { - updateSelectButton(); - } - if(evt.getPropertyName().equals(AddImageWizardChooseDataSourceVisual.EVENT.FOCUS_NEXT.toString())) { - moveFocusToSelect(); - } - } - - }); - currentPanel.select(); - updateSelectButton(); - } - // // * Focuses the select button for easy enter-pressing access. // @@ -134,7 +111,13 @@ public class MissingImageDialog extends javax.swing.JDialog { // * Enables/disables the select button based off the current panel. // private void updateSelectButton() { - this.selectButton.setEnabled(currentPanel.enableNext()); + + // Enable this based on whether there is a valid path + if (!pathNameTextField.getText().isEmpty()) { + String filePath = pathNameTextField.getText(); + boolean isExist = Case.pathExists(filePath) || Case.driveExists(filePath); + selectButton.setEnabled(isExist); + } } // @@ -150,9 +133,8 @@ public class MissingImageDialog extends javax.swing.JDialog { selectButton = new javax.swing.JButton(); cancelButton = new javax.swing.JButton(); containerPanel = new javax.swing.JPanel(); - typeComboBox = new javax.swing.JComboBox(); - typeTabel = new javax.swing.JLabel(); - typePanel = new javax.swing.JPanel(); + pathNameTextField = new javax.swing.JTextField(); + browseButton = new javax.swing.JButton(); titleLabel = new javax.swing.JLabel(); titleSeparator = new javax.swing.JSeparator(); @@ -193,43 +175,39 @@ public class MissingImageDialog extends javax.swing.JDialog { .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); - org.openide.awt.Mnemonics.setLocalizedText(typeTabel, org.openide.util.NbBundle.getMessage(MissingImageDialog.class, "MissingImageDialog.typeTabel.text")); // NOI18N + pathNameTextField.setText(org.openide.util.NbBundle.getMessage(MissingImageDialog.class, "MissingImageDialog.pathNameTextField.text")); // NOI18N + pathNameTextField.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + pathNameTextFieldActionPerformed(evt); + } + }); - javax.swing.GroupLayout typePanelLayout = new javax.swing.GroupLayout(typePanel); - typePanel.setLayout(typePanelLayout); - typePanelLayout.setHorizontalGroup( - typePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 0, Short.MAX_VALUE) - ); - typePanelLayout.setVerticalGroup( - typePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 57, Short.MAX_VALUE) - ); + org.openide.awt.Mnemonics.setLocalizedText(browseButton, org.openide.util.NbBundle.getMessage(MissingImageDialog.class, "MissingImageDialog.browseButton.text")); // NOI18N + browseButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + browseButtonActionPerformed(evt); + } + }); javax.swing.GroupLayout containerPanelLayout = new javax.swing.GroupLayout(containerPanel); containerPanel.setLayout(containerPanelLayout); containerPanelLayout.setHorizontalGroup( containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(containerPanelLayout.createSequentialGroup() - .addGap(10, 10, 10) - .addGroup(containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(typePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addGroup(containerPanelLayout.createSequentialGroup() - .addComponent(typeTabel) - .addGap(18, 18, 18) - .addComponent(typeComboBox, 0, 298, Short.MAX_VALUE))) - .addContainerGap()) + .addContainerGap() + .addComponent(pathNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 285, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(browseButton) + .addContainerGap(83, Short.MAX_VALUE)) ); containerPanelLayout.setVerticalGroup( containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(containerPanelLayout.createSequentialGroup() - .addGap(0, 0, 0) + .addGap(18, 18, 18) .addGroup(containerPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(typeTabel) - .addComponent(typeComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(typePanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addContainerGap()) + .addComponent(pathNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(browseButton)) + .addContainerGap(62, Short.MAX_VALUE)) ); titleLabel.setFont(new java.awt.Font("Tahoma", 1, 12)); // NOI18N @@ -270,7 +248,7 @@ public class MissingImageDialog extends javax.swing.JDialog { private void selectButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectButtonActionPerformed try { - String newPath = currentPanel.getContentPaths(); + String newPath = pathNameTextField.getText(); //TODO handle local files db.setImagePaths(obj_id, Arrays.asList(new String[]{newPath})); } catch (TskCoreException ex) { @@ -283,16 +261,43 @@ public class MissingImageDialog extends javax.swing.JDialog { cancel(); }//GEN-LAST:event_cancelButtonActionPerformed + private void pathNameTextFieldActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_pathNameTextFieldActionPerformed + // TODO add your handling code here: + + updateSelectButton(); + }//GEN-LAST:event_pathNameTextFieldActionPerformed + + private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed + + + + String oldText = pathNameTextField.getText(); + + // set the current directory of the FileChooser if the ImagePath Field is valid + File currentDir = new File(oldText); + if (currentDir.exists()) { + fc.setCurrentDirectory(currentDir); + } + + int retval = fc.showOpenDialog(this); + if (retval == JFileChooser.APPROVE_OPTION) { + String path = fc.getSelectedFile().getPath(); + pathNameTextField.setText(path); + } + //pcs.firePropertyChange(DataSourceProcessor.DSP_PANEL_EVENT.FOCUS_NEXT.toString(), false, true); + + updateSelectButton(); + }//GEN-LAST:event_browseButtonActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JButton browseButton; private javax.swing.JPanel buttonPanel; private javax.swing.JButton cancelButton; private javax.swing.JPanel containerPanel; + private javax.swing.JTextField pathNameTextField; private javax.swing.JButton selectButton; private javax.swing.JLabel titleLabel; private javax.swing.JSeparator titleSeparator; - private javax.swing.JComboBox typeComboBox; - private javax.swing.JPanel typePanel; - private javax.swing.JLabel typeTabel; // End of variables declaration//GEN-END:variables // @@ -308,41 +313,5 @@ public class MissingImageDialog extends javax.swing.JDialog { } } -// -// * ComboBoxModel to control typeComboBox and supply ImageTypePanels. -// - private class ImageTypeModel implements ComboBoxModel { - ContentTypePanel selected; - ContentTypePanel[] types = ContentTypePanel.getPanels(); - @Override - public void setSelectedItem(Object anItem) { - selected = (ContentTypePanel) anItem; - updateCurrentPanel(selected); - } - - @Override - public Object getSelectedItem() { - return selected; - } - - @Override - public int getSize() { - return types.length; - } - - @Override - public Object getElementAt(int index) { - return types[index]; - } - - @Override - public void addListDataListener(ListDataListener l) { - } - - @Override - public void removeListDataListener(ListDataListener l) { - } - } -} -********************************/ \ No newline at end of file +} \ No newline at end of file From c13f41f67cf2028c2d6942e86812f327f16245b0 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 28 Oct 2013 15:09:58 -0400 Subject: [PATCH 054/169] Changed plumbing for adding content to hash db actions --- .../ContextMenuActionsProvider.java | 37 +++++++++++ .../coreutils/ContextMenuExtensionPoint.java | 45 ++++++++++++++ .../autopsy/datamodel/DirectoryNode.java | 2 - .../sleuthkit/autopsy/datamodel/FileNode.java | 2 - .../autopsy/datamodel/LayoutFileNode.java | 2 - .../autopsy/datamodel/LocalFileNode.java | 2 - .../datamodel/VirtualDirectoryNode.java | 2 - .../directorytree/DataResultFilterNode.java | 5 -- .../ExplorerNodeActionVisitor.java | 5 -- .../AddContentToHashDbAction.java | 61 +++++++++++++------ .../autopsy/hashdatabase/HashDbXML.java | 1 - .../KeywordSearchFilterNode.java | 2 +- 12 files changed, 127 insertions(+), 39 deletions(-) create mode 100755 Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/ContextMenuActionsProvider.java create mode 100755 Core/src/org/sleuthkit/autopsy/coreutils/ContextMenuExtensionPoint.java rename {Core/src/org/sleuthkit/autopsy/directorytree => HashDatabase/src/org/sleuthkit/autopsy/hashdatabase}/AddContentToHashDbAction.java (58%) diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/ContextMenuActionsProvider.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/ContextMenuActionsProvider.java new file mode 100755 index 0000000000..1d84ca2c6c --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/ContextMenuActionsProvider.java @@ -0,0 +1,37 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 - 2013 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.corecomponentinterfaces; + +import java.util.List; +import javax.swing.Action; + +/** + * Implementers of this interface provide Actions that will be added to context + * menus in Autopsy. + */ +public interface ContextMenuActionsProvider { + /** + * Gets context menu Actions appropriate to the org.sleuthkit.datamodel + * objects in the NetBeans Lookup for the active TopComponent. + * Implementers can discover the data model objects by calling + * org.openide.util.Utilities.actionsGlobalContext().lookupAll(). + * @return A list, possibly empty, of Action objects. + */ + List getActions(); +} diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ContextMenuExtensionPoint.java b/Core/src/org/sleuthkit/autopsy/coreutils/ContextMenuExtensionPoint.java new file mode 100755 index 0000000000..f066d20de9 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ContextMenuExtensionPoint.java @@ -0,0 +1,45 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 - 2013 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.coreutils; + +import org.openide.util.Lookup; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import javax.swing.Action; +import org.sleuthkit.autopsy.corecomponentinterfaces.ContextMenuActionsProvider; + +/** + * This class implements the ContextMenuActionsProvider extension point. + */ +public class ContextMenuExtensionPoint { + /** + * Gets all of the Actions provided by registered implementers of the + * ContextMenuActionsProvider interface. + * @return A list, possibly empty, of Action objects. + */ + static public List getActions() { + ArrayList actions = new ArrayList<>(); + Collection actionProviders = Lookup.getDefault().lookupAll(ContextMenuActionsProvider.class); + for (ContextMenuActionsProvider provider : actionProviders) { + actions.addAll(provider.getActions()); + } + return actions; + } +} diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java index a2828140ab..182a64c61d 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java @@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; import java.util.List; import javax.swing.Action; -import org.sleuthkit.autopsy.directorytree.AddContentToHashDbAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; @@ -78,7 +77,6 @@ public class DirectoryNode extends AbstractFsContentNode { actions.add(ExtractAction.getInstance()); actions.add(null); // creates a menu separator actions.add(TagAbstractFileAction.getInstance()); - actions.add(AddContentToHashDbAction.getInstance()); return actions.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java index 614b34daff..04c0c1a078 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java @@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; import java.util.List; import javax.swing.Action; -import org.sleuthkit.autopsy.directorytree.AddContentToHashDbAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; @@ -86,7 +85,6 @@ public class FileNode extends AbstractFsContentNode { actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this)); actionsList.add(null); // creates a menu separator actionsList.add(TagAbstractFileAction.getInstance()); - actionsList.add(AddContentToHashDbAction.getInstance()); return actionsList.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java index d7384b05d8..5dd48d1ae1 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java @@ -24,7 +24,6 @@ import java.util.List; import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; -import org.sleuthkit.autopsy.directorytree.AddContentToHashDbAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; @@ -110,7 +109,6 @@ public class LayoutFileNode extends AbstractAbstractFileNode { actionsList.add(ExtractAction.getInstance()); actionsList.add(null); // creates a menu separator actionsList.add(TagAbstractFileAction.getInstance()); - actionsList.add(AddContentToHashDbAction.getInstance()); return actionsList.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java index be3a93f602..af8ef7549f 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java @@ -26,7 +26,6 @@ import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode.TYPE; -import org.sleuthkit.autopsy.directorytree.AddContentToHashDbAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; @@ -94,7 +93,6 @@ public class LocalFileNode extends AbstractAbstractFileNode { actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this)); actionsList.add(null); // creates a menu separator actionsList.add(TagAbstractFileAction.getInstance()); - actionsList.add(AddContentToHashDbAction.getInstance()); return actionsList.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java index c0b9a6a841..76062876bc 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java @@ -25,7 +25,6 @@ import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.directorytree.AddContentToHashDbAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; @@ -83,7 +82,6 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode visit(final Directory d) { List actions = new ArrayList<>(); actions.add(TagAbstractFileAction.getInstance()); - actions.add(AddContentToHashDbAction.getInstance()); return actions; } @@ -111,7 +110,6 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default actions = new ArrayList<>(); actions.add(ExtractAction.getInstance()); actions.add(TagAbstractFileAction.getInstance()); - actions.add(AddContentToHashDbAction.getInstance()); return actions; } @@ -120,7 +118,6 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default actions = new ArrayList<>(); actions.add(ExtractAction.getInstance()); actions.add(TagAbstractFileAction.getInstance()); - actions.add(AddContentToHashDbAction.getInstance()); return actions; } @@ -129,7 +126,6 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default actions = new ArrayList<>(); actions.add(ExtractAction.getInstance()); actions.add(TagAbstractFileAction.getInstance()); - actions.add(AddContentToHashDbAction.getInstance()); return actions; } @@ -138,7 +134,6 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default actions = new ArrayList<>(); actions.add(ExtractAction.getInstance()); actions.add(TagAbstractFileAction.getInstance()); - actions.add(AddContentToHashDbAction.getInstance()); return actions; } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/AddContentToHashDbAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java similarity index 58% rename from Core/src/org/sleuthkit/autopsy/directorytree/AddContentToHashDbAction.java rename to HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java index 44999ef5c1..e7ee2e548d 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/AddContentToHashDbAction.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java @@ -16,25 +16,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.directorytree; +package org.sleuthkit.autopsy.hashdatabase; import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; import java.util.Collection; import java.util.logging.Level; import javax.swing.AbstractAction; import javax.swing.Action; +import javax.swing.JMenu; +import javax.swing.JMenuItem; import javax.swing.JOptionPane; import org.openide.util.Utilities; import org.openide.util.Lookup; -import org.sleuthkit.autopsy.coreutils.Logger; +import org.openide.util.actions.Presenter; import org.sleuthkit.autopsy.ingest.IngestConfigurator; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.TskCoreException; /** * Instances of this Action allow users to content to a hash database. */ -public class AddContentToHashDbAction extends AbstractAction { +public class AddContentToHashDbAction extends AbstractAction implements Presenter.Popup { // This class is a singleton to support multi-selection of nodes, since // org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every // node in the array returns a reference to the same action object from Node.getActions(boolean). @@ -81,21 +85,44 @@ public class AddContentToHashDbAction extends AbstractAction { super(SINGLE_SELECTION_NAME); } + @Override + public JMenuItem getPopupPresenter() { + return new AddContentToHashDbMenu(); + } + @Override public void actionPerformed(ActionEvent event) { - Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); - for (AbstractFile file : selectedFiles) { - try { - // RJCTODO: Complete this method. - String md5Hash = file.getMd5Hash(); - if (null != md5Hash) { - throw new TskCoreException("RJCTODO"); - } + } + + private class AddContentToHashDbMenu extends JMenu { + AddContentToHashDbMenu() { + // RJCTODO: Need super call? + + // Get the current set of updateable hash databases and add each + // one as a menu item. + for (final HashDb database : HashDbXML.getCurrent().getKnownBadSets()) { + if (database.isUpdateable()) { + JMenuItem databaseItem = add(database.getName()); + databaseItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); + for (AbstractFile file : selectedFiles) { + String md5Hash = file.getMd5Hash(); + if (null != md5Hash) { + try { + database.addContentHash(file); + } + catch (TskCoreException ex) { + Logger.getLogger(AddContentToHashDbAction.class.getName()).log(Level.SEVERE, "Error tagging result", ex); + JOptionPane.showMessageDialog(null, "Unable to add " + file.getName() + "to hash database.", "Add to Hash Database Error", JOptionPane.ERROR_MESSAGE); + } + } + } + } + }); + } } - catch (TskCoreException ex) { - Logger.getLogger(AddContentToHashDbAction.class.getName()).log(Level.SEVERE, "Error tagging result", ex); - JOptionPane.showMessageDialog(null, "Unable to add " + file.getName() + "to hash database.", "Add to Hash Database Error", JOptionPane.ERROR_MESSAGE); - } - } - } + } + } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java index 0ac5f8b31c..e8f0ff8bee 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java @@ -32,7 +32,6 @@ import javax.xml.parsers.ParserConfigurationException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.XMLUtil; -import org.sleuthkit.autopsy.directorytree.AddContentToHashDbAction; import org.sleuthkit.autopsy.hashdatabase.HashDb.DBType; import org.sleuthkit.datamodel.SleuthkitJNI; import org.sleuthkit.datamodel.TskCoreException; diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java index 006839fcc5..8f83110767 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java @@ -33,7 +33,7 @@ import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.directorytree.AddContentToHashDbAction; +import org.sleuthkit.autopsy.hashdatabase.AddContentToHashDbAction; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentVisitor; import org.sleuthkit.datamodel.DerivedFile; From 0ce636ebf612d81407582e2d6915c04e1219bf0a Mon Sep 17 00:00:00 2001 From: raman-bt Date: Mon, 28 Oct 2013 15:48:27 -0400 Subject: [PATCH 055/169] Cleaned up the storing/reading of last selected data source path - delegated it to the DataSourceProcessor specific Panels, to handle as appropriate. --- .../AddImageWizardChooseDataSourcePanel.java | 22 ++---------- .../AddImageWizardIngestConfigPanel.java | 2 +- .../autopsy/casemodule/AddLocalFilesTask.java | 3 +- .../autopsy/casemodule/ImageDSProcessor.java | 9 ++--- .../autopsy/casemodule/ImageFilePanel.java | 34 ++++++++++++++----- .../casemodule/LocalDiskDSProcessor.java | 7 +--- .../autopsy/casemodule/LocalDiskPanel.java | 2 -- .../casemodule/LocalFilesDSProcessor.java | 13 ++----- 8 files changed, 38 insertions(+), 54 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java index 1588d865b5..d662439f3b 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourcePanel.java @@ -180,16 +180,6 @@ class AddImageWizardChooseDataSourcePanel implements WizardDescriptor.Panel rawExt = Arrays.asList(new String[]{".img", ".dd", ".001", ".aa", ".raw"}); static final String rawDesc = "Raw Images (*.img, *.dd, *.001, *.aa, *.raw)"; static GeneralFilter rawFilter = new GeneralFilter(rawExt, rawDesc); @@ -71,6 +75,9 @@ public class ImageFilePanel extends JPanel implements DocumentListener { fc.addChoosableFileFilter(encaseFilter); fc.setFileFilter(allFilter); + + pcs = new PropertyChangeSupport(this); + createTimeZoneList(); } @@ -171,7 +178,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener { .addComponent(noFatOrphansCheckbox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(descLabel) - .addContainerGap(73, Short.MAX_VALUE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); }// //GEN-END:initComponents @@ -226,16 +233,11 @@ public class ImageFilePanel extends JPanel implements DocumentListener { return noFatOrphansCheckbox.isSelected(); } - public String getContentType() { - return "IMAGE"; - } + public void reset() { - //reset the UI elements to default - - pathTextField.setText(null); - - + //reset the UI elements to default + pathTextField.setText(null); } /** @@ -256,6 +258,20 @@ public class ImageFilePanel extends JPanel implements DocumentListener { } + public void storeSettings() { + + String imagePathName = getContentPaths(); + String imagePath = imagePathName.substring(0, imagePathName.lastIndexOf(File.separator) + 1); + + ModuleSettings.setConfigSetting(ImageFilePanel.class.getName(), PROP_LASTIMAGE_PATH, imagePath); + } + + public void readSettings() { + + String lastImagePath = ModuleSettings.getConfigSetting(ImageFilePanel.class.getName(), PROP_LASTIMAGE_PATH); + if (!lastImagePath.isEmpty()) + pathTextField.setText(lastImagePath); + } /** * Creates the drop down list for the time zones and then makes the local * machine time zone to be selected. diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java index d6b8007fdb..325d9d9a2f 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java @@ -84,8 +84,6 @@ public class LocalDiskDSProcessor implements DataSourceProcessor { **/ @Override public JPanel getPanel() { - - // RAMAN TBD: we should ask the panel to preload with any saved settings localDiskPanel.select(); return localDiskPanel; @@ -115,10 +113,7 @@ public class LocalDiskDSProcessor implements DataSourceProcessor { callbackObj = cbObj; cancelled = false; - if (!localDiskOptionsSet) - { - // RAMAN TBD: we should ask the panel to save the current settings - + if (!localDiskOptionsSet) { // get the image options from the panel localDiskPath = localDiskPanel.getContentPaths(); timeZone = localDiskPanel.getTimeZone(); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java index 5b2e95ce04..22f1ed07f3 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java @@ -221,8 +221,6 @@ public class LocalDiskPanel extends JPanel { public void reset() { //nothing to reset - // RAMAN TBD this should reset the UI elements? - } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java index 085c0b65c1..539bb2e050 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java @@ -79,11 +79,7 @@ public class LocalFilesDSProcessor implements DataSourceProcessor { **/ @Override public JPanel getPanel() { - - // RAMAN TBD: we should ask the panel to preload with any saved settings - - localFilesPanel.select(); - + localFilesPanel.select(); return localFilesPanel; } /** @@ -111,11 +107,8 @@ public class LocalFilesDSProcessor implements DataSourceProcessor { callbackObj = cbObj; cancelled = false; - if (!localFilesOptionsSet) - { - // RAMAN TBD: we should ask the panel to save the current settings - - // get the image options from the panel + if (!localFilesOptionsSet) { + // get the selected file paths from the panel localFilesPath = localFilesPanel.getContentPaths(); } From 40ee532e1cd961c0b5256a1a0509ac97078879ea Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 28 Oct 2013 17:47:20 -0400 Subject: [PATCH 056/169] Implemented ContextMenuActionProvider interface in HashDatabase module --- .../ContextMenuActionsProvider.java | 11 ++-- .../coreutils/ContextMenuExtensionPoint.java | 6 +- .../autopsy/datamodel/DirectoryNode.java | 2 + .../sleuthkit/autopsy/datamodel/FileNode.java | 2 + .../autopsy/datamodel/LayoutFileNode.java | 2 + .../autopsy/datamodel/LocalFileNode.java | 2 + .../datamodel/VirtualDirectoryNode.java | 2 + .../directorytree/DataResultFilterNode.java | 6 ++ .../ExplorerNodeActionVisitor.java | 6 ++ .../AddContentToHashDbAction.java | 62 +++++++++++-------- .../HashDbContextMenuActionsProvider.java | 41 ++++++++++++ .../KeywordSearchFilterNode.java | 4 +- 12 files changed, 113 insertions(+), 33 deletions(-) create mode 100755 HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbContextMenuActionsProvider.java diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/ContextMenuActionsProvider.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/ContextMenuActionsProvider.java index 1d84ca2c6c..aff714f736 100755 --- a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/ContextMenuActionsProvider.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/ContextMenuActionsProvider.java @@ -27,11 +27,12 @@ import javax.swing.Action; */ public interface ContextMenuActionsProvider { /** - * Gets context menu Actions appropriate to the org.sleuthkit.datamodel - * objects in the NetBeans Lookup for the active TopComponent. - * Implementers can discover the data model objects by calling - * org.openide.util.Utilities.actionsGlobalContext().lookupAll(). + * Gets context menu Actions for the currently selected data model objects + * exposed by the NetBeans Lookup of the active TopComponent. Implementers + * should discover the selected objects by calling + * org.openide.util.Utilities.actionsGlobalContext().lookupAll() for the + * org.sleuthkit.datamodel classes of interest to the provider. * @return A list, possibly empty, of Action objects. */ - List getActions(); + public List getActions(); } diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ContextMenuExtensionPoint.java b/Core/src/org/sleuthkit/autopsy/coreutils/ContextMenuExtensionPoint.java index f066d20de9..fcf626283c 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ContextMenuExtensionPoint.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ContextMenuExtensionPoint.java @@ -38,7 +38,11 @@ public class ContextMenuExtensionPoint { ArrayList actions = new ArrayList<>(); Collection actionProviders = Lookup.getDefault().lookupAll(ContextMenuActionsProvider.class); for (ContextMenuActionsProvider provider : actionProviders) { - actions.addAll(provider.getActions()); + List providerActions = provider.getActions(); + if (!providerActions.isEmpty()) { + actions.add(null); // Separator to set off this provider's actions. + actions.addAll(provider.getActions()); + } } return actions; } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java index 182a64c61d..ca7aae9a04 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DirectoryNode.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; import java.util.List; import javax.swing.Action; +import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; @@ -77,6 +78,7 @@ public class DirectoryNode extends AbstractFsContentNode { actions.add(ExtractAction.getInstance()); actions.add(null); // creates a menu separator actions.add(TagAbstractFileAction.getInstance()); + actions.addAll(ContextMenuExtensionPoint.getActions()); return actions.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java index 04c0c1a078..4403463706 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileNode.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.datamodel; import java.util.ArrayList; import java.util.List; import javax.swing.Action; +import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; @@ -85,6 +86,7 @@ public class FileNode extends AbstractFsContentNode { actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this)); actionsList.add(null); // creates a menu separator actionsList.add(TagAbstractFileAction.getInstance()); + actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java index 5dd48d1ae1..aace8dc731 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LayoutFileNode.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; +import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; @@ -109,6 +110,7 @@ public class LayoutFileNode extends AbstractAbstractFileNode { actionsList.add(ExtractAction.getInstance()); actionsList.add(null); // creates a menu separator actionsList.add(TagAbstractFileAction.getInstance()); + actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java index af8ef7549f..19a2d15314 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/LocalFileNode.java @@ -25,6 +25,7 @@ import java.util.List; import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; +import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.datamodel.DisplayableItemNode.TYPE; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; @@ -93,6 +94,7 @@ public class LocalFileNode extends AbstractAbstractFileNode { actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this)); actionsList.add(null); // creates a menu separator actionsList.add(TagAbstractFileAction.getInstance()); + actionsList.addAll(ContextMenuExtensionPoint.getActions()); return actionsList.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java index 76062876bc..d7d4fdda17 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Map; import javax.swing.Action; import org.openide.nodes.Sheet; +import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; @@ -82,6 +83,7 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode visit(final Directory d) { List actions = new ArrayList<>(); actions.add(TagAbstractFileAction.getInstance()); + actions.addAll(ContextMenuExtensionPoint.getActions()); return actions; } @@ -110,6 +112,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default actions = new ArrayList<>(); actions.add(ExtractAction.getInstance()); actions.add(TagAbstractFileAction.getInstance()); + actions.addAll(ContextMenuExtensionPoint.getActions()); return actions; } @@ -118,6 +121,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default actions = new ArrayList<>(); actions.add(ExtractAction.getInstance()); actions.add(TagAbstractFileAction.getInstance()); + actions.addAll(ContextMenuExtensionPoint.getActions()); return actions; } @@ -126,6 +130,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default actions = new ArrayList<>(); actions.add(ExtractAction.getInstance()); actions.add(TagAbstractFileAction.getInstance()); + actions.addAll(ContextMenuExtensionPoint.getActions()); return actions; } @@ -134,6 +139,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default actions = new ArrayList<>(); actions.add(ExtractAction.getInstance()); actions.add(TagAbstractFileAction.getInstance()); + actions.addAll(ContextMenuExtensionPoint.getActions()); return actions; } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java index e7ee2e548d..250d44e0a5 100755 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.hashdatabase; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.Collection; +import java.util.List; import java.util.logging.Level; import javax.swing.AbstractAction; import javax.swing.Action; @@ -44,8 +45,9 @@ public class AddContentToHashDbAction extends AbstractAction implements Presente // node in the array returns a reference to the same action object from Node.getActions(boolean). private static AddContentToHashDbAction instance; private static String SINGLE_SELECTION_NAME = "Add file to hash database"; - private static String MULTIPLE_SELECTION_NAME = "Add files to hash database"; - + private static String MULTIPLE_SELECTION_NAME = "Add files to hash database"; + private String menuText; + public static synchronized AddContentToHashDbAction getInstance() { if (null == instance) { instance = new AddContentToHashDbAction(); @@ -53,6 +55,7 @@ public class AddContentToHashDbAction extends AbstractAction implements Presente instance.setEnabled(true); instance.putValue(Action.NAME, SINGLE_SELECTION_NAME); + instance.menuText = SINGLE_SELECTION_NAME; // Disable the action if file ingest is in progress. IngestConfigurator ingestConfigurator = Lookup.getDefault().lookup(IngestConfigurator.class); @@ -65,6 +68,7 @@ public class AddContentToHashDbAction extends AbstractAction implements Presente Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); if (selectedFiles.size() > 1) { instance.putValue(Action.NAME, MULTIPLE_SELECTION_NAME); + instance.menuText = MULTIPLE_SELECTION_NAME; } if (selectedFiles.isEmpty()) { instance.setEnabled(false); @@ -87,7 +91,7 @@ public class AddContentToHashDbAction extends AbstractAction implements Presente @Override public JMenuItem getPopupPresenter() { - return new AddContentToHashDbMenu(); + return new AddContentToHashDbMenu(menuText); } @Override @@ -95,34 +99,42 @@ public class AddContentToHashDbAction extends AbstractAction implements Presente } private class AddContentToHashDbMenu extends JMenu { - AddContentToHashDbMenu() { - // RJCTODO: Need super call? + AddContentToHashDbMenu(String menuText) { + super(menuText); // Get the current set of updateable hash databases and add each // one as a menu item. - for (final HashDb database : HashDbXML.getCurrent().getKnownBadSets()) { - if (database.isUpdateable()) { - JMenuItem databaseItem = add(database.getName()); - databaseItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); - for (AbstractFile file : selectedFiles) { - String md5Hash = file.getMd5Hash(); - if (null != md5Hash) { - try { - database.addContentHash(file); - } - catch (TskCoreException ex) { - Logger.getLogger(AddContentToHashDbAction.class.getName()).log(Level.SEVERE, "Error tagging result", ex); - JOptionPane.showMessageDialog(null, "Unable to add " + file.getName() + "to hash database.", "Add to Hash Database Error", JOptionPane.ERROR_MESSAGE); - } - } + List hashDatabases = HashDbXML.getCurrent().getKnownBadSets(); + if (!hashDatabases.isEmpty()) { + for (final HashDb database : HashDbXML.getCurrent().getKnownBadSets()) { + if (database.isUpdateable()) { + JMenuItem databaseItem = add(database.getName()); + databaseItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); + for (AbstractFile file : selectedFiles) { + String md5Hash = file.getMd5Hash(); + if (null != md5Hash) { + try { + database.addContentHash(file); + } + catch (TskCoreException ex) { + Logger.getLogger(AddContentToHashDbAction.class.getName()).log(Level.SEVERE, "Error adding to hash database", ex); + JOptionPane.showMessageDialog(null, "Unable to add " + file.getName() + "to hash database.", "Add to Hash Database Error", JOptionPane.ERROR_MESSAGE); + } + } + } } - } - }); + }); + } } } + else { + JMenuItem empty = new JMenuItem("No hash databases"); + empty.setEnabled(false); + add(empty); + } } } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbContextMenuActionsProvider.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbContextMenuActionsProvider.java new file mode 100755 index 0000000000..6f03e7095b --- /dev/null +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbContextMenuActionsProvider.java @@ -0,0 +1,41 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 - 2013 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.hashdatabase; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import javax.swing.Action; +import org.openide.util.Utilities; +import org.openide.util.lookup.ServiceProvider; +import org.sleuthkit.autopsy.corecomponentinterfaces.ContextMenuActionsProvider; +import org.sleuthkit.datamodel.AbstractFile; + +@ServiceProvider(service = ContextMenuActionsProvider.class) +public class HashDbContextMenuActionsProvider implements ContextMenuActionsProvider { + @Override + public List getActions() { + ArrayList actions = new ArrayList<>(); + Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); + if (!selectedFiles.isEmpty()) { + actions.add(AddContentToHashDbAction.getInstance()); + } + return actions; + } +} diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java index 8f83110767..603682c9da 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/KeywordSearchFilterNode.java @@ -28,12 +28,12 @@ import org.openide.nodes.PropertySupport; import org.openide.nodes.Sheet; import org.openide.util.lookup.Lookups; import org.openide.util.lookup.ProxyLookup; +import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.hashdatabase.AddContentToHashDbAction; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.ContentVisitor; import org.sleuthkit.datamodel.DerivedFile; @@ -153,7 +153,7 @@ class KeywordSearchFilterNode extends FilterNode { actions.add(new HashSearchAction("Search for files with the same MD5 hash", getOriginal())); actions.add(null); // creates a menu separator actions.add(TagAbstractFileAction.getInstance()); - actions.add(AddContentToHashDbAction.getInstance()); + actions.addAll(ContextMenuExtensionPoint.getActions()); return actions; } From 657552661d9e875358b48afefedec87265ad480f Mon Sep 17 00:00:00 2001 From: raman-bt Date: Tue, 29 Oct 2013 09:24:21 -0400 Subject: [PATCH 057/169] i. Bugfix in readSettings() ii Adjusted the size of the Image & Local disk so they are fully visible in design view. --- .../autopsy/casemodule/ImageFilePanel.form | 2 +- .../autopsy/casemodule/ImageFilePanel.java | 18 ++++++++++-------- .../autopsy/casemodule/LocalDiskPanel.form | 2 +- .../autopsy/casemodule/LocalDiskPanel.java | 2 +- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form index 5d919e225a..b201296bfa 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form @@ -66,7 +66,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java index 975665a4a1..c70b8f1f7f 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java @@ -40,6 +40,7 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings; */ public class ImageFilePanel extends JPanel implements DocumentListener { + private static final String PROP_LASTIMAGE_PATH = "LBL_LastImage_PATH"; static final List rawExt = Arrays.asList(new String[]{".img", ".dd", ".001", ".aa", ".raw"}); @@ -178,7 +179,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener { .addComponent(noFatOrphansCheckbox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(descLabel) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap(33, Short.MAX_VALUE)) ); }// //GEN-END:initComponents @@ -259,18 +260,19 @@ public class ImageFilePanel extends JPanel implements DocumentListener { public void storeSettings() { - String imagePathName = getContentPaths(); - String imagePath = imagePathName.substring(0, imagePathName.lastIndexOf(File.separator) + 1); - - ModuleSettings.setConfigSetting(ImageFilePanel.class.getName(), PROP_LASTIMAGE_PATH, imagePath); + if (null != imagePathName ) { + String imagePath = imagePathName.substring(0, imagePathName.lastIndexOf(File.separator) + 1); + ModuleSettings.setConfigSetting(ImageFilePanel.class.getName(), PROP_LASTIMAGE_PATH, imagePath); + } } public void readSettings() { - String lastImagePath = ModuleSettings.getConfigSetting(ImageFilePanel.class.getName(), PROP_LASTIMAGE_PATH); - if (!lastImagePath.isEmpty()) - pathTextField.setText(lastImagePath); + if (null != lastImagePath) { + if (!lastImagePath.isEmpty()) + pathTextField.setText(lastImagePath); + } } /** * Creates the drop down list for the time zones and then makes the local diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.form index 2b1062c834..58e493e793 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.form @@ -61,7 +61,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java index 22f1ed07f3..ba746b7595 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskPanel.java @@ -157,7 +157,7 @@ public class LocalDiskPanel extends JPanel { .addComponent(noFatOrphansCheckbox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(descLabel) - .addContainerGap(27, Short.MAX_VALUE)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables From 0b985703b738ee6b9af65dbb224917fbd9a3daa7 Mon Sep 17 00:00:00 2001 From: raman-bt Date: Tue, 29 Oct 2013 14:30:51 -0400 Subject: [PATCH 058/169] Ensure that the core DataSourceProcessors appear at the top in the wizard, and in a specific order. And there is a separator between 'core' DSPs and others. --- .../AddImageWizardChooseDataSourceVisual.java | 67 +++++++++++++++---- .../autopsy/casemodule/ImageDSProcessor.java | 2 +- .../casemodule/LocalDiskDSProcessor.java | 2 +- .../casemodule/LocalFilesDSProcessor.java | 2 +- 4 files changed, 58 insertions(+), 15 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java index 42a49daf56..dacec10e23 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java @@ -22,22 +22,20 @@ package org.sleuthkit.autopsy.casemodule; import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; +import java.awt.Component; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Calendar; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.SimpleTimeZone; -import java.util.TimeZone; import java.util.logging.Level; -import javax.swing.ComboBoxModel; import javax.swing.JPanel; +import javax.swing.JList; +import javax.swing.JSeparator; import javax.swing.event.DocumentEvent; -import javax.swing.event.ListDataListener; +import javax.swing.ListCellRenderer; import org.openide.util.Lookup; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; @@ -57,6 +55,7 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { private Map datasourceProcessorsMap = new HashMap(); + List coreDSPTypes = new ArrayList(); /** * Creates new form AddImageVisualPanel1 @@ -71,28 +70,49 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { } private void customInit() { + + typePanel.setLayout(new BorderLayout()); discoverDataSourceProcessors(); - + // set up the DSP type combobox typeComboBox.removeAllItems(); + Set dspTypes = datasourceProcessorsMap.keySet(); - for(String dspType:dspTypes){ + + // make a list of core DSPs + // ensure that the core DSPs are at the top and in a fixed order + coreDSPTypes.add(ImageDSProcessor.dsType); + coreDSPTypes.add(LocalDiskDSProcessor.dsType); + coreDSPTypes.add(LocalFilesDSProcessor.dsType); + + for(String dspType:coreDSPTypes){ typeComboBox.addItem(dspType); } + // now add any addtional DSPs that haven't already been added + for(String dspType:dspTypes){ + if (!coreDSPTypes.contains(dspType)) { + typeComboBox.addItem(dspType); + } + } + + // set a custom renderer that draws a separator at the end of the core DSPs in the combobox + typeComboBox.setRenderer(new ComboboxSeparatorRenderer(typeComboBox.getRenderer()){ + @Override + protected boolean addSeparatorAfter(JList list, Object value, int index){ + return (index == coreDSPTypes.size() - 1); + } + }); + //add actionlistner to listen for change ActionListener cbActionListener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { dspSelectionChanged(); - } }; typeComboBox.addActionListener(cbActionListener); - - typePanel.setLayout(new BorderLayout()); - typeComboBox.setSelectedIndex(0); } @@ -290,4 +310,27 @@ final class AddImageWizardChooseDataSourceVisual extends JPanel { this.wizPanel.enableNextButton(getCurrentDSProcessor().validatePanel()); } + + public abstract class ComboboxSeparatorRenderer implements ListCellRenderer{ + private ListCellRenderer delegate; + private JPanel separatorPanel = new JPanel(new BorderLayout()); + private JSeparator separator = new JSeparator(); + + public ComboboxSeparatorRenderer(ListCellRenderer delegate){ + this.delegate = delegate; + } + + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus){ + Component comp = delegate.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus); + if(index!=-1 && addSeparatorAfter(list, value, index)){ + separatorPanel.removeAll(); + separatorPanel.add(comp, BorderLayout.CENTER); + separatorPanel.add(separator, BorderLayout.SOUTH); + return separatorPanel; + }else + return comp; + } + + protected abstract boolean addSeparatorAfter(JList list, Object value, int index); + } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java index b82f59a4c6..0a56499828 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java @@ -40,7 +40,7 @@ public class ImageDSProcessor implements DataSourceProcessor { static final Logger logger = Logger.getLogger(ImageDSProcessor.class.getName()); // Data source type handled by this processor - private final String dsType = "Image File"; + protected final static String dsType = "Image File"; // The Config UI panel that plugins into the Choose Data Source Wizard private ImageFilePanel imageFilePanel; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java index 325d9d9a2f..cbaa520249 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalDiskDSProcessor.java @@ -33,7 +33,7 @@ public class LocalDiskDSProcessor implements DataSourceProcessor { static final Logger logger = Logger.getLogger(ImageDSProcessor.class.getName()); // Data source type handled by this processor - private final String dsType = "Local Disk"; + static protected final String dsType = "Local Disk"; // The Config UI panel that plugins into the Choose Data Source Wizard private LocalDiskPanel localDiskPanel; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java index 539bb2e050..3c6089d4a3 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/LocalFilesDSProcessor.java @@ -32,7 +32,7 @@ public class LocalFilesDSProcessor implements DataSourceProcessor { static final Logger logger = Logger.getLogger(LocalFilesDSProcessor.class.getName()); // Data source type handled by this processor - private final String dsType = "Logical Files"; + protected static final String dsType = "Logical Files"; // The Config UI panel that plugins into the Choose Data Source Wizard private LocalFilesPanel localFilesPanel; From 58ce29be25e8af5bd19660ff64cf35873f18cadc Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Tue, 29 Oct 2013 18:43:27 -0400 Subject: [PATCH 059/169] Added XML file save to HasDb.openDatabase() --- .../src/org/sleuthkit/autopsy/hashdatabase/HashDb.java | 6 ++++-- .../autopsy/hashdatabase/HashDbImportDatabaseDialog.java | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index e86dcc2492..e92a40be1b 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -85,12 +85,14 @@ public class HashDb implements Comparable { } static private void addToXMLFile(HashDb database) { + HashDbXML xmlFileManager = HashDbXML.getCurrent(); if (database.getDbType() == HashDb.DBType.NSRL) { - HashDbXML.getCurrent().setNSRLSet(database); + xmlFileManager.setNSRLSet(database); } else { - HashDbXML.getCurrent().addKnownBadSet(database); + xmlFileManager.addKnownBadSet(database); } + xmlFileManager.save(); } static public List getUpdateableHashDatabases() { diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java index 71d769f8df..910cd6cacb 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java @@ -306,7 +306,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { try { - HashDb db = HashDb.openHashDatabase(databaseNameTextField.getText(), databasePathTextField.getText(), useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); + HashDb.openHashDatabase(databaseNameTextField.getText(), databasePathTextField.getText(), useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); } catch (TskException ex) { logger.log(Level.WARNING, "Invalid database: ", ex); JOptionPane.showMessageDialog(this, "Database file you chose cannot be opened.\n" + "If it was just an index, please try to recreate it from the database"); From 6bcbc2eb11c786e4f4baa70ad89ae952c420aac0 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Tue, 29 Oct 2013 19:44:20 -0400 Subject: [PATCH 060/169] Added needed space to an error message in AddContentToHashDbAction --- .../autopsy/hashdatabase/AddContentToHashDbAction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java index 250d44e0a5..c92f0722cd 100755 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java @@ -121,7 +121,7 @@ public class AddContentToHashDbAction extends AbstractAction implements Presente } catch (TskCoreException ex) { Logger.getLogger(AddContentToHashDbAction.class.getName()).log(Level.SEVERE, "Error adding to hash database", ex); - JOptionPane.showMessageDialog(null, "Unable to add " + file.getName() + "to hash database.", "Add to Hash Database Error", JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(null, "Unable to add " + file.getName() + " to hash database.", "Add to Hash Database Error", JOptionPane.ERROR_MESSAGE); } } } From 6fda5b6793ea7ace50f29251574d22245b19e6d5 Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Wed, 30 Oct 2013 18:34:16 -0400 Subject: [PATCH 061/169] Fix compile error due to rename of newHashDatabase(). --- HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index e92a40be1b..3105e40296 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -79,7 +79,7 @@ public class HashDb implements Comparable { } static public HashDb createHashDatabase(String name, String databasePath, boolean useForIngest, boolean showInboxMessages, DBType type) throws TskCoreException { - HashDb database = new HashDb(SleuthkitJNI.newHashDatabase(databasePath), name, Collections.singletonList(databasePath), useForIngest, showInboxMessages, type); + HashDb database = new HashDb(SleuthkitJNI.createHashDatabase(databasePath), name, Collections.singletonList(databasePath), useForIngest, showInboxMessages, type); addToXMLFile(database); return database; } From 6407d3835f998ef2463f9c1686467f9cbcbdadb2 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 31 Oct 2013 09:56:25 -0400 Subject: [PATCH 062/169] Interim checkin of new hash db API work --- .../AddContentToHashDbAction.java | 2 +- .../autopsy/hashdatabase/HashDb.java | 91 ++++++-------- .../HashDbImportDatabaseDialog.java | 114 +++++++----------- .../hashdatabase/HashDbIngestModule.java | 4 +- .../hashdatabase/HashDbManagementPanel.java | 9 +- .../autopsy/hashdatabase/HashDbXML.java | 5 +- .../autopsy/hashdatabase/ModalNoButtons.form | 1 + 7 files changed, 92 insertions(+), 134 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java index c92f0722cd..1715c15e52 100755 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java @@ -117,7 +117,7 @@ public class AddContentToHashDbAction extends AbstractAction implements Presente String md5Hash = file.getMd5Hash(); if (null != md5Hash) { try { - database.addContentHash(file); + database.addToHashDatabase(file); } catch (TskCoreException ex) { Logger.getLogger(AddContentToHashDbAction.class.getName()).log(Level.SEVERE, "Error adding to hash database", ex); diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index e92a40be1b..d993eb2ff6 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -36,16 +36,12 @@ import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskException; /** - * Hash database representation of NSRL and Known Bad hash databases - * with indexing capability - * + * Instances of this class represent known file hash set databases. */ public class HashDb implements Comparable { - enum EVENT {INDEXING_DONE }; private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); - public enum DBType{ NSRL("NSRL"), KNOWN_BAD("Known Bad"); @@ -65,7 +61,7 @@ public class HashDb implements Comparable { private static final String INDEX_SUFFIX_OLD = "-md5.idx"; private String name; - private List databasePaths; // TODO: Only need a single path, may only need to store handle + private String databasePath; private boolean useForIngest; private boolean showInboxMessages; private boolean indexing; @@ -73,20 +69,20 @@ public class HashDb implements Comparable { private int handle; static public HashDb openHashDatabase(String name, String databasePath, boolean useForIngest, boolean showInboxMessages, DBType type) throws TskCoreException { - HashDb database = new HashDb(SleuthkitJNI.openHashDatabase(databasePath), name, Collections.singletonList(databasePath), useForIngest, showInboxMessages, type); + HashDb database = new HashDb(SleuthkitJNI.openHashDatabase(databasePath), name, databasePath, useForIngest, showInboxMessages, type); addToXMLFile(database); return database; } static public HashDb createHashDatabase(String name, String databasePath, boolean useForIngest, boolean showInboxMessages, DBType type) throws TskCoreException { - HashDb database = new HashDb(SleuthkitJNI.newHashDatabase(databasePath), name, Collections.singletonList(databasePath), useForIngest, showInboxMessages, type); + HashDb database = new HashDb(SleuthkitJNI.createHashDatabase(databasePath), name, databasePath, useForIngest, showInboxMessages, type); addToXMLFile(database); return database; } static private void addToXMLFile(HashDb database) { HashDbXML xmlFileManager = HashDbXML.getCurrent(); - if (database.getDbType() == HashDb.DBType.NSRL) { + if (database.getDbType() == DBType.NSRL) { xmlFileManager.setNSRLSet(database); } else { @@ -106,10 +102,10 @@ public class HashDb implements Comparable { return updateableDbs; } - private HashDb(int handle, String name, List databasePaths, boolean useForIngest, boolean showInboxMessages, DBType type) { + private HashDb(int handle, String name, String databasePath, boolean useForIngest, boolean showInboxMessages, DBType type) { this.handle = handle; this.name = name; - this.databasePaths = databasePaths; + this.databasePath = databasePath; this.useForIngest = useForIngest; this.showInboxMessages = showInboxMessages; this.type = type; @@ -121,8 +117,9 @@ public class HashDb implements Comparable { return true; } - public void addContentHash(Content content) throws TskCoreException { - // @@@ This only works for AbstractFiles at present. + public void addToHashDatabase(Content content) throws TskCoreException { + // TODO: This only works for AbstractFiles at present. Change when Content + // can be queried for hashes. if (content instanceof AbstractFile) { AbstractFile file = (AbstractFile)content; if (null != file.getMd5Hash()) { @@ -155,8 +152,8 @@ public class HashDb implements Comparable { return name; } - List getDatabasePaths() { - return databasePaths; + String getDatabasePath() { + return databasePath; } void setUseForIngest(boolean useForIngest) { @@ -167,18 +164,6 @@ public class HashDb implements Comparable { this.showInboxMessages = showInboxMessages; } - void setName(String name) { - this.name = name; - } - - void setDatabasePaths(List databasePaths) { - this.databasePaths = databasePaths; - } - - void setDbType(DBType type) { - this.type = type; - } - /** * Checks if the database exists. * @return true if a file exists at the database path, else false @@ -193,9 +178,11 @@ public class HashDb implements Comparable { */ boolean indexExists() { try { - return hasIndex(databasePaths.get(0)); // TODO: support multiple paths - } catch (TskException ex) { - Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Error checking if index exists.", ex); + // RJCTODO: Replace with new API call. + return SleuthkitJNI.lookupIndexExists(databasePath); + } + catch (TskException ex) { + Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Error checking if index exists", ex); return false; } } @@ -205,7 +192,7 @@ public class HashDb implements Comparable { * @return a File initialized with the database path */ File databaseFile() { - return new File(databasePaths.get(0)); // TODO: don't support multiple paths + return new File(databasePath); } /** @@ -214,7 +201,7 @@ public class HashDb implements Comparable { * path */ File indexFile() { - return new File(toIndexPath(databasePaths.get(0))); // TODO: don't support multiple paths + return new File(toIndexPath(databasePath)); } /** @@ -224,6 +211,7 @@ public class HashDb implements Comparable { * file, else false */ boolean isOutdated() { + // RJCTODO: Need to adapt this to set status correctly File i = indexFile(); File db = databaseFile(); @@ -243,19 +231,25 @@ public class HashDb implements Comparable { * @return IndexStatus enum according to their definitions */ IndexStatus status() { - boolean i = this.indexExists(); - boolean db = this.databaseExists(); - - if(indexing) + // RJCTODO: Fix this using new API + + if (indexing) { return IndexStatus.INDEXING; - if (i) { - if (db) { + } + +// if (SleuthkitJNI.hashDatabaseIsLookupIndexOnly(handle)) { +// return databaseExists() ? IndexStatus.NO_INDEX : IndexStatus.NONE; +// } + + if (indexExists()) { + if (databaseExists()) { return this.isOutdated() ? IndexStatus.INDEX_OUTDATED : IndexStatus.INDEX_CURRENT; - } else { + } + else { return IndexStatus.NO_DB; } } else { - return db ? IndexStatus.NO_INDEX : IndexStatus.NONE; + return databaseExists() ? IndexStatus.NO_INDEX : IndexStatus.NONE; } } @@ -337,32 +331,21 @@ public class HashDb implements Comparable { return this.name.compareTo(o.name); } - /* Thread that creates a database's index */ private class CreateIndex extends SwingWorker { - private ProgressHandle progress; - CreateIndex(){}; + CreateIndex() { + }; @Override protected Object doInBackground() throws Exception { progress = ProgressHandleFactory.createHandle("Indexing " + name); - - /** We need proper cancel support in TSK to make the task cancellable - new Cancellable() { - Override - public boolean cancel() { - return CreateIndex.this.cancel(true); - } - }); - */ progress.start(); progress.switchToIndeterminate(); - SleuthkitJNI.createLookupIndex(databasePaths.get(0)); + SleuthkitJNI.createLookupIndex(databasePath); return null; } - /* clean up or start the worker threads */ @Override protected void done() { indexing = false; diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java index 910cd6cacb..99428cc10e 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011 - 2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,35 +16,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.hashdatabase; import java.awt.Dimension; import java.awt.Toolkit; import java.io.File; import java.io.IOException; -import java.util.Arrays; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.filechooser.FileNameExtensionFilter; import org.sleuthkit.autopsy.hashdatabase.HashDb.DBType; -import org.sleuthkit.datamodel.SleuthkitJNI; -import org.sleuthkit.datamodel.TskException; +import org.sleuthkit.datamodel.TskCoreException; /** - * - * @author dfickling + * Instances of this class allow a user to select a hash database for import. */ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { + private JFileChooser fileChooser = new JFileChooser(); + private HashDb importedHashDatabase; - private JFileChooser fc = new JFileChooser(); - private String databaseName; - private static final Logger logger = Logger.getLogger(HashDbImportDatabaseDialog.class.getName()); - /** - * Creates new form HashDbImportDatabaseDialog - */ HashDbImportDatabaseDialog() { super(new javax.swing.JFrame(), "Import Hash Database", true); setResizable(false); @@ -53,27 +45,20 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { } void customizeComponents() { - fc.setDragEnabled(false); - fc.setFileSelectionMode(JFileChooser.FILES_ONLY); + fileChooser.setDragEnabled(false); + fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); String[] EXTENSION = new String[] { "txt", "kdb", "idx", "hash", "Hash", "hsh"}; - FileNameExtensionFilter filter = new FileNameExtensionFilter( - "Hash Database File", EXTENSION); - fc.setFileFilter(filter); - fc.setMultiSelectionEnabled(false); + FileNameExtensionFilter filter = new FileNameExtensionFilter("Hash Database File", EXTENSION); + fileChooser.setFileFilter(filter); + fileChooser.setMultiSelectionEnabled(false); } - String display() { + HashDb display() { + // Center and display the dialog. Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); - - // set the popUp window / JFrame - int w = this.getSize().width; - int h = this.getSize().height; - - // set the location of the popUp Window on the center of the screen - setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2); - + setLocation((screenDimension.width - getSize().width) / 2, (screenDimension.height - getSize().height) / 2); this.setVisible(true); - return databaseName; + return importedHashDatabase; } /** @@ -227,36 +212,21 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { }// //GEN-END:initComponents private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed - String oldText = databasePathTextField.getText(); - // set the current directory of the FileChooser if the databasePath Field is valid - File currentDir = new File(oldText); + File currentDir = new File(databasePathTextField.getText()); if (currentDir.exists()) { - fc.setCurrentDirectory(currentDir); + fileChooser.setCurrentDirectory(currentDir); } - int retval = fc.showOpenDialog(this); + int retval = fileChooser.showOpenDialog(this); if (retval == JFileChooser.APPROVE_OPTION) { - File f = fc.getSelectedFile(); + File f = fileChooser.getSelectedFile(); try { String filePath = f.getCanonicalPath(); - if (HashDb.isIndexPath(filePath)) { - filePath = HashDb.toDatabasePath(filePath); - } - String derivedName = SleuthkitJNI.getDatabaseName(filePath); databasePathTextField.setText(filePath); - databaseNameTextField.setText(derivedName); - if (derivedName.toLowerCase().contains("nsrl")) { - nsrlRadioButton.setSelected(true); - nsrlRadioButtonActionPerformed(null); - } - } catch (IOException ex) { - logger.log(Level.WARNING, "Couldn't get selected file path.", ex); - } catch (TskException ex) { - logger.log(Level.WARNING, "Invalid database: ", ex); - int tryAgain = JOptionPane.showConfirmDialog(this, "Database file you chose cannot be opened.\n" + "If it was just an index, please try to recreate it from the database.\n" + "Would you like to choose another database?", "Invalid File", JOptionPane.YES_NO_OPTION); - if (tryAgain == JOptionPane.YES_OPTION) { - browseButtonActionPerformed(evt); - } - } + databaseNameTextField.setText(HashDb.toDatabasePath(filePath)); + } + catch (IOException ex) { + Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.WARNING, "Failed to get path of selected file", ex); + } } }//GEN-LAST:event_browseButtonActionPerformed @@ -279,46 +249,48 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { JOptionPane.showMessageDialog(this, "Database path cannot be empty"); return; } + if(databaseNameTextField.getText().isEmpty()) { - JOptionPane.showMessageDialog(this, "Database name cannot be empty"); + JOptionPane.showMessageDialog(this, "Database display name cannot be empty"); return; } + + String filePath; try { - File db = new File(databasePathTextField.getText()); - File idx = new File(databasePathTextField.getText() + ".kdb"); - File idx_old = new File(databasePathTextField.getText() + "-md5.idx"); - if (!db.exists() && !idx.exists() && !idx_old.exists()) { + File file = new File(databasePathTextField.getText()); + if (!file.exists()) { JOptionPane.showMessageDialog(this, "Selected file does not exist"); return; } - String path = db.getCanonicalPath(); - SleuthkitJNI.getDatabaseName(path); - } catch (Exception ex) { + filePath = file.getCanonicalPath(); + } + catch (IOException ex) { + Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.WARNING, "Invalid database: ", ex); JOptionPane.showMessageDialog(this, "Database file you chose cannot be opened.\n" + "If it was just an index, please try to recreate it from the database"); return; } + DBType type; - if(nsrlRadioButton.isSelected()) { + if (nsrlRadioButton.isSelected()) { type = DBType.NSRL; - } else { + } + else { type = DBType.KNOWN_BAD; } - try - { - HashDb.openHashDatabase(databaseNameTextField.getText(), databasePathTextField.getText(), useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); - } catch (TskException ex) { - logger.log(Level.WARNING, "Invalid database: ", ex); + try { + importedHashDatabase = HashDb.openHashDatabase(databaseNameTextField.getText(), filePath, useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); + } + catch (TskCoreException ex) { + Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.WARNING, "Invalid database: ", ex); JOptionPane.showMessageDialog(this, "Database file you chose cannot be opened.\n" + "If it was just an index, please try to recreate it from the database"); return; } - - databaseName = databaseNameTextField.getText(); + this.dispose(); }//GEN-LAST:event_okButtonActionPerformed private void useForIngestCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useForIngestCheckboxActionPerformed - // TODO add your handling code here: }//GEN-LAST:event_useForIngestCheckboxActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java index 5d83630b62..dae714a6db 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java @@ -99,14 +99,14 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { if (nsrl != null && nsrl.getUseForIngest() && IndexStatus.isIngestible(nsrl.status())) { nsrlIsSet = true; this.nsrlSet = nsrl; - nsrlPointer = skCase.setNSRLDatabase(nsrl.getDatabasePaths().get(0)); + nsrlPointer = skCase.setNSRLDatabase(nsrl.getDatabasePath()); } for (HashDb db : hdbxml.getKnownBadSets()) { IndexStatus status = db.status(); if (db.getUseForIngest() && IndexStatus.isIngestible(status)) { knownBadIsSet = true; - int ret = skCase.addKnownBadDatabase(db.getDatabasePaths().get(0)); // TODO: support multiple paths + int ret = skCase.addKnownBadDatabase(db.getDatabasePath()); knownBadSets.put(ret, db); } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java index 76ad80bbd9..812b6a3849 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java @@ -110,7 +110,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP } setButtonFromIndexStatus(this.indexButton, this.hashDbIndexStatusLabel, status); - String shortenPath = db.getDatabasePaths().get(0); + String shortenPath = db.getDatabasePath(); this.hashDbLocationLabel.setToolTipText(shortenPath); if(shortenPath.length() > 50){ shortenPath = shortenPath.substring(0, 10 + shortenPath.substring(10).indexOf(File.separator) + 1) + "..." + @@ -633,10 +633,11 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP private javax.swing.JLabel typeLabel; private javax.swing.JCheckBox useForIngestCheckbox; // End of variables declaration//GEN-END:variables + private void importHashSet(java.awt.event.ActionEvent evt) { - String name = new HashDbImportDatabaseDialog().display(); - if(name != null) { - hashSetTableModel.selectRowByName(name); + HashDb hashDb = new HashDbImportDatabaseDialog().display(); + if (hashDb != null) { + hashSetTableModel.selectRowByName(hashDb.getName()); } resync(); } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java index e8f0ff8bee..fcff2bf385 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.hashdatabase; import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.logging.Level; import javax.swing.JFileChooser; @@ -205,7 +206,7 @@ public class HashDbXML { for (HashDb set : knownBadSets) { String useForIngest = Boolean.toString(set.getUseForIngest()); String showInboxMessages = Boolean.toString(set.getShowInboxMessages()); - List paths = set.getDatabasePaths(); + List paths = Collections.singletonList(set.getDatabasePath()); String type = DBType.KNOWN_BAD.toString(); Element setEl = doc.createElement(SET_EL); @@ -227,7 +228,7 @@ public class HashDbXML { if(nsrlSet != null) { String useForIngest = Boolean.toString(nsrlSet.getUseForIngest()); String showInboxMessages = Boolean.toString(nsrlSet.getShowInboxMessages()); - List paths = nsrlSet.getDatabasePaths(); + List paths = Collections.singletonList(nsrlSet.getDatabasePath()); String type = DBType.NSRL.toString(); Element setEl = doc.createElement(SET_EL); diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.form index df913c59e1..7ed52bedf9 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.form @@ -17,6 +17,7 @@ + From e7824e879fbe71f945995dcf6cd7040d4c4e4495 Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Thu, 31 Oct 2013 16:52:24 -0400 Subject: [PATCH 063/169] Added new regression test for HashDB JNI operations. --- .../autopsy/testing/RegressionTest.java | 42 ++++++++++++++++++- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java b/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java index b7c798e4ea..af3ebc35c6 100644 --- a/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java +++ b/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java @@ -60,6 +60,9 @@ import org.netbeans.junit.NbModuleSuite; import org.openide.util.Exceptions; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.keywordsearch.*; +import org.sleuthkit.datamodel.SleuthkitJNI; +import org.sleuthkit.datamodel.TskData; +import org.sleuthkit.datamodel.TskException; /** * This test expects the following system properties to be set: img_path: The @@ -93,7 +96,8 @@ public class RegressionTest extends TestCase { NbModuleSuite.Configuration conf = NbModuleSuite.createConfiguration(RegressionTest.class). clusters(".*"). enableModules(".*"); - conf = conf.addTest("testNewCaseWizardOpen", + conf = conf.addTest("testHashDbJni", + "testNewCaseWizardOpen", "testNewCaseWizard", "testStartAddDataSource", "testConfigureIngest1", @@ -103,7 +107,8 @@ public class RegressionTest extends TestCase { "testAddSourceWizard1", "testIngest", "testGenerateReportToolbar", - "testGenerateReportButton"); + "testGenerateReportButton" + ); return NbModuleSuite.create(conf); @@ -125,6 +130,39 @@ public class RegressionTest extends TestCase { public void tearDown() { } + public void testHashDbJni() { + logger.info("HashDb JNI"); + try + { + String hashfn = "regtestHash.kdb"; + String md5hash = "b8c51089ebcdf9f11154a021438f5bd6"; + String md5hash2 = "cb4aca35f3fd54aacf96da9cd9acadb8"; + String md5hashBad = "35b299c6fcf47ece375b3221bdc16969"; + + logger.info("Creating hash db " + hashfn); + int handle = SleuthkitJNI.createHashDatabase(hashfn); + + logger.info("Adding hash " + md5hash); + SleuthkitJNI.addToHashDatabase("", md5hash, "", "", handle); + + logger.info("Adding hash " + md5hash2); + SleuthkitJNI.addToHashDatabase("", md5hash2, "", "", handle); + + logger.info("Querying for known hash " + md5hash); + TskData.FileKnown k = SleuthkitJNI.lookupInHashDatabase(md5hash, handle); + logger.info("Query result: " + k.toString()); + + logger.info("Querying for unknown hash " + md5hashBad); + TskData.FileKnown k2 = SleuthkitJNI.lookupInHashDatabase(md5hashBad, handle); + logger.info("Query result: " + k2.toString()); + + } catch (TskException ex) { + logger.log(Level.WARNING, "Database creation error: ", ex); + logger.info("A TskException occurred."); + return; + } + } + public void testNewCaseWizardOpen() { logger.info("New Case"); NbDialogOperator nbdo = new NbDialogOperator("Welcome"); From a3d5c123450f6551b21c1ff6d2d2888f4d1f7305 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 31 Oct 2013 21:02:31 -0400 Subject: [PATCH 064/169] Interim checkin --- .../AddContentToHashDbAction.java | 6 +- .../HashDatabaseOptionsPanelController.java | 2 +- .../autopsy/hashdatabase/HashDb.java | 341 +++++++----------- .../HashDbCreateDatabaseDialog.java | 20 +- .../HashDbImportDatabaseDialog.java | 10 +- .../hashdatabase/HashDbIngestModule.java | 22 +- .../hashdatabase/HashDbManagementPanel.java | 120 +++--- .../hashdatabase/HashDbSimplePanel.java | 80 ++-- .../autopsy/hashdatabase/HashDbXML.java | 242 +++++++++---- .../autopsy/hashdatabase/IndexStatus.java | 28 +- .../autopsy/hashdatabase/ModalNoButtons.java | 4 +- 11 files changed, 423 insertions(+), 452 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java index 1715c15e52..ca4d481097 100755 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java @@ -104,11 +104,11 @@ public class AddContentToHashDbAction extends AbstractAction implements Presente // Get the current set of updateable hash databases and add each // one as a menu item. - List hashDatabases = HashDbXML.getCurrent().getKnownBadSets(); + List hashDatabases = HashDbXML.getInstance().getKnownBadSets(); if (!hashDatabases.isEmpty()) { - for (final HashDb database : HashDbXML.getCurrent().getKnownBadSets()) { + for (final HashDb database : HashDbXML.getInstance().getKnownBadSets()) { if (database.isUpdateable()) { - JMenuItem databaseItem = add(database.getName()); + JMenuItem databaseItem = add(database.getDisplayName()); databaseItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDatabaseOptionsPanelController.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDatabaseOptionsPanelController.java index 2492db7d5f..7b81b5619f 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDatabaseOptionsPanelController.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDatabaseOptionsPanelController.java @@ -55,7 +55,7 @@ public final class HashDatabaseOptionsPanelController extends OptionsPanelContro @Override public void cancel() { // Reset the XML on cancel - HashDbXML.getCurrent().reload(); + HashDbXML.getInstance().reload(); } @Override diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index d993eb2ff6..e791f3caac 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -20,108 +20,92 @@ package org.sleuthkit.autopsy.hashdatabase; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; -import java.io.File; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.logging.Level; import javax.swing.SwingWorker; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; -import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SleuthkitJNI; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.datamodel.TskException; /** * Instances of this class represent known file hash set databases. */ +// TODO: Make this an inner class of a rewritten HashDbXML, and give it a private constructor. public class HashDb implements Comparable { - enum EVENT {INDEXING_DONE }; - private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); + enum EVENT {INDEXING_DONE}; - public enum DBType{ - NSRL("NSRL"), KNOWN_BAD("Known Bad"); + enum KNOWN_FILES_HASH_SET_TYPE{ + NSRL("NSRL"), + KNOWN_BAD("Known Bad"); private String displayName; - private DBType(String displayName) { + private KNOWN_FILES_HASH_SET_TYPE(String displayName) { this.displayName = displayName; } - public String getDisplayName() { + String getDisplayName() { return this.displayName; } } - // Suffix added to the end of a database name to get its index file - private static final String INDEX_SUFFIX = ".kdb"; - private static final String INDEX_SUFFIX_OLD = "-md5.idx"; + private static final String INDEX_FILE_EXTENSION = ".kdb"; + private static final String LEGACY_INDEX_FILE_EXTENSION = "-md5.idx"; - private String name; + private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); + private String displayName; private String databasePath; private boolean useForIngest; private boolean showInboxMessages; - private boolean indexing; - private DBType type; + private KNOWN_FILES_HASH_SET_TYPE type; private int handle; + private boolean indexing; + private boolean acceptsUpdates = false; - static public HashDb openHashDatabase(String name, String databasePath, boolean useForIngest, boolean showInboxMessages, DBType type) throws TskCoreException { - HashDb database = new HashDb(SleuthkitJNI.openHashDatabase(databasePath), name, databasePath, useForIngest, showInboxMessages, type); - addToXMLFile(database); - return database; - } - - static public HashDb createHashDatabase(String name, String databasePath, boolean useForIngest, boolean showInboxMessages, DBType type) throws TskCoreException { - HashDb database = new HashDb(SleuthkitJNI.createHashDatabase(databasePath), name, databasePath, useForIngest, showInboxMessages, type); - addToXMLFile(database); - return database; - } - - static private void addToXMLFile(HashDb database) { - HashDbXML xmlFileManager = HashDbXML.getCurrent(); - if (database.getDbType() == DBType.NSRL) { - xmlFileManager.setNSRLSet(database); - } - else { - xmlFileManager.addKnownBadSet(database); - } - xmlFileManager.save(); - } - - static public List getUpdateableHashDatabases() { - ArrayList updateableDbs = new ArrayList<>(); - List candidateDbs = HashDbXML.getCurrent().getKnownBadSets(); - for (HashDb db : candidateDbs) { - if (db.isUpdateable()) { - updateableDbs.add(db); - } - } - return updateableDbs; - } - - private HashDb(int handle, String name, String databasePath, boolean useForIngest, boolean showInboxMessages, DBType type) { - this.handle = handle; - this.name = name; + HashDb(int handle, String name, String databasePath, boolean useForIngest, boolean showInboxMessages, KNOWN_FILES_HASH_SET_TYPE type) { + this.displayName = name; this.databasePath = databasePath; this.useForIngest = useForIngest; this.showInboxMessages = showInboxMessages; this.type = type; + this.handle = handle; this.indexing = false; + + try { + acceptsUpdates = SleuthkitJNI.isUpdateableHashDatabase(this.handle); + } + catch (TskCoreException ex) { + // RJCTODO + acceptsUpdates = false; + } + } + + @Override + public int compareTo(HashDb o) { + return this.displayName.compareTo(o.displayName); + } + + /** + * Indicates whether the hash database accepts updates. + * @return True if the database accepts updates, false otherwise. + */ + boolean isUpdateable() { + return acceptsUpdates; } - public boolean isUpdateable() { - // RJCTODO: Complete this - return true; - } - + /** + * Adds hashes of content (if calculated) to the hash database. + * @param content The content for which the calculated hashes, if any, are to be added to the hash database. + * @throws TskCoreException + */ public void addToHashDatabase(Content content) throws TskCoreException { // TODO: This only works for AbstractFiles at present. Change when Content // can be queried for hashes. + assert content instanceof AbstractFile; if (content instanceof AbstractFile) { AbstractFile file = (AbstractFile)content; + // TODO: Add support for SHA-1 and SHA-256 hashes. if (null != file.getMd5Hash()) { SleuthkitJNI.addToHashDatabase(file.getName(), file.getMd5Hash(), "", "", handle); } @@ -135,152 +119,62 @@ public class HashDb implements Comparable { void removePropertyChangeListener(PropertyChangeListener pcl) { pcs.removePropertyChangeListener(pcl); } - - boolean getUseForIngest() { - return useForIngest; - } - - boolean getShowInboxMessages() { - return showInboxMessages; - } - - DBType getDbType() { - return type; - } - - String getName() { - return name; + + String getDisplayName() { + return displayName; } String getDatabasePath() { return databasePath; } + KNOWN_FILES_HASH_SET_TYPE getKnownType() { + return type; + } + + boolean getUseForIngest() { + return useForIngest; + } + void setUseForIngest(boolean useForIngest) { this.useForIngest = useForIngest; } + + boolean getShowInboxMessages() { + return showInboxMessages; + } void setShowInboxMessages(boolean showInboxMessages) { this.showInboxMessages = showInboxMessages; } - - /** - * Checks if the database exists. - * @return true if a file exists at the database path, else false - */ - boolean databaseExists() { - return databaseFile().exists(); - } - - /** - * Checks if Sleuth Kit can open the index for the database path. - * @return true if the index was found and opened successfully, else false - */ - boolean indexExists() { + + boolean hasLookupIndex() { try { - // RJCTODO: Replace with new API call. - return SleuthkitJNI.lookupIndexExists(databasePath); - } - catch (TskException ex) { - Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Error checking if index exists", ex); + return SleuthkitJNI.lookupIndexForHashDatabaseExists(handle); + } + catch (TskCoreException ex) { + // RJCTODO return false; } } - - /** - * Gets the database file. - * @return a File initialized with the database path - */ - File databaseFile() { - return new File(databasePath); + + boolean hasLegacyLookupIndexOnly() throws TskCoreException { + // RJCTODO: Add SleuthkitJNI call + return false; } - /** - * Gets the index file - * @return a File initialized with an index path derived from the database - * path - */ - File indexFile() { - return new File(toIndexPath(databasePath)); - } - - /** - * Checks if the index file is older than the database file - * @return true if there is are files at the index path and the database - * path, and the index file has an older modified-time than the database - * file, else false - */ - boolean isOutdated() { - // RJCTODO: Need to adapt this to set status correctly - File i = indexFile(); - File db = databaseFile(); - - return i.exists() && db.exists() && isOlderThan(i, db); + // TODO: This is a temporary expedient until HashDb becomes an inner class of HashDbXML. + void setAcceptsUpdates(boolean acceptsUpdates) { + this.acceptsUpdates = acceptsUpdates; } - /** - * Checks if the database is being indexed - */ - boolean isIndexing() { - return indexing; - } - - /** - * Returns the status of the HashDb as determined from indexExists(), - * databaseExists(), and isOutdated() - * @return IndexStatus enum according to their definitions - */ - IndexStatus status() { - // RJCTODO: Fix this using new API - - if (indexing) { - return IndexStatus.INDEXING; - } - -// if (SleuthkitJNI.hashDatabaseIsLookupIndexOnly(handle)) { -// return databaseExists() ? IndexStatus.NO_INDEX : IndexStatus.NONE; -// } - - if (indexExists()) { - if (databaseExists()) { - return this.isOutdated() ? IndexStatus.INDEX_OUTDATED : IndexStatus.INDEX_CURRENT; - } - else { - return IndexStatus.NO_DB; - } - } else { - return databaseExists() ? IndexStatus.NO_INDEX : IndexStatus.NONE; - } - } - - /** - * Tries to index the database (overwrites any existing index) - * @throws TskException if an error occurs in the SleuthKit bindings - */ - void createIndex() throws TskException { - indexing = true; - CreateIndex creator = new CreateIndex(); - creator.execute(); - } - - /** - * Checks if one file is older than an other - * @param a first file - * @param b second file - * @return true if the first file's last modified data is before the second - * file's last modified date - */ - private static boolean isOlderThan(File a, File b) { - return a.lastModified() < b.lastModified(); - } - /** * Determines if a path points to an index by checking the suffix * @param path * @return true if index */ static boolean isIndexPath(String path) { - return (path.endsWith(INDEX_SUFFIX) || path.endsWith(INDEX_SUFFIX_OLD)); + return (path.endsWith(INDEX_FILE_EXTENSION) || path.endsWith(LEGACY_INDEX_FILE_EXTENSION)); } /** @@ -289,10 +183,10 @@ public class HashDb implements Comparable { * @return */ static String toDatabasePath(String indexPath) { - if (indexPath.endsWith(INDEX_SUFFIX_OLD)) { - return indexPath.substring(0, indexPath.lastIndexOf(INDEX_SUFFIX_OLD)); + if (indexPath.endsWith(LEGACY_INDEX_FILE_EXTENSION)) { + return indexPath.substring(0, indexPath.lastIndexOf(LEGACY_INDEX_FILE_EXTENSION)); } else { - return indexPath.substring(0, indexPath.lastIndexOf(INDEX_SUFFIX)); + return indexPath.substring(0, indexPath.lastIndexOf(INDEX_FILE_EXTENSION)); } } @@ -302,35 +196,59 @@ public class HashDb implements Comparable { * @return */ static String toIndexPath(String databasePath) { - return databasePath.concat(INDEX_SUFFIX); + return databasePath.concat(INDEX_FILE_EXTENSION); + } + + boolean isIndexing() { + return indexing; } - /** - * Derives old-format index path from an database path by appending the suffix. - * @param databasePath - * @return - */ - static String toOldIndexPath(String databasePath) { - return databasePath.concat(INDEX_SUFFIX_OLD); - } - - /** - * Calls Sleuth Kit method via JNI to determine whether there is an - * index for the given path - * @param databasePath path Path for the database the index is of - * (database doesn't have to actually exist)' - * @return true if index exists - * @throws TskException if there is an error in the JNI call - */ - static boolean hasIndex(String databasePath) throws TskException { - return SleuthkitJNI.lookupIndexExists(databasePath); + IndexStatus getStatus() { + // RJCTODO: Fix this using new API + + if (indexing) { + return IndexStatus.INDEXING; + } + +// return new File(databasePath).exists(); + + +// return new File(toIndexPath(databasePath)); + + +// if (SleuthkitJNI.hashDatabaseIsLookupIndexOnly(handle)) { +// return databaseExists() ? IndexStatus.NO_INDEX : IndexStatus.NONE; +// } + +// return databasePath.concat(LEGACY_INDEX_FILE_EXTENSION); + + + // Outdated applies only to legacy databases where the legacy index file exists and is older +// File i = indexFile(); +// File db = new File(databasePath); +// +// return i.exists() && db.exists() && isOlderThan(i, db); +// +// if (indexExists()) { +// if (databaseSourceFileExists()) { +// return this.isOutdated() ? IndexStatus.INDEX_OUTDATED : IndexStatus.INDEX_CURRENT; +// } +// else { +// return IndexStatus.NO_DB; +// } +// } else { +// return databaseSourceFileExists() ? IndexStatus.NO_INDEX : IndexStatus.NONE; +// } + return IndexStatus.INDEXING; } - - @Override - public int compareTo(HashDb o) { - return this.name.compareTo(o.name); + + // Tries to index the database (overwrites any existing index) using a + // SwingWorker. + void createIndex() throws TskCoreException { + CreateIndex creator = new CreateIndex(); + creator.execute(); } - + private class CreateIndex extends SwingWorker { private ProgressHandle progress; @@ -339,10 +257,11 @@ public class HashDb implements Comparable { @Override protected Object doInBackground() throws Exception { - progress = ProgressHandleFactory.createHandle("Indexing " + name); + indexing = true; + progress = ProgressHandleFactory.createHandle("Indexing " + displayName); progress.start(); progress.switchToIndeterminate(); - SleuthkitJNI.createLookupIndex(databasePath); + SleuthkitJNI.createLookupIndexForHashDatabase(handle); return null; } @@ -350,7 +269,7 @@ public class HashDb implements Comparable { protected void done() { indexing = false; progress.finish(); - pcs.firePropertyChange(EVENT.INDEXING_DONE.toString(), null, name); + pcs.firePropertyChange(EVENT.INDEXING_DONE.toString(), null, displayName); } } } \ No newline at end of file diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java index f17eabd0bd..43ca4be56c 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java @@ -29,8 +29,9 @@ import org.sleuthkit.autopsy.coreutils.Logger; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.filechooser.FileNameExtensionFilter; -import org.sleuthkit.autopsy.hashdatabase.HashDb.DBType; +import org.sleuthkit.autopsy.hashdatabase.HashDb.KNOWN_FILES_HASH_SET_TYPE; import org.sleuthkit.datamodel.SleuthkitJNI; +import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskException; /** @@ -40,7 +41,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { private JFileChooser fc; - private String databaseName; + private HashDb hashDb = null; private static final Logger logger = Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()); /** * Creates new form HashDbCreateDatabaseDialog @@ -78,7 +79,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { fc.setMultiSelectionEnabled(false); } - String display() { + HashDb display() { Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); // set the popUp window / JFrame @@ -89,7 +90,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2); this.setVisible(true); - return databaseName; + return hashDb; } /** @@ -296,23 +297,22 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { return; } - DBType type; + KNOWN_FILES_HASH_SET_TYPE type; if(nsrlRadioButton.isSelected()) { - type = DBType.NSRL; + type = KNOWN_FILES_HASH_SET_TYPE.NSRL; } else { - type = DBType.KNOWN_BAD; + type = KNOWN_FILES_HASH_SET_TYPE.KNOWN_BAD; } try { - HashDb db = HashDb.createHashDatabase(databaseNameTextField.getText(), databasePathTextField.getText(), useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); - } catch (TskException ex) { + hashDb = HashDbXML.getInstance().createHashDatabase(databaseNameTextField.getText(), databasePathTextField.getText(), useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); + } catch (TskCoreException ex) { logger.log(Level.WARNING, "Database creation error: ", ex); JOptionPane.showMessageDialog(this, "Database file cannot be created.\n"); return; } - databaseName = databaseNameTextField.getText(); this.dispose(); }//GEN-LAST:event_okButtonActionPerformed diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java index 99428cc10e..f841d77101 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java @@ -27,7 +27,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.filechooser.FileNameExtensionFilter; -import org.sleuthkit.autopsy.hashdatabase.HashDb.DBType; +import org.sleuthkit.autopsy.hashdatabase.HashDb.KNOWN_FILES_HASH_SET_TYPE; import org.sleuthkit.datamodel.TskCoreException; /** @@ -270,16 +270,16 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { return; } - DBType type; + KNOWN_FILES_HASH_SET_TYPE type; if (nsrlRadioButton.isSelected()) { - type = DBType.NSRL; + type = KNOWN_FILES_HASH_SET_TYPE.NSRL; } else { - type = DBType.KNOWN_BAD; + type = KNOWN_FILES_HASH_SET_TYPE.KNOWN_BAD; } try { - importedHashDatabase = HashDb.openHashDatabase(databaseNameTextField.getText(), filePath, useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); + importedHashDatabase = HashDbXML.getInstance().importHashDatabase(databaseNameTextField.getText(), filePath, useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); } catch (TskCoreException ex) { Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.WARNING, "Invalid database: ", ex); diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java index dae714a6db..d4a1a2506f 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java @@ -87,23 +87,23 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { services = IngestServices.getDefault(); this.skCase = Case.getCurrentCase().getSleuthkitCase(); try { - HashDbXML hdbxml = HashDbXML.getCurrent(); + HashDbXML hdbxml = HashDbXML.getInstance(); nsrlSet = null; knownBadSets.clear(); - skCase.clearLookupDatabases(); + hdbxml.closeHashDatabases(); nsrlIsSet = false; knownBadIsSet = false; calcHashesIsSet = hdbxml.getCalculate(); HashDb nsrl = hdbxml.getNSRLSet(); - if (nsrl != null && nsrl.getUseForIngest() && IndexStatus.isIngestible(nsrl.status())) { + if (nsrl != null && nsrl.getUseForIngest() && IndexStatus.isIngestible(nsrl.getStatus())) { nsrlIsSet = true; this.nsrlSet = nsrl; nsrlPointer = skCase.setNSRLDatabase(nsrl.getDatabasePath()); } for (HashDb db : hdbxml.getKnownBadSets()) { - IndexStatus status = db.status(); + IndexStatus status = db.getStatus(); if (db.getUseForIngest() && IndexStatus.isIngestible(status)) { knownBadIsSet = true; int ret = skCase.addKnownBadDatabase(db.getDatabasePath()); @@ -140,7 +140,7 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { detailsSb.append("

Databases Used:

\n
    "); for (HashDb db : knownBadSets.values()) { - detailsSb.append("
  • ").append(db.getName()).append("
  • \n"); + detailsSb.append("
  • ").append(db.getDisplayName()).append("
  • \n"); } detailsSb.append("
"); @@ -151,7 +151,7 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { private void clearHashDatabaseHandles() { try { - skCase.clearLookupDatabases(); + HashDbXML.getInstance().closeHashDatabases(); } catch (TskCoreException ex) { logger.log(Level.WARNING, "Error clearing hash database handles. ", ex); } @@ -218,7 +218,7 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { @Override public javax.swing.JPanel getSimpleConfiguration(String context) { - HashDbXML.getCurrent().reload(); + HashDbXML.getInstance().reload(); return new HashDbSimplePanel(); } @@ -243,7 +243,7 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { @Override public void saveSimpleConfiguration() { - HashDbXML.getCurrent().save(); + HashDbXML.getInstance().save(); } private void processBadFile(AbstractFile abstractFile, String md5Hash, String hashSetName, boolean showInboxMessage) { @@ -343,7 +343,7 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { "Error encountered while setting known bad state for " + name + ".")); ret = ProcessResult.ERROR; } - String hashSetName = entry.getValue().getName(); + String hashSetName = entry.getValue().getDisplayName(); processBadFile(file, md5Hash, hashSetName, entry.getValue().getShowInboxMessages()); } } @@ -379,9 +379,9 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { public ArrayList getKnownBadSetNames() { ArrayList knownBadSetNames = new ArrayList<>(); - HashDbXML hdbxml = HashDbXML.getCurrent(); + HashDbXML hdbxml = HashDbXML.getInstance(); for (HashDb db : hdbxml.getKnownBadSets()) { - knownBadSetNames.add(db.getName()); + knownBadSetNames.add(db.getDisplayName()); } return knownBadSetNames; } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java index 812b6a3849..693d01f3b2 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java @@ -43,6 +43,7 @@ import javax.swing.table.TableCellRenderer; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.datamodel.TskCoreException; final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsPanel { @@ -77,7 +78,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP if (!listSelectionModel.isSelectionEmpty()) { int index = listSelectionModel.getMinSelectionIndex(); listSelectionModel.setSelectionInterval(index, index); - HashDbXML loader = HashDbXML.getCurrent(); + HashDbXML loader = HashDbXML.getInstance(); HashDb current = loader.getAllSets().get(index); initUI(current); } else { @@ -90,20 +91,20 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP private void initUI(HashDb db) { boolean useForIngestEnabled = db != null && !ingestRunning; boolean useForIngestSelected = db != null && db.getUseForIngest(); - boolean showInboxMessagesEnabled = db != null && !ingestRunning && useForIngestSelected && db.getDbType().equals(HashDb.DBType.KNOWN_BAD); + boolean showInboxMessagesEnabled = db != null && !ingestRunning && useForIngestSelected && db.getKnownType().equals(HashDb.KNOWN_FILES_HASH_SET_TYPE.KNOWN_BAD); boolean showInboxMessagesSelected = db != null && db.getShowInboxMessages(); boolean deleteButtonEnabled = db != null && !ingestRunning; boolean importButtonEnabled = !ingestRunning; if (db == null) { - setButtonFromIndexStatus(this.indexButton, this.hashDbIndexStatusLabel, IndexStatus.NONE); + setButtonFromIndexStatus(this.indexButton, this.hashDbIndexStatusLabel, IndexStatus.NO_INDEX); this.hashDbLocationLabel.setText("No database selected"); this.hashDbNameLabel.setText("No database selected"); this.hashDbIndexStatusLabel.setText("No database selected"); this.hashDbTypeLabel.setText("No database selected"); } else { //check if dn in indexing state - String dbName = db.getName(); - IndexStatus status = db.status(); + String dbName = db.getDisplayName(); + IndexStatus status = db.getStatus(); Boolean state = indexingState.get(dbName); if (state != null && state.equals(Boolean.TRUE) ) { status = IndexStatus.INDEXING; @@ -117,8 +118,8 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP shortenPath.substring((shortenPath.length() - 20) + shortenPath.substring(shortenPath.length() - 20).indexOf(File.separator)); } this.hashDbLocationLabel.setText(shortenPath); - this.hashDbNameLabel.setText(db.getName()); - this.hashDbTypeLabel.setText(db.getDbType().getDisplayName()); + this.hashDbNameLabel.setText(db.getDisplayName()); + this.hashDbTypeLabel.setText(db.getKnownType().getDisplayName()); } this.useForIngestCheckbox.setSelected(useForIngestSelected); this.useForIngestCheckbox.setEnabled(useForIngestEnabled); @@ -142,7 +143,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP int selection = getSelection(); if(selection != -1) { - initUI(HashDbXML.getCurrent().getAllSets().get(selection)); + initUI(HashDbXML.getInstance().getAllSets().get(selection)); } } @@ -397,7 +398,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP private void indexButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_indexButtonActionPerformed int selected = getSelection(); - final HashDb current = HashDbXML.getCurrent().getAllSets().get(selected); + final HashDb current = HashDbXML.getInstance().getAllSets().get(selected); current.addPropertyChangeListener(new PropertyChangeListener() { @Override @@ -406,19 +407,19 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP //update tracking of indexing status indexingState.put((String)evt.getNewValue(), Boolean.FALSE); - setButtonFromIndexStatus(indexButton, hashDbIndexStatusLabel, current.status()); + setButtonFromIndexStatus(indexButton, hashDbIndexStatusLabel, current.getStatus()); resync(); } } }); - indexingState.put(current.getName(), Boolean.TRUE); + indexingState.put(current.getDisplayName(), Boolean.TRUE); ModalNoButtons singleMNB = new ModalNoButtons(this, new Frame(), current); //Modal reference, to be removed later singleMNB.setLocationRelativeTo(null); singleMNB.setVisible(true); singleMNB.setModal(true); //End Modal reference - indexingState.put(current.getName(), Boolean.FALSE); - setButtonFromIndexStatus(indexButton, this.hashDbIndexStatusLabel, current.status()); + indexingState.put(current.getDisplayName(), Boolean.FALSE); + setButtonFromIndexStatus(indexButton, this.hashDbIndexStatusLabel, current.getStatus()); }//GEN-LAST:event_indexButtonActionPerformed private void deleteButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteButtonActionPerformed @@ -428,15 +429,15 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) { int selected = getSelection(); - HashDbXML xmlHandle = HashDbXML.getCurrent(); + HashDbXML xmlHandle = HashDbXML.getInstance(); if (xmlHandle.getNSRLSet() != null) { if (selected == 0) { - HashDbXML.getCurrent().removeNSRLSet(); + HashDbXML.getInstance().removeNSRLSet(); } else { - HashDbXML.getCurrent().removeKnownBadSetAt(selected - 1); + HashDbXML.getInstance().removeKnownBadSetAt(selected - 1); } } else { - HashDbXML.getCurrent().removeKnownBadSetAt(selected); + HashDbXML.getInstance().removeKnownBadSetAt(selected); } hashSetTableModel.resync(); } @@ -445,15 +446,15 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP private void hashSetTableKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_hashSetTableKeyPressed if (evt.getKeyCode() == KeyEvent.VK_DELETE) { int selected = getSelection(); - HashDbXML xmlHandle = HashDbXML.getCurrent(); + HashDbXML xmlHandle = HashDbXML.getInstance(); if (xmlHandle.getNSRLSet() != null) { if (selected == 0) { - HashDbXML.getCurrent().removeNSRLSet(); + HashDbXML.getInstance().removeNSRLSet(); } else { - HashDbXML.getCurrent().removeKnownBadSetAt(selected - 1); + HashDbXML.getInstance().removeKnownBadSetAt(selected - 1); } } else { - HashDbXML.getCurrent().removeKnownBadSetAt(selected); + HashDbXML.getInstance().removeKnownBadSetAt(selected); } } hashSetTableModel.resync(); @@ -461,43 +462,43 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP private void useForIngestCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useForIngestCheckboxActionPerformed int selected = getSelection(); - HashDbXML xmlHandle = HashDbXML.getCurrent(); + HashDbXML xmlHandle = HashDbXML.getInstance(); if (xmlHandle.getNSRLSet() != null) { if (selected == 0) { - HashDb current = HashDbXML.getCurrent().getNSRLSet(); + HashDb current = HashDbXML.getInstance().getNSRLSet(); current.setUseForIngest(useForIngestCheckbox.isSelected()); - HashDbXML.getCurrent().setNSRLSet(current); + HashDbXML.getInstance().setNSRLSet(current); } else { - HashDb current = HashDbXML.getCurrent().getKnownBadSets().remove(selected - 1); + HashDb current = HashDbXML.getInstance().getKnownBadSets().remove(selected - 1); current.setUseForIngest(useForIngestCheckbox.isSelected()); - HashDbXML.getCurrent().addKnownBadSet(selected - 1, current); + HashDbXML.getInstance().addKnownBadSet(selected - 1, current); this.showInboxMessagesCheckBox.setEnabled(useForIngestCheckbox.isSelected()); } } else { - HashDb current = HashDbXML.getCurrent().getKnownBadSets().remove(selected); + HashDb current = HashDbXML.getInstance().getKnownBadSets().remove(selected); current.setUseForIngest(useForIngestCheckbox.isSelected()); - HashDbXML.getCurrent().addKnownBadSet(selected, current); + HashDbXML.getInstance().addKnownBadSet(selected, current); this.showInboxMessagesCheckBox.setEnabled(useForIngestCheckbox.isSelected()); } }//GEN-LAST:event_useForIngestCheckboxActionPerformed private void showInboxMessagesCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showInboxMessagesCheckBoxActionPerformed int selected = getSelection(); - HashDbXML xmlHandle = HashDbXML.getCurrent(); + HashDbXML xmlHandle = HashDbXML.getInstance(); if (xmlHandle.getNSRLSet() != null) { if (selected == 0) { - HashDb current = HashDbXML.getCurrent().getNSRLSet(); + HashDb current = HashDbXML.getInstance().getNSRLSet(); current.setShowInboxMessages(showInboxMessagesCheckBox.isSelected()); - HashDbXML.getCurrent().setNSRLSet(current); + HashDbXML.getInstance().setNSRLSet(current); } else { - HashDb current = HashDbXML.getCurrent().getKnownBadSets().remove(selected - 1); + HashDb current = HashDbXML.getInstance().getKnownBadSets().remove(selected - 1); current.setShowInboxMessages(showInboxMessagesCheckBox.isSelected()); - HashDbXML.getCurrent().addKnownBadSet(selected - 1, current); + HashDbXML.getInstance().addKnownBadSet(selected - 1, current); } } else { - HashDb current = HashDbXML.getCurrent().getKnownBadSets().remove(selected); + HashDb current = HashDbXML.getInstance().getKnownBadSets().remove(selected); current.setShowInboxMessages(showInboxMessagesCheckBox.isSelected()); - HashDbXML.getCurrent().addKnownBadSet(selected, current); + HashDbXML.getInstance().addKnownBadSet(selected, current); } }//GEN-LAST:event_showInboxMessagesCheckBoxActionPerformed @@ -512,7 +513,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP @Override public void load() { hashSetTable.clearSelection(); // Deselect all rows - HashDbXML.getCurrent().reload(); // Reload XML + HashDbXML.getInstance().reload(); // Reload XML initUI(null); // Update the UI hashSetTableModel.resync(); // resync the table setIngestStatus(IngestManager.getDefault().isIngestRunning()); // check if ingest is running @@ -539,7 +540,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP else if (unindexed.size() > 1){ showInvalidIndex(true, unindexed); } - HashDbXML.getCurrent().save(); + HashDbXML.getInstance().save(); } @@ -550,18 +551,18 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP * @param toRemove a list of HashDbs that are unindexed */ void removeThese(List toRemove) { - HashDbXML xmlHandle = HashDbXML.getCurrent(); + HashDbXML xmlHandle = HashDbXML.getInstance(); for (HashDb hdb : toRemove) { for (int i = 0; i < hashSetTableModel.getRowCount(); i++) { if (hashSetTableModel.getDBAt(i).equals(hdb)) { if (xmlHandle.getNSRLSet() != null) { if (i == 0) { - HashDbXML.getCurrent().removeNSRLSet(); + HashDbXML.getInstance().removeNSRLSet(); } else { - HashDbXML.getCurrent().removeKnownBadSetAt(i - 1); + HashDbXML.getInstance().removeKnownBadSetAt(i - 1); } } else { - HashDbXML.getCurrent().removeKnownBadSetAt(i); + HashDbXML.getInstance().removeKnownBadSetAt(i); } hashSetTableModel.resync(); } @@ -579,7 +580,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP String total = ""; String message; for(HashDb hdb : unindexed){ - total+= "\n" + hdb.getName(); + total+= "\n" + hdb.getDisplayName(); } if(plural){ message = "The following databases are not indexed, would you like to index them now? \n " + total; @@ -637,15 +638,15 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP private void importHashSet(java.awt.event.ActionEvent evt) { HashDb hashDb = new HashDbImportDatabaseDialog().display(); if (hashDb != null) { - hashSetTableModel.selectRowByName(hashDb.getName()); + hashSetTableModel.selectRowByName(hashDb.getDisplayName()); } resync(); } private void createHashSet(java.awt.event.ActionEvent evt) { - String name = new HashDbCreateDatabaseDialog().display(); - if(name != null) { - hashSetTableModel.selectRowByName(name); + HashDb hashDb = new HashDbCreateDatabaseDialog().display(); + if (null != hashDb) { + hashSetTableModel.selectRowByName(hashDb.getDisplayName()); } resync(); } @@ -675,7 +676,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP private class HashSetTableModel extends AbstractTableModel { - private HashDbXML xmlHandle = HashDbXML.getCurrent(); + private HashDbXML xmlHandle = HashDbXML.getInstance(); @Override public int getColumnCount() { @@ -695,18 +696,17 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP @Override public Object getValueAt(int rowIndex, int columnIndex) { if(xmlHandle.getNSRLSet() == null) { - return getDBAt(rowIndex).getName(); + return getDBAt(rowIndex).getDisplayName(); } else { - return rowIndex == 0 ? getDBAt(rowIndex).getName() + " (NSRL)" : getDBAt(rowIndex).getName(); + return rowIndex == 0 ? getDBAt(rowIndex).getDisplayName() + " (NSRL)" : getDBAt(rowIndex).getDisplayName(); } } //Internal function for determining whether a companion -md5.idx file exists private boolean indexExists(int rowIndex){ - return getDBAt(rowIndex).indexExists(); + return getDBAt(rowIndex).hasLookupIndex(); } - - + //Internal function for getting the DB at a certain index. Used as-is, as well as by dispatch from getValueAt() and indexExists() private HashDb getDBAt(int rowIndex){ if (xmlHandle.getNSRLSet() != null) { @@ -725,18 +725,18 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP HashDb NSRL = xmlHandle.getNSRLSet(); List bad = xmlHandle.getKnownBadSets(); if(NSRL != null) { - if(NSRL.getName().equals(name)) { + if(NSRL.getDisplayName().equals(name)) { setSelection(0); } else { for(int i=0; i sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,18 +16,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/* - * HashDbSimplePanel.java - * - * Created on May 7, 2012, 10:38:26 AM - */ package org.sleuthkit.autopsy.hashdatabase; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.List; -import org.sleuthkit.autopsy.coreutils.Logger; import javax.swing.JOptionPane; import javax.swing.JTable; import javax.swing.table.AbstractTableModel; @@ -35,16 +28,13 @@ import javax.swing.table.TableColumn; import org.sleuthkit.autopsy.ingest.IngestManager; /** - * - * @author dfickling + * Instances of this class are used as a file ingest module configuration panel + * by the known files hash set lookup file ingest module. */ -public class HashDbSimplePanel extends javax.swing.JPanel { - - private static final Logger logger = Logger.getLogger(HashDbSimplePanel.class.getName()); +public class HashDbSimplePanel extends javax.swing.JPanel { private HashTableModel knownBadTableModel; private HashDb nsrl; - /** Creates new form HashDbSimplePanel */ public HashDbSimplePanel() { knownBadTableModel = new HashTableModel(); initComponents(); @@ -52,12 +42,9 @@ public class HashDbSimplePanel extends javax.swing.JPanel { } private void reloadCalc() { - final HashDbXML xmlHandle = HashDbXML.getCurrent(); + final HashDbXML xmlHandle = HashDbXML.getInstance(); final HashDb nsrlDb = xmlHandle.getNSRLSet(); - final boolean nsrlUsed = - nsrlDb != null - && nsrlDb.getUseForIngest()== true - && nsrlDb.indexExists(); + final boolean nsrlUsed = nsrlDb != null && nsrlDb.getUseForIngest()== true && nsrlDb.hasLookupIndex(); final List knowns = xmlHandle.getKnownBadSets(); final boolean knownExists = !knowns.isEmpty(); boolean knownUsed = false; @@ -70,8 +57,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { } } - if(! nsrlUsed - && ! knownUsed ) { + if (!nsrlUsed && !knownUsed ) { calcHashesButton.setEnabled(true); calcHashesButton.setSelected(true); xmlHandle.setCalculate(true); @@ -83,7 +69,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { } private void customizeComponents() { - final HashDbXML xmlHandle = HashDbXML.getCurrent(); + final HashDbXML xmlHandle = HashDbXML.getInstance(); calcHashesButton.addActionListener( new ActionListener() { @Override @@ -93,8 +79,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { } else { xmlHandle.setCalculate(false); } - } - + } }); notableHashTable.setModel(knownBadTableModel); @@ -104,7 +89,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { //customize column witdhs final int width1 = jScrollPane1.getPreferredSize().width; notableHashTable.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN); - TableColumn column1 = null; + TableColumn column1; for (int i = 0; i < notableHashTable.getColumnCount(); i++) { column1 = notableHashTable.getColumnModel().getColumn(i); if (i == 0) { @@ -117,6 +102,24 @@ public class HashDbSimplePanel extends javax.swing.JPanel { reloadSets(); } + private void reloadSets() { + nsrl = HashDbXML.getInstance().getNSRLSet(); + + if (nsrl == null || nsrl.getUseForIngest() == false) { + nsrlDbLabelVal.setText("Disabled"); + } + else if (nsrl.hasLookupIndex() == false) { + nsrlDbLabelVal.setText("Disabled (No index)"); + } + else { + nsrlDbLabelVal.setText("Enabled"); + } + + reloadCalc(); + + knownBadTableModel.resync(); + } + /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is @@ -193,29 +196,9 @@ public class HashDbSimplePanel extends javax.swing.JPanel { private javax.swing.JLabel nsrlDbLabelVal; // End of variables declaration//GEN-END:variables - private void reloadSets() { - nsrl = HashDbXML.getCurrent().getNSRLSet(); - - if (nsrl == null || nsrl.getUseForIngest() == false) { - nsrlDbLabelVal.setText("Disabled"); - } - else if (nsrl.indexExists() == false) { - nsrlDbLabelVal.setText("Disabled (No index)"); - } - else { - nsrlDbLabelVal.setText("Enabled"); - } - - reloadCalc(); - - knownBadTableModel.resync(); - } - - - private class HashTableModel extends AbstractTableModel { - private HashDbXML xmlHandle = HashDbXML.getCurrent(); + private HashDbXML xmlHandle = HashDbXML.getInstance(); private void resync() { fireTableDataChanged(); @@ -245,7 +228,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { if (columnIndex == 0) { return db.getUseForIngest(); } else { - return db.getName(); + return db.getDisplayName(); } } } @@ -259,7 +242,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { public void setValueAt(Object aValue, int rowIndex, int columnIndex) { if(columnIndex == 0){ HashDb db = xmlHandle.getKnownBadSets().get(rowIndex); - if(((Boolean) getValueAt(rowIndex, columnIndex)) || IndexStatus.isIngestible(db.status())) { + if(((Boolean) getValueAt(rowIndex, columnIndex)) || IndexStatus.isIngestible(db.getStatus())) { db.setUseForIngest((Boolean) aValue); } else { JOptionPane.showMessageDialog(HashDbSimplePanel.this, "Databases must be indexed before they can be used for ingest"); @@ -272,6 +255,5 @@ public class HashDbSimplePanel extends javax.swing.JPanel { public Class getColumnClass(int c) { return getValueAt(0, c).getClass(); } - } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java index fcff2bf385..fb527ec43f 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java @@ -33,13 +33,24 @@ import javax.xml.parsers.ParserConfigurationException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.XMLUtil; -import org.sleuthkit.autopsy.hashdatabase.HashDb.DBType; +import org.sleuthkit.autopsy.hashdatabase.HashDb.KNOWN_FILES_HASH_SET_TYPE; import org.sleuthkit.datamodel.SleuthkitJNI; import org.sleuthkit.datamodel.TskCoreException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; +/** + * This class is a singleton that handles the import and creation of known files + * hash set databases, manages the instances of the databases, and provides a + * means for persisting the configuration of the hash sets. + */ +// TODO: The class needs to renamed to something like HashDbManager - its use of +// XML as a configuration persistence mechanism should be an implementation detail +// hidden from its clients. More importantly, this class should be rewritten into +// full and true encapsulation of state and behavior rather than a mixture of a +// configuration manager with something that can be manipulated like a mere data +// structure by its clients. public class HashDbXML { private static final String ROOT_EL = "hash_sets"; private static final String SET_EL = "hash_set"; @@ -63,110 +74,171 @@ public class HashDbXML { private String xmlFile; private boolean calculate; - private HashDbXML(String xmlFile) { - knownBadSets = new ArrayList<>(); - this.xmlFile = xmlFile; - } - /** - * get instance for managing the current keyword list of the application + * Gets the singleton instance of this class. */ - static synchronized HashDbXML getCurrent() { + static synchronized HashDbXML getInstance() { if (currentInstance == null) { currentInstance = new HashDbXML(CUR_HASHSET_FILE); currentInstance.reload(); } return currentInstance; } + + private HashDbXML(String xmlFile) { + knownBadSets = new ArrayList<>(); + this.xmlFile = xmlFile; + } + + /** + * Imports an existing known files hash database. + * @param displayName Name used to represent the database in user interface components. + * @param databasePath Full path to the database file to be created. The file name component of the path must have a ".kdb" extension. + * @param useForIngest A flag indicating whether or not the data base should be used during the file ingest process. + * @param showInboxMessages A flag indicating whether messages indicating lookup hits should be sent to the application in box. + * @param type The known type of the database. + * @return A HashDb object representation of the new hash database. + * @throws TskCoreException + */ + // TODO: When this class is rewritten, this method should become private. It should add the HashDb object to the appropriate internal collection + // and to the XML file, and should save the XML file. + HashDb importHashDatabase(String displayName, String databasePath, boolean useForIngest, boolean showInboxMessages, KNOWN_FILES_HASH_SET_TYPE type) throws TskCoreException { + return new HashDb(SleuthkitJNI.openHashDatabase(databasePath), displayName, databasePath, useForIngest, showInboxMessages, type); + } /** - * Get the hash sets + * Creates a new known files hash database. + * @param displayName Name used to represent the database in user interface components. + * @param databasePath Full path to the database file to be created. The file name component of the path must have a ".kdb" extension. + * @param useForIngest A flag indicating whether or not the data base should be used during the file ingest process. + * @param showInboxMessages A flag indicating whether messages indicating lookup hits should be sent to the application in box. + * @param type The known type of the database. + * @return A HashDb object representation of the opened hash database. + * @throws TskCoreException */ - public List getAllSets() { - List ret = new ArrayList<>(); - if(nsrlSet != null) { - ret.add(nsrlSet); - } - ret.addAll(knownBadSets); - return ret; + // TODO: When this class is rewritten, this method should become private. It should add the HashDb object to the appropriate internal collection + // and to the XML file, and should save the XML file. + HashDb createHashDatabase(String name, String databasePath, boolean useForIngest, boolean showInboxMessages, KNOWN_FILES_HASH_SET_TYPE type) throws TskCoreException { + return new HashDb(SleuthkitJNI.createHashDatabase(databasePath), name, databasePath, useForIngest, showInboxMessages, type); } - - /** - * Get the Known Bad sets + + /** + * Sets the configured National Software Reference Library (NSRL) known + * files hash set. Does not save the configuration. */ - public List getKnownBadSets() { - return knownBadSets; + // TODO: When this class is rewritten, the class should be responsible for saving + // the configuration rather than deferring this responsibility to its clients. + public void setNSRLSet(HashDb set) { + this.nsrlSet = set; } - + /** - * Get the NSRL set + * Gets the configured National Software Reference Library (NSRL) known files hash set. + * @return A HashDb object representing the hash set or null if an NSRL set + * has not been added to the configuration. */ public HashDb getNSRLSet() { return nsrlSet; } - - /** - * Add a known bad hash set + + /** + * Removes the configured National Software Reference Library (NSRL) known + * files hash set. Does not save the configuration. */ + // TODO: When this class is rewritten, the class should be responsible for saving + // the configuration rather than deferring this responsibility to its clients. + public void removeNSRLSet() { + this.nsrlSet = null; + } + + /** + * Adds a known bad files hash set to the configuration. Does not save the + * configuration. + */ + // TODO: When this class is rewritten, the class should be responsible for saving + // the configuration rather than deferring this responsibility to its clients. public void addKnownBadSet(HashDb set) { knownBadSets.add(set); - //save(); } - + /** - * Add a known bad hash set + * Adds a known bad files hash set to the configuration. The set is added to + * the internal known bad sets collection at the index specified by the + * caller. Note that this method does not save the configuration. */ + // TODO: This method is an OO abomination that should be discarded when this + // class is rewritten. public void addKnownBadSet(int index, HashDb set) { knownBadSets.add(index, set); - //save(); } - - /** - * Set the NSRL hash set (override old set) + + /** + * Gets the configured known bad files hash sets. + * @return A list, possibly empty, of HashDb objects representing the hash + * sets. */ - public void setNSRLSet(HashDb set) { - this.nsrlSet = set; - //save(); - } - - /** - * Remove a hash known bad set - */ - public void removeKnownBadSetAt(int index) { - knownBadSets.remove(index); - //save(); + public List getKnownBadSets() { + return Collections.unmodifiableList(knownBadSets); } /** - * Remove the NSRL database + * Removes the known bad files hash set from the internal known bad files + * hash sets collection at the specified index. Does not save the configuration. */ - public void removeNSRLSet() { - this.nsrlSet = null; - //save(); + // TODO: This method is an OO abomination that should be replaced by a proper + // remove() when this class is rewritten. Also, the class should be responsible for saving + // the configuration rather than deferring this responsibility to its clients. + public void removeKnownBadSetAt(int index) { + knownBadSets.remove(index); + } + + /** + * Gets the configured known files hash sets that accept updates. + * @return A list, possibly empty, of HashDb objects. + */ + public List getUpdateableHashSets() { + ArrayList updateableDbs = new ArrayList<>(); + for (HashDb db : knownBadSets) { + if (db.isUpdateable()) { + updateableDbs.add(db); + } + } + return Collections.unmodifiableList(updateableDbs); + } + + /** + * Gets all of the configured known files hash sets. + * @return A list, possibly empty, of HashDb objects representing the hash + * sets. + */ + public List getAllSets() { + List hashDbs = new ArrayList<>(); + if (nsrlSet != null) { + hashDbs.add(nsrlSet); + } + hashDbs.addAll(knownBadSets); + return Collections.unmodifiableList(hashDbs); } /** - * load the file or create new + * Reloads the configuration file if it exists, creates it otherwise. */ + // TODO: When this class is rewritten, the class should be responsible for saving + // the configuration rather than deferring this responsibility to its clients. public void reload() { + // TODO: This does not look like it is correct. Revisit when time permits. boolean created = false; - - //TODO clearing the list causes a bug: we lose track of the state - //whether db is being indexed, we should somehow preserve the state when loading new HashDb objects - knownBadSets.clear(); nsrlSet = null; + knownBadSets.clear(); - if (!this.setsFileExists()) { - //create new if it doesn't exist + if (!setsFileExists()) { save(); created = true; } - //load, if fails to load create new; save regardless load(); if (!created) { - //create new if failed to load save(); } } @@ -175,22 +247,27 @@ public class HashDbXML { * Sets the local variable calculate to the given boolean. * @param set the state to make calculate */ + // TODO: Does this have any use? public void setCalculate(boolean set) { this.calculate = set; - //save(); } /** * Returns the value of the local boolean calculate. * @return true if calculate is true, false otherwise */ + // TODO: Does this have any use? public boolean getCalculate() { return this.calculate; } /** - * writes out current sets file replacing the last one + * Saves the known files hash sets configuration to disk. + * @return True on success, false otherwise. */ + // TODO: When this class is rewritten, the class should be responsible for saving + // the configuration rather than deferring this responsibility to its clients. + // It looks like there is code duplication here. public boolean save() { boolean success = false; @@ -203,14 +280,15 @@ public class HashDbXML { Element rootEl = doc.createElement(ROOT_EL); doc.appendChild(rootEl); + // TODO: Remove all the multiple database paths stuff, it was a mistake. for (HashDb set : knownBadSets) { String useForIngest = Boolean.toString(set.getUseForIngest()); String showInboxMessages = Boolean.toString(set.getShowInboxMessages()); List paths = Collections.singletonList(set.getDatabasePath()); - String type = DBType.KNOWN_BAD.toString(); + String type = KNOWN_FILES_HASH_SET_TYPE.KNOWN_BAD.toString(); Element setEl = doc.createElement(SET_EL); - setEl.setAttribute(SET_NAME_ATTR, set.getName()); + setEl.setAttribute(SET_NAME_ATTR, set.getDisplayName()); setEl.setAttribute(SET_TYPE_ATTR, type); setEl.setAttribute(SET_USE_FOR_INGEST_ATTR, useForIngest); setEl.setAttribute(SET_SHOW_INBOX_MESSAGES, showInboxMessages); @@ -225,14 +303,15 @@ public class HashDbXML { rootEl.appendChild(setEl); } + // TODO: Remove all the multiple database paths stuff, it was a mistake. if(nsrlSet != null) { String useForIngest = Boolean.toString(nsrlSet.getUseForIngest()); String showInboxMessages = Boolean.toString(nsrlSet.getShowInboxMessages()); List paths = Collections.singletonList(nsrlSet.getDatabasePath()); - String type = DBType.NSRL.toString(); + String type = KNOWN_FILES_HASH_SET_TYPE.NSRL.toString(); Element setEl = doc.createElement(SET_EL); - setEl.setAttribute(SET_NAME_ATTR, nsrlSet.getName()); + setEl.setAttribute(SET_NAME_ATTR, nsrlSet.getDisplayName()); setEl.setAttribute(SET_TYPE_ATTR, type); setEl.setAttribute(SET_USE_FOR_INGEST_ATTR, useForIngest); setEl.setAttribute(SET_SHOW_INBOX_MESSAGES, showInboxMessages); @@ -246,23 +325,22 @@ public class HashDbXML { } rootEl.appendChild(setEl); } - + + // TODO: Does this have any use? String calcValue = Boolean.toString(calculate); Element setCalc = doc.createElement(SET_CALC); setCalc.setAttribute(SET_VALUE, calcValue); rootEl.appendChild(setCalc); success = XMLUtil.saveDoc(HashDbXML.class, xmlFile, ENCODING, doc); - } catch (ParserConfigurationException e) { + } + catch (ParserConfigurationException e) { logger.log(Level.SEVERE, "Error saving hash sets: can't initialize parser.", e); } return success; } - /** - * load and parse XML, then dispose - */ - public boolean load() { + private boolean load() { final Document doc = XMLUtil.loadDoc(HashDbXML.class, xmlFile, XSDFILE); if (doc == null) { return false; @@ -288,8 +366,7 @@ public class HashDbXML { Boolean showInboxMessagesBool = Boolean.parseBoolean(showInboxMessages); List paths = new ArrayList<>(); - // Parse all paths - // @@@ TODO: There is no need for more than one path. + // TODO: Remove all the multiple database paths stuff, it was a mistake. NodeList pathsNList = setEl.getElementsByTagName(PATH_EL); final int numPaths = pathsNList.getLength(); for (int j = 0; j < numPaths; ++j) { @@ -336,12 +413,15 @@ public class HashDbXML { logger.log(Level.WARNING, "No paths were set for hash_set at index {0}. Removing the database.", i); } else { - DBType typeDBType = DBType.valueOf(type); + KNOWN_FILES_HASH_SET_TYPE typeDBType = KNOWN_FILES_HASH_SET_TYPE.valueOf(type); try { - // @@@ Note that this method calls back to addKnownBadSet() or setNSRLSet(). - // In the future, this class will become an inner class of HashDb and will only handle reading and - // writing the XML file. - HashDb.openHashDatabase(name, paths.get(0), useForIngestBool, showInboxMessagesBool, typeDBType); + HashDb db = importHashDatabase(name, paths.get(0), useForIngestBool, showInboxMessagesBool, typeDBType); + if (typeDBType == KNOWN_FILES_HASH_SET_TYPE.NSRL) { + setNSRLSet(db); + } + else { + addKnownBadSet(db); + } } catch (TskCoreException ex) { Logger.getLogger(HashDbXML.class.getName()).log(Level.SEVERE, "Error opening hash database", ex); @@ -425,7 +505,13 @@ public class HashDbXML { private boolean setsFileExists() { File f = new File(xmlFile); return f.exists() && f.canRead() && f.canWrite(); - } - + } + /** + * Closes all open hash databases. + * @throws TskCoreException + */ + void closeHashDatabases() throws TskCoreException { + SleuthkitJNI.closeHashDatabases(); + } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/IndexStatus.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/IndexStatus.java index cf02a9f326..9867257b68 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/IndexStatus.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/IndexStatus.java @@ -26,29 +26,23 @@ package org.sleuthkit.autopsy.hashdatabase; enum IndexStatus { /** - * The index and database both exist, and the index is older. + * The index exists but the database does not. This indicates a text index + * without an accompanying text database. */ - INDEX_OUTDATED("WARNING: Index is older than database"), + INDEX_ONLY("Index only"), /** - * The index and database both exist, and the index is not older. + * The database exists but the index does not. This indicates a text database + * with no index. */ - INDEX_CURRENT("Database and index exist"), + NO_INDEX("No index"), /** - * The index exists but the database does not. + * The index is currently being generated. */ - NO_DB("Index exists (no database)"), + INDEXING("Index is currently being generated"), /** - * The database exists but the index does not. + * The index is generated. */ - NO_INDEX("ERROR: Index does not exist"), - /** - * Neither the index nor the database exists. - */ - NONE("ERROR: No index or database"), - /** - * The index is currently being generated - */ - INDEXING("Index is currently being generated"); + INDEXED("Indexed"); private String message; @@ -68,6 +62,6 @@ enum IndexStatus { } public static boolean isIngestible(IndexStatus status) { - return status == NO_DB || status == INDEX_CURRENT || status == INDEX_OUTDATED; + return status == INDEX_ONLY || status == INDEXED; } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java index 4a7862bea1..4d7e6f38c4 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java @@ -203,7 +203,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen */ private void indexThis() { this.INDEXING_PROGBAR.setIndeterminate(true); - currentDb = this.toIndex.getName(); + currentDb = this.toIndex.getDisplayName(); this.CURRENTDB_LABEL.setText("(" + currentDb + ")"); this.length = 1; this.CURRENTLYON_LABEL.setText("Currently indexing 1 database"); @@ -224,7 +224,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen length = this.unindexed.size(); this.INDEXING_PROGBAR.setIndeterminate(true); for (HashDb db : this.unindexed) { - currentDb = db.getName(); + currentDb = db.getDisplayName(); this.CURRENTDB_LABEL.setText("(" + currentDb + ")"); this.CURRENTLYON_LABEL.setText("Currently indexing 1 of " + length); if (!db.isIndexing()) { From 5b071ef991a6406593b06f3c645e6033aae5fd3a Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Fri, 1 Nov 2013 17:16:17 -0400 Subject: [PATCH 065/169] lookupIndexForHashDatabaseExists was renamed. --- HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index e791f3caac..de690820a9 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -150,7 +150,7 @@ public class HashDb implements Comparable { boolean hasLookupIndex() { try { - return SleuthkitJNI.lookupIndexForHashDatabaseExists(handle); + return SleuthkitJNI.hashDatabaseHasLegacyLookupIndexOnly(handle); } catch (TskCoreException ex) { // RJCTODO From f550722e6ae86fed2bfb66b9e47c02c5a69c16e9 Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Fri, 1 Nov 2013 17:17:33 -0400 Subject: [PATCH 066/169] Rename "Create Database" button to "New Database" and change icon to be consistent with new keyword list. --- .../autopsy/hashdatabase/Bundle.properties | 2 +- .../hashdatabase/HashDbManagementPanel.form | 5 +---- .../hashdatabase/HashDbManagementPanel.java | 3 +-- .../org/sleuthkit/autopsy/hashdatabase/new16.png | Bin 0 -> 1661 bytes 4 files changed, 3 insertions(+), 7 deletions(-) create mode 100644 HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/new16.png diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties index e02678bfe5..822541f5fa 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties @@ -73,4 +73,4 @@ HashDbCreateDatabaseDialog.okButton.text=OK HashDbCreateDatabaseDialog.useForIngestCheckbox.text=Enable for ingest HashDbCreateDatabaseDialog.jLabel1.text=Display name of database: HashDbCreateDatabaseDialog.databaseNameTextField.text= -HashDbManagementPanel.importButton1.text=Create Database +HashDbManagementPanel.importButton1.text=New Database diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form index 6a5753371f..121d7644c8 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form @@ -385,14 +385,11 @@ - + - - - diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java index 693d01f3b2..488286a794 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java @@ -280,9 +280,8 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP org.openide.awt.Mnemonics.setLocalizedText(optionsLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.optionsLabel.text")); // NOI18N - importButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/btn_icon_create_new_16.png"))); // NOI18N + importButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/new16.png"))); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(importButton1, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.importButton1.text")); // NOI18N - importButton1.setMargin(new java.awt.Insets(2, 11, 2, 14)); importButton1.setMaximumSize(new java.awt.Dimension(140, 25)); importButton1.setMinimumSize(new java.awt.Dimension(140, 25)); importButton1.setPreferredSize(new java.awt.Dimension(140, 25)); diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/new16.png b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/new16.png new file mode 100644 index 0000000000000000000000000000000000000000..f286d2b6c08f6d06e4d8143b9eabde178ae7c591 GIT binary patch literal 1661 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf4nJ za0`Jj+tIX_n~5oC^DMQ#CujeSKy zVsdtBi9%9pdS;%jl7fPQl0s&Rtx~wDuYqrYb81GWM^#a3aFt(3a#eP+Wr~u$9hXgo z6;N|-YDuC(MQ%=Bu~mhw64*>DAR8pCucQE0Qj%?}1aWkPZ-9bxeo?A|iJqZuvVpOQ zf{B@)k-3qjxtWeaaAJvqS7M%mk-37AfdP;(vNANZGBE@?1`L$!xPY`xQA(Oskc%7C zP9V=#DWjyMz)D}gyu4hm+*mKaC|%#s($Z4jz)0W7NEfI=x41H|B(Xv_uUHvk2+SOp z)Z*l#%mQ$5fy_-z$}cUkRZ;?31P4&hB^JOf$}5Hj9xxd7D-sLz4fPE4;U)t$+5iQu zz!8yO6q28xV}~WqY(P3u6d`Oy=udS?EJ?KkhKGf&fswAEd5D3Lm9d$XiD?v)euyG8 z?Y{XbnQ4_s+KqLMOhODTtqcsTOpKt~krY9-+vtM=0x4j?p$_sBnz#ai082@RhgU&q zQ4Tm-Qj+ykb5e6t^Gb?=VP=RLW+};5Y57IDi6wTKxryni`UQFEHu?xbyzYaz8kj7A z$xbgQE&AS2kV>*VwVqd5hxeTe)u>*a{V2c<8CeJ_!oe z`f>1K%#VNjKgXU6WRR1y`@ccwb(^u;QWa03Nh%BD*4OXe_paW+_p`QwDZ}Yac{#t| zTG}Q`6j{h*Y>hgTw%Pi4;gz##&6%^}k3?Rz7d%qP(~x`HM2h$J=RMyU#2H%zI6hv# zx-B;@j<1~ImMTMN=*7~x3LF!H7G+AUT2*A|z~Q(y%=xm(k|`XDddy2Qxf&K}tXLJ* z#g)PNp;lf~_4LzCN>hTSotx{|Ubfp;fJLIM@%`_s96*=df6px7D#%bMb2-QCVySKM ztb3oT9x)im@U3pp=qiX6Kk+M$!ELdiPrjnK*n-tH@r+-pY`^`keVH!dwrz&RhJXYo zyXCH{

jf7WXFSTW}=-%N>w11Dz|$1@!=SaSRArrU454ty>?uv+O$>!eQcImYLnxNG$*UdpL w-#>o*UBCbH<;(dB*|$UW=A3`dpm#ui>Ee?P2bFSG0IL87Pgg&ebxsLQ06SFuDgXcg literal 0 HcmV?d00001 From 593cdef606c0af51daa7373812d9b890dbc1daf1 Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Fri, 1 Nov 2013 17:27:53 -0400 Subject: [PATCH 067/169] Rearrange the HashDb mgmt buttons to be more consistent with Keyword List mgmt layout. --- .../hashdatabase/HashDbManagementPanel.form | 20 +++++++++---------- .../hashdatabase/HashDbManagementPanel.java | 17 ++++++++-------- 2 files changed, 17 insertions(+), 20 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form index 121d7644c8..5530d19c33 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form @@ -62,14 +62,7 @@ - - - - - - - - + @@ -115,7 +108,12 @@ - + + + + + + @@ -176,10 +174,10 @@ - + - + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java index 488286a794..6e4a2b17d9 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java @@ -300,12 +300,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(hashDatabasesLabel) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) - .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(importButton, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(deleteButton, javax.swing.GroupLayout.PREFERRED_SIZE, 132, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 275, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addGroup(layout.createSequentialGroup() @@ -339,7 +334,11 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP .addComponent(useForIngestCheckbox) .addComponent(showInboxMessagesCheckBox) .addComponent(indexButton, javax.swing.GroupLayout.PREFERRED_SIZE, 75, javax.swing.GroupLayout.PREFERRED_SIZE))))) - .addComponent(importButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createSequentialGroup() + .addComponent(importButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(importButton, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(deleteButton, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap(40, Short.MAX_VALUE)) ); layout.setVerticalGroup( @@ -388,9 +387,9 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(importButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(deleteButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(importButton1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(importButton1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(deleteButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addContainerGap()) ); }// //GEN-END:initComponents From 9bb68be4605790b44495997f05b07eae402ba786 Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Fri, 1 Nov 2013 17:28:43 -0400 Subject: [PATCH 068/169] Do not change the file path when the user is trying to make a new database. --- .../autopsy/hashdatabase/HashDbCreateDatabaseDialog.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java index 43ca4be56c..7cc74400c7 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java @@ -257,9 +257,6 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { try { String filePath = f.getCanonicalPath(); - if (HashDb.isIndexPath(filePath)) { - filePath = HashDb.toDatabasePath(filePath); - } String derivedName = f.getName(); databasePathTextField.setText(filePath); databaseNameTextField.setText(derivedName); From 1bdc69dc1ea422d829f655665d107d2d41ab42cc Mon Sep 17 00:00:00 2001 From: raman-bt Date: Mon, 4 Nov 2013 12:47:44 -0500 Subject: [PATCH 069/169] Tweaked the ImageFilePanel so it can be used by any other DataSourceProcessor that needs an image path, a timezone string and the "no fat orphans" flag. --- .../AddImageWizardChooseDataSourceVisual.java | 4 +- .../autopsy/casemodule/GeneralFilter.java | 11 ++++ .../autopsy/casemodule/ImageDSProcessor.java | 32 +++++++++- .../autopsy/casemodule/ImageFilePanel.form | 2 +- .../autopsy/casemodule/ImageFilePanel.java | 64 +++++++++---------- .../casemodule/MissingImageDialog.java | 21 ++++-- 6 files changed, 90 insertions(+), 44 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java index dacec10e23..885b5cced0 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardChooseDataSourceVisual.java @@ -41,8 +41,8 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; /** - * visual component for the first panel of add image wizard. Allows user to pick - * data source and timezone. + * visual component for the first panel of add image wizard. + * Allows the user to choose the data source type and then select the data source * */ final class AddImageWizardChooseDataSourceVisual extends JPanel { diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/GeneralFilter.java b/Core/src/org/sleuthkit/autopsy/casemodule/GeneralFilter.java index b550a0a275..9b9a091466 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/GeneralFilter.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/GeneralFilter.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.casemodule; import java.io.File; import java.util.List; +import java.util.Arrays; import javax.swing.filechooser.FileFilter; /** @@ -28,6 +29,16 @@ import javax.swing.filechooser.FileFilter; */ public class GeneralFilter extends FileFilter{ + + // Extensions & Descriptions for commonly used filters + public static final List RAW_IMAGE_EXTS = Arrays.asList(new String[]{".img", ".dd", ".001", ".aa", ".raw", ".bin"}); + public static final String RAW_IMAGE_DESC = "Raw Images (*.img, *.dd, *.001, *.aa, *.raw, *.bin)"; + + public static final List ENCASE_IMAGE_EXTS = Arrays.asList(new String[]{".e01"}); + public static final String ENCASE_IMAGE_DESC = "Encase Images (*.e01)"; + + + private List extensions; private String desc; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java index 0a56499828..a60cf66468 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageDSProcessor.java @@ -21,6 +21,10 @@ package org.sleuthkit.autopsy.casemodule; import java.util.logging.Level; import javax.swing.JPanel; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import javax.swing.filechooser.FileFilter; import org.openide.util.lookup.ServiceProvider; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.corecomponentinterfaces.DSPProgressMonitor; @@ -37,6 +41,8 @@ import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; @ServiceProvider(service = DataSourceProcessor.class) public class ImageDSProcessor implements DataSourceProcessor { + + static final Logger logger = Logger.getLogger(ImageDSProcessor.class.getName()); // Data source type handled by this processor @@ -60,7 +66,29 @@ public class ImageDSProcessor implements DataSourceProcessor { private String imagePath; private String timeZone; private boolean noFatOrphans; - + + + + + static final GeneralFilter rawFilter = new GeneralFilter(GeneralFilter.RAW_IMAGE_EXTS, GeneralFilter.RAW_IMAGE_DESC); + static final GeneralFilter encaseFilter = new GeneralFilter(GeneralFilter.ENCASE_IMAGE_EXTS, GeneralFilter.ENCASE_IMAGE_DESC); + + static final List allExt = new ArrayList(); + static { + allExt.addAll(GeneralFilter.RAW_IMAGE_EXTS); + allExt.addAll(GeneralFilter.ENCASE_IMAGE_EXTS); + } + static final String allDesc = "All Supported Types"; + static final GeneralFilter allFilter = new GeneralFilter(allExt, allDesc); + + static final List filtersList = new ArrayList(); + + static { + filtersList.add(allFilter); + filtersList.add(rawFilter); + filtersList.add(encaseFilter); + } + /* * A no argument constructor is required for the NM lookup() method to create an object @@ -68,7 +96,7 @@ public class ImageDSProcessor implements DataSourceProcessor { public ImageDSProcessor() { // Create the config panel - imageFilePanel = ImageFilePanel.getDefault(); + imageFilePanel = ImageFilePanel.createInstance(ImageDSProcessor.class.getName(), filtersList); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form index b201296bfa..886767fa57 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.form @@ -66,7 +66,7 @@ - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java index c70b8f1f7f..03dd184e8c 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/ImageFilePanel.java @@ -31,6 +31,7 @@ import javax.swing.JFileChooser; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.JPanel; +import javax.swing.filechooser.FileFilter; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; import org.sleuthkit.autopsy.coreutils.ModuleSettings; @@ -40,57 +41,52 @@ import org.sleuthkit.autopsy.coreutils.ModuleSettings; */ public class ImageFilePanel extends JPanel implements DocumentListener { - - private static final String PROP_LASTIMAGE_PATH = "LBL_LastImage_PATH"; + private final String PROP_LASTIMAGE_PATH = "LBL_LastImage_PATH"; - static final List rawExt = Arrays.asList(new String[]{".img", ".dd", ".001", ".aa", ".raw"}); - static final String rawDesc = "Raw Images (*.img, *.dd, *.001, *.aa, *.raw)"; - static GeneralFilter rawFilter = new GeneralFilter(rawExt, rawDesc); - static final List encaseExt = Arrays.asList(new String[]{".e01"}); - static final String encaseDesc = "Encase Images (*.e01)"; - static GeneralFilter encaseFilter = new GeneralFilter(encaseExt, encaseDesc); - static final List allExt = new ArrayList(); - - static { - allExt.addAll(rawExt); - allExt.addAll(encaseExt); - } - static final String allDesc = "All Supported Types"; - static GeneralFilter allFilter = new GeneralFilter(allExt, allDesc); - - - - private static ImageFilePanel instance = null; private PropertyChangeSupport pcs = null; private JFileChooser fc = new JFileChooser(); + + // Externally supplied name is used to store settings + private String contextName; /** * Creates new form ImageFilePanel + * @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 */ - public ImageFilePanel() { + private ImageFilePanel(String context, List fileChooserFilters) { initComponents(); fc.setDragEnabled(false); fc.setFileSelectionMode(JFileChooser.FILES_ONLY); fc.setMultiSelectionEnabled(false); - fc.addChoosableFileFilter(rawFilter); - fc.addChoosableFileFilter(encaseFilter); - fc.setFileFilter(allFilter); + boolean firstFilter = true; + for (FileFilter filter: fileChooserFilters ) { + if (firstFilter) { // set the first on the list as the default selection + fc.setFileFilter(filter); + firstFilter = false; + } + else { + fc.addChoosableFileFilter(filter); + } + } + this.contextName = context; pcs = new PropertyChangeSupport(this); createTimeZoneList(); } /** - * Returns the default instance of a ImageFilePanel. + * Creates and returns an instance of a ImageFilePanel. */ - public static synchronized ImageFilePanel getDefault() { - if (instance == null) { - instance = new ImageFilePanel(); - instance.postInit(); - } - return instance; + public static synchronized ImageFilePanel createInstance(String context, List fileChooserFilters) { + + ImageFilePanel instance = new ImageFilePanel(context, fileChooserFilters ); + + instance.postInit(); + + return instance; } //post-constructor initialization to properly initialize listener support @@ -230,7 +226,7 @@ public class ImageFilePanel extends JPanel implements DocumentListener { } - boolean getNoFatOrphans() { + public boolean getNoFatOrphans() { return noFatOrphansCheckbox.isSelected(); } @@ -263,12 +259,12 @@ public class ImageFilePanel extends JPanel implements DocumentListener { String imagePathName = getContentPaths(); if (null != imagePathName ) { String imagePath = imagePathName.substring(0, imagePathName.lastIndexOf(File.separator) + 1); - ModuleSettings.setConfigSetting(ImageFilePanel.class.getName(), PROP_LASTIMAGE_PATH, imagePath); + ModuleSettings.setConfigSetting(contextName, PROP_LASTIMAGE_PATH, imagePath); } } public void readSettings() { - String lastImagePath = ModuleSettings.getConfigSetting(ImageFilePanel.class.getName(), PROP_LASTIMAGE_PATH); + String lastImagePath = ModuleSettings.getConfigSetting(contextName, PROP_LASTIMAGE_PATH); if (null != lastImagePath) { if (!lastImagePath.isEmpty()) pathTextField.setText(lastImagePath); diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java index deec62e813..d54c52fc4b 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/MissingImageDialog.java @@ -24,12 +24,14 @@ import java.awt.Toolkit; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.util.Arrays; +import java.util.List; +import java.util.ArrayList; import java.util.logging.Level; import java.io.File; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JOptionPane; -import org.sleuthkit.autopsy.casemodule.ImageFilePanel; +import org.sleuthkit.autopsy.casemodule.GeneralFilter; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.SleuthkitCase; @@ -44,6 +46,16 @@ public class MissingImageDialog extends javax.swing.JDialog { + static final GeneralFilter rawFilter = new GeneralFilter(GeneralFilter.RAW_IMAGE_EXTS, GeneralFilter.RAW_IMAGE_DESC); + static final GeneralFilter encaseFilter = new GeneralFilter(GeneralFilter.ENCASE_IMAGE_EXTS, GeneralFilter.ENCASE_IMAGE_DESC); + + static final List allExt = new ArrayList(); + static { + allExt.addAll(GeneralFilter.RAW_IMAGE_EXTS); + allExt.addAll(GeneralFilter.ENCASE_IMAGE_EXTS); + } + static final String allDesc = "All Supported Types"; + static final GeneralFilter allFilter = new GeneralFilter(allExt, allDesc); private JFileChooser fc = new JFileChooser(); @@ -57,10 +69,9 @@ public class MissingImageDialog extends javax.swing.JDialog { fc.setFileSelectionMode(JFileChooser.FILES_ONLY); fc.setMultiSelectionEnabled(false); - // borrow the filters from ImageFilePanel - fc.addChoosableFileFilter(ImageFilePanel.rawFilter); - fc.addChoosableFileFilter(ImageFilePanel.encaseFilter); - fc.setFileFilter(ImageFilePanel.allFilter); + fc.addChoosableFileFilter(rawFilter); + fc.addChoosableFileFilter(encaseFilter); + fc.setFileFilter(allFilter); customInit(); From cda61becb93667c8912d7aeea537c68aae1f598c Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 4 Nov 2013 15:24:19 -0500 Subject: [PATCH 070/169] Fixed name of SleuthkitJNI method call in HashDb class --- HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index e791f3caac..91a86ab134 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -150,7 +150,7 @@ public class HashDb implements Comparable { boolean hasLookupIndex() { try { - return SleuthkitJNI.lookupIndexForHashDatabaseExists(handle); + return SleuthkitJNI.hashDatabaseHasLookupIndex(handle); } catch (TskCoreException ex) { // RJCTODO From d1ef3ae9df65be64c4b1bd21aac2dc7e012940cf Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 4 Nov 2013 18:25:02 -0500 Subject: [PATCH 071/169] First cut at fully integrated create hash database capability --- HashDatabase/nbproject/project.xml | 9 + .../AddContentToHashDbAction.java | 40 ++-- .../autopsy/hashdatabase/HashDb.java | 197 +++++++++--------- .../HashDbCreateDatabaseDialog.java | 108 ++++------ .../HashDbImportDatabaseDialog.java | 59 +++--- .../hashdatabase/HashDbIngestModule.java | 3 +- .../hashdatabase/HashDbManagementPanel.java | 51 +++-- .../hashdatabase/HashDbSimplePanel.java | 18 +- .../autopsy/hashdatabase/HashDbXML.java | 191 ++++++----------- .../autopsy/hashdatabase/ModalNoButtons.java | 2 +- 10 files changed, 313 insertions(+), 365 deletions(-) diff --git a/HashDatabase/nbproject/project.xml b/HashDatabase/nbproject/project.xml index 3a743f01d0..cedf7748b2 100644 --- a/HashDatabase/nbproject/project.xml +++ b/HashDatabase/nbproject/project.xml @@ -81,6 +81,15 @@ 7.0 + + org.sleuthkit.autopsy.corelibs + + + + 3 + 1.1 + + org.sleuthkit.autopsy.hashdatabase diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java index ca4d481097..7f01819fdd 100755 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java @@ -106,28 +106,26 @@ public class AddContentToHashDbAction extends AbstractAction implements Presente // one as a menu item. List hashDatabases = HashDbXML.getInstance().getKnownBadSets(); if (!hashDatabases.isEmpty()) { - for (final HashDb database : HashDbXML.getInstance().getKnownBadSets()) { - if (database.isUpdateable()) { - JMenuItem databaseItem = add(database.getDisplayName()); - databaseItem.addActionListener(new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); - for (AbstractFile file : selectedFiles) { - String md5Hash = file.getMd5Hash(); - if (null != md5Hash) { - try { - database.addToHashDatabase(file); - } - catch (TskCoreException ex) { - Logger.getLogger(AddContentToHashDbAction.class.getName()).log(Level.SEVERE, "Error adding to hash database", ex); - JOptionPane.showMessageDialog(null, "Unable to add " + file.getName() + " to hash database.", "Add to Hash Database Error", JOptionPane.ERROR_MESSAGE); - } - } - } + for (final HashDb database : HashDbXML.getInstance().getUpdateableHashSets()) { + JMenuItem databaseItem = add(database.getDisplayName()); + databaseItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); + for (AbstractFile file : selectedFiles) { + String md5Hash = file.getMd5Hash(); + if (null != md5Hash) { + try { + database.add(file); + } + catch (TskCoreException ex) { + Logger.getLogger(AddContentToHashDbAction.class.getName()).log(Level.SEVERE, "Error adding to hash database", ex); + JOptionPane.showMessageDialog(null, "Unable to add " + file.getName() + " to hash database.", "Add to Hash Database Error", JOptionPane.ERROR_MESSAGE); + } + } } - }); - } + } + }); } } else { diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index 1c194a7541..024ea46764 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -27,21 +27,24 @@ import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SleuthkitJNI; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; /** - * Instances of this class represent known file hash set databases. + * Instances of this class represent the hash databases underlying known files + * hash sets. */ -// TODO: Make this an inner class of a rewritten HashDbXML, and give it a private constructor. public class HashDb implements Comparable { - enum EVENT {INDEXING_DONE}; + public enum Event { + INDEXING_DONE + } - enum KNOWN_FILES_HASH_SET_TYPE{ + public enum KnownFilesType{ NSRL("NSRL"), KNOWN_BAD("Known Bad"); private String displayName; - private KNOWN_FILES_HASH_SET_TYPE(String displayName) { + private KnownFilesType(String displayName) { this.displayName = displayName; } @@ -50,20 +53,47 @@ public class HashDb implements Comparable { } } + /** + * Opens an existing hash database. + * @param hashSetName Hash set name used to represent the hash database in user interface components. + * @param databasePath Full path to the database file to be created. The file name component of the path must have a ".kdb" extension. + * @param useForIngest A flag indicating whether or not the hash database should be used during ingest. + * @param showInboxMessages A flag indicating whether hash set hit messages should be sent to the application inbox. + * @param knownType The known files type of the database. + * @return A HashDb object representation of the new hash database. + * @throws TskCoreException + */ + public static HashDb openHashDatabase(String hashSetName, String databasePath, boolean useForIngest, boolean showInboxMessages, KnownFilesType knownType) throws TskCoreException { + return new HashDb(SleuthkitJNI.openHashDatabase(databasePath), hashSetName, databasePath, useForIngest, showInboxMessages, knownType); + } + + /** + * Creates a new hash database. + * @param hashSetName Name used to represent the database in user interface components. + * @param databasePath Full path to the database file to be created. The file name component of the path must have a ".kdb" extension. + * @param useForIngest A flag indicating whether or not the data base should be used during the file ingest process. + * @param showInboxMessages A flag indicating whether messages indicating lookup hits should be sent to the application in box. + * @param knownType The known files type of the database. + * @return A HashDb object representation of the opened hash database. + * @throws TskCoreException + */ + public static HashDb createHashDatabase(String hashSetName, String databasePath, boolean useForIngest, boolean showInboxMessages, KnownFilesType type) throws TskCoreException { + return new HashDb(SleuthkitJNI.createHashDatabase(databasePath), hashSetName, databasePath, useForIngest, showInboxMessages, type); + } + private static final String INDEX_FILE_EXTENSION = ".kdb"; private static final String LEGACY_INDEX_FILE_EXTENSION = "-md5.idx"; - private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); + private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this); private String displayName; private String databasePath; private boolean useForIngest; private boolean showInboxMessages; - private KNOWN_FILES_HASH_SET_TYPE type; + private KnownFilesType type; private int handle; private boolean indexing; - private boolean acceptsUpdates = false; - HashDb(int handle, String name, String databasePath, boolean useForIngest, boolean showInboxMessages, KNOWN_FILES_HASH_SET_TYPE type) { + HashDb(int handle, String name, String databasePath, boolean useForIngest, boolean showInboxMessages, KnownFilesType type) { this.displayName = name; this.databasePath = databasePath; this.useForIngest = useForIngest; @@ -71,14 +101,6 @@ public class HashDb implements Comparable { this.type = type; this.handle = handle; this.indexing = false; - - try { - acceptsUpdates = SleuthkitJNI.isUpdateableHashDatabase(this.handle); - } - catch (TskCoreException ex) { - // RJCTODO - acceptsUpdates = false; - } } @Override @@ -86,38 +108,12 @@ public class HashDb implements Comparable { return this.displayName.compareTo(o.displayName); } - /** - * Indicates whether the hash database accepts updates. - * @return True if the database accepts updates, false otherwise. - */ - boolean isUpdateable() { - return acceptsUpdates; - } - - /** - * Adds hashes of content (if calculated) to the hash database. - * @param content The content for which the calculated hashes, if any, are to be added to the hash database. - * @throws TskCoreException - */ - public void addToHashDatabase(Content content) throws TskCoreException { - // TODO: This only works for AbstractFiles at present. Change when Content - // can be queried for hashes. - assert content instanceof AbstractFile; - if (content instanceof AbstractFile) { - AbstractFile file = (AbstractFile)content; - // TODO: Add support for SHA-1 and SHA-256 hashes. - if (null != file.getMd5Hash()) { - SleuthkitJNI.addToHashDatabase(file.getName(), file.getMd5Hash(), "", "", handle); - } - } - } - void addPropertyChangeListener(PropertyChangeListener pcl) { - pcs.addPropertyChangeListener(pcl); + propertyChangeSupport.addPropertyChangeListener(pcl); } void removePropertyChangeListener(PropertyChangeListener pcl) { - pcs.removePropertyChangeListener(pcl); + propertyChangeSupport.removePropertyChangeListener(pcl); } String getDisplayName() { @@ -128,7 +124,7 @@ public class HashDb implements Comparable { return databasePath; } - KNOWN_FILES_HASH_SET_TYPE getKnownType() { + KnownFilesType getKnownFilesType() { return type; } @@ -158,37 +154,55 @@ public class HashDb implements Comparable { } } - boolean hasLegacyLookupIndexOnly() throws TskCoreException { + boolean hasTextLookupIndexOnly() throws TskCoreException { return SleuthkitJNI.hashDatabaseHasLegacyLookupIndexOnly(handle); } - // TODO: This is a temporary expedient until HashDb becomes an inner class of HashDbXML. - void setAcceptsUpdates(boolean acceptsUpdates) { - this.acceptsUpdates = acceptsUpdates; + /** + * Indicates whether the hash database accepts updates. + * @return True if the database accepts updates, false otherwise. + */ + public boolean isUpdateable() throws TskCoreException { + return SleuthkitJNI.isUpdateableHashDatabase(this.handle); } /** - * Determines if a path points to an index by checking the suffix - * @param path - * @return true if index + * Adds hashes of content (if calculated) to the hash database. + * @param content The content for which the calculated hashes, if any, are to be added to the hash database. + * @throws TskCoreException */ - static boolean isIndexPath(String path) { - return (path.endsWith(INDEX_FILE_EXTENSION) || path.endsWith(LEGACY_INDEX_FILE_EXTENSION)); - } - - /** - * Derives database path from an image path by removing the suffix. - * @param indexPath - * @return - */ - static String toDatabasePath(String indexPath) { - if (indexPath.endsWith(LEGACY_INDEX_FILE_EXTENSION)) { - return indexPath.substring(0, indexPath.lastIndexOf(LEGACY_INDEX_FILE_EXTENSION)); - } else { - return indexPath.substring(0, indexPath.lastIndexOf(INDEX_FILE_EXTENSION)); + public void add(Content content) throws TskCoreException { + // TODO: This only works for AbstractFiles at present. Change when Content + // can be queried for hashes. + assert content instanceof AbstractFile; + if (content instanceof AbstractFile) { + AbstractFile file = (AbstractFile)content; + // TODO: Add support for SHA-1 and SHA-256 hashes. + if (null != file.getMd5Hash()) { + SleuthkitJNI.addToHashDatabase(file.getName(), file.getMd5Hash(), "", "", handle); + } } } - + + public TskData.FileKnown lookUp(Content content) throws TskCoreException { + TskData.FileKnown result = TskData.FileKnown.UKNOWN; + // TODO: This only works for AbstractFiles at present. Change when Content can be queried for hashes. + assert content instanceof AbstractFile; + if (content instanceof AbstractFile) { + AbstractFile file = (AbstractFile)content; + // TODO: Add support for SHA-1 and SHA-256 hashes. + if (null != file.getMd5Hash()) { + if (type == KnownFilesType.NSRL) { + result = SleuthkitJNI.lookupInNSRLDatabase(file.getMd5Hash()); + } + else { + result = SleuthkitJNI.lookupInHashDatabase(file.getMd5Hash(), handle); + } + } + } + return result; + } + /** * Derives index path from an database path by appending the suffix. * @param databasePath @@ -202,43 +216,22 @@ public class HashDb implements Comparable { return indexing; } - IndexStatus getStatus() { - // RJCTODO: Fix this using new API + IndexStatus getStatus() throws TskCoreException { + IndexStatus status = IndexStatus.NO_INDEX; if (indexing) { - return IndexStatus.INDEXING; + status = IndexStatus.INDEXING; + } + else if (hasLookupIndex()) { + if (hasTextLookupIndexOnly()) { + status = IndexStatus.INDEX_ONLY; + } + else { + status = IndexStatus.INDEXED; + } } -// return new File(databasePath).exists(); - - -// return new File(toIndexPath(databasePath)); - - -// if (SleuthkitJNI.hashDatabaseIsLookupIndexOnly(handle)) { -// return databaseExists() ? IndexStatus.NO_INDEX : IndexStatus.NONE; -// } - -// return databasePath.concat(LEGACY_INDEX_FILE_EXTENSION); - - - // Outdated applies only to legacy databases where the legacy index file exists and is older -// File i = indexFile(); -// File db = new File(databasePath); -// -// return i.exists() && db.exists() && isOlderThan(i, db); -// -// if (indexExists()) { -// if (databaseSourceFileExists()) { -// return this.isOutdated() ? IndexStatus.INDEX_OUTDATED : IndexStatus.INDEX_CURRENT; -// } -// else { -// return IndexStatus.NO_DB; -// } -// } else { -// return databaseSourceFileExists() ? IndexStatus.NO_INDEX : IndexStatus.NONE; -// } - return IndexStatus.INDEXING; + return status; } // Tries to index the database (overwrites any existing index) using a @@ -268,7 +261,7 @@ public class HashDb implements Comparable { protected void done() { indexing = false; progress.finish(); - pcs.firePropertyChange(EVENT.INDEXING_DONE.toString(), null, displayName); + propertyChangeSupport.firePropertyChange(Event.INDEXING_DONE.toString(), null, displayName); } } } \ No newline at end of file diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java index 7cc74400c7..86d01b8def 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java @@ -23,38 +23,33 @@ import java.awt.Dimension; import java.awt.Toolkit; import java.io.File; import java.io.IOException; -import java.util.Arrays; import java.util.logging.Level; import org.sleuthkit.autopsy.coreutils.Logger; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.filechooser.FileNameExtensionFilter; -import org.sleuthkit.autopsy.hashdatabase.HashDb.KNOWN_FILES_HASH_SET_TYPE; -import org.sleuthkit.datamodel.SleuthkitJNI; +import org.apache.commons.io.FilenameUtils; +import org.sleuthkit.autopsy.hashdatabase.HashDb.KnownFilesType; import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.datamodel.TskException; -/** - * Creation is a different GUI class than importing - */ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { - - private JFileChooser fc; - - private HashDb hashDb = null; - private static final Logger logger = Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()); - /** - * Creates new form HashDbCreateDatabaseDialog - */ + private JFileChooser fileChooser; + private HashDb newHashDb = null; + HashDbCreateDatabaseDialog() { super(new javax.swing.JFrame(), "Create Hash Database", true); - setResizable(false); - - fc = new JFileChooser() { + setResizable(false); + fileChooser = new JFileChooser() { @Override public void approveSelection() { - File ftemp = getSelectedFile(); - if (ftemp.exists()) { + File selectedFile = getSelectedFile(); + if (!FilenameUtils.getExtension(selectedFile.getName()).equalsIgnoreCase("kdb")) { + if (JOptionPane.showConfirmDialog(this, "The file must have a .kdb extension.", "File Name Error", JOptionPane.OK_CANCEL_OPTION) == JOptionPane.CANCEL_OPTION) { + cancelSelection(); + } + return; + } + if (selectedFile.exists()) { int r = JOptionPane.showConfirmDialog(this, "A file with this name already exists. Please enter a new filename.", "Existing File", JOptionPane.OK_CANCEL_OPTION); if (r == JOptionPane.CANCEL_OPTION) { cancelSelection(); @@ -70,27 +65,20 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { } void customizeComponents() { - fc.setDragEnabled(false); - fc.setFileSelectionMode(JFileChooser.FILES_ONLY); + fileChooser.setDragEnabled(false); + fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); String[] EXTENSION = new String[] { "txt", "kdb", "idx", "hash", "Hash", "hsh"}; - FileNameExtensionFilter filter = new FileNameExtensionFilter( - "Hash Database File", EXTENSION); - fc.setFileFilter(filter); - fc.setMultiSelectionEnabled(false); + FileNameExtensionFilter filter = new FileNameExtensionFilter("Hash Database File", EXTENSION); + fileChooser.setFileFilter(filter); + fileChooser.setMultiSelectionEnabled(false); } - HashDb display() { + HashDb doDialog() { + newHashDb = null; Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); - - // set the popUp window / JFrame - int w = this.getSize().width; - int h = this.getSize().height; - - // set the location of the popUp Window on the center of the screen - setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2); - - this.setVisible(true); - return hashDb; + setLocation((screenDimension.width - getSize().width) / 2, (screenDimension.height - getSize().height) / 2); + this.setVisible(true); + return newHashDb; } /** @@ -245,28 +233,20 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { }// //GEN-END:initComponents private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed - String oldText = databasePathTextField.getText(); - // set the current directory of the FileChooser if the databasePath Field is valid - File currentDir = new File(oldText); - if (currentDir.exists()) { - fc.setCurrentDirectory(currentDir); - } - int retval = fc.showSaveDialog(this); - if (retval == JFileChooser.APPROVE_OPTION) { - File f = fc.getSelectedFile(); - - try { - String filePath = f.getCanonicalPath(); - String derivedName = f.getName(); - databasePathTextField.setText(filePath); - databaseNameTextField.setText(derivedName); - if (derivedName.toLowerCase().contains("nsrl")) { + try { + fileChooser.setSelectedFile(new File("hash.kdb")); + if (fileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) { + File databaseFile = fileChooser.getSelectedFile(); + databasePathTextField.setText(databaseFile.getCanonicalPath()); + databaseNameTextField.setText(FilenameUtils.removeExtension(databaseFile.getName())); + if (databaseNameTextField.getText().toLowerCase().contains("nsrl")) { nsrlRadioButton.setSelected(true); nsrlRadioButtonActionPerformed(null); } - } catch (IOException ex) { - logger.log(Level.WARNING, "Couldn't get selected file path.", ex); - } + } + } + catch (IOException ex) { + Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()).log(Level.WARNING, "Couldn't get selected file path.", ex); } }//GEN-LAST:event_browseButtonActionPerformed @@ -294,19 +274,20 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { return; } - KNOWN_FILES_HASH_SET_TYPE type; + KnownFilesType type; if(nsrlRadioButton.isSelected()) { - type = KNOWN_FILES_HASH_SET_TYPE.NSRL; + type = KnownFilesType.NSRL; } else { - type = KNOWN_FILES_HASH_SET_TYPE.KNOWN_BAD; + type = KnownFilesType.KNOWN_BAD; } try { - hashDb = HashDbXML.getInstance().createHashDatabase(databaseNameTextField.getText(), databasePathTextField.getText(), useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Database creation error: ", ex); - JOptionPane.showMessageDialog(this, "Database file cannot be created.\n"); + newHashDb = HashDb.createHashDatabase(databaseNameTextField.getText(), databasePathTextField.getText(), useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); + } + catch (TskCoreException ex) { + Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()).log(Level.SEVERE, "Hash database creation error", ex); + JOptionPane.showMessageDialog(this, "Failed to create hash database."); return; } @@ -314,7 +295,6 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { }//GEN-LAST:event_okButtonActionPerformed private void useForIngestCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useForIngestCheckboxActionPerformed - // TODO add your handling code here: }//GEN-LAST:event_useForIngestCheckboxActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java index f841d77101..42e8af23a8 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java @@ -27,15 +27,16 @@ import org.sleuthkit.autopsy.coreutils.Logger; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.filechooser.FileNameExtensionFilter; -import org.sleuthkit.autopsy.hashdatabase.HashDb.KNOWN_FILES_HASH_SET_TYPE; +import org.sleuthkit.autopsy.hashdatabase.HashDb.KnownFilesType; import org.sleuthkit.datamodel.TskCoreException; +import org.apache.commons.io.FilenameUtils; /** * Instances of this class allow a user to select a hash database for import. */ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { private JFileChooser fileChooser = new JFileChooser(); - private HashDb importedHashDatabase; + private HashDb selectedHashDb; HashDbImportDatabaseDialog() { super(new javax.swing.JFrame(), "Import Hash Database", true); @@ -53,12 +54,15 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { fileChooser.setMultiSelectionEnabled(false); } - HashDb display() { + HashDb doDialog() { + selectedHashDb = null; + // Center and display the dialog. Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); setLocation((screenDimension.width - getSize().width) / 2, (screenDimension.height - getSize().height) / 2); this.setVisible(true); - return importedHashDatabase; + + return selectedHashDb; } /** @@ -215,17 +219,15 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { File currentDir = new File(databasePathTextField.getText()); if (currentDir.exists()) { fileChooser.setCurrentDirectory(currentDir); - } - int retval = fileChooser.showOpenDialog(this); - if (retval == JFileChooser.APPROVE_OPTION) { - File f = fileChooser.getSelectedFile(); + } + if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { + File databaseFile = fileChooser.getSelectedFile(); try { - String filePath = f.getCanonicalPath(); - databasePathTextField.setText(filePath); - databaseNameTextField.setText(HashDb.toDatabasePath(filePath)); + databasePathTextField.setText(databaseFile.getCanonicalPath()); + databaseNameTextField.setText(FilenameUtils.removeExtension(databaseFile.getName())); } catch (IOException ex) { - Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.WARNING, "Failed to get path of selected file", ex); + Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.SEVERE, "Failed to get path of selected database", ex); } } }//GEN-LAST:event_browseButtonActionPerformed @@ -246,44 +248,45 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed if(databasePathTextField.getText().isEmpty()) { - JOptionPane.showMessageDialog(this, "Database path cannot be empty"); + JOptionPane.showMessageDialog(this, "Database path cannot be empty."); return; } if(databaseNameTextField.getText().isEmpty()) { - JOptionPane.showMessageDialog(this, "Database display name cannot be empty"); + JOptionPane.showMessageDialog(this, "Database display name cannot be empty."); return; } - + + File file = new File(databasePathTextField.getText()); + if (!file.exists()) { + JOptionPane.showMessageDialog(this, "Selected database does not exist."); + return; + } + String filePath; try { - File file = new File(databasePathTextField.getText()); - if (!file.exists()) { - JOptionPane.showMessageDialog(this, "Selected file does not exist"); - return; - } filePath = file.getCanonicalPath(); } catch (IOException ex) { - Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.WARNING, "Invalid database: ", ex); - JOptionPane.showMessageDialog(this, "Database file you chose cannot be opened.\n" + "If it was just an index, please try to recreate it from the database"); + Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.SEVERE, "Failed to get path of selected database", ex); + JOptionPane.showMessageDialog(this, "Failed to get path of selected database."); return; } - KNOWN_FILES_HASH_SET_TYPE type; + KnownFilesType type; if (nsrlRadioButton.isSelected()) { - type = KNOWN_FILES_HASH_SET_TYPE.NSRL; + type = KnownFilesType.NSRL; } else { - type = KNOWN_FILES_HASH_SET_TYPE.KNOWN_BAD; + type = KnownFilesType.KNOWN_BAD; } try { - importedHashDatabase = HashDbXML.getInstance().importHashDatabase(databaseNameTextField.getText(), filePath, useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); + selectedHashDb = HashDb.openHashDatabase(databaseNameTextField.getText(), filePath, useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); } catch (TskCoreException ex) { - Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.WARNING, "Invalid database: ", ex); - JOptionPane.showMessageDialog(this, "Database file you chose cannot be opened.\n" + "If it was just an index, please try to recreate it from the database"); + Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.WARNING, "Failed to open hash database at " + filePath, ex); + JOptionPane.showMessageDialog(this, "Failed to import selected database.\nPlease verify that the selected file is a hash database."); return; } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java index d4a1a2506f..a39292889d 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java @@ -90,10 +90,9 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { HashDbXML hdbxml = HashDbXML.getInstance(); nsrlSet = null; knownBadSets.clear(); - hdbxml.closeHashDatabases(); nsrlIsSet = false; knownBadIsSet = false; - calcHashesIsSet = hdbxml.getCalculate(); + calcHashesIsSet = hdbxml.shouldAlwaysCalculateHashes(); HashDb nsrl = hdbxml.getNSRLSet(); if (nsrl != null && nsrl.getUseForIngest() && IndexStatus.isIngestible(nsrl.getStatus())) { diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java index 6e4a2b17d9..43afd118c1 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java @@ -91,7 +91,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP private void initUI(HashDb db) { boolean useForIngestEnabled = db != null && !ingestRunning; boolean useForIngestSelected = db != null && db.getUseForIngest(); - boolean showInboxMessagesEnabled = db != null && !ingestRunning && useForIngestSelected && db.getKnownType().equals(HashDb.KNOWN_FILES_HASH_SET_TYPE.KNOWN_BAD); + boolean showInboxMessagesEnabled = db != null && !ingestRunning && useForIngestSelected && db.getKnownFilesType().equals(HashDb.KnownFilesType.KNOWN_BAD); boolean showInboxMessagesSelected = db != null && db.getShowInboxMessages(); boolean deleteButtonEnabled = db != null && !ingestRunning; boolean importButtonEnabled = !ingestRunning; @@ -104,7 +104,13 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP } else { //check if dn in indexing state String dbName = db.getDisplayName(); - IndexStatus status = db.getStatus(); + IndexStatus status = IndexStatus.NO_INDEX; + try { + status = db.getStatus(); + } + catch (TskCoreException ex) { + // RJCTODO + } Boolean state = indexingState.get(dbName); if (state != null && state.equals(Boolean.TRUE) ) { status = IndexStatus.INDEXING; @@ -119,7 +125,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP } this.hashDbLocationLabel.setText(shortenPath); this.hashDbNameLabel.setText(db.getDisplayName()); - this.hashDbTypeLabel.setText(db.getKnownType().getDisplayName()); + this.hashDbTypeLabel.setText(db.getKnownFilesType().getDisplayName()); } this.useForIngestCheckbox.setSelected(useForIngestSelected); this.useForIngestCheckbox.setEnabled(useForIngestEnabled); @@ -401,23 +407,36 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP @Override public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals(HashDb.EVENT.INDEXING_DONE.toString())) { + if (evt.getPropertyName().equals(HashDb.Event.INDEXING_DONE.toString())) { //update tracking of indexing status indexingState.put((String)evt.getNewValue(), Boolean.FALSE); - - setButtonFromIndexStatus(indexButton, hashDbIndexStatusLabel, current.getStatus()); + IndexStatus status = IndexStatus.NO_INDEX; + try { + status = current.getStatus(); + } + catch (TskCoreException ex) { + // RJCTODO + } + setButtonFromIndexStatus(indexButton, hashDbIndexStatusLabel, status); resync(); } } }); - indexingState.put(current.getDisplayName(), Boolean.TRUE); - ModalNoButtons singleMNB = new ModalNoButtons(this, new Frame(), current); //Modal reference, to be removed later - singleMNB.setLocationRelativeTo(null); - singleMNB.setVisible(true); - singleMNB.setModal(true); //End Modal reference - indexingState.put(current.getDisplayName(), Boolean.FALSE); - setButtonFromIndexStatus(indexButton, this.hashDbIndexStatusLabel, current.getStatus()); + indexingState.put(current.getDisplayName(), Boolean.TRUE); + ModalNoButtons singleMNB = new ModalNoButtons(this, new Frame(), current); //Modal reference, to be removed later + singleMNB.setLocationRelativeTo(null); + singleMNB.setVisible(true); + singleMNB.setModal(true); //End Modal reference + indexingState.put(current.getDisplayName(), Boolean.FALSE); + IndexStatus status = IndexStatus.NO_INDEX; + try { + status = current.getStatus(); + } + catch (TskCoreException ex) { + // RJCTODO + } + setButtonFromIndexStatus(indexButton, this.hashDbIndexStatusLabel, status); }//GEN-LAST:event_indexButtonActionPerformed private void deleteButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteButtonActionPerformed @@ -634,16 +653,18 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP // End of variables declaration//GEN-END:variables private void importHashSet(java.awt.event.ActionEvent evt) { - HashDb hashDb = new HashDbImportDatabaseDialog().display(); + HashDb hashDb = new HashDbImportDatabaseDialog().doDialog(); if (hashDb != null) { + HashDbXML.getInstance().addSet(hashDb); hashSetTableModel.selectRowByName(hashDb.getDisplayName()); } resync(); } private void createHashSet(java.awt.event.ActionEvent evt) { - HashDb hashDb = new HashDbCreateDatabaseDialog().display(); + HashDb hashDb = new HashDbCreateDatabaseDialog().doDialog(); if (null != hashDb) { + HashDbXML.getInstance().addSet(hashDb); hashSetTableModel.selectRowByName(hashDb.getDisplayName()); } resync(); diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.java index c1b82a8f89..81c2adac37 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.java @@ -26,6 +26,7 @@ import javax.swing.JTable; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableColumn; import org.sleuthkit.autopsy.ingest.IngestManager; +import org.sleuthkit.datamodel.TskCoreException; /** * Instances of this class are used as a file ingest module configuration panel @@ -60,11 +61,11 @@ public class HashDbSimplePanel extends javax.swing.JPanel { if (!nsrlUsed && !knownUsed ) { calcHashesButton.setEnabled(true); calcHashesButton.setSelected(true); - xmlHandle.setCalculate(true); + xmlHandle.setShouldAlwaysCalculateHashes(true); } else { calcHashesButton.setEnabled(false); calcHashesButton.setSelected(false); - xmlHandle.setCalculate(false); + xmlHandle.setShouldAlwaysCalculateHashes(false); } } @@ -75,9 +76,9 @@ public class HashDbSimplePanel extends javax.swing.JPanel { @Override public void actionPerformed(ActionEvent e) { if(calcHashesButton.isSelected()) { - xmlHandle.setCalculate(true); + xmlHandle.setShouldAlwaysCalculateHashes(true); } else { - xmlHandle.setCalculate(false); + xmlHandle.setShouldAlwaysCalculateHashes(false); } } }); @@ -242,7 +243,14 @@ public class HashDbSimplePanel extends javax.swing.JPanel { public void setValueAt(Object aValue, int rowIndex, int columnIndex) { if(columnIndex == 0){ HashDb db = xmlHandle.getKnownBadSets().get(rowIndex); - if(((Boolean) getValueAt(rowIndex, columnIndex)) || IndexStatus.isIngestible(db.getStatus())) { + IndexStatus status = IndexStatus.NO_INDEX; + try { + status = db.getStatus(); + } + catch (TskCoreException ex) { + // RJCTODO + } + if(((Boolean) getValueAt(rowIndex, columnIndex)) || IndexStatus.isIngestible(status)) { db.setUseForIngest((Boolean) aValue); } else { JOptionPane.showMessageDialog(HashDbSimplePanel.this, "Databases must be indexed before they can be used for ingest"); diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java index fb527ec43f..e333e0c1f7 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java @@ -33,7 +33,7 @@ import javax.xml.parsers.ParserConfigurationException; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.XMLUtil; -import org.sleuthkit.autopsy.hashdatabase.HashDb.KNOWN_FILES_HASH_SET_TYPE; +import org.sleuthkit.autopsy.hashdatabase.HashDb.KnownFilesType; import org.sleuthkit.datamodel.SleuthkitJNI; import org.sleuthkit.datamodel.TskCoreException; import org.w3c.dom.Document; @@ -41,16 +41,10 @@ import org.w3c.dom.Element; import org.w3c.dom.NodeList; /** - * This class is a singleton that handles the import and creation of known files - * hash set databases, manages the instances of the databases, and provides a - * means for persisting the configuration of the hash sets. + * This class is a singleton that manages the configuration of the hash databases + * that serve as hash sets for the identification of known files, known good files, + * and known bad files. */ -// TODO: The class needs to renamed to something like HashDbManager - its use of -// XML as a configuration persistence mechanism should be an implementation detail -// hidden from its clients. More importantly, this class should be rewritten into -// full and true encapsulation of state and behavior rather than a mixture of a -// configuration manager with something that can be manipulated like a mere data -// structure by its clients. public class HashDbXML { private static final String ROOT_EL = "hash_sets"; private static final String SET_EL = "hash_set"; @@ -63,71 +57,45 @@ public class HashDbXML { private static final String CUR_HASHSETS_FILE_NAME = "hashsets.xml"; private static final String XSDFILE = "HashsetsSchema.xsd"; private static final String ENCODING = "UTF-8"; - private static final String CUR_HASHSET_FILE = PlatformUtil.getUserConfigDirectory() + File.separator + CUR_HASHSETS_FILE_NAME; private static final String SET_CALC = "hash_calculate"; private static final String SET_VALUE = "value"; private static final Logger logger = Logger.getLogger(HashDbXML.class.getName()); - private static HashDbXML currentInstance; - - private List knownBadSets; + private static HashDbXML instance; + private List knownBadSets = new ArrayList<>(); private HashDb nsrlSet; - private String xmlFile; - private boolean calculate; + private boolean alwaysCalculateHashes; + private String xmlFile = PlatformUtil.getUserConfigDirectory() + File.separator + CUR_HASHSETS_FILE_NAME; /** * Gets the singleton instance of this class. */ - static synchronized HashDbXML getInstance() { - if (currentInstance == null) { - currentInstance = new HashDbXML(CUR_HASHSET_FILE); - currentInstance.reload(); + public static synchronized HashDbXML getInstance() { + if (instance == null) { + instance = new HashDbXML(); + instance.reload(); } - return currentInstance; + return instance; } - private HashDbXML(String xmlFile) { - knownBadSets = new ArrayList<>(); - this.xmlFile = xmlFile; + private HashDbXML() { } - + /** - * Imports an existing known files hash database. - * @param displayName Name used to represent the database in user interface components. - * @param databasePath Full path to the database file to be created. The file name component of the path must have a ".kdb" extension. - * @param useForIngest A flag indicating whether or not the data base should be used during the file ingest process. - * @param showInboxMessages A flag indicating whether messages indicating lookup hits should be sent to the application in box. - * @param type The known type of the database. - * @return A HashDb object representation of the new hash database. - * @throws TskCoreException + * Adds a hash database to the hash set configuration. */ - // TODO: When this class is rewritten, this method should become private. It should add the HashDb object to the appropriate internal collection - // and to the XML file, and should save the XML file. - HashDb importHashDatabase(String displayName, String databasePath, boolean useForIngest, boolean showInboxMessages, KNOWN_FILES_HASH_SET_TYPE type) throws TskCoreException { - return new HashDb(SleuthkitJNI.openHashDatabase(databasePath), displayName, databasePath, useForIngest, showInboxMessages, type); + public void addSet(HashDb set) { + if (set.getKnownFilesType() == HashDb.KnownFilesType.NSRL) { + setNSRLSet(set); + } + else { + addKnownBadSet(set); + } } - /** - * Creates a new known files hash database. - * @param displayName Name used to represent the database in user interface components. - * @param databasePath Full path to the database file to be created. The file name component of the path must have a ".kdb" extension. - * @param useForIngest A flag indicating whether or not the data base should be used during the file ingest process. - * @param showInboxMessages A flag indicating whether messages indicating lookup hits should be sent to the application in box. - * @param type The known type of the database. - * @return A HashDb object representation of the opened hash database. - * @throws TskCoreException - */ - // TODO: When this class is rewritten, this method should become private. It should add the HashDb object to the appropriate internal collection - // and to the XML file, and should save the XML file. - HashDb createHashDatabase(String name, String databasePath, boolean useForIngest, boolean showInboxMessages, KNOWN_FILES_HASH_SET_TYPE type) throws TskCoreException { - return new HashDb(SleuthkitJNI.createHashDatabase(databasePath), name, databasePath, useForIngest, showInboxMessages, type); - } - /** * Sets the configured National Software Reference Library (NSRL) known * files hash set. Does not save the configuration. */ - // TODO: When this class is rewritten, the class should be responsible for saving - // the configuration rather than deferring this responsibility to its clients. public void setNSRLSet(HashDb set) { this.nsrlSet = set; } @@ -145,8 +113,6 @@ public class HashDbXML { * Removes the configured National Software Reference Library (NSRL) known * files hash set. Does not save the configuration. */ - // TODO: When this class is rewritten, the class should be responsible for saving - // the configuration rather than deferring this responsibility to its clients. public void removeNSRLSet() { this.nsrlSet = null; } @@ -155,8 +121,6 @@ public class HashDbXML { * Adds a known bad files hash set to the configuration. Does not save the * configuration. */ - // TODO: When this class is rewritten, the class should be responsible for saving - // the configuration rather than deferring this responsibility to its clients. public void addKnownBadSet(HashDb set) { knownBadSets.add(set); } @@ -166,8 +130,6 @@ public class HashDbXML { * the internal known bad sets collection at the index specified by the * caller. Note that this method does not save the configuration. */ - // TODO: This method is an OO abomination that should be discarded when this - // class is rewritten. public void addKnownBadSet(int index, HashDb set) { knownBadSets.add(index, set); } @@ -185,9 +147,6 @@ public class HashDbXML { * Removes the known bad files hash set from the internal known bad files * hash sets collection at the specified index. Does not save the configuration. */ - // TODO: This method is an OO abomination that should be replaced by a proper - // remove() when this class is rewritten. Also, the class should be responsible for saving - // the configuration rather than deferring this responsibility to its clients. public void removeKnownBadSetAt(int index) { knownBadSets.remove(index); } @@ -199,8 +158,13 @@ public class HashDbXML { public List getUpdateableHashSets() { ArrayList updateableDbs = new ArrayList<>(); for (HashDb db : knownBadSets) { - if (db.isUpdateable()) { - updateableDbs.add(db); + try { + if (db.isUpdateable()) { + updateableDbs.add(db); + } + } + catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Error checking updateable status of " + db.getDatabasePath(), ex); } } return Collections.unmodifiableList(updateableDbs); @@ -223,8 +187,6 @@ public class HashDbXML { /** * Reloads the configuration file if it exists, creates it otherwise. */ - // TODO: When this class is rewritten, the class should be responsible for saving - // the configuration rather than deferring this responsibility to its clients. public void reload() { // TODO: This does not look like it is correct. Revisit when time permits. boolean created = false; @@ -244,30 +206,27 @@ public class HashDbXML { } /** - * Sets the local variable calculate to the given boolean. - * @param set the state to make calculate + * Sets the value for the flag indicates whether hashes should be calculated + * for content even if no hash databases are configured. */ - // TODO: Does this have any use? - public void setCalculate(boolean set) { - this.calculate = set; + public void setShouldAlwaysCalculateHashes(boolean alwaysCalculateHashes) { + this.alwaysCalculateHashes = alwaysCalculateHashes; } /** - * Returns the value of the local boolean calculate. - * @return true if calculate is true, false otherwise + * Accesses the flag that indicates whether hashes should be calculated + * for content even if no hash databases are configured. */ - // TODO: Does this have any use? - public boolean getCalculate() { - return this.calculate; + public boolean shouldAlwaysCalculateHashes() { + return alwaysCalculateHashes; } /** - * Saves the known files hash sets configuration to disk. + * Saves the known files hash sets configuration to disk. Note that the + * configuration is only saved on demand to support cancellation of + * configuration panels and dialogs. * @return True on success, false otherwise. */ - // TODO: When this class is rewritten, the class should be responsible for saving - // the configuration rather than deferring this responsibility to its clients. - // It looks like there is code duplication here. public boolean save() { boolean success = false; @@ -285,7 +244,7 @@ public class HashDbXML { String useForIngest = Boolean.toString(set.getUseForIngest()); String showInboxMessages = Boolean.toString(set.getShowInboxMessages()); List paths = Collections.singletonList(set.getDatabasePath()); - String type = KNOWN_FILES_HASH_SET_TYPE.KNOWN_BAD.toString(); + String type = KnownFilesType.KNOWN_BAD.toString(); Element setEl = doc.createElement(SET_EL); setEl.setAttribute(SET_NAME_ATTR, set.getDisplayName()); @@ -303,12 +262,12 @@ public class HashDbXML { rootEl.appendChild(setEl); } - // TODO: Remove all the multiple database paths stuff, it was a mistake. + // TODO: Remove all the multiple database paths stuff. if(nsrlSet != null) { String useForIngest = Boolean.toString(nsrlSet.getUseForIngest()); String showInboxMessages = Boolean.toString(nsrlSet.getShowInboxMessages()); List paths = Collections.singletonList(nsrlSet.getDatabasePath()); - String type = KNOWN_FILES_HASH_SET_TYPE.NSRL.toString(); + String type = KnownFilesType.NSRL.toString(); Element setEl = doc.createElement(SET_EL); setEl.setAttribute(SET_NAME_ATTR, nsrlSet.getDisplayName()); @@ -326,8 +285,7 @@ public class HashDbXML { rootEl.appendChild(setEl); } - // TODO: Does this have any use? - String calcValue = Boolean.toString(calculate); + String calcValue = Boolean.toString(alwaysCalculateHashes); Element setCalc = doc.createElement(SET_CALC); setCalc.setAttribute(SET_VALUE, calcValue); rootEl.appendChild(setCalc); @@ -366,7 +324,8 @@ public class HashDbXML { Boolean showInboxMessagesBool = Boolean.parseBoolean(showInboxMessages); List paths = new ArrayList<>(); - // TODO: Remove all the multiple database paths stuff, it was a mistake. + // TODO: Remove all the multiple database paths stuff. + // RJCTODO: Rework this to do a search a bit differently, or simply indicate the file is missing... NodeList pathsNList = setEl.getElementsByTagName(PATH_EL); final int numPaths = pathsNList.getLength(); for (int j = 0; j < numPaths; ++j) { @@ -413,10 +372,10 @@ public class HashDbXML { logger.log(Level.WARNING, "No paths were set for hash_set at index {0}. Removing the database.", i); } else { - KNOWN_FILES_HASH_SET_TYPE typeDBType = KNOWN_FILES_HASH_SET_TYPE.valueOf(type); + KnownFilesType typeDBType = KnownFilesType.valueOf(type); try { - HashDb db = importHashDatabase(name, paths.get(0), useForIngestBool, showInboxMessagesBool, typeDBType); - if (typeDBType == KNOWN_FILES_HASH_SET_TYPE.NSRL) { + HashDb db = HashDb.openHashDatabase(name, paths.get(0), useForIngestBool, showInboxMessagesBool, typeDBType); + if (typeDBType == KnownFilesType.NSRL) { setNSRLSet(db); } else { @@ -438,7 +397,7 @@ public class HashDbXML { for(int i=0; i= length) { this.INDEXING_PROGBAR.setValue(100); this.setModal(false); From 7971872940cec74501be7a754e98f2ab5b633021 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Tue, 5 Nov 2013 22:22:34 -0500 Subject: [PATCH 072/169] Getting the advanced config UI for hash databases to work --- .../AddContentToHashDbAction.java | 4 +- .../autopsy/hashdatabase/Bundle.properties | 44 +- .../HashDatabaseOptionsPanelController.java | 8 +- .../autopsy/hashdatabase/HashDb.java | 7 +- .../HashDbCreateDatabaseDialog.java | 6 +- .../HashDbImportDatabaseDialog.java | 12 +- .../hashdatabase/HashDbIngestModule.java | 78 +- .../hashdatabase/HashDbSimplePanel.java | 20 +- ...l.form => HashSetsConfigurationPanel.form} | 44 +- ...l.java => HashSetsConfigurationPanel.java} | 808 ++++++++---------- .../{HashDbXML.java => HashSetsManager.java} | 284 +++--- .../autopsy/hashdatabase/IndexStatus.java | 7 +- .../autopsy/hashdatabase/ModalNoButtons.java | 6 +- 13 files changed, 618 insertions(+), 710 deletions(-) rename HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/{HashDbManagementPanel.form => HashSetsConfigurationPanel.form} (89%) rename HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/{HashDbManagementPanel.java => HashSetsConfigurationPanel.java} (58%) rename HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/{HashDbXML.java => HashSetsManager.java} (70%) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java index 7f01819fdd..8056c176c5 100755 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java @@ -104,9 +104,9 @@ public class AddContentToHashDbAction extends AbstractAction implements Presente // Get the current set of updateable hash databases and add each // one as a menu item. - List hashDatabases = HashDbXML.getInstance().getKnownBadSets(); + List hashDatabases = HashSetsManager.getInstance().getKnownBadHashSets(); if (!hashDatabases.isEmpty()) { - for (final HashDb database : HashDbXML.getInstance().getUpdateableHashSets()) { + for (final HashDb database : HashSetsManager.getInstance().getUpdateableHashSets()) { JMenuItem databaseItem = add(database.getDisplayName()); databaseItem.addActionListener(new ActionListener() { @Override diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties index 822541f5fa..4efbb6dca4 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties @@ -25,27 +25,6 @@ HashDbSearchPanel.cancelButton.text=Cancel HashDbSimplePanel.calcHashesButton.text=Calculate hashes even if no hash database is selected HashDbSimplePanel.nsrlDbLabel.text=NSRL Database: HashDbSimplePanel.nsrlDbLabelVal.text=- -HashDbManagementPanel.hashDbIndexStatusLabel.text=No database selected -HashDbManagementPanel.jLabel2.text=Name: -HashDbManagementPanel.showInboxMessagesCheckBox.text=Enable sending messages to inbox during ingest -HashDbManagementPanel.useForIngestCheckbox.text=Enable for ingest -HashDbManagementPanel.indexButton.text=Index -HashDbManagementPanel.indexLabel.text=Index Status: -HashDbManagementPanel.optionsLabel.text=Options -HashDbManagementPanel.jLabel4.text=Location: -HashDbManagementPanel.jLabel6.text=Type: -HashDbManagementPanel.ingestWarningLabel.text=Ingest is ongoing, some settings will be unavailable until it finishes. -HashDbManagementPanel.hashDbTypeLabel.text=No database selected -HashDbManagementPanel.typeLabel.text=Type: -HashDbManagementPanel.deleteButton.text=Delete Database -HashDbManagementPanel.importButton.text=Import Database -HashDbManagementPanel.hashDbNameLabel.text=No database selected -HashDbManagementPanel.nameLabel.text=Name: -HashDbManagementPanel.jButton3.text=Import Database -HashDbManagementPanel.locationLabel.text=Location: -HashDbManagementPanel.hashDbLocationLabel.text=No database selected -HashDbManagementPanel.informationLabel.text=Information -HashDbManagementPanel.hashDatabasesLabel.text=Hash Databases: OpenIDE-Module-Short-Description=Hash Database Ingest Module and hash db tools ModalNoButtons.CURRENTLYON_LABEL.text=Currently Indexing x of y ModalNoButtons.GO_GET_COFFEE_LABEL.text=Hash databases are currently being indexed, this may take some time. @@ -73,4 +52,25 @@ HashDbCreateDatabaseDialog.okButton.text=OK HashDbCreateDatabaseDialog.useForIngestCheckbox.text=Enable for ingest HashDbCreateDatabaseDialog.jLabel1.text=Display name of database: HashDbCreateDatabaseDialog.databaseNameTextField.text= -HashDbManagementPanel.importButton1.text=New Database +HashSetsConfigurationPanel.importButton1.text=New Database +HashSetsConfigurationPanel.jButton3.text=Import Database +HashSetsConfigurationPanel.jLabel6.text=Type: +HashSetsConfigurationPanel.jLabel4.text=Location: +HashSetsConfigurationPanel.jLabel2.text=Name: +HashSetsConfigurationPanel.hashDbTypeLabel.text=No database selected +HashSetsConfigurationPanel.deleteButton.text=Delete Database +HashSetsConfigurationPanel.hashDbIndexStatusLabel.text=No database selected +HashSetsConfigurationPanel.indexLabel.text=Index Status: +HashSetsConfigurationPanel.indexButton.text=Index +HashSetsConfigurationPanel.locationLabel.text=Location: +HashSetsConfigurationPanel.ingestWarningLabel.text=Ingest is ongoing, some settings will be unavailable until it finishes. +HashSetsConfigurationPanel.hashDbLocationLabel.text=No database selected +HashSetsConfigurationPanel.typeLabel.text=Type: +HashSetsConfigurationPanel.hashDatabasesLabel.text=Hash Databases: +HashSetsConfigurationPanel.importButton.text=Import Database +HashSetsConfigurationPanel.hashDbNameLabel.text=No database selected +HashSetsConfigurationPanel.nameLabel.text=Name: +HashSetsConfigurationPanel.informationLabel.text=Information +HashSetsConfigurationPanel.optionsLabel.text=Options +HashSetsConfigurationPanel.useForIngestCheckbox.text=Enable for ingest +HashSetsConfigurationPanel.showInboxMessagesCheckBox.text=Enable sending messages to inbox during ingest diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDatabaseOptionsPanelController.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDatabaseOptionsPanelController.java index 7b81b5619f..8523116156 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDatabaseOptionsPanelController.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDatabaseOptionsPanelController.java @@ -36,7 +36,7 @@ id = "HashDatabase") @org.openide.util.NbBundle.Messages({"OptionsCategory_Name_HashDatabase=Hash Database", "OptionsCategory_Keywords_HashDatabase=Hash Database"}) public final class HashDatabaseOptionsPanelController extends OptionsPanelController { - private HashDbManagementPanel panel; + private HashSetsConfigurationPanel panel; private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); private boolean changed; @@ -55,7 +55,7 @@ public final class HashDatabaseOptionsPanelController extends OptionsPanelContro @Override public void cancel() { // Reset the XML on cancel - HashDbXML.getInstance().reload(); + HashSetsManager.getInstance().loadLastSavedConfiguration(); } @Override @@ -88,9 +88,9 @@ public final class HashDatabaseOptionsPanelController extends OptionsPanelContro pcs.removePropertyChangeListener(l); } - private HashDbManagementPanel getPanel() { + private HashSetsConfigurationPanel getPanel() { if (panel == null) { - panel = new HashDbManagementPanel(); + panel = new HashSetsConfigurationPanel(); } return panel; } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index 024ea46764..27078e012e 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -64,7 +64,12 @@ public class HashDb implements Comparable { * @throws TskCoreException */ public static HashDb openHashDatabase(String hashSetName, String databasePath, boolean useForIngest, boolean showInboxMessages, KnownFilesType knownType) throws TskCoreException { - return new HashDb(SleuthkitJNI.openHashDatabase(databasePath), hashSetName, databasePath, useForIngest, showInboxMessages, knownType); + if (knownType == HashDb.KnownFilesType.NSRL) { + return new HashDb(SleuthkitJNI.openNSRLDatabase(databasePath), hashSetName, databasePath, useForIngest, showInboxMessages, knownType); + } + else { + return new HashDb(SleuthkitJNI.openHashDatabase(databasePath), hashSetName, databasePath, useForIngest, showInboxMessages, knownType); + } } /** diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java index 86d01b8def..1a69551f0b 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java @@ -58,8 +58,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { } super.approveSelection(); } - }; - + }; initComponents(); customizeComponents(); } @@ -75,9 +74,12 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { HashDb doDialog() { newHashDb = null; + + // Center and display the dialog. Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); setLocation((screenDimension.width - getSize().width) / 2, (screenDimension.height - getSize().height) / 2); this.setVisible(true); + return newHashDb; } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java index 42e8af23a8..8dc8e459ed 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java @@ -216,10 +216,6 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { }// //GEN-END:initComponents private void browseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseButtonActionPerformed - File currentDir = new File(databasePathTextField.getText()); - if (currentDir.exists()) { - fileChooser.setCurrentDirectory(currentDir); - } if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { File databaseFile = fileChooser.getSelectedFile(); try { @@ -256,7 +252,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { JOptionPane.showMessageDialog(this, "Database display name cannot be empty."); return; } - + File file = new File(databasePathTextField.getText()); if (!file.exists()) { JOptionPane.showMessageDialog(this, "Selected database does not exist."); @@ -282,7 +278,11 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { } try { - selectedHashDb = HashDb.openHashDatabase(databaseNameTextField.getText(), filePath, useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); + selectedHashDb = HashDb.openHashDatabase(databaseNameTextField.getText(), filePath, useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); + + +// if (!selectedHashDb.hasTextLookupIndexOnly()) + } catch (TskCoreException ex) { Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.WARNING, "Failed to open hash database at " + filePath, ex); diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java index a39292889d..7fb3650df8 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011-2013 Basis Technology Corp. + * Copyright 2011 - 2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,7 +24,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; -import org.openide.util.Exceptions; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.PipelineContext; @@ -68,7 +67,7 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { static long calctime = 0; static long lookuptime = 0; private Map knownBadSets = new HashMap<>(); - private HashDbManagementPanel panel; + private HashSetsConfigurationPanel panel; private final Hash hasher = new Hash(); private HashDbIngestModule() { @@ -82,26 +81,41 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { return instance; } + @Override + public String getName() { + return MODULE_NAME; + } + + @Override + public String getDescription() { + return MODULE_DESCRIPTION; + } + + @Override + public String getVersion() { + return MODULE_VERSION; + } + @Override public void init(IngestModuleInit initContext) { services = IngestServices.getDefault(); this.skCase = Case.getCurrentCase().getSleuthkitCase(); try { - HashDbXML hdbxml = HashDbXML.getInstance(); + HashSetsManager hdbxml = HashSetsManager.getInstance(); nsrlSet = null; knownBadSets.clear(); nsrlIsSet = false; knownBadIsSet = false; calcHashesIsSet = hdbxml.shouldAlwaysCalculateHashes(); - HashDb nsrl = hdbxml.getNSRLSet(); + HashDb nsrl = hdbxml.getNSRLHashSet(); if (nsrl != null && nsrl.getUseForIngest() && IndexStatus.isIngestible(nsrl.getStatus())) { nsrlIsSet = true; this.nsrlSet = nsrl; nsrlPointer = skCase.setNSRLDatabase(nsrl.getDatabasePath()); } - for (HashDb db : hdbxml.getKnownBadSets()) { + for (HashDb db : hdbxml.getKnownBadHashSets()) { IndexStatus status = db.getStatus(); if (db.getUseForIngest() && IndexStatus.isIngestible(status)) { knownBadIsSet = true; @@ -144,51 +158,13 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { detailsSb.append(""); services.postMessage(IngestMessage.createMessage(++messageId, IngestMessage.MessageType.INFO, this, "Hash Lookup Results", detailsSb.toString())); - clearHashDatabaseHandles(); } } - - private void clearHashDatabaseHandles() { - try { - HashDbXML.getInstance().closeHashDatabases(); - } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Error clearing hash database handles. ", ex); - } - this.nsrlIsSet = false; - this.knownBadIsSet = false; - } - /** - * notification from manager to stop processing due to some interruption - * (user, error, exception) - */ @Override public void stop() { - clearHashDatabaseHandles(); } - - /** - * get specific name of the module should be unique across modules, a - * user-friendly name of the module shown in GUI - * - * @return The name of this Ingest Module - */ - @Override - public String getName() { - return MODULE_NAME; - } - - @Override - public String getDescription() { - return MODULE_DESCRIPTION; - } - - @Override - public String getVersion() { - return MODULE_VERSION; - } - - + @Override public ProcessResult process(PipelineContextpipelineContext, AbstractFile file) { //skip unalloc @@ -217,7 +193,7 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { @Override public javax.swing.JPanel getSimpleConfiguration(String context) { - HashDbXML.getInstance().reload(); + HashSetsManager.getInstance().loadLastSavedConfiguration(); return new HashDbSimplePanel(); } @@ -233,16 +209,16 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { getPanel().store(); } - private HashDbManagementPanel getPanel() { + private HashSetsConfigurationPanel getPanel() { if (panel == null) { - panel = new HashDbManagementPanel(); + panel = new HashSetsConfigurationPanel(); } return panel; } @Override public void saveSimpleConfiguration() { - HashDbXML.getInstance().save(); + HashSetsManager.getInstance().save(); } private void processBadFile(AbstractFile abstractFile, String md5Hash, String hashSetName, boolean showInboxMessage) { @@ -378,8 +354,8 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { public ArrayList getKnownBadSetNames() { ArrayList knownBadSetNames = new ArrayList<>(); - HashDbXML hdbxml = HashDbXML.getInstance(); - for (HashDb db : hdbxml.getKnownBadSets()) { + HashSetsManager hdbxml = HashSetsManager.getInstance(); + for (HashDb db : hdbxml.getKnownBadHashSets()) { knownBadSetNames.add(db.getDisplayName()); } return knownBadSetNames; diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.java index 81c2adac37..c065211ebe 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.java @@ -43,10 +43,10 @@ public class HashDbSimplePanel extends javax.swing.JPanel { } private void reloadCalc() { - final HashDbXML xmlHandle = HashDbXML.getInstance(); - final HashDb nsrlDb = xmlHandle.getNSRLSet(); + final HashSetsManager xmlHandle = HashSetsManager.getInstance(); + final HashDb nsrlDb = xmlHandle.getNSRLHashSet(); final boolean nsrlUsed = nsrlDb != null && nsrlDb.getUseForIngest()== true && nsrlDb.hasLookupIndex(); - final List knowns = xmlHandle.getKnownBadSets(); + final List knowns = xmlHandle.getKnownBadHashSets(); final boolean knownExists = !knowns.isEmpty(); boolean knownUsed = false; if (knownExists) { @@ -70,7 +70,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { } private void customizeComponents() { - final HashDbXML xmlHandle = HashDbXML.getInstance(); + final HashSetsManager xmlHandle = HashSetsManager.getInstance(); calcHashesButton.addActionListener( new ActionListener() { @Override @@ -104,7 +104,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { } private void reloadSets() { - nsrl = HashDbXML.getInstance().getNSRLSet(); + nsrl = HashSetsManager.getInstance().getNSRLHashSet(); if (nsrl == null || nsrl.getUseForIngest() == false) { nsrlDbLabelVal.setText("Disabled"); @@ -199,7 +199,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { private class HashTableModel extends AbstractTableModel { - private HashDbXML xmlHandle = HashDbXML.getInstance(); + private HashSetsManager xmlHandle = HashSetsManager.getInstance(); private void resync() { fireTableDataChanged(); @@ -207,7 +207,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { @Override public int getRowCount() { - int size = xmlHandle.getKnownBadSets().size(); + int size = xmlHandle.getKnownBadHashSets().size(); return size == 0 ? 1 : size; } @@ -218,14 +218,14 @@ public class HashDbSimplePanel extends javax.swing.JPanel { @Override public Object getValueAt(int rowIndex, int columnIndex) { - if (xmlHandle.getKnownBadSets().isEmpty()) { + if (xmlHandle.getKnownBadHashSets().isEmpty()) { if (columnIndex == 0) { return ""; } else { return "Disabled"; } } else { - HashDb db = xmlHandle.getKnownBadSets().get(rowIndex); + HashDb db = xmlHandle.getKnownBadHashSets().get(rowIndex); if (columnIndex == 0) { return db.getUseForIngest(); } else { @@ -242,7 +242,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { @Override public void setValueAt(Object aValue, int rowIndex, int columnIndex) { if(columnIndex == 0){ - HashDb db = xmlHandle.getKnownBadSets().get(rowIndex); + HashDb db = xmlHandle.getKnownBadHashSets().get(rowIndex); IndexStatus status = IndexStatus.NO_INDEX; try { status = db.getStatus(); diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.form similarity index 89% rename from HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form rename to HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.form index 5530d19c33..a476718dd9 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.form @@ -5,21 +5,21 @@ - + - + - + @@ -29,7 +29,7 @@ - + @@ -190,7 +190,7 @@ - + @@ -230,7 +230,7 @@ - + @@ -252,7 +252,7 @@ - + @@ -271,70 +271,70 @@ - + - + - + - + - + - + - + - + - + - + @@ -345,7 +345,7 @@ - + @@ -355,7 +355,7 @@ - + @@ -365,14 +365,14 @@ - + - + @@ -386,7 +386,7 @@ - + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.java similarity index 58% rename from HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java rename to HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.java index 43afd118c1..8de8c7a85b 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManagementPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011 - 2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.sleuthkit.autopsy.hashdatabase; import java.awt.Color; @@ -27,9 +26,7 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JLabel; @@ -42,117 +39,313 @@ import javax.swing.table.AbstractTableModel; import javax.swing.table.TableCellRenderer; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.coreutils.Logger; +import static org.sleuthkit.autopsy.hashdatabase.IndexStatus.NO_INDEX; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.TskCoreException; -final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsPanel { - - private HashSetTableModel hashSetTableModel; - private static final Logger logger = Logger.getLogger(HashDbManagementPanel.class.getName()); - private boolean ingestRunning = false; - - - //keep track of dbs being indexed, since HashDb objects are reloaded, - //we cannot rely on their status - private final MapindexingState = new HashMap(); - - HashDbManagementPanel() { - this.hashSetTableModel = new HashSetTableModel(); - initComponents(); - customizeComponents(); +/** + * Instances of this class provide a UI for managing the hash sets configuration. + */ +final class HashSetsConfigurationPanel extends javax.swing.JPanel implements OptionsPanel { + private HashSetsManager hashSetManager = HashSetsManager.getInstance(); + private HashSetTableModel hashSetTableModel = new HashSetTableModel(); + HashSetsConfigurationPanel() { + initComponents(); + customizeComponents(); } private void customizeComponents() { - setName("Hash Database Configuration"); + setName("Hash Set Configuration"); this.ingestWarningLabel.setVisible(false); this.hashSetTable.setModel(hashSetTableModel); this.hashSetTable.setTableHeader(null); hashSetTable.getParent().setBackground(hashSetTable.getBackground()); hashSetTable.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION); hashSetTable.getSelectionModel().addListSelectionListener(new ListSelectionListener() { - @Override public void valueChanged(ListSelectionEvent e) { - ListSelectionModel listSelectionModel = (ListSelectionModel) e.getSource(); - if (!listSelectionModel.isSelectionEmpty()) { - int index = listSelectionModel.getMinSelectionIndex(); - listSelectionModel.setSelectionInterval(index, index); - HashDbXML loader = HashDbXML.getInstance(); - HashDb current = loader.getAllSets().get(index); - initUI(current); - } else { - initUI(null); + if (!e.getValueIsAdjusting()) { + updateComponents(); } } }); } - private void initUI(HashDb db) { + private void updateComponents() { + HashDb db = ((HashSetTable)hashSetTable).getSelection(); + if (db == null) { + hashDbLocationLabel.setText("No database selected"); + hashDbNameLabel.setText("No database selected"); + hashDbIndexStatusLabel.setText("No database selected"); + hashDbTypeLabel.setText("No database selected"); + } + else { + this.hashDbLocationLabel.setToolTipText(db.getDatabasePath()); + if (db.getDatabasePath().length() > 50){ + String shortenedPath = db.getDatabasePath(); + shortenedPath = shortenedPath.substring(0, 10 + shortenedPath.substring(10).indexOf(File.separator) + 1) + "..." + shortenedPath.substring((shortenedPath.length() - 20) + shortenedPath.substring(shortenedPath.length() - 20).indexOf(File.separator)); + hashDbLocationLabel.setText(shortenedPath); + } + else { + hashDbLocationLabel.setText(db.getDatabasePath()); + } + hashDbNameLabel.setText(db.getDisplayName()); + hashDbTypeLabel.setText(db.getKnownFilesType().getDisplayName()); + } + updateStatusComponents(db); + boolean ingestRunning = IngestManager.getDefault().isIngestRunning(); boolean useForIngestEnabled = db != null && !ingestRunning; boolean useForIngestSelected = db != null && db.getUseForIngest(); boolean showInboxMessagesEnabled = db != null && !ingestRunning && useForIngestSelected && db.getKnownFilesType().equals(HashDb.KnownFilesType.KNOWN_BAD); boolean showInboxMessagesSelected = db != null && db.getShowInboxMessages(); boolean deleteButtonEnabled = db != null && !ingestRunning; boolean importButtonEnabled = !ingestRunning; - if (db == null) { - setButtonFromIndexStatus(this.indexButton, this.hashDbIndexStatusLabel, IndexStatus.NO_INDEX); - this.hashDbLocationLabel.setText("No database selected"); - this.hashDbNameLabel.setText("No database selected"); - this.hashDbIndexStatusLabel.setText("No database selected"); - this.hashDbTypeLabel.setText("No database selected"); - } else { - //check if dn in indexing state - String dbName = db.getDisplayName(); - IndexStatus status = IndexStatus.NO_INDEX; + useForIngestCheckbox.setSelected(useForIngestSelected); + useForIngestCheckbox.setEnabled(useForIngestEnabled); + showInboxMessagesCheckBox.setSelected(showInboxMessagesSelected); + showInboxMessagesCheckBox.setEnabled(showInboxMessagesEnabled); + deleteButton.setEnabled(deleteButtonEnabled); + importButton.setEnabled(importButtonEnabled); + optionsLabel.setEnabled(useForIngestEnabled || showInboxMessagesEnabled); + optionsSeparator.setEnabled(useForIngestEnabled || showInboxMessagesEnabled); + ingestWarningLabel.setVisible(ingestRunning); + importButton.setEnabled(!ingestRunning); // RJCTODO: What about the other buttons? + } + + void updateStatusComponents(HashDb hashDb) { + if (hashDb == null) { + indexButton.setText("Index"); + hashDbIndexStatusLabel.setForeground(Color.black); + indexButton.setEnabled(false); + } + else { + IndexStatus status = IndexStatus.UNKNOWN; try { - status = db.getStatus(); + status = hashDb.getStatus(); } catch (TskCoreException ex) { - // RJCTODO + // RJCTODO: Need a status unknown? + // Logger.getLogger(HashDbIngestModule.class.getName()) + } + + hashDbIndexStatusLabel.setText(status.message()); + switch (status) { + case NO_INDEX: + indexButton.setText("Index"); + hashDbIndexStatusLabel.setForeground(Color.red); + indexButton.setEnabled(true); + break; + case INDEXING: + indexButton.setText("Indexing"); + hashDbIndexStatusLabel.setForeground(Color.black); + indexButton.setEnabled(false); + break; + case UNKNOWN: + indexButton.setText("Index"); + hashDbIndexStatusLabel.setForeground(Color.red); + indexButton.setEnabled(false); + case INDEXED: + case INDEX_ONLY: + default: + indexButton.setText("Index"); + hashDbIndexStatusLabel.setForeground(Color.black); + indexButton.setEnabled(false); + break; } - Boolean state = indexingState.get(dbName); - if (state != null && state.equals(Boolean.TRUE) ) { - status = IndexStatus.INDEXING; - } - - setButtonFromIndexStatus(this.indexButton, this.hashDbIndexStatusLabel, status); - String shortenPath = db.getDatabasePath(); - this.hashDbLocationLabel.setToolTipText(shortenPath); - if(shortenPath.length() > 50){ - shortenPath = shortenPath.substring(0, 10 + shortenPath.substring(10).indexOf(File.separator) + 1) + "..." + - shortenPath.substring((shortenPath.length() - 20) + shortenPath.substring(shortenPath.length() - 20).indexOf(File.separator)); - } - this.hashDbLocationLabel.setText(shortenPath); - this.hashDbNameLabel.setText(db.getDisplayName()); - this.hashDbTypeLabel.setText(db.getKnownFilesType().getDisplayName()); } - this.useForIngestCheckbox.setSelected(useForIngestSelected); - this.useForIngestCheckbox.setEnabled(useForIngestEnabled); - this.showInboxMessagesCheckBox.setSelected(showInboxMessagesSelected); - this.showInboxMessagesCheckBox.setEnabled(showInboxMessagesEnabled); - this.deleteButton.setEnabled(deleteButtonEnabled); - this.importButton.setEnabled(importButtonEnabled); - this.optionsLabel.setEnabled(useForIngestEnabled || showInboxMessagesEnabled); - this.optionsSeparator.setEnabled(useForIngestEnabled || showInboxMessagesEnabled); + + if (IngestManager.getDefault().isIngestRunning()) { + indexButton.setEnabled(false); + } + } + + @Override + public void load() { + hashSetTable.clearSelection(); + hashSetTableModel.refresh(); +// updateComponents(null); + } + + @Override + public void store() { + //Checking for for any unindexed databases + List unindexed = new ArrayList<>(); + for (HashDb hashSet : hashSetManager.getAllHashSets()) { + if (!hashSet.hasLookupIndex()) { + unindexed.add(hashSet); + } + } + + // RJCTODO:Whaaaaat? + //If unindexed ones are found, show a popup box that will either index them, or remove them. + if (unindexed.size() == 1){ + showInvalidIndex(false, unindexed); + } + else if (unindexed.size() > 1){ + showInvalidIndex(true, unindexed); + } + + hashSetManager.save(); } /** - * Sets the current state of ingest. - * Don't allow any changes if ingest is running. - * @param running Whether ingest is running or not. + * Removes a list of HashDbs from the dialog panel that do not have a companion -md5.idx file. + * Occurs when user clicks "No" to the dialog popup box. + * @param toRemove a list of HashDbs that are unindexed + */ + void removeThese(List toRemove) { + for (HashDb hashDb : toRemove) { + hashSetManager.removeHashSet(hashDb); + } + hashSetTableModel.refresh(); + } + + /** + * Displays the popup box that tells user that some of his databases are unindexed, along with solutions. + * This method is related to ModalNoButtons, to be removed at a later date. + * @param plural Whether or not there are multiple unindexed databases + * @param unindexed The list of unindexed databases. Can be of size 1. */ - private void setIngestStatus(boolean running) { - ingestRunning = running; - ingestWarningLabel.setVisible(running); - importButton.setEnabled(!running); - - int selection = getSelection(); - if(selection != -1) { - initUI(HashDbXML.getInstance().getAllSets().get(selection)); + private void showInvalidIndex(boolean plural, List unindexed){ + String total = ""; + String message; + for(HashDb hdb : unindexed){ + total+= "\n" + hdb.getDisplayName(); + } + if(plural){ + message = "The following databases are not indexed, would you like to index them now? \n " + total; + } + else{ + message = "The following database is not indexed, would you like to index it now? \n" + total; + } + int res = JOptionPane.showConfirmDialog(this, message, "Unindexed databases", JOptionPane.YES_NO_OPTION); + if(res == JOptionPane.YES_OPTION){ + ModalNoButtons indexingDialog = new ModalNoButtons(this, new Frame(),unindexed); + indexingDialog.setLocationRelativeTo(null); + indexingDialog.setVisible(true); + indexingDialog.setModal(true); + hashSetTableModel.refresh(); + } + if(res == JOptionPane.NO_OPTION){ + JOptionPane.showMessageDialog(this, "All unindexed databases will be removed the list"); + removeThese(unindexed); } } + boolean valid() { + // TODO check whether form is consistent and complete + return true; + } + + /** + * This class implements a table for displaying configured hash sets. + */ + private class HashSetTable extends JTable { + @Override + public Component prepareRenderer(TableCellRenderer renderer, int row, int column) { + // Use the hash set name as the cell text. + JComponent cellRenderer = (JComponent)super.prepareRenderer(renderer, row, column); + cellRenderer.setToolTipText((String)getValueAt(row, column)); + + // Give the user a visual indication of any hash sets with a hash + // database that needs to be indexed by displaying the hash set name + // in red. + if (hashSetTableModel.indexExists(row)){ + cellRenderer.setForeground(Color.black); + } + else{ + cellRenderer.setForeground(Color.red); + } + + return cellRenderer; + } + + public HashDb getSelection() { + return hashSetTableModel.getHashSetAt(getSelectionModel().getMinSelectionIndex()); + } + + public void setSelection(int index) { + if (index >= 0 && index < hashSetTable.getRowCount()) { + getSelectionModel().setSelectionInterval(index, index); + } + } + + public void selectRowByName(String name) { + setSelection(hashSetTableModel.getIndexByName(name)); + } + } + + /** + * This class implements the table model for the table used to display + * configured hash sets. + */ + private class HashSetTableModel extends AbstractTableModel { + List hashSets = HashSetsManager.getInstance().getAllHashSets(); + + @Override + public int getColumnCount() { + return 1; + } + + @Override + public int getRowCount() { + return hashSets.size(); + } + + @Override + public String getColumnName(int column) { + return "Name"; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + return hashSets.get(rowIndex).getDisplayName(); + } + + private boolean indexExists(int rowIndex){ + return hashSets.get(rowIndex).hasLookupIndex(); + } + + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return false; + } + + @Override + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + throw new UnsupportedOperationException("Editing of cells is not supported"); + } + + @Override + public Class getColumnClass(int c) { + return getValueAt(0, c).getClass(); + } + + HashDb getHashSetAt(int index) { + if (!hashSets.isEmpty() && index >= 0 && index < hashSets.size()) { + return hashSets.get(index); + } + else { + return null; + } + } + + int getIndexByName(String name) { + for (int i = 0; i < hashSets.size(); ++i) { + if (hashSets.get(i).getDisplayName().equals(name)) { + return i; + } + } + return -1; + } + + void refresh() { + hashSets = HashSetsManager.getInstance().getAllHashSets(); + fireTableDataChanged(); + } + } + /** * 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 @@ -188,20 +381,20 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP optionsSeparator = new javax.swing.JSeparator(); importButton1 = new javax.swing.JButton(); - org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.jLabel2.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.jLabel2.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jLabel4, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.jLabel4.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jLabel4, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.jLabel4.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jLabel6, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.jLabel6.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jLabel6, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.jLabel6.text")); // NOI18N jButton3.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jButton3, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.jButton3.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jButton3, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.jButton3.text")); // NOI18N setMinimumSize(new java.awt.Dimension(700, 500)); setPreferredSize(new java.awt.Dimension(700, 500)); ingestWarningLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/warning16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(ingestWarningLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.ingestWarningLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(ingestWarningLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.ingestWarningLabel.text")); // NOI18N hashSetTable.setModel(new javax.swing.table.DefaultTableModel( new Object [][] { @@ -221,7 +414,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP jScrollPane1.setViewportView(hashSetTable); deleteButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/delete16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(deleteButton, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.deleteButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(deleteButton, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.deleteButton.text")); // NOI18N deleteButton.setMaximumSize(new java.awt.Dimension(140, 25)); deleteButton.setMinimumSize(new java.awt.Dimension(140, 25)); deleteButton.setPreferredSize(new java.awt.Dimension(140, 25)); @@ -232,7 +425,7 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP }); importButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/import16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(importButton, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.importButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(importButton, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.importButton.text")); // NOI18N importButton.setMaximumSize(new java.awt.Dimension(140, 25)); importButton.setMinimumSize(new java.awt.Dimension(140, 25)); importButton.setPreferredSize(new java.awt.Dimension(140, 25)); @@ -242,25 +435,25 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP } }); - org.openide.awt.Mnemonics.setLocalizedText(hashDatabasesLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.hashDatabasesLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(hashDatabasesLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.hashDatabasesLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(nameLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.nameLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(nameLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.nameLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(hashDbNameLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.hashDbNameLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(hashDbNameLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.hashDbNameLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(hashDbLocationLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.hashDbLocationLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(hashDbLocationLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.hashDbLocationLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(locationLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.locationLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(locationLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.locationLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(typeLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.typeLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(typeLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.typeLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(hashDbTypeLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.hashDbTypeLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(hashDbTypeLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.hashDbTypeLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(hashDbIndexStatusLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.hashDbIndexStatusLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(hashDbIndexStatusLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.hashDbIndexStatusLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(indexLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.indexLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(indexLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.indexLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(indexButton, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.indexButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(indexButton, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.indexButton.text")); // NOI18N indexButton.setEnabled(false); indexButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -268,26 +461,26 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP } }); - org.openide.awt.Mnemonics.setLocalizedText(useForIngestCheckbox, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.useForIngestCheckbox.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(useForIngestCheckbox, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.useForIngestCheckbox.text")); // NOI18N useForIngestCheckbox.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { useForIngestCheckboxActionPerformed(evt); } }); - org.openide.awt.Mnemonics.setLocalizedText(showInboxMessagesCheckBox, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.showInboxMessagesCheckBox.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(showInboxMessagesCheckBox, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.showInboxMessagesCheckBox.text")); // NOI18N showInboxMessagesCheckBox.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { showInboxMessagesCheckBoxActionPerformed(evt); } }); - org.openide.awt.Mnemonics.setLocalizedText(informationLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.informationLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(informationLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.informationLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(optionsLabel, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.optionsLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(optionsLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.optionsLabel.text")); // NOI18N importButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/new16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(importButton1, org.openide.util.NbBundle.getMessage(HashDbManagementPanel.class, "HashDbManagementPanel.importButton1.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(importButton1, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.importButton1.text")); // NOI18N importButton1.setMaximumSize(new java.awt.Dimension(140, 25)); importButton1.setMinimumSize(new java.awt.Dimension(140, 25)); importButton1.setPreferredSize(new java.awt.Dimension(140, 25)); @@ -401,228 +594,88 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP }// //GEN-END:initComponents private void indexButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_indexButtonActionPerformed - int selected = getSelection(); - final HashDb current = HashDbXML.getInstance().getAllSets().get(selected); - current.addPropertyChangeListener(new PropertyChangeListener() { - - @Override - public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals(HashDb.Event.INDEXING_DONE.toString())) { - //update tracking of indexing status - indexingState.put((String)evt.getNewValue(), Boolean.FALSE); - IndexStatus status = IndexStatus.NO_INDEX; - try { - status = current.getStatus(); + final HashDb hashDbToBeIndexed = ((HashSetTable)hashSetTable).getSelection(); + if (hashDbToBeIndexed != null) { + // Add a listener for the INDEXING_DONE event. The listener will update + // the UI. + hashDbToBeIndexed.addPropertyChangeListener(new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals(HashDb.Event.INDEXING_DONE.toString())) { + HashDb selectedHashDb = ((HashSetTable)hashSetTable).getSelection(); + if (selectedHashDb != null && hashDbToBeIndexed != null && hashDbToBeIndexed.equals(selectedHashDb)) { + updateStatusComponents(selectedHashDb); + } } - catch (TskCoreException ex) { - // RJCTODO - } - setButtonFromIndexStatus(indexButton, hashDbIndexStatusLabel, status); - resync(); - } - } + } + }); - }); - indexingState.put(current.getDisplayName(), Boolean.TRUE); - ModalNoButtons singleMNB = new ModalNoButtons(this, new Frame(), current); //Modal reference, to be removed later - singleMNB.setLocationRelativeTo(null); - singleMNB.setVisible(true); - singleMNB.setModal(true); //End Modal reference - indexingState.put(current.getDisplayName(), Boolean.FALSE); - IndexStatus status = IndexStatus.NO_INDEX; - try { - status = current.getStatus(); + // Display a modal dialog box to kick off the indexing on a worker thread + // and try to persuade the user to wait for the indexing task to finish. + // TODO: This defeats the purpose of doing the indexing on a worker thread. + // The user may also cancel the dialog and change the hash sets configuration. + // That should be fine, as long as the indexing DB is not deleted, which + // shu;d be able to be controlled. + ModalNoButtons indexDialog = new ModalNoButtons(this, new Frame(), hashDbToBeIndexed); + indexDialog.setLocationRelativeTo(null); + indexDialog.setVisible(true); + indexDialog.setModal(true); } - catch (TskCoreException ex) { - // RJCTODO - } - setButtonFromIndexStatus(indexButton, this.hashDbIndexStatusLabel, status); }//GEN-LAST:event_indexButtonActionPerformed private void deleteButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteButtonActionPerformed - if (JOptionPane.showConfirmDialog(null, "This will remove the hash database entry globally (for all Cases). Do you want to proceed? ", - "Deleting a Hash Database Entry", - JOptionPane.YES_NO_OPTION, - JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) { - - int selected = getSelection(); - HashDbXML xmlHandle = HashDbXML.getInstance(); - if (xmlHandle.getNSRLSet() != null) { - if (selected == 0) { - HashDbXML.getInstance().removeNSRLSet(); - } else { - HashDbXML.getInstance().removeKnownBadSetAt(selected - 1); - } - } else { - HashDbXML.getInstance().removeKnownBadSetAt(selected); + if (JOptionPane.showConfirmDialog(null, "This will remove the hash database entry globally (for all Cases). Do you want to proceed? ", "Deleting a Hash Database Entry", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) { + HashDb hashDb = ((HashSetTable)hashSetTable).getSelection(); + if (hashDb != null) { + hashSetManager.removeHashSet(hashDb); + hashSetTableModel.refresh(); } - hashSetTableModel.resync(); } }//GEN-LAST:event_deleteButtonActionPerformed private void hashSetTableKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_hashSetTableKeyPressed if (evt.getKeyCode() == KeyEvent.VK_DELETE) { - int selected = getSelection(); - HashDbXML xmlHandle = HashDbXML.getInstance(); - if (xmlHandle.getNSRLSet() != null) { - if (selected == 0) { - HashDbXML.getInstance().removeNSRLSet(); - } else { - HashDbXML.getInstance().removeKnownBadSetAt(selected - 1); - } - } else { - HashDbXML.getInstance().removeKnownBadSetAt(selected); + HashDb hashDb = ((HashSetTable)hashSetTable).getSelection(); + if (hashDb != null) { + hashSetManager.removeHashSet(hashDb); + hashSetTableModel.refresh(); } - } - hashSetTableModel.resync(); + } }//GEN-LAST:event_hashSetTableKeyPressed private void useForIngestCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_useForIngestCheckboxActionPerformed - int selected = getSelection(); - HashDbXML xmlHandle = HashDbXML.getInstance(); - if (xmlHandle.getNSRLSet() != null) { - if (selected == 0) { - HashDb current = HashDbXML.getInstance().getNSRLSet(); - current.setUseForIngest(useForIngestCheckbox.isSelected()); - HashDbXML.getInstance().setNSRLSet(current); - } else { - HashDb current = HashDbXML.getInstance().getKnownBadSets().remove(selected - 1); - current.setUseForIngest(useForIngestCheckbox.isSelected()); - HashDbXML.getInstance().addKnownBadSet(selected - 1, current); - this.showInboxMessagesCheckBox.setEnabled(useForIngestCheckbox.isSelected()); - } - } else { - HashDb current = HashDbXML.getInstance().getKnownBadSets().remove(selected); - current.setUseForIngest(useForIngestCheckbox.isSelected()); - HashDbXML.getInstance().addKnownBadSet(selected, current); - this.showInboxMessagesCheckBox.setEnabled(useForIngestCheckbox.isSelected()); + HashDb hashDb = ((HashSetTable)hashSetTable).getSelection(); + if (hashDb != null) { + hashDb.setUseForIngest(useForIngestCheckbox.isSelected()); + showInboxMessagesCheckBox.setEnabled(useForIngestCheckbox.isSelected()); } }//GEN-LAST:event_useForIngestCheckboxActionPerformed private void showInboxMessagesCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showInboxMessagesCheckBoxActionPerformed - int selected = getSelection(); - HashDbXML xmlHandle = HashDbXML.getInstance(); - if (xmlHandle.getNSRLSet() != null) { - if (selected == 0) { - HashDb current = HashDbXML.getInstance().getNSRLSet(); - current.setShowInboxMessages(showInboxMessagesCheckBox.isSelected()); - HashDbXML.getInstance().setNSRLSet(current); - } else { - HashDb current = HashDbXML.getInstance().getKnownBadSets().remove(selected - 1); - current.setShowInboxMessages(showInboxMessagesCheckBox.isSelected()); - HashDbXML.getInstance().addKnownBadSet(selected - 1, current); - } - } else { - HashDb current = HashDbXML.getInstance().getKnownBadSets().remove(selected); - current.setShowInboxMessages(showInboxMessagesCheckBox.isSelected()); - HashDbXML.getInstance().addKnownBadSet(selected, current); + HashDb hashDb = ((HashSetTable)hashSetTable).getSelection(); + if (hashDb != null) { + hashDb.setShowInboxMessages(showInboxMessagesCheckBox.isSelected()); } }//GEN-LAST:event_showInboxMessagesCheckBoxActionPerformed private void importButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importButtonActionPerformed - importHashSet(evt); + HashDb hashDb = new HashDbImportDatabaseDialog().doDialog(); + if (hashDb != null) { + hashSetManager.addHashSet(hashDb); + hashSetTableModel.refresh(); + ((HashSetTable)hashSetTable).selectRowByName(hashDb.getDisplayName()); + } }//GEN-LAST:event_importButtonActionPerformed private void importButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importButton1ActionPerformed - createHashSet(evt); + HashDb hashDb = new HashDbCreateDatabaseDialog().doDialog(); + if (null != hashDb) { + hashSetManager.addHashSet(hashDb); + hashSetTableModel.refresh(); + ((HashSetTable)hashSetTable).selectRowByName(hashDb.getDisplayName()); + } }//GEN-LAST:event_importButton1ActionPerformed - - @Override - public void load() { - hashSetTable.clearSelection(); // Deselect all rows - HashDbXML.getInstance().reload(); // Reload XML - initUI(null); // Update the UI - hashSetTableModel.resync(); // resync the table - setIngestStatus(IngestManager.getDefault().isIngestRunning()); // check if ingest is running - } - - @Override - /** - * Saves the HashDb's current state. - * This version of store is modified heavily to make use of the ModalNoButtons class. - * The only call that matters is the final HashDbXML.getCurrent().save() - */ - public void store() { - //Checking for for any unindexed databases - List unindexed = new ArrayList(); - for(int i = 0; i < hashSetTableModel.getRowCount(); i++){ - if(! hashSetTableModel.indexExists(i)){ - unindexed.add(hashSetTableModel.getDBAt(i)); - } - } - //If unindexed ones are found, show a popup box that will either index them, or remove them. - if (unindexed.size() == 1){ - showInvalidIndex(false, unindexed); - } - else if (unindexed.size() > 1){ - showInvalidIndex(true, unindexed); - } - HashDbXML.getInstance().save(); - - } - - - /** - * Removes a list of HashDbs from the dialog panel that do not have a companion -md5.idx file. - * Occurs when user clicks "No" to the dialog popup box. - * @param toRemove a list of HashDbs that are unindexed - */ - void removeThese(List toRemove) { - HashDbXML xmlHandle = HashDbXML.getInstance(); - for (HashDb hdb : toRemove) { - for (int i = 0; i < hashSetTableModel.getRowCount(); i++) { - if (hashSetTableModel.getDBAt(i).equals(hdb)) { - if (xmlHandle.getNSRLSet() != null) { - if (i == 0) { - HashDbXML.getInstance().removeNSRLSet(); - } else { - HashDbXML.getInstance().removeKnownBadSetAt(i - 1); - } - } else { - HashDbXML.getInstance().removeKnownBadSetAt(i); - } - hashSetTableModel.resync(); - } - } - } - } - - /** - * Displays the popup box that tells user that some of his databases are unindexed, along with solutions. - * This method is related to ModalNoButtons, to be removed at a later date. - * @param plural Whether or not there are multiple unindexed databases - * @param unindexed The list of unindexed databases. Can be of size 1. - */ - private void showInvalidIndex(boolean plural, List unindexed){ - String total = ""; - String message; - for(HashDb hdb : unindexed){ - total+= "\n" + hdb.getDisplayName(); - } - if(plural){ - message = "The following databases are not indexed, would you like to index them now? \n " + total; - } - else{ - message = "The following database is not indexed, would you like to index it now? \n" + total; - } - int res = JOptionPane.showConfirmDialog(this, message, "Unindexed databases", JOptionPane.YES_NO_OPTION); - if(res == JOptionPane.YES_OPTION){ - ModalNoButtons indexingDialog = new ModalNoButtons(this, new Frame(),unindexed); - indexingDialog.setLocationRelativeTo(null); - indexingDialog.setVisible(true); - indexingDialog.setModal(true); - hashSetTableModel.resync(); - } - if(res == JOptionPane.NO_OPTION){ - JOptionPane.showMessageDialog(this, "All unindexed databases will be removed the list"); - removeThese(unindexed); - } - } - - boolean valid() { - // TODO check whether form is consistent and complete - return true; - } + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton deleteButton; private javax.swing.JLabel hashDatabasesLabel; @@ -651,173 +704,4 @@ final class HashDbManagementPanel extends javax.swing.JPanel implements OptionsP private javax.swing.JLabel typeLabel; private javax.swing.JCheckBox useForIngestCheckbox; // End of variables declaration//GEN-END:variables - - private void importHashSet(java.awt.event.ActionEvent evt) { - HashDb hashDb = new HashDbImportDatabaseDialog().doDialog(); - if (hashDb != null) { - HashDbXML.getInstance().addSet(hashDb); - hashSetTableModel.selectRowByName(hashDb.getDisplayName()); - } - resync(); - } - - private void createHashSet(java.awt.event.ActionEvent evt) { - HashDb hashDb = new HashDbCreateDatabaseDialog().doDialog(); - if (null != hashDb) { - HashDbXML.getInstance().addSet(hashDb); - hashSetTableModel.selectRowByName(hashDb.getDisplayName()); - } - resync(); - } - - /** - * The visual display of hash databases loaded. - */ - private class HashSetTable extends JTable { - @Override - public Component prepareRenderer(TableCellRenderer renderer, int row, int column) { - Component c = super.prepareRenderer(renderer, row, column); - JComponent jc = (JComponent) c; - String valueText = (String) getValueAt(row, column); - jc.setToolTipText(valueText); - - //Letting the user know which DBs need to be indexed - if(hashSetTableModel.indexExists(row)){ - c.setForeground(Color.black); - } - else{ - c.setForeground(Color.red); - } - return c; - } - } - - - private class HashSetTableModel extends AbstractTableModel { - - private HashDbXML xmlHandle = HashDbXML.getInstance(); - - @Override - public int getColumnCount() { - return 1; - } - - @Override - public int getRowCount() { - return xmlHandle.getAllSets().size(); - } - - @Override - public String getColumnName(int column) { - return "Name"; - } - - @Override - public Object getValueAt(int rowIndex, int columnIndex) { - if(xmlHandle.getNSRLSet() == null) { - return getDBAt(rowIndex).getDisplayName(); - } else { - return rowIndex == 0 ? getDBAt(rowIndex).getDisplayName() + " (NSRL)" : getDBAt(rowIndex).getDisplayName(); - } - } - - //Internal function for determining whether a companion -md5.idx file exists - private boolean indexExists(int rowIndex){ - return getDBAt(rowIndex).hasLookupIndex(); - } - - //Internal function for getting the DB at a certain index. Used as-is, as well as by dispatch from getValueAt() and indexExists() - private HashDb getDBAt(int rowIndex){ - if (xmlHandle.getNSRLSet() != null) { - if(rowIndex == 0) { - return xmlHandle.getNSRLSet(); - } else { - return xmlHandle.getKnownBadSets().get(rowIndex-1); - } - } else { - return xmlHandle.getKnownBadSets().get(rowIndex); - } - } - - // Selects the row with the given name - private void selectRowByName(String name) { - HashDb NSRL = xmlHandle.getNSRLSet(); - List bad = xmlHandle.getKnownBadSets(); - if(NSRL != null) { - if(NSRL.getDisplayName().equals(name)) { - setSelection(0); - } else { - for(int i=0; i getColumnClass(int c) { - return getValueAt(0, c).getClass(); - } - - void resync() { - fireTableDataChanged(); - } - } - - static void setButtonFromIndexStatus(JButton theButton, JLabel theLabel, IndexStatus status) { - theLabel.setText(status.message()); - switch (status) { - case NO_INDEX: - theButton.setText("Index"); - theLabel.setForeground(Color.red); - theButton.setEnabled(true); - break; - case INDEXING: - theButton.setText("Indexing"); - theLabel.setForeground(Color.black); - theButton.setEnabled(false); - break; - default: - theButton.setText("Index"); - theLabel.setForeground(Color.black); - theButton.setEnabled(false); - } - if (IngestManager.getDefault().isIngestRunning()) { - theButton.setEnabled(false); - } - } - - private int getSelection() { - return hashSetTable.getSelectionModel().getMinSelectionIndex(); - } - - private void setSelection(int index) { - if(index >= 0 && index < hashSetTable.getRowCount()) { - hashSetTable.getSelectionModel().setSelectionInterval(index, index); - } - } - void resync() { - int index = getSelection(); - this.hashSetTableModel.resync(); - setSelection(index); - } - } \ No newline at end of file diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsManager.java similarity index 70% rename from HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java rename to HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsManager.java index e333e0c1f7..a763184527 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsManager.java @@ -45,7 +45,7 @@ import org.w3c.dom.NodeList; * that serve as hash sets for the identification of known files, known good files, * and known bad files. */ -public class HashDbXML { +public class HashSetsManager { private static final String ROOT_EL = "hash_sets"; private static final String SET_EL = "hash_set"; private static final String SET_NAME_ATTR = "name"; @@ -59,105 +59,115 @@ public class HashDbXML { private static final String ENCODING = "UTF-8"; private static final String SET_CALC = "hash_calculate"; private static final String SET_VALUE = "value"; - private static final Logger logger = Logger.getLogger(HashDbXML.class.getName()); - private static HashDbXML instance; - private List knownBadSets = new ArrayList<>(); - private HashDb nsrlSet; - private boolean alwaysCalculateHashes; + private static final Logger logger = Logger.getLogger(HashSetsManager.class.getName()); + private static HashSetsManager instance; private String xmlFile = PlatformUtil.getUserConfigDirectory() + File.separator + CUR_HASHSETS_FILE_NAME; - + private List knownBadHashSets = new ArrayList<>(); + private HashDb nsrlHashSet; + private boolean alwaysCalculateHashes; + /** * Gets the singleton instance of this class. */ - public static synchronized HashDbXML getInstance() { + public static synchronized HashSetsManager getInstance() { if (instance == null) { - instance = new HashDbXML(); - instance.reload(); + instance = new HashSetsManager(); } return instance; } - private HashDbXML() { + private HashSetsManager() { + if (hashSetsConfigurationFileExists()) { + readHashSetsConfigurationFromDisk(); + } } /** - * Adds a hash database to the hash set configuration. - */ - public void addSet(HashDb set) { - if (set.getKnownFilesType() == HashDb.KnownFilesType.NSRL) { - setNSRLSet(set); - } - else { - addKnownBadSet(set); - } - } - - /** - * Sets the configured National Software Reference Library (NSRL) known - * files hash set. Does not save the configuration. - */ - public void setNSRLSet(HashDb set) { - this.nsrlSet = set; - } - - /** - * Gets the configured National Software Reference Library (NSRL) known files hash set. - * @return A HashDb object representing the hash set or null if an NSRL set - * has not been added to the configuration. - */ - public HashDb getNSRLSet() { - return nsrlSet; - } - - /** - * Removes the configured National Software Reference Library (NSRL) known - * files hash set. Does not save the configuration. - */ - public void removeNSRLSet() { - this.nsrlSet = null; - } - - /** - * Adds a known bad files hash set to the configuration. Does not save the + * Adds a hash set to the configuration as the designated National Software + * Reference Library (NSRL) hash set. Assumes that the hash set previously + * designated as NSRL set, if any, is not being indexed. Does not save the * configuration. */ - public void addKnownBadSet(HashDb set) { - knownBadSets.add(set); + public void setNSRLHashSet(HashDb set) { + if (nsrlHashSet != null) { + // RJCTODO: When the closeHashDatabase() API exists, close the existing database + } + nsrlHashSet = set; } - - /** - * Adds a known bad files hash set to the configuration. The set is added to - * the internal known bad sets collection at the index specified by the - * caller. Note that this method does not save the configuration. + + /** + * Gets the hash set from the configuration, if any, that is designated as + * the National Software Reference Library (NSRL) hash set. + * @return A HashDb object representing the hash set or null. */ - public void addKnownBadSet(int index, HashDb set) { - knownBadSets.add(index, set); + public HashDb getNSRLHashSet() { + return nsrlHashSet; } + + /** + * Removes the hash set designated as the National Software Reference + * Library (NSRL) hash set from the configuration. Does not save the + * configuration. + */ + public void removeNSRLHashSet() { + if (nsrlHashSet != null) { + // RJCTODO: When the closeHashDatabase() API exists, close the existing database + } + nsrlHashSet = null; + } + + /** + * Adds a hash set to the configuration as a known bad files hash set. Does + * not check for duplication of sets and does not save the configuration. + */ + public void addKnownBadHashSet(HashDb set) { + knownBadHashSets.add(set); + } /** * Gets the configured known bad files hash sets. - * @return A list, possibly empty, of HashDb objects representing the hash - * sets. + * @return A list, possibly empty, of HashDb objects. */ - public List getKnownBadSets() { - return Collections.unmodifiableList(knownBadSets); + public List getKnownBadHashSets() { + return Collections.unmodifiableList(knownBadHashSets); } - /** - * Removes the known bad files hash set from the internal known bad files - * hash sets collection at the specified index. Does not save the configuration. + /** + * Adds a hash set to the configuration. If the hash set is designated as + * the National Software Reference Library (NSRL) hash set, it is assumed + * the the hash set previously designated as the NSRL set, if any, is not + * being indexed. Does not check for duplication of sets and does not save + * the configuration. */ - public void removeKnownBadSetAt(int index) { - knownBadSets.remove(index); + public void addHashSet(HashDb hashSet) { + if (hashSet.getKnownFilesType() == HashDb.KnownFilesType.NSRL) { + setNSRLHashSet(hashSet); + } + else { + addKnownBadHashSet(hashSet); + } } - + + /** + * Removes a hash set from the hash sets configuration. + */ + public void removeHashSet(HashDb hashSetToRemove) { + if (nsrlHashSet != null && nsrlHashSet.equals(hashSetToRemove)) { + removeNSRLHashSet(); + } + else { + knownBadHashSets.remove(hashSetToRemove); + // RJCTODO: Close HashDb + } + } + /** * Gets the configured known files hash sets that accept updates. * @return A list, possibly empty, of HashDb objects. */ public List getUpdateableHashSets() { ArrayList updateableDbs = new ArrayList<>(); - for (HashDb db : knownBadSets) { + for (HashDb db : knownBadHashSets) { try { if (db.isUpdateable()) { updateableDbs.add(db); @@ -171,38 +181,55 @@ public class HashDbXML { } /** - * Gets all of the configured known files hash sets. + * Gets all of the configured hash sets. * @return A list, possibly empty, of HashDb objects representing the hash * sets. */ - public List getAllSets() { + public List getAllHashSets() { List hashDbs = new ArrayList<>(); - if (nsrlSet != null) { - hashDbs.add(nsrlSet); + if (nsrlHashSet != null) { + hashDbs.add(nsrlHashSet); } - hashDbs.addAll(knownBadSets); + hashDbs.addAll(knownBadHashSets); return Collections.unmodifiableList(hashDbs); } + /** Gets the configured hash set, if any, with a given name. + * @return A HashDb object or null. + */ + public HashDb getHashSetByName(String name) { + if (nsrlHashSet != null && nsrlHashSet.getDisplayName().equals(name)) { + return nsrlHashSet; + } + + for (HashDb hashSet : knownBadHashSets) { + if (hashSet.getDisplayName().equals(name)) { + return hashSet; + } + } + + return null; + } + +// public HashDb getHashSetAt(int index) + + // RJCTODO: Get rid of this /** - * Reloads the configuration file if it exists, creates it otherwise. + * Adds a hash set to the configuration as a known bad files hash set. The + * set is added to the internal known bad sets collection at the index + * specified by the caller. Does not save the configuration. */ - public void reload() { - // TODO: This does not look like it is correct. Revisit when time permits. - boolean created = false; - - nsrlSet = null; - knownBadSets.clear(); - - if (!setsFileExists()) { - save(); - created = true; - } + public void addKnownBadSet(int index, HashDb set) { + knownBadHashSets.add(index, set); + } - load(); - if (!created) { - save(); - } + // RJCTODO: Get rid of this + /** + * Removes the known bad files hash set from the internal known bad files + * hash sets collection at the specified index. Does not save the configuration. + */ + public void removeKnownBadSetAt(int index) { + knownBadHashSets.remove(index); } /** @@ -222,12 +249,39 @@ public class HashDbXML { } /** - * Saves the known files hash sets configuration to disk. Note that the - * configuration is only saved on demand to support cancellation of - * configuration panels and dialogs. + * Saves the hash sets configuration. Note that the configuration is only + * saved on demand to support cancellation of configuration panels. * @return True on success, false otherwise. */ public boolean save() { + return writeHashSetConfigurationToDisk(); + } + + /** + * Restores the last saved hash sets configuration. This supports + * cancellation of configuration panels. + */ + public void loadLastSavedConfiguration() { + try { + SleuthkitJNI.closeHashDatabases(); + } + catch (TskCoreException ex) { + // RJCTODO: Log + } + + nsrlHashSet = null; + knownBadHashSets.clear(); + if (hashSetsConfigurationFileExists()) { + readHashSetsConfigurationFromDisk(); + } + } + + private boolean hashSetsConfigurationFileExists() { + File f = new File(xmlFile); + return f.exists() && f.canRead() && f.canWrite(); + } + + private boolean writeHashSetConfigurationToDisk() { boolean success = false; DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance(); @@ -240,7 +294,7 @@ public class HashDbXML { doc.appendChild(rootEl); // TODO: Remove all the multiple database paths stuff, it was a mistake. - for (HashDb set : knownBadSets) { + for (HashDb set : knownBadHashSets) { String useForIngest = Boolean.toString(set.getUseForIngest()); String showInboxMessages = Boolean.toString(set.getShowInboxMessages()); List paths = Collections.singletonList(set.getDatabasePath()); @@ -263,14 +317,14 @@ public class HashDbXML { } // TODO: Remove all the multiple database paths stuff. - if(nsrlSet != null) { - String useForIngest = Boolean.toString(nsrlSet.getUseForIngest()); - String showInboxMessages = Boolean.toString(nsrlSet.getShowInboxMessages()); - List paths = Collections.singletonList(nsrlSet.getDatabasePath()); + if(nsrlHashSet != null) { + String useForIngest = Boolean.toString(nsrlHashSet.getUseForIngest()); + String showInboxMessages = Boolean.toString(nsrlHashSet.getShowInboxMessages()); + List paths = Collections.singletonList(nsrlHashSet.getDatabasePath()); String type = KnownFilesType.NSRL.toString(); Element setEl = doc.createElement(SET_EL); - setEl.setAttribute(SET_NAME_ATTR, nsrlSet.getDisplayName()); + setEl.setAttribute(SET_NAME_ATTR, nsrlHashSet.getDisplayName()); setEl.setAttribute(SET_TYPE_ATTR, type); setEl.setAttribute(SET_USE_FOR_INGEST_ATTR, useForIngest); setEl.setAttribute(SET_SHOW_INBOX_MESSAGES, showInboxMessages); @@ -290,16 +344,16 @@ public class HashDbXML { setCalc.setAttribute(SET_VALUE, calcValue); rootEl.appendChild(setCalc); - success = XMLUtil.saveDoc(HashDbXML.class, xmlFile, ENCODING, doc); + success = XMLUtil.saveDoc(HashSetsManager.class, xmlFile, ENCODING, doc); } catch (ParserConfigurationException e) { logger.log(Level.SEVERE, "Error saving hash sets: can't initialize parser.", e); } - return success; + return success; } - - private boolean load() { - final Document doc = XMLUtil.loadDoc(HashDbXML.class, xmlFile, XSDFILE); + + private boolean readHashSetsConfigurationFromDisk() { + final Document doc = XMLUtil.loadDoc(HashSetsManager.class, xmlFile, XSDFILE); if (doc == null) { return false; } @@ -376,14 +430,14 @@ public class HashDbXML { try { HashDb db = HashDb.openHashDatabase(name, paths.get(0), useForIngestBool, showInboxMessagesBool, typeDBType); if (typeDBType == KnownFilesType.NSRL) { - setNSRLSet(db); + setNSRLHashSet(db); } else { - addKnownBadSet(db); + addKnownBadHashSet(db); } } catch (TskCoreException ex) { - Logger.getLogger(HashDbXML.class.getName()).log(Level.SEVERE, "Error opening hash database", ex); + Logger.getLogger(HashSetsManager.class.getName()).log(Level.SEVERE, "Error opening hash database", ex); JOptionPane.showMessageDialog(null, "Unable to open " + paths.get(0) + " hash database.", "Open Hash Database Error", JOptionPane.ERROR_MESSAGE); } } @@ -434,21 +488,5 @@ public class HashDbXML { } return filePath; - } - - private boolean setsFileExists() { - File f = new File(xmlFile); - return f.exists() && f.canRead() && f.canWrite(); } - - /** - * Closes all open hash databases. - * @throws TskCoreException - */ - // TODO: Think about whether this should be exposed, and if so, where it should be exposed. - // The ability to add to hash databases implies that the databases should generally not be closed - // until removal or application exit. - void closeHashDatabases() throws TskCoreException { - SleuthkitJNI.closeHashDatabases(); - } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/IndexStatus.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/IndexStatus.java index 9867257b68..c48ecdab9b 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/IndexStatus.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/IndexStatus.java @@ -42,8 +42,11 @@ enum IndexStatus { /** * The index is generated. */ - INDEXED("Indexed"); - + INDEXED("Indexed"), + /** + * An error occurred while determining status. + */ + UNKNOWN("Error determining status"); private String message; /** diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java index 0828b14adc..2ff7930c0a 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java @@ -42,7 +42,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen List unindexed; HashDb toIndex; - HashDbManagementPanel hdbmp; + HashSetsConfigurationPanel hdbmp; int length = 0; int currentcount = 1; String currentDb = ""; @@ -53,7 +53,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen * @param parent Swing parent frame. * @param unindexed the list of unindexed databases to index. */ - ModalNoButtons(HashDbManagementPanel hdbmp, java.awt.Frame parent, List unindexed) { + ModalNoButtons(HashSetsConfigurationPanel hdbmp, java.awt.Frame parent, List unindexed) { super(parent, "Indexing databases", true); this.unindexed = unindexed; this.toIndex = null; @@ -68,7 +68,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen * @param parent Swing parent frame. * @param unindexed The unindexed database to index. */ - ModalNoButtons(HashDbManagementPanel hdbmp, java.awt.Frame parent, HashDb unindexed){ + ModalNoButtons(HashSetsConfigurationPanel hdbmp, java.awt.Frame parent, HashDb unindexed){ super(parent, "Indexing database", true); this.unindexed = null; this.toIndex = unindexed; From 64c7ea9b4327aafca8b04275f6c89dc1c7cf7057 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Tue, 5 Nov 2013 22:41:50 -0500 Subject: [PATCH 073/169] Fixed erroneous case fall through --- .../autopsy/hashdatabase/HashSetsConfigurationPanel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.java index 8de8c7a85b..decf6fc47e 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.java @@ -27,9 +27,7 @@ import java.beans.PropertyChangeListener; import java.io.File; import java.util.ArrayList; import java.util.List; -import javax.swing.JButton; import javax.swing.JComponent; -import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JTable; import javax.swing.ListSelectionModel; @@ -145,7 +143,9 @@ final class HashSetsConfigurationPanel extends javax.swing.JPanel implements Opt indexButton.setText("Index"); hashDbIndexStatusLabel.setForeground(Color.red); indexButton.setEnabled(false); + break; case INDEXED: + // TODO: Restore ability to re-index an indexed case INDEX_ONLY: default: indexButton.setText("Index"); From a8f33373ab47e378e5d9bbee6b2f125a2fec7a11 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 6 Nov 2013 12:58:06 -0500 Subject: [PATCH 074/169] Completed adaptation of hash db UI/module to new hash db API --- .../AddContentToHashDbAction.java | 4 +- .../autopsy/hashdatabase/Bundle.properties | 52 +-- .../HashDatabaseOptionsPanelController.java | 8 +- ...ationPanel.form => HashDbConfigPanel.form} | 44 +-- ...ationPanel.java => HashDbConfigPanel.java} | 54 +-- .../hashdatabase/HashDbIngestModule.java | 366 ++++++++---------- ...ashSetsManager.java => HashDbManager.java} | 18 +- ...anel.form => HashDbSimpleConfigPanel.form} | 8 +- ...anel.java => HashDbSimpleConfigPanel.java} | 22 +- .../autopsy/hashdatabase/ModalNoButtons.java | 6 +- 10 files changed, 277 insertions(+), 305 deletions(-) rename HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/{HashSetsConfigurationPanel.form => HashDbConfigPanel.form} (88%) rename HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/{HashSetsConfigurationPanel.java => HashDbConfigPanel.java} (91%) rename HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/{HashSetsManager.java => HashDbManager.java} (94%) rename HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/{HashDbSimplePanel.form => HashDbSimpleConfigPanel.form} (89%) rename HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/{HashDbSimplePanel.java => HashDbSimpleConfigPanel.java} (92%) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java index 8056c176c5..bf1c776357 100755 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java @@ -104,9 +104,9 @@ public class AddContentToHashDbAction extends AbstractAction implements Presente // Get the current set of updateable hash databases and add each // one as a menu item. - List hashDatabases = HashSetsManager.getInstance().getKnownBadHashSets(); + List hashDatabases = HashDbManager.getInstance().getKnownBadHashSets(); if (!hashDatabases.isEmpty()) { - for (final HashDb database : HashSetsManager.getInstance().getUpdateableHashSets()) { + for (final HashDb database : HashDbManager.getInstance().getUpdateableHashSets()) { JMenuItem databaseItem = add(database.getDisplayName()); databaseItem.addActionListener(new ActionListener() { @Override diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties index 4efbb6dca4..0d0a92c58d 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties @@ -8,7 +8,6 @@ HashDbSimplePanel.knownLabel.text=NSRL Database: HashDbSimplePanel.notableLabel.text=Known Bad Database(s): HashDbSimplePanel.knownValLabel.text=- HashDbSimplePanel.notableValLabel.text=- -HashDbSimplePanel.jLabel1.text=Enable known bad databases for ingest: HashDbSearchPanel.hashTable.columnModel.title0=MD5 Hashes HashDbSearchPanel.hashTable.columnModel.title3=Title 4 HashDbSearchPanel.hashTable.columnModel.title2=Title 3 @@ -22,9 +21,6 @@ HashDbSearchPanel.titleLabel.text=Search for files with the following MD5 hash(e HashDbSearchPanel.errorField.text=Error: Not all files have been hashed. HashDbSearchPanel.saveBox.text=Remember Hashes HashDbSearchPanel.cancelButton.text=Cancel -HashDbSimplePanel.calcHashesButton.text=Calculate hashes even if no hash database is selected -HashDbSimplePanel.nsrlDbLabel.text=NSRL Database: -HashDbSimplePanel.nsrlDbLabelVal.text=- OpenIDE-Module-Short-Description=Hash Database Ingest Module and hash db tools ModalNoButtons.CURRENTLYON_LABEL.text=Currently Indexing x of y ModalNoButtons.GO_GET_COFFEE_LABEL.text=Hash databases are currently being indexed, this may take some time. @@ -52,25 +48,29 @@ HashDbCreateDatabaseDialog.okButton.text=OK HashDbCreateDatabaseDialog.useForIngestCheckbox.text=Enable for ingest HashDbCreateDatabaseDialog.jLabel1.text=Display name of database: HashDbCreateDatabaseDialog.databaseNameTextField.text= -HashSetsConfigurationPanel.importButton1.text=New Database -HashSetsConfigurationPanel.jButton3.text=Import Database -HashSetsConfigurationPanel.jLabel6.text=Type: -HashSetsConfigurationPanel.jLabel4.text=Location: -HashSetsConfigurationPanel.jLabel2.text=Name: -HashSetsConfigurationPanel.hashDbTypeLabel.text=No database selected -HashSetsConfigurationPanel.deleteButton.text=Delete Database -HashSetsConfigurationPanel.hashDbIndexStatusLabel.text=No database selected -HashSetsConfigurationPanel.indexLabel.text=Index Status: -HashSetsConfigurationPanel.indexButton.text=Index -HashSetsConfigurationPanel.locationLabel.text=Location: -HashSetsConfigurationPanel.ingestWarningLabel.text=Ingest is ongoing, some settings will be unavailable until it finishes. -HashSetsConfigurationPanel.hashDbLocationLabel.text=No database selected -HashSetsConfigurationPanel.typeLabel.text=Type: -HashSetsConfigurationPanel.hashDatabasesLabel.text=Hash Databases: -HashSetsConfigurationPanel.importButton.text=Import Database -HashSetsConfigurationPanel.hashDbNameLabel.text=No database selected -HashSetsConfigurationPanel.nameLabel.text=Name: -HashSetsConfigurationPanel.informationLabel.text=Information -HashSetsConfigurationPanel.optionsLabel.text=Options -HashSetsConfigurationPanel.useForIngestCheckbox.text=Enable for ingest -HashSetsConfigurationPanel.showInboxMessagesCheckBox.text=Enable sending messages to inbox during ingest +HashDbConfigPanel.nameLabel.text=Name: +HashDbConfigPanel.hashDbNameLabel.text=No database selected +HashDbConfigPanel.deleteButton.text=Delete Database +HashDbConfigPanel.importButton.text=Import Database +HashDbConfigPanel.hashDatabasesLabel.text=Hash Databases: +HashDbConfigPanel.hashDbLocationLabel.text=No database selected +HashDbConfigPanel.ingestWarningLabel.text=Ingest is ongoing, some settings will be unavailable until it finishes. +HashDbConfigPanel.jButton3.text=Import Database +HashDbConfigPanel.jLabel6.text=Type: +HashDbConfigPanel.jLabel4.text=Location: +HashDbConfigPanel.jLabel2.text=Name: +HashDbConfigPanel.importButton1.text=New Database +HashDbConfigPanel.optionsLabel.text=Options +HashDbConfigPanel.typeLabel.text=Type: +HashDbConfigPanel.locationLabel.text=Location: +HashDbConfigPanel.hashDbIndexStatusLabel.text=No database selected +HashDbConfigPanel.hashDbTypeLabel.text=No database selected +HashDbConfigPanel.indexButton.text=Index +HashDbConfigPanel.indexLabel.text=Index Status: +HashDbConfigPanel.showInboxMessagesCheckBox.text=Enable sending messages to inbox during ingest +HashDbConfigPanel.useForIngestCheckbox.text=Enable for ingest +HashDbConfigPanel.informationLabel.text=Information +HashDbSimpleConfigPanel.nsrlDbLabelVal.text=- +HashDbSimpleConfigPanel.calcHashesButton.text=Calculate hashes even if no hash database is selected +HashDbSimpleConfigPanel.jLabel1.text=Enable known bad databases for ingest: +HashDbSimpleConfigPanel.nsrlDbLabel.text=NSRL Database: diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDatabaseOptionsPanelController.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDatabaseOptionsPanelController.java index 8523116156..3e8fa443aa 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDatabaseOptionsPanelController.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDatabaseOptionsPanelController.java @@ -36,7 +36,7 @@ id = "HashDatabase") @org.openide.util.NbBundle.Messages({"OptionsCategory_Name_HashDatabase=Hash Database", "OptionsCategory_Keywords_HashDatabase=Hash Database"}) public final class HashDatabaseOptionsPanelController extends OptionsPanelController { - private HashSetsConfigurationPanel panel; + private HashDbConfigPanel panel; private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); private boolean changed; @@ -55,7 +55,7 @@ public final class HashDatabaseOptionsPanelController extends OptionsPanelContro @Override public void cancel() { // Reset the XML on cancel - HashSetsManager.getInstance().loadLastSavedConfiguration(); + HashDbManager.getInstance().loadLastSavedConfiguration(); } @Override @@ -88,9 +88,9 @@ public final class HashDatabaseOptionsPanelController extends OptionsPanelContro pcs.removePropertyChangeListener(l); } - private HashSetsConfigurationPanel getPanel() { + private HashDbConfigPanel getPanel() { if (panel == null) { - panel = new HashSetsConfigurationPanel(); + panel = new HashDbConfigPanel(); } return panel; } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.form similarity index 88% rename from HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.form rename to HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.form index a476718dd9..9b1d50cc52 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.form @@ -5,21 +5,21 @@ - + - + - + @@ -29,7 +29,7 @@ - + @@ -190,7 +190,7 @@ - + @@ -230,7 +230,7 @@ - + @@ -252,7 +252,7 @@ - + @@ -271,70 +271,70 @@ - + - + - + - + - + - + - + - + - + - + @@ -345,7 +345,7 @@ - + @@ -355,7 +355,7 @@ - + @@ -365,14 +365,14 @@ - + - + @@ -386,7 +386,7 @@ - + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java similarity index 91% rename from HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.java rename to HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java index decf6fc47e..85e5a178f5 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsConfigurationPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java @@ -44,11 +44,11 @@ import org.sleuthkit.datamodel.TskCoreException; /** * Instances of this class provide a UI for managing the hash sets configuration. */ -final class HashSetsConfigurationPanel extends javax.swing.JPanel implements OptionsPanel { - private HashSetsManager hashSetManager = HashSetsManager.getInstance(); +final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel { + private HashDbManager hashSetManager = HashDbManager.getInstance(); private HashSetTableModel hashSetTableModel = new HashSetTableModel(); - HashSetsConfigurationPanel() { + HashDbConfigPanel() { initComponents(); customizeComponents(); } @@ -281,7 +281,7 @@ final class HashSetsConfigurationPanel extends javax.swing.JPanel implements Opt * configured hash sets. */ private class HashSetTableModel extends AbstractTableModel { - List hashSets = HashSetsManager.getInstance().getAllHashSets(); + List hashSets = HashDbManager.getInstance().getAllHashSets(); @Override public int getColumnCount() { @@ -341,7 +341,7 @@ final class HashSetsConfigurationPanel extends javax.swing.JPanel implements Opt } void refresh() { - hashSets = HashSetsManager.getInstance().getAllHashSets(); + hashSets = HashDbManager.getInstance().getAllHashSets(); fireTableDataChanged(); } } @@ -381,20 +381,20 @@ final class HashSetsConfigurationPanel extends javax.swing.JPanel implements Opt optionsSeparator = new javax.swing.JSeparator(); importButton1 = new javax.swing.JButton(); - org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.jLabel2.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.jLabel2.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jLabel4, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.jLabel4.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jLabel4, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.jLabel4.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jLabel6, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.jLabel6.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jLabel6, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.jLabel6.text")); // NOI18N jButton3.setFont(new java.awt.Font("Tahoma", 0, 14)); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(jButton3, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.jButton3.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(jButton3, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.jButton3.text")); // NOI18N setMinimumSize(new java.awt.Dimension(700, 500)); setPreferredSize(new java.awt.Dimension(700, 500)); ingestWarningLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/warning16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(ingestWarningLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.ingestWarningLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(ingestWarningLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.ingestWarningLabel.text")); // NOI18N hashSetTable.setModel(new javax.swing.table.DefaultTableModel( new Object [][] { @@ -414,7 +414,7 @@ final class HashSetsConfigurationPanel extends javax.swing.JPanel implements Opt jScrollPane1.setViewportView(hashSetTable); deleteButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/delete16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(deleteButton, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.deleteButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(deleteButton, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.deleteButton.text")); // NOI18N deleteButton.setMaximumSize(new java.awt.Dimension(140, 25)); deleteButton.setMinimumSize(new java.awt.Dimension(140, 25)); deleteButton.setPreferredSize(new java.awt.Dimension(140, 25)); @@ -425,7 +425,7 @@ final class HashSetsConfigurationPanel extends javax.swing.JPanel implements Opt }); importButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/import16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(importButton, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.importButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(importButton, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.importButton.text")); // NOI18N importButton.setMaximumSize(new java.awt.Dimension(140, 25)); importButton.setMinimumSize(new java.awt.Dimension(140, 25)); importButton.setPreferredSize(new java.awt.Dimension(140, 25)); @@ -435,25 +435,25 @@ final class HashSetsConfigurationPanel extends javax.swing.JPanel implements Opt } }); - org.openide.awt.Mnemonics.setLocalizedText(hashDatabasesLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.hashDatabasesLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(hashDatabasesLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.hashDatabasesLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(nameLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.nameLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(nameLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.nameLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(hashDbNameLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.hashDbNameLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(hashDbNameLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.hashDbNameLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(hashDbLocationLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.hashDbLocationLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(hashDbLocationLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.hashDbLocationLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(locationLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.locationLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(locationLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.locationLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(typeLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.typeLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(typeLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.typeLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(hashDbTypeLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.hashDbTypeLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(hashDbTypeLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.hashDbTypeLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(hashDbIndexStatusLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.hashDbIndexStatusLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(hashDbIndexStatusLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.hashDbIndexStatusLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(indexLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.indexLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(indexLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.indexLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(indexButton, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.indexButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(indexButton, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.indexButton.text")); // NOI18N indexButton.setEnabled(false); indexButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -461,26 +461,26 @@ final class HashSetsConfigurationPanel extends javax.swing.JPanel implements Opt } }); - org.openide.awt.Mnemonics.setLocalizedText(useForIngestCheckbox, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.useForIngestCheckbox.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(useForIngestCheckbox, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.useForIngestCheckbox.text")); // NOI18N useForIngestCheckbox.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { useForIngestCheckboxActionPerformed(evt); } }); - org.openide.awt.Mnemonics.setLocalizedText(showInboxMessagesCheckBox, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.showInboxMessagesCheckBox.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(showInboxMessagesCheckBox, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.showInboxMessagesCheckBox.text")); // NOI18N showInboxMessagesCheckBox.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { showInboxMessagesCheckBoxActionPerformed(evt); } }); - org.openide.awt.Mnemonics.setLocalizedText(informationLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.informationLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(informationLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.informationLabel.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(optionsLabel, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.optionsLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(optionsLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.optionsLabel.text")); // NOI18N importButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/new16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(importButton1, org.openide.util.NbBundle.getMessage(HashSetsConfigurationPanel.class, "HashSetsConfigurationPanel.importButton1.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(importButton1, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.importButton1.text")); // NOI18N importButton1.setMaximumSize(new java.awt.Dimension(140, 25)); importButton1.setMinimumSize(new java.awt.Dimension(140, 25)); importButton1.setPreferredSize(new java.awt.Dimension(140, 25)); diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java index 7fb3650df8..18b6a3914e 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java @@ -48,30 +48,24 @@ import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskException; public class HashDbIngestModule extends IngestModuleAbstractFile { - private static HashDbIngestModule instance = null; public final static String MODULE_NAME = "Hash Lookup"; public final static String MODULE_DESCRIPTION = "Identifies known and notables files using supplied hash databases, such as a standard NSRL database."; final public static String MODULE_VERSION = "1.0"; private static final Logger logger = Logger.getLogger(HashDbIngestModule.class.getName()); + private HashDbConfigPanel panel; private IngestServices services; private SleuthkitCase skCase; private static int messageId = 0; - private int knownBadCount; - // Whether or not to do hash lookups (only set to true if there are dbs set) - private boolean nsrlIsSet; - private boolean knownBadIsSet; + private int knownBadCount = 0; private boolean calcHashesIsSet; - private HashDb nsrlSet; - private int nsrlPointer; + private HashDb nsrlHashSet; + private ArrayList knownBadHashSets = new ArrayList<>(); static long calctime = 0; static long lookuptime = 0; - private Map knownBadSets = new HashMap<>(); - private HashSetsConfigurationPanel panel; private final Hash hasher = new Hash(); private HashDbIngestModule() { - knownBadCount = 0; } public static synchronized HashDbIngestModule getDefault() { @@ -95,76 +89,78 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { public String getVersion() { return MODULE_VERSION; } + + @Override + public boolean hasSimpleConfiguration() { + return true; + } + + @Override + public javax.swing.JPanel getSimpleConfiguration(String context) { + return new HashDbSimpleConfigPanel(); + } + + @Override + public void saveSimpleConfiguration() { + HashDbManager.getInstance().save(); + } + + @Override + public boolean hasAdvancedConfiguration() { + return true; + } + + @Override + public javax.swing.JPanel getAdvancedConfiguration(String context) { + if (panel == null) { + panel = new HashDbConfigPanel(); + } + panel.load(); + return panel; + } + + @Override + public void saveAdvancedConfiguration() { + if (panel != null) { + panel.store(); + } + } + @Override public void init(IngestModuleInit initContext) { services = IngestServices.getDefault(); - this.skCase = Case.getCurrentCase().getSleuthkitCase(); - try { - HashSetsManager hdbxml = HashSetsManager.getInstance(); - nsrlSet = null; - knownBadSets.clear(); - nsrlIsSet = false; - knownBadIsSet = false; - calcHashesIsSet = hdbxml.shouldAlwaysCalculateHashes(); + skCase = Case.getCurrentCase().getSleuthkitCase(); + HashDbManager hashDbManager = HashDbManager.getInstance(); - HashDb nsrl = hdbxml.getNSRLHashSet(); - if (nsrl != null && nsrl.getUseForIngest() && IndexStatus.isIngestible(nsrl.getStatus())) { - nsrlIsSet = true; - this.nsrlSet = nsrl; - nsrlPointer = skCase.setNSRLDatabase(nsrl.getDatabasePath()); - } + nsrlHashSet = null; + knownBadHashSets.clear(); + calcHashesIsSet = hashDbManager.shouldAlwaysCalculateHashes(); - for (HashDb db : hdbxml.getKnownBadHashSets()) { - IndexStatus status = db.getStatus(); - if (db.getUseForIngest() && IndexStatus.isIngestible(status)) { - knownBadIsSet = true; - int ret = skCase.addKnownBadDatabase(db.getDatabasePath()); - knownBadSets.put(ret, db); - } - } + HashDb nsrl = hashDbManager.getNSRLHashSet(); + if (nsrl != null && nsrl.getUseForIngest() && nsrl.hasLookupIndex()) { + nsrlHashSet = nsrl; + } - if (!nsrlIsSet) { - this.services.postMessage(IngestMessage.createWarningMessage(++messageId, this, "No NSRL database set", "Known file search will not be executed.")); - } - if (!knownBadIsSet) { - this.services.postMessage(IngestMessage.createWarningMessage(++messageId, this, "No known bad database set", "Known bad file search will not be executed.")); + for (HashDb db : hashDbManager.getKnownBadHashSets()) { + if (db.getUseForIngest() && db.hasLookupIndex()) { + knownBadHashSets.add(db); } + } - } catch (TskException ex) { - logger.log(Level.SEVERE, "Setting NSRL and Known database failed", ex); - this.services.postMessage(IngestMessage.createErrorMessage(++messageId, this, "Error Configuring Hash Databases", "Setting NSRL and Known database failed.")); + if (nsrlHashSet == null) { + services.postMessage(IngestMessage.createWarningMessage(++messageId, this, "No NSRL database set", "Known file search will not be executed.")); + } + if (knownBadHashSets.isEmpty()) { + services.postMessage(IngestMessage.createWarningMessage(++messageId, this, "No known bad database set", "Known bad file search will not be executed.")); } } @Override - public void complete() { - if ((knownBadIsSet) || (nsrlIsSet)) { - StringBuilder detailsSb = new StringBuilder(); - //details - detailsSb.append("

").append(columnHeader).append("
"); - - detailsSb.append(""); - detailsSb.append(""); - - detailsSb.append("\n"); - detailsSb.append("\n"); - detailsSb.append("
Known bads found:").append(knownBadCount).append("
Total Calculation Time").append(calctime).append("
Total Lookup Time").append(lookuptime).append("
"); - - detailsSb.append("

Databases Used:

\n
    "); - for (HashDb db : knownBadSets.values()) { - detailsSb.append("
  • ").append(db.getDisplayName()).append("
  • \n"); - } - - detailsSb.append("
"); - services.postMessage(IngestMessage.createMessage(++messageId, IngestMessage.MessageType.INFO, this, "Hash Lookup Results", detailsSb.toString())); - } + public boolean hasBackgroundJobsRunning() { + return false; } - - @Override - public void stop() { - } - + @Override public ProcessResult process(PipelineContextpipelineContext, AbstractFile file) { //skip unalloc @@ -174,51 +170,87 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { return processFile(file); } - - - @Override - public boolean hasBackgroundJobsRunning() { - return false; - } - - @Override - public boolean hasSimpleConfiguration() { - return true; - } - - @Override - public boolean hasAdvancedConfiguration() { - return true; - } - - @Override - public javax.swing.JPanel getSimpleConfiguration(String context) { - HashSetsManager.getInstance().loadLastSavedConfiguration(); - return new HashDbSimplePanel(); - } - - @Override - public javax.swing.JPanel getAdvancedConfiguration(String context) { - //return HashDbManagementPanel.getDefault(); - getPanel().load(); - return getPanel(); - } - - @Override - public void saveAdvancedConfiguration() { - getPanel().store(); - } - - private HashSetsConfigurationPanel getPanel() { - if (panel == null) { - panel = new HashSetsConfigurationPanel(); + + private ProcessResult processFile(AbstractFile file) { + // bail out if we have no hashes set + if ((nsrlHashSet == null) && (knownBadHashSets.isEmpty()) && (calcHashesIsSet == false)) { + return ProcessResult.OK; } - return panel; - } - @Override - public void saveSimpleConfiguration() { - HashSetsManager.getInstance().save(); + // calc hash value + String name = file.getName(); + String md5Hash = file.getMd5Hash(); + if (md5Hash == null || md5Hash.isEmpty()) { + try { + long calcstart = System.currentTimeMillis(); + md5Hash = hasher.calculateMd5(file); + calctime += (System.currentTimeMillis() - calcstart); + } catch (IOException ex) { + logger.log(Level.WARNING, "Error calculating hash of file " + name, ex); + services.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestModule.this, "Read Error: " + name, + "Error encountered while calculating the hash value for " + name + ".")); + return ProcessResult.ERROR; + } + } + + // look up in known bad first + TskData.FileKnown status = TskData.FileKnown.UKNOWN; + boolean foundBad = false; + ProcessResult ret = ProcessResult.OK; + for (HashDb db : knownBadHashSets) { + try { + long lookupstart = System.currentTimeMillis(); + status = db.lookUp(file); + lookuptime += (System.currentTimeMillis() - lookupstart); + } catch (TskException ex) { + logger.log(Level.WARNING, "Couldn't lookup known bad hash for file " + name + " - see sleuthkit log for details", ex); + services.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestModule.this, "Hash Lookup Error: " + name, + "Error encountered while looking up known bad hash value for " + name + ".")); + ret = ProcessResult.ERROR; + } + + if (status.equals(TskData.FileKnown.BAD)) { + foundBad = true; + knownBadCount += 1; + try { + skCase.setKnown(file, TskData.FileKnown.BAD); + } catch (TskException ex) { + logger.log(Level.WARNING, "Couldn't set known bad state for file " + name + " - see sleuthkit log for details", ex); + services.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestModule.this, "Hash Lookup Error: " + name, + "Error encountered while setting known bad state for " + name + ".")); + ret = ProcessResult.ERROR; + } + String hashSetName = db.getDisplayName(); + processBadFile(file, md5Hash, hashSetName, db.getShowInboxMessages()); + } + } + + // only do NSRL if we didn't find a known bad + if (!foundBad && nsrlHashSet != null) { + try { + long lookupstart = System.currentTimeMillis(); + status = nsrlHashSet.lookUp(file); + lookuptime += (System.currentTimeMillis() - lookupstart); + } catch (TskException ex) { + logger.log(Level.WARNING, "Couldn't lookup NSRL hash for file " + name + " - see sleuthkit log for details", ex); + services.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestModule.this, "Hash Lookup Error: " + name, + "Error encountered while looking up NSRL hash value for " + name + ".")); + ret = ProcessResult.ERROR; + } + + if (status.equals(TskData.FileKnown.KNOWN)) { + try { + skCase.setKnown(file, TskData.FileKnown.KNOWN); + } catch (TskException ex) { + logger.log(Level.WARNING, "Couldn't set known state for file " + name + " - see sleuthkit log for details", ex); + services.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestModule.this, "Hash Lookup Error: " + name, + "Error encountered while setting known (NSRL) state for " + name + ".")); + ret = ProcessResult.ERROR; + } + } + } + + return ret; } private void processBadFile(AbstractFile abstractFile, String md5Hash, String hashSetName, boolean showInboxMessage) { @@ -264,101 +296,41 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { } } + + @Override + public void complete() { + if ((!knownBadHashSets.isEmpty()) || (nsrlHashSet != null)) { + StringBuilder detailsSb = new StringBuilder(); + //details + detailsSb.append(""); - private ProcessResult processFile(AbstractFile file) { - // bail out if we have no hashes set - if ((nsrlIsSet == false) && (knownBadIsSet == false) && (calcHashesIsSet == false)) { - return ProcessResult.OK; - } + detailsSb.append(""); + detailsSb.append(""); - // calc hash value - String name = file.getName(); - String md5Hash = file.getMd5Hash(); - if (md5Hash == null || md5Hash.isEmpty()) { - try { - long calcstart = System.currentTimeMillis(); - md5Hash = hasher.calculateMd5(file); - calctime += (System.currentTimeMillis() - calcstart); - } catch (IOException ex) { - logger.log(Level.WARNING, "Error calculating hash of file " + name, ex); - services.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestModule.this, "Read Error: " + name, - "Error encountered while calculating the hash value for " + name + ".")); - return ProcessResult.ERROR; - } - } + detailsSb.append("\n"); + detailsSb.append("\n"); + detailsSb.append("
Known bads found:").append(knownBadCount).append("
Total Calculation Time").append(calctime).append("
Total Lookup Time").append(lookuptime).append("
"); - - // look up in known bad first - TskData.FileKnown status = TskData.FileKnown.UKNOWN; - boolean foundBad = false; - ProcessResult ret = ProcessResult.OK; - - if (knownBadIsSet) { - for (Map.Entry entry : knownBadSets.entrySet()) { - - try { - long lookupstart = System.currentTimeMillis(); - status = skCase.knownBadLookupMd5(md5Hash, entry.getKey()); - lookuptime += (System.currentTimeMillis() - lookupstart); - } catch (TskException ex) { - logger.log(Level.WARNING, "Couldn't lookup known bad hash for file " + name + " - see sleuthkit log for details", ex); - services.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestModule.this, "Hash Lookup Error: " + name, - "Error encountered while looking up known bad hash value for " + name + ".")); - ret = ProcessResult.ERROR; - } - - if (status.equals(TskData.FileKnown.BAD)) { - foundBad = true; - knownBadCount += 1; - try { - skCase.setKnown(file, TskData.FileKnown.BAD); - } catch (TskException ex) { - logger.log(Level.WARNING, "Couldn't set known bad state for file " + name + " - see sleuthkit log for details", ex); - services.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestModule.this, "Hash Lookup Error: " + name, - "Error encountered while setting known bad state for " + name + ".")); - ret = ProcessResult.ERROR; - } - String hashSetName = entry.getValue().getDisplayName(); - processBadFile(file, md5Hash, hashSetName, entry.getValue().getShowInboxMessages()); - } - } - } - - // only do NSRL if we didn't find a known bad - if (!foundBad && nsrlIsSet) { - try { - long lookupstart = System.currentTimeMillis(); - status = skCase.nsrlLookupMd5(md5Hash); - lookuptime += (System.currentTimeMillis() - lookupstart); - } catch (TskException ex) { - logger.log(Level.WARNING, "Couldn't lookup NSRL hash for file " + name + " - see sleuthkit log for details", ex); - services.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestModule.this, "Hash Lookup Error: " + name, - "Error encountered while looking up NSRL hash value for " + name + ".")); - ret = ProcessResult.ERROR; + detailsSb.append("

Databases Used:

\n
    "); + for (HashDb db : knownBadHashSets) { + detailsSb.append("
  • ").append(db.getDisplayName()).append("
  • \n"); } - if (status.equals(TskData.FileKnown.KNOWN)) { - try { - skCase.setKnown(file, TskData.FileKnown.KNOWN); - } catch (TskException ex) { - logger.log(Level.WARNING, "Couldn't set known state for file " + name + " - see sleuthkit log for details", ex); - services.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestModule.this, "Hash Lookup Error: " + name, - "Error encountered while setting known (NSRL) state for " + name + ".")); - ret = ProcessResult.ERROR; - } - } + detailsSb.append("
"); + services.postMessage(IngestMessage.createMessage(++messageId, IngestMessage.MessageType.INFO, this, "Hash Lookup Results", detailsSb.toString())); } - - return ret; } - public ArrayList getKnownBadSetNames() { - ArrayList knownBadSetNames = new ArrayList<>(); - HashSetsManager hdbxml = HashSetsManager.getInstance(); - for (HashDb db : hdbxml.getKnownBadHashSets()) { - knownBadSetNames.add(db.getDisplayName()); - } - return knownBadSetNames; + @Override + public void stop() { } - + +// public ArrayList getKnownBadSetNames() { +// ArrayList knownBadSetNames = new ArrayList<>(); +// HashDbManager hdbxml = HashDbManager.getInstance(); +// for (HashDb db : hdbxml.getKnownBadHashSets()) { +// knownBadSetNames.add(db.getDisplayName()); +// } +// return knownBadSetNames; +// } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsManager.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java similarity index 94% rename from HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsManager.java rename to HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java index a763184527..a041fd19a1 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashSetsManager.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java @@ -45,7 +45,7 @@ import org.w3c.dom.NodeList; * that serve as hash sets for the identification of known files, known good files, * and known bad files. */ -public class HashSetsManager { +public class HashDbManager { private static final String ROOT_EL = "hash_sets"; private static final String SET_EL = "hash_set"; private static final String SET_NAME_ATTR = "name"; @@ -59,8 +59,8 @@ public class HashSetsManager { private static final String ENCODING = "UTF-8"; private static final String SET_CALC = "hash_calculate"; private static final String SET_VALUE = "value"; - private static final Logger logger = Logger.getLogger(HashSetsManager.class.getName()); - private static HashSetsManager instance; + private static final Logger logger = Logger.getLogger(HashDbManager.class.getName()); + private static HashDbManager instance; private String xmlFile = PlatformUtil.getUserConfigDirectory() + File.separator + CUR_HASHSETS_FILE_NAME; private List knownBadHashSets = new ArrayList<>(); private HashDb nsrlHashSet; @@ -69,14 +69,14 @@ public class HashSetsManager { /** * Gets the singleton instance of this class. */ - public static synchronized HashSetsManager getInstance() { + public static synchronized HashDbManager getInstance() { if (instance == null) { - instance = new HashSetsManager(); + instance = new HashDbManager(); } return instance; } - private HashSetsManager() { + private HashDbManager() { if (hashSetsConfigurationFileExists()) { readHashSetsConfigurationFromDisk(); } @@ -344,7 +344,7 @@ public class HashSetsManager { setCalc.setAttribute(SET_VALUE, calcValue); rootEl.appendChild(setCalc); - success = XMLUtil.saveDoc(HashSetsManager.class, xmlFile, ENCODING, doc); + success = XMLUtil.saveDoc(HashDbManager.class, xmlFile, ENCODING, doc); } catch (ParserConfigurationException e) { logger.log(Level.SEVERE, "Error saving hash sets: can't initialize parser.", e); @@ -353,7 +353,7 @@ public class HashSetsManager { } private boolean readHashSetsConfigurationFromDisk() { - final Document doc = XMLUtil.loadDoc(HashSetsManager.class, xmlFile, XSDFILE); + final Document doc = XMLUtil.loadDoc(HashDbManager.class, xmlFile, XSDFILE); if (doc == null) { return false; } @@ -437,7 +437,7 @@ public class HashSetsManager { } } catch (TskCoreException ex) { - Logger.getLogger(HashSetsManager.class.getName()).log(Level.SEVERE, "Error opening hash database", ex); + Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error opening hash database", ex); JOptionPane.showMessageDialog(null, "Unable to open " + paths.get(0) + " hash database.", "Open Hash Database Error", JOptionPane.ERROR_MESSAGE); } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.form similarity index 89% rename from HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.form rename to HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.form index dc1fc4d1c0..3ad95c5229 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.form @@ -85,28 +85,28 @@ - + - + - + - + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.java similarity index 92% rename from HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.java rename to HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.java index c065211ebe..f33040b36b 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimplePanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.java @@ -32,18 +32,18 @@ import org.sleuthkit.datamodel.TskCoreException; * Instances of this class are used as a file ingest module configuration panel * by the known files hash set lookup file ingest module. */ -public class HashDbSimplePanel extends javax.swing.JPanel { +public class HashDbSimpleConfigPanel extends javax.swing.JPanel { private HashTableModel knownBadTableModel; private HashDb nsrl; - public HashDbSimplePanel() { + public HashDbSimpleConfigPanel() { knownBadTableModel = new HashTableModel(); initComponents(); customizeComponents(); } private void reloadCalc() { - final HashSetsManager xmlHandle = HashSetsManager.getInstance(); + final HashDbManager xmlHandle = HashDbManager.getInstance(); final HashDb nsrlDb = xmlHandle.getNSRLHashSet(); final boolean nsrlUsed = nsrlDb != null && nsrlDb.getUseForIngest()== true && nsrlDb.hasLookupIndex(); final List knowns = xmlHandle.getKnownBadHashSets(); @@ -70,7 +70,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { } private void customizeComponents() { - final HashSetsManager xmlHandle = HashSetsManager.getInstance(); + final HashDbManager xmlHandle = HashDbManager.getInstance(); calcHashesButton.addActionListener( new ActionListener() { @Override @@ -104,7 +104,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { } private void reloadSets() { - nsrl = HashSetsManager.getInstance().getNSRLHashSet(); + nsrl = HashDbManager.getInstance().getNSRLHashSet(); if (nsrl == null || nsrl.getUseForIngest() == false) { nsrlDbLabelVal.setText("Disabled"); @@ -144,13 +144,13 @@ public class HashDbSimplePanel extends javax.swing.JPanel { notableHashTable.setShowVerticalLines(false); jScrollPane1.setViewportView(notableHashTable); - jLabel1.setText(org.openide.util.NbBundle.getMessage(HashDbSimplePanel.class, "HashDbSimplePanel.jLabel1.text")); // NOI18N + jLabel1.setText(org.openide.util.NbBundle.getMessage(HashDbSimpleConfigPanel.class, "HashDbSimpleConfigPanel.jLabel1.text")); // NOI18N - nsrlDbLabel.setText(org.openide.util.NbBundle.getMessage(HashDbSimplePanel.class, "HashDbSimplePanel.nsrlDbLabel.text")); // NOI18N + nsrlDbLabel.setText(org.openide.util.NbBundle.getMessage(HashDbSimpleConfigPanel.class, "HashDbSimpleConfigPanel.nsrlDbLabel.text")); // NOI18N - calcHashesButton.setText(org.openide.util.NbBundle.getMessage(HashDbSimplePanel.class, "HashDbSimplePanel.calcHashesButton.text")); // NOI18N + calcHashesButton.setText(org.openide.util.NbBundle.getMessage(HashDbSimpleConfigPanel.class, "HashDbSimpleConfigPanel.calcHashesButton.text")); // NOI18N - nsrlDbLabelVal.setText(org.openide.util.NbBundle.getMessage(HashDbSimplePanel.class, "HashDbSimplePanel.nsrlDbLabelVal.text")); // NOI18N + nsrlDbLabelVal.setText(org.openide.util.NbBundle.getMessage(HashDbSimpleConfigPanel.class, "HashDbSimpleConfigPanel.nsrlDbLabelVal.text")); // NOI18N javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -199,7 +199,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { private class HashTableModel extends AbstractTableModel { - private HashSetsManager xmlHandle = HashSetsManager.getInstance(); + private HashDbManager xmlHandle = HashDbManager.getInstance(); private void resync() { fireTableDataChanged(); @@ -253,7 +253,7 @@ public class HashDbSimplePanel extends javax.swing.JPanel { if(((Boolean) getValueAt(rowIndex, columnIndex)) || IndexStatus.isIngestible(status)) { db.setUseForIngest((Boolean) aValue); } else { - JOptionPane.showMessageDialog(HashDbSimplePanel.this, "Databases must be indexed before they can be used for ingest"); + JOptionPane.showMessageDialog(HashDbSimpleConfigPanel.this, "Databases must be indexed before they can be used for ingest"); } reloadSets(); } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java index 2ff7930c0a..61e55c07b3 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java @@ -42,7 +42,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen List unindexed; HashDb toIndex; - HashSetsConfigurationPanel hdbmp; + HashDbConfigPanel hdbmp; int length = 0; int currentcount = 1; String currentDb = ""; @@ -53,7 +53,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen * @param parent Swing parent frame. * @param unindexed the list of unindexed databases to index. */ - ModalNoButtons(HashSetsConfigurationPanel hdbmp, java.awt.Frame parent, List unindexed) { + ModalNoButtons(HashDbConfigPanel hdbmp, java.awt.Frame parent, List unindexed) { super(parent, "Indexing databases", true); this.unindexed = unindexed; this.toIndex = null; @@ -68,7 +68,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen * @param parent Swing parent frame. * @param unindexed The unindexed database to index. */ - ModalNoButtons(HashSetsConfigurationPanel hdbmp, java.awt.Frame parent, HashDb unindexed){ + ModalNoButtons(HashDbConfigPanel hdbmp, java.awt.Frame parent, HashDb unindexed){ super(parent, "Indexing database", true); this.unindexed = null; this.toIndex = unindexed; From e78f49ee33a5a3d04c5a00fae155ed33e4249d43 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 6 Nov 2013 15:44:26 -0500 Subject: [PATCH 075/169] Assorted fixes to new hash database capabilities --- .../autopsy/hashdatabase/Bundle.properties | 6 +- .../autopsy/hashdatabase/HashDb.java | 9 +- .../hashdatabase/HashDbConfigPanel.form | 30 +- .../hashdatabase/HashDbConfigPanel.java | 291 ++++++++++-------- 4 files changed, 179 insertions(+), 157 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties index 0d0a92c58d..c079f5c2c3 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties @@ -50,8 +50,6 @@ HashDbCreateDatabaseDialog.jLabel1.text=Display name of database: HashDbCreateDatabaseDialog.databaseNameTextField.text= HashDbConfigPanel.nameLabel.text=Name: HashDbConfigPanel.hashDbNameLabel.text=No database selected -HashDbConfigPanel.deleteButton.text=Delete Database -HashDbConfigPanel.importButton.text=Import Database HashDbConfigPanel.hashDatabasesLabel.text=Hash Databases: HashDbConfigPanel.hashDbLocationLabel.text=No database selected HashDbConfigPanel.ingestWarningLabel.text=Ingest is ongoing, some settings will be unavailable until it finishes. @@ -59,7 +57,6 @@ HashDbConfigPanel.jButton3.text=Import Database HashDbConfigPanel.jLabel6.text=Type: HashDbConfigPanel.jLabel4.text=Location: HashDbConfigPanel.jLabel2.text=Name: -HashDbConfigPanel.importButton1.text=New Database HashDbConfigPanel.optionsLabel.text=Options HashDbConfigPanel.typeLabel.text=Type: HashDbConfigPanel.locationLabel.text=Location: @@ -74,3 +71,6 @@ HashDbSimpleConfigPanel.nsrlDbLabelVal.text=- HashDbSimpleConfigPanel.calcHashesButton.text=Calculate hashes even if no hash database is selected HashDbSimpleConfigPanel.jLabel1.text=Enable known bad databases for ingest: HashDbSimpleConfigPanel.nsrlDbLabel.text=NSRL Database: +HashDbConfigPanel.newDatabaseButton.text=New Database +HashDbConfigPanel.importDatabaseButton.text=Import Database +HashDbConfigPanel.deleteDatabaseButton.text=Delete Database diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index 27078e012e..251a3e07cc 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -64,12 +64,7 @@ public class HashDb implements Comparable { * @throws TskCoreException */ public static HashDb openHashDatabase(String hashSetName, String databasePath, boolean useForIngest, boolean showInboxMessages, KnownFilesType knownType) throws TskCoreException { - if (knownType == HashDb.KnownFilesType.NSRL) { - return new HashDb(SleuthkitJNI.openNSRLDatabase(databasePath), hashSetName, databasePath, useForIngest, showInboxMessages, knownType); - } - else { - return new HashDb(SleuthkitJNI.openHashDatabase(databasePath), hashSetName, databasePath, useForIngest, showInboxMessages, knownType); - } + return new HashDb(SleuthkitJNI.openHashDatabase(databasePath), hashSetName, databasePath, useForIngest, showInboxMessages, knownType); } /** @@ -258,7 +253,7 @@ public class HashDb implements Comparable { progress = ProgressHandleFactory.createHandle("Indexing " + displayName); progress.start(); progress.switchToIndeterminate(); - SleuthkitJNI.createLookupIndexForHashDatabase(handle); + SleuthkitJNI.createLookupIndexForHashDatabase(handle); // RJCTODO: There is nobody to catch, fix this. return null; } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.form index 9b1d50cc52..1d841ad64a 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.form @@ -109,11 +109,11 @@ - + - + - + @@ -173,11 +173,11 @@ - - + + - + @@ -224,13 +224,13 @@ - + - + @@ -243,16 +243,16 @@ - + - + - + @@ -265,7 +265,7 @@ - + @@ -380,13 +380,13 @@ - + - + @@ -399,7 +399,7 @@ - + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java index 85e5a178f5..e24ac3a7a1 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java @@ -50,7 +50,8 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel HashDbConfigPanel() { initComponents(); - customizeComponents(); + customizeComponents(); + updateComponentsForNoSelection(); } private void customizeComponents() { @@ -67,104 +68,126 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel updateComponents(); } } - }); + }); } private void updateComponents() { HashDb db = ((HashSetTable)hashSetTable).getSelection(); - if (db == null) { - hashDbLocationLabel.setText("No database selected"); - hashDbNameLabel.setText("No database selected"); - hashDbIndexStatusLabel.setText("No database selected"); - hashDbTypeLabel.setText("No database selected"); + if (db != null) { + updateComponentsForSelection(db); } else { - this.hashDbLocationLabel.setToolTipText(db.getDatabasePath()); - if (db.getDatabasePath().length() > 50){ - String shortenedPath = db.getDatabasePath(); - shortenedPath = shortenedPath.substring(0, 10 + shortenedPath.substring(10).indexOf(File.separator) + 1) + "..." + shortenedPath.substring((shortenedPath.length() - 20) + shortenedPath.substring(shortenedPath.length() - 20).indexOf(File.separator)); - hashDbLocationLabel.setText(shortenedPath); - } - else { - hashDbLocationLabel.setText(db.getDatabasePath()); - } - hashDbNameLabel.setText(db.getDisplayName()); - hashDbTypeLabel.setText(db.getKnownFilesType().getDisplayName()); - } - updateStatusComponents(db); - boolean ingestRunning = IngestManager.getDefault().isIngestRunning(); - boolean useForIngestEnabled = db != null && !ingestRunning; - boolean useForIngestSelected = db != null && db.getUseForIngest(); - boolean showInboxMessagesEnabled = db != null && !ingestRunning && useForIngestSelected && db.getKnownFilesType().equals(HashDb.KnownFilesType.KNOWN_BAD); - boolean showInboxMessagesSelected = db != null && db.getShowInboxMessages(); - boolean deleteButtonEnabled = db != null && !ingestRunning; - boolean importButtonEnabled = !ingestRunning; - useForIngestCheckbox.setSelected(useForIngestSelected); - useForIngestCheckbox.setEnabled(useForIngestEnabled); - showInboxMessagesCheckBox.setSelected(showInboxMessagesSelected); - showInboxMessagesCheckBox.setEnabled(showInboxMessagesEnabled); - deleteButton.setEnabled(deleteButtonEnabled); - importButton.setEnabled(importButtonEnabled); - optionsLabel.setEnabled(useForIngestEnabled || showInboxMessagesEnabled); - optionsSeparator.setEnabled(useForIngestEnabled || showInboxMessagesEnabled); - ingestWarningLabel.setVisible(ingestRunning); - importButton.setEnabled(!ingestRunning); // RJCTODO: What about the other buttons? + updateComponentsForNoSelection(); + } } - void updateStatusComponents(HashDb hashDb) { - if (hashDb == null) { - indexButton.setText("Index"); - hashDbIndexStatusLabel.setForeground(Color.black); - indexButton.setEnabled(false); + private void updateComponentsForNoSelection() { + boolean ingestIsRunning = IngestManager.getDefault().isIngestRunning(); + + // Update labels. + hashDbLocationLabel.setText("No database selected"); + hashDbNameLabel.setText("No database selected"); + hashDbIndexStatusLabel.setText("No database selected"); + hashDbTypeLabel.setText("No database selected"); + + // Update indexing components. + indexButton.setText("Index"); + hashDbIndexStatusLabel.setForeground(Color.black); + indexButton.setEnabled(false); + + // Update ingest options. + useForIngestCheckbox.setSelected(false); + useForIngestCheckbox.setEnabled(false); + showInboxMessagesCheckBox.setSelected(false); + showInboxMessagesCheckBox.setEnabled(false); + optionsLabel.setEnabled(false); + optionsSeparator.setEnabled(false); + + // Update database action buttons. + newDatabaseButton.setEnabled(!ingestIsRunning); + importDatabaseButton.setEnabled(!ingestIsRunning); + deleteDatabaseButton.setEnabled(false); + + // Update ingest in progress warning label. + ingestWarningLabel.setVisible(ingestIsRunning); + } + + private void updateComponentsForSelection(HashDb db) { + boolean ingestIsRunning = IngestManager.getDefault().isIngestRunning(); + + // Update labels. + hashDbLocationLabel.setToolTipText(db.getDatabasePath()); + if (db.getDatabasePath().length() > 50){ + String shortenedPath = db.getDatabasePath(); + shortenedPath = shortenedPath.substring(0, 10 + shortenedPath.substring(10).indexOf(File.separator) + 1) + "..." + shortenedPath.substring((shortenedPath.length() - 20) + shortenedPath.substring(shortenedPath.length() - 20).indexOf(File.separator)); + hashDbLocationLabel.setText(shortenedPath); } else { - IndexStatus status = IndexStatus.UNKNOWN; - try { - status = hashDb.getStatus(); - } - catch (TskCoreException ex) { - // RJCTODO: Need a status unknown? - // Logger.getLogger(HashDbIngestModule.class.getName()) - } - - hashDbIndexStatusLabel.setText(status.message()); - switch (status) { - case NO_INDEX: - indexButton.setText("Index"); - hashDbIndexStatusLabel.setForeground(Color.red); - indexButton.setEnabled(true); - break; - case INDEXING: - indexButton.setText("Indexing"); - hashDbIndexStatusLabel.setForeground(Color.black); - indexButton.setEnabled(false); - break; - case UNKNOWN: - indexButton.setText("Index"); - hashDbIndexStatusLabel.setForeground(Color.red); - indexButton.setEnabled(false); - break; - case INDEXED: - // TODO: Restore ability to re-index an indexed - case INDEX_ONLY: - default: - indexButton.setText("Index"); - hashDbIndexStatusLabel.setForeground(Color.black); - indexButton.setEnabled(false); - break; - } + hashDbLocationLabel.setText(db.getDatabasePath()); } - - if (IngestManager.getDefault().isIngestRunning()) { + hashDbNameLabel.setText(db.getDisplayName()); + hashDbTypeLabel.setText(db.getKnownFilesType().getDisplayName()); + + // Update indexing components. + IndexStatus status = IndexStatus.UNKNOWN; + try { + status = db.getStatus(); + } + catch (TskCoreException ex) { + // RJCTODO + // Logger.getLogger(HashDbIngestModule.class.getName()) + } + hashDbIndexStatusLabel.setText(status.message()); + switch (status) { + case NO_INDEX: + indexButton.setText("Index"); + hashDbIndexStatusLabel.setForeground(Color.red); + indexButton.setEnabled(true); + break; + case INDEXING: + indexButton.setText("Indexing"); + hashDbIndexStatusLabel.setForeground(Color.black); + indexButton.setEnabled(false); + break; + case UNKNOWN: + indexButton.setText("Index"); + hashDbIndexStatusLabel.setForeground(Color.red); + indexButton.setEnabled(false); + break; + case INDEXED: + // TODO: Restore ability to re-index an indexed database. + case INDEX_ONLY: + default: + indexButton.setText("Index"); + hashDbIndexStatusLabel.setForeground(Color.black); + indexButton.setEnabled(false); + break; + } + if (ingestIsRunning) { indexButton.setEnabled(false); } + + // Update ingest option components. + useForIngestCheckbox.setSelected(db.getUseForIngest()); + useForIngestCheckbox.setEnabled(!ingestIsRunning); + showInboxMessagesCheckBox.setSelected(db.getShowInboxMessages()); + showInboxMessagesCheckBox.setEnabled(!ingestIsRunning && db.getUseForIngest() && db.getKnownFilesType().equals(HashDb.KnownFilesType.KNOWN_BAD)); + optionsLabel.setEnabled(!ingestIsRunning && db.getUseForIngest() && db.getKnownFilesType().equals(HashDb.KnownFilesType.KNOWN_BAD)); + optionsSeparator.setEnabled(!ingestIsRunning && db.getUseForIngest() && db.getKnownFilesType().equals(HashDb.KnownFilesType.KNOWN_BAD)); + + // Update database action buttons. + deleteDatabaseButton.setEnabled(!ingestIsRunning); + importDatabaseButton.setEnabled(!ingestIsRunning); + importDatabaseButton.setEnabled(!ingestIsRunning); + + // Update ingest in progress warning label. + ingestWarningLabel.setVisible(ingestIsRunning); } @Override public void load() { hashSetTable.clearSelection(); - hashSetTableModel.refresh(); -// updateComponents(null); + hashSetTableModel.refreshModel(); } @Override @@ -176,8 +199,7 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel unindexed.add(hashSet); } } - - // RJCTODO:Whaaaaat? + //If unindexed ones are found, show a popup box that will either index them, or remove them. if (unindexed.size() == 1){ showInvalidIndex(false, unindexed); @@ -185,7 +207,7 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel else if (unindexed.size() > 1){ showInvalidIndex(true, unindexed); } - + hashSetManager.save(); } @@ -198,7 +220,7 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel for (HashDb hashDb : toRemove) { hashSetManager.removeHashSet(hashDb); } - hashSetTableModel.refresh(); + hashSetTableModel.refreshModel(); } /** @@ -225,7 +247,7 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel indexingDialog.setLocationRelativeTo(null); indexingDialog.setVisible(true); indexingDialog.setModal(true); - hashSetTableModel.refresh(); + hashSetTableModel.refreshModel(); } if(res == JOptionPane.NO_OPTION){ JOptionPane.showMessageDialog(this, "All unindexed databases will be removed the list"); @@ -340,9 +362,13 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel return -1; } - void refresh() { + void refreshModel() { hashSets = HashDbManager.getInstance().getAllHashSets(); - fireTableDataChanged(); + refreshDisplay(); + } + + void refreshDisplay() { + fireTableDataChanged(); } } @@ -361,8 +387,8 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel ingestWarningLabel = new javax.swing.JLabel(); jScrollPane1 = new javax.swing.JScrollPane(); hashSetTable = new HashSetTable(); - deleteButton = new javax.swing.JButton(); - importButton = new javax.swing.JButton(); + deleteDatabaseButton = new javax.swing.JButton(); + importDatabaseButton = new javax.swing.JButton(); hashDatabasesLabel = new javax.swing.JLabel(); nameLabel = new javax.swing.JLabel(); hashDbNameLabel = new javax.swing.JLabel(); @@ -379,7 +405,7 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel optionsLabel = new javax.swing.JLabel(); informationSeparator = new javax.swing.JSeparator(); optionsSeparator = new javax.swing.JSeparator(); - importButton1 = new javax.swing.JButton(); + newDatabaseButton = new javax.swing.JButton(); org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.jLabel2.text")); // NOI18N @@ -413,25 +439,25 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel }); jScrollPane1.setViewportView(hashSetTable); - deleteButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/delete16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(deleteButton, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.deleteButton.text")); // NOI18N - deleteButton.setMaximumSize(new java.awt.Dimension(140, 25)); - deleteButton.setMinimumSize(new java.awt.Dimension(140, 25)); - deleteButton.setPreferredSize(new java.awt.Dimension(140, 25)); - deleteButton.addActionListener(new java.awt.event.ActionListener() { + deleteDatabaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/delete16.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(deleteDatabaseButton, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.deleteDatabaseButton.text")); // NOI18N + deleteDatabaseButton.setMaximumSize(new java.awt.Dimension(140, 25)); + deleteDatabaseButton.setMinimumSize(new java.awt.Dimension(140, 25)); + deleteDatabaseButton.setPreferredSize(new java.awt.Dimension(140, 25)); + deleteDatabaseButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - deleteButtonActionPerformed(evt); + deleteDatabaseButtonActionPerformed(evt); } }); - importButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/import16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(importButton, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.importButton.text")); // NOI18N - importButton.setMaximumSize(new java.awt.Dimension(140, 25)); - importButton.setMinimumSize(new java.awt.Dimension(140, 25)); - importButton.setPreferredSize(new java.awt.Dimension(140, 25)); - importButton.addActionListener(new java.awt.event.ActionListener() { + importDatabaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/import16.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(importDatabaseButton, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.importDatabaseButton.text")); // NOI18N + importDatabaseButton.setMaximumSize(new java.awt.Dimension(140, 25)); + importDatabaseButton.setMinimumSize(new java.awt.Dimension(140, 25)); + importDatabaseButton.setPreferredSize(new java.awt.Dimension(140, 25)); + importDatabaseButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - importButtonActionPerformed(evt); + importDatabaseButtonActionPerformed(evt); } }); @@ -479,14 +505,14 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel org.openide.awt.Mnemonics.setLocalizedText(optionsLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.optionsLabel.text")); // NOI18N - importButton1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/new16.png"))); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(importButton1, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.importButton1.text")); // NOI18N - importButton1.setMaximumSize(new java.awt.Dimension(140, 25)); - importButton1.setMinimumSize(new java.awt.Dimension(140, 25)); - importButton1.setPreferredSize(new java.awt.Dimension(140, 25)); - importButton1.addActionListener(new java.awt.event.ActionListener() { + newDatabaseButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/hashdatabase/new16.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(newDatabaseButton, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.newDatabaseButton.text")); // NOI18N + newDatabaseButton.setMaximumSize(new java.awt.Dimension(140, 25)); + newDatabaseButton.setMinimumSize(new java.awt.Dimension(140, 25)); + newDatabaseButton.setPreferredSize(new java.awt.Dimension(140, 25)); + newDatabaseButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - importButton1ActionPerformed(evt); + newDatabaseButtonActionPerformed(evt); } }); @@ -534,10 +560,10 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel .addComponent(showInboxMessagesCheckBox) .addComponent(indexButton, javax.swing.GroupLayout.PREFERRED_SIZE, 75, javax.swing.GroupLayout.PREFERRED_SIZE))))) .addGroup(layout.createSequentialGroup() - .addComponent(importButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(newDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(importButton, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(deleteButton, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(importDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(deleteDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap(40, Short.MAX_VALUE)) ); layout.setVerticalGroup( @@ -585,10 +611,10 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 391, Short.MAX_VALUE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(importButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(importButton1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(importDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(newDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(deleteButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(deleteDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addContainerGap()) ); }// //GEN-END:initComponents @@ -604,8 +630,9 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel if (evt.getPropertyName().equals(HashDb.Event.INDEXING_DONE.toString())) { HashDb selectedHashDb = ((HashSetTable)hashSetTable).getSelection(); if (selectedHashDb != null && hashDbToBeIndexed != null && hashDbToBeIndexed.equals(selectedHashDb)) { - updateStatusComponents(selectedHashDb); + updateComponents(); } + hashSetTableModel.refreshDisplay(); } } }); @@ -623,22 +650,22 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel } }//GEN-LAST:event_indexButtonActionPerformed - private void deleteButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteButtonActionPerformed + private void deleteDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteDatabaseButtonActionPerformed if (JOptionPane.showConfirmDialog(null, "This will remove the hash database entry globally (for all Cases). Do you want to proceed? ", "Deleting a Hash Database Entry", JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) { HashDb hashDb = ((HashSetTable)hashSetTable).getSelection(); if (hashDb != null) { hashSetManager.removeHashSet(hashDb); - hashSetTableModel.refresh(); + hashSetTableModel.refreshModel(); } } - }//GEN-LAST:event_deleteButtonActionPerformed + }//GEN-LAST:event_deleteDatabaseButtonActionPerformed private void hashSetTableKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_hashSetTableKeyPressed if (evt.getKeyCode() == KeyEvent.VK_DELETE) { HashDb hashDb = ((HashSetTable)hashSetTable).getSelection(); if (hashDb != null) { hashSetManager.removeHashSet(hashDb); - hashSetTableModel.refresh(); + hashSetTableModel.refreshModel(); } } }//GEN-LAST:event_hashSetTableKeyPressed @@ -658,34 +685,33 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel } }//GEN-LAST:event_showInboxMessagesCheckBoxActionPerformed - private void importButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importButtonActionPerformed + private void importDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importDatabaseButtonActionPerformed HashDb hashDb = new HashDbImportDatabaseDialog().doDialog(); if (hashDb != null) { hashSetManager.addHashSet(hashDb); - hashSetTableModel.refresh(); + hashSetTableModel.refreshModel(); ((HashSetTable)hashSetTable).selectRowByName(hashDb.getDisplayName()); } - }//GEN-LAST:event_importButtonActionPerformed + }//GEN-LAST:event_importDatabaseButtonActionPerformed - private void importButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importButton1ActionPerformed + private void newDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newDatabaseButtonActionPerformed HashDb hashDb = new HashDbCreateDatabaseDialog().doDialog(); if (null != hashDb) { hashSetManager.addHashSet(hashDb); - hashSetTableModel.refresh(); + hashSetTableModel.refreshModel(); ((HashSetTable)hashSetTable).selectRowByName(hashDb.getDisplayName()); } - }//GEN-LAST:event_importButton1ActionPerformed + }//GEN-LAST:event_newDatabaseButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.JButton deleteButton; + private javax.swing.JButton deleteDatabaseButton; private javax.swing.JLabel hashDatabasesLabel; private javax.swing.JLabel hashDbIndexStatusLabel; private javax.swing.JLabel hashDbLocationLabel; private javax.swing.JLabel hashDbNameLabel; private javax.swing.JLabel hashDbTypeLabel; private javax.swing.JTable hashSetTable; - private javax.swing.JButton importButton; - private javax.swing.JButton importButton1; + private javax.swing.JButton importDatabaseButton; private javax.swing.JButton indexButton; private javax.swing.JLabel indexLabel; private javax.swing.JLabel informationLabel; @@ -698,6 +724,7 @@ final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel private javax.swing.JScrollPane jScrollPane1; private javax.swing.JLabel locationLabel; private javax.swing.JLabel nameLabel; + private javax.swing.JButton newDatabaseButton; private javax.swing.JLabel optionsLabel; private javax.swing.JSeparator optionsSeparator; private javax.swing.JCheckBox showInboxMessagesCheckBox; From 00acd6d854115c9a94a3882a22f68886e4d9c797 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 6 Nov 2013 16:05:42 -0500 Subject: [PATCH 076/169] Line endings fix --- .../autopsy/hashdatabase/Bundle.properties | 128 +-- .../autopsy/hashdatabase/HashDb.java | 606 ++++++------- .../autopsy/hashdatabase/HashDbXML.java | 850 +++++++++--------- 3 files changed, 792 insertions(+), 792 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties index a9aead73cb..bf9c210f1a 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties @@ -1,64 +1,64 @@ -OpenIDE-Module-Display-Category=Ingest Module -OpenIDE-Module-Long-Description=\ - Hash Database ingest module. \n\n\ - The ingest module analyzes files in the disk image and marks them as "known" (based on NSRL database lookup for "known" files) and "bad / interesting" (based on one or more databases supplied by the user).\n\n\ - The module also contains additional non-ingest tools that are integrated in the GUI, such as file lookup by hash and hash database configuration. -OpenIDE-Module-Name=HashDatabase -HashDbSimplePanel.knownLabel.text=NSRL Database: -HashDbSimplePanel.notableLabel.text=Known Bad Database(s): -HashDbSimplePanel.knownValLabel.text=- -HashDbSimplePanel.notableValLabel.text=- -HashDbSimplePanel.jLabel1.text=Enable known bad databases for ingest: -HashDbAddDatabaseDialog.cancelButton.text=Cancel -HashDbAddDatabaseDialog.okButton.text=OK -HashDbAddDatabaseDialog.nsrlRadioButton.text=NSRL -HashDbAddDatabaseDialog.knownBadRadioButton.text=Known Bad -HashDbAddDatabaseDialog.databasePathTextField.text= -HashDbAddDatabaseDialog.browseButton.text=Browse -HashDbAddDatabaseDialog.jLabel1.text=Enter the name of the database: -HashDbAddDatabaseDialog.databaseNameTextField.text= -HashDbAddDatabaseDialog.jLabel2.text=Select the type of database: -HashDbAddDatabaseDialog.useForIngestCheckbox.text=Enable for ingest -HashDbAddDatabaseDialog.sendInboxMessagesCheckbox.text=Enable sending messages to inbox during ingest -HashDbSearchPanel.hashTable.columnModel.title0=MD5 Hashes -HashDbSearchPanel.hashTable.columnModel.title3=Title 4 -HashDbSearchPanel.hashTable.columnModel.title2=Title 3 -HashDbSearchPanel.hashTable.columnModel.title1=Title 2 -HashDbSearchPanel.addButton.text=Add Hash -HashDbSearchPanel.hashField.text= -HashDbSearchPanel.hashLabel.text=MD5 hash: -HashDbSearchPanel.searchButton.text=Search -HashDbSearchPanel.removeButton.text=Remove Selected -HashDbSearchPanel.titleLabel.text=Search for files with the following MD5 hash(es): -HashDbSearchPanel.errorField.text=Error: Not all files have been hashed. -HashDbSearchPanel.saveBox.text=Remember Hashes -HashDbSearchPanel.cancelButton.text=Cancel -HashDbSimplePanel.calcHashesButton.text=Calculate hashes even if no hash database is selected -HashDbSimplePanel.nsrlDbLabel.text=NSRL Database: -HashDbSimplePanel.nsrlDbLabelVal.text=- -HashDbManagementPanel.hashDbIndexStatusLabel.text=No database selected -HashDbManagementPanel.jLabel2.text=Name: -HashDbManagementPanel.showInboxMessagesCheckBox.text=Enable sending messages to inbox during ingest -HashDbManagementPanel.useForIngestCheckbox.text=Enable for ingest -HashDbManagementPanel.indexButton.text=Index -HashDbManagementPanel.indexLabel.text=Index Status: -HashDbManagementPanel.optionsLabel.text=Options -HashDbManagementPanel.jLabel4.text=Location: -HashDbManagementPanel.jLabel6.text=Type: -HashDbManagementPanel.ingestWarningLabel.text=Ingest is ongoing, some settings will be unavailable until it finishes. -HashDbManagementPanel.hashDbTypeLabel.text=No database selected -HashDbManagementPanel.typeLabel.text=Type: -HashDbManagementPanel.deleteButton.text=Delete Database -HashDbManagementPanel.importButton.text=Import Database -HashDbManagementPanel.hashDbNameLabel.text=No database selected -HashDbManagementPanel.nameLabel.text=Name: -HashDbManagementPanel.jButton3.text=Import Database -HashDbManagementPanel.locationLabel.text=Location: -HashDbManagementPanel.hashDbLocationLabel.text=No database selected -HashDbManagementPanel.informationLabel.text=Information -HashDbManagementPanel.hashDatabasesLabel.text=Hash Databases: -OpenIDE-Module-Short-Description=Hash Database Ingest Module and hash db tools -ModalNoButtons.CURRENTLYON_LABEL.text=Currently Indexing x of y -ModalNoButtons.GO_GET_COFFEE_LABEL.text=Hash databases are currently being indexed, this may take some time. -ModalNoButtons.CURRENTDB_LABEL.text=(CurrentDb) -ModalNoButtons.CANCEL_BUTTON.text=Cancel +OpenIDE-Module-Display-Category=Ingest Module +OpenIDE-Module-Long-Description=\ + Hash Database ingest module. \n\n\ + The ingest module analyzes files in the disk image and marks them as "known" (based on NSRL database lookup for "known" files) and "bad / interesting" (based on one or more databases supplied by the user).\n\n\ + The module also contains additional non-ingest tools that are integrated in the GUI, such as file lookup by hash and hash database configuration. +OpenIDE-Module-Name=HashDatabase +HashDbSimplePanel.knownLabel.text=NSRL Database: +HashDbSimplePanel.notableLabel.text=Known Bad Database(s): +HashDbSimplePanel.knownValLabel.text=- +HashDbSimplePanel.notableValLabel.text=- +HashDbSimplePanel.jLabel1.text=Enable known bad databases for ingest: +HashDbAddDatabaseDialog.cancelButton.text=Cancel +HashDbAddDatabaseDialog.okButton.text=OK +HashDbAddDatabaseDialog.nsrlRadioButton.text=NSRL +HashDbAddDatabaseDialog.knownBadRadioButton.text=Known Bad +HashDbAddDatabaseDialog.databasePathTextField.text= +HashDbAddDatabaseDialog.browseButton.text=Browse +HashDbAddDatabaseDialog.jLabel1.text=Enter the name of the database: +HashDbAddDatabaseDialog.databaseNameTextField.text= +HashDbAddDatabaseDialog.jLabel2.text=Select the type of database: +HashDbAddDatabaseDialog.useForIngestCheckbox.text=Enable for ingest +HashDbAddDatabaseDialog.sendInboxMessagesCheckbox.text=Enable sending messages to inbox during ingest +HashDbSearchPanel.hashTable.columnModel.title0=MD5 Hashes +HashDbSearchPanel.hashTable.columnModel.title3=Title 4 +HashDbSearchPanel.hashTable.columnModel.title2=Title 3 +HashDbSearchPanel.hashTable.columnModel.title1=Title 2 +HashDbSearchPanel.addButton.text=Add Hash +HashDbSearchPanel.hashField.text= +HashDbSearchPanel.hashLabel.text=MD5 hash: +HashDbSearchPanel.searchButton.text=Search +HashDbSearchPanel.removeButton.text=Remove Selected +HashDbSearchPanel.titleLabel.text=Search for files with the following MD5 hash(es): +HashDbSearchPanel.errorField.text=Error: Not all files have been hashed. +HashDbSearchPanel.saveBox.text=Remember Hashes +HashDbSearchPanel.cancelButton.text=Cancel +HashDbSimplePanel.calcHashesButton.text=Calculate hashes even if no hash database is selected +HashDbSimplePanel.nsrlDbLabel.text=NSRL Database: +HashDbSimplePanel.nsrlDbLabelVal.text=- +HashDbManagementPanel.hashDbIndexStatusLabel.text=No database selected +HashDbManagementPanel.jLabel2.text=Name: +HashDbManagementPanel.showInboxMessagesCheckBox.text=Enable sending messages to inbox during ingest +HashDbManagementPanel.useForIngestCheckbox.text=Enable for ingest +HashDbManagementPanel.indexButton.text=Index +HashDbManagementPanel.indexLabel.text=Index Status: +HashDbManagementPanel.optionsLabel.text=Options +HashDbManagementPanel.jLabel4.text=Location: +HashDbManagementPanel.jLabel6.text=Type: +HashDbManagementPanel.ingestWarningLabel.text=Ingest is ongoing, some settings will be unavailable until it finishes. +HashDbManagementPanel.hashDbTypeLabel.text=No database selected +HashDbManagementPanel.typeLabel.text=Type: +HashDbManagementPanel.deleteButton.text=Delete Database +HashDbManagementPanel.importButton.text=Import Database +HashDbManagementPanel.hashDbNameLabel.text=No database selected +HashDbManagementPanel.nameLabel.text=Name: +HashDbManagementPanel.jButton3.text=Import Database +HashDbManagementPanel.locationLabel.text=Location: +HashDbManagementPanel.hashDbLocationLabel.text=No database selected +HashDbManagementPanel.informationLabel.text=Information +HashDbManagementPanel.hashDatabasesLabel.text=Hash Databases: +OpenIDE-Module-Short-Description=Hash Database Ingest Module and hash db tools +ModalNoButtons.CURRENTLYON_LABEL.text=Currently Indexing x of y +ModalNoButtons.GO_GET_COFFEE_LABEL.text=Hash databases are currently being indexed, this may take some time. +ModalNoButtons.CURRENTDB_LABEL.text=(CurrentDb) +ModalNoButtons.CANCEL_BUTTON.text=Cancel diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index 9a08234eab..47d3e58c52 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -1,304 +1,304 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011 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.hashdatabase; - -import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; -import java.io.File; -import java.util.List; -import java.util.logging.Level; -import javax.swing.SwingWorker; -import org.netbeans.api.progress.ProgressHandle; -import org.netbeans.api.progress.ProgressHandleFactory; -import org.openide.util.Cancellable; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.datamodel.SleuthkitJNI; -import org.sleuthkit.datamodel.TskException; - -/** - * Hash database representation of NSRL and Known Bad hash databases - * with indexing capability - * - */ -public class HashDb implements Comparable { - - enum EVENT {INDEXING_DONE }; - private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); - - - public enum DBType{ - NSRL("NSRL"), KNOWN_BAD("Known Bad"); - - private String displayName; - - private DBType(String displayName) { - this.displayName = displayName; - } - - public String getDisplayName() { - return this.displayName; - } - } - - // Suffix added to the end of a database name to get its index file - private static final String INDEX_SUFFIX = "-md5.idx"; - - private String name; - private List databasePaths; // TODO: Length limited to one for now... - private boolean useForIngest; - private boolean showInboxMessages; - private boolean indexing; - private DBType type; - - public HashDb(String name, List databasePaths, boolean useForIngest, boolean showInboxMessages, DBType type) { - this.name = name; - this.databasePaths = databasePaths; - this.useForIngest = useForIngest; - this.showInboxMessages = showInboxMessages; - this.type = type; - this.indexing = false; - } - - void addPropertyChangeListener(PropertyChangeListener pcl) { - pcs.addPropertyChangeListener(pcl); - } - - void removePropertyChangeListener(PropertyChangeListener pcl) { - pcs.removePropertyChangeListener(pcl); - } - - boolean getUseForIngest() { - return useForIngest; - } - - boolean getShowInboxMessages() { - return showInboxMessages; - } - - DBType getDbType() { - return type; - } - - String getName() { - return name; - } - - List getDatabasePaths() { - return databasePaths; - } - - void setUseForIngest(boolean useForIngest) { - this.useForIngest = useForIngest; - } - - void setShowInboxMessages(boolean showInboxMessages) { - this.showInboxMessages = showInboxMessages; - } - - void setName(String name) { - this.name = name; - } - - void setDatabasePaths(List databasePaths) { - this.databasePaths = databasePaths; - } - - void setDbType(DBType type) { - this.type = type; - } - - /** - * Checks if the database exists. - * @return true if a file exists at the database path, else false - */ - boolean databaseExists() { - return databaseFile().exists(); - } - - /** - * Checks if Sleuth Kit can open the index for the database path. - * @return true if the index was found and opened successfully, else false - */ - boolean indexExists() { - try { - return hasIndex(databasePaths.get(0)); // TODO: support multiple paths - } catch (TskException ex) { - Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Error checking if index exists.", ex); - return false; - } - } - - /** - * Gets the database file. - * @return a File initialized with the database path - */ - File databaseFile() { - return new File(databasePaths.get(0)); // TODO: support multiple paths - } - - /** - * Gets the index file - * @return a File initialized with an index path derived from the database - * path - */ - File indexFile() { - return new File(toIndexPath(databasePaths.get(0))); // TODO: support multiple paths - } - - /** - * Checks if the index file is older than the database file - * @return true if there is are files at the index path and the database - * path, and the index file has an older modified-time than the database - * file, else false - */ - boolean isOutdated() { - File i = indexFile(); - File db = databaseFile(); - - return i.exists() && db.exists() && isOlderThan(i, db); - } - - /** - * Checks if the database is being indexed - */ - boolean isIndexing() { - return indexing; - } - - /** - * Returns the status of the HashDb as determined from indexExists(), - * databaseExists(), and isOutdated() - * @return IndexStatus enum according to their definitions - */ - IndexStatus status() { - boolean i = this.indexExists(); - boolean db = this.databaseExists(); - - if(indexing) - return IndexStatus.INDEXING; - if (i) { - if (db) { - return this.isOutdated() ? IndexStatus.INDEX_OUTDATED : IndexStatus.INDEX_CURRENT; - } else { - return IndexStatus.NO_DB; - } - } else { - return db ? IndexStatus.NO_INDEX : IndexStatus.NONE; - } - } - - /** - * Tries to index the database (overwrites any existing index) - * @throws TskException if an error occurs in the SleuthKit bindings - */ - void createIndex() throws TskException { - indexing = true; - CreateIndex creator = new CreateIndex(); - creator.execute(); - } - - /** - * Checks if one file is older than an other - * @param a first file - * @param b second file - * @return true if the first file's last modified data is before the second - * file's last modified date - */ - private static boolean isOlderThan(File a, File b) { - return a.lastModified() < b.lastModified(); - } - - /** - * Determines if a path points to an index by checking the suffix - * @param path - * @return true if index - */ - static boolean isIndexPath(String path) { - return path.endsWith(INDEX_SUFFIX); - } - - /** - * Derives database path from an image path by removing the suffix. - * @param indexPath - * @return - */ - static String toDatabasePath(String indexPath) { - return indexPath.substring(0, indexPath.lastIndexOf(INDEX_SUFFIX)); - } - - /** - * Derives image path from an database path by appending the suffix. - * @param databasePath - * @return - */ - static String toIndexPath(String databasePath) { - return databasePath.concat(INDEX_SUFFIX); - } - - /** - * Calls Sleuth Kit method via JNI to determine whether there is an - * index for the given path - * @param databasePath path Path for the database the index is of - * (database doesn't have to actually exist)' - * @return true if index exists - * @throws TskException if there is an error in the JNI call - */ - static boolean hasIndex(String databasePath) throws TskException { - return SleuthkitJNI.lookupIndexExists(databasePath); - } - - @Override - public int compareTo(HashDb o) { - return this.name.compareTo(o.name); - } - - /* Thread that creates a database's index */ - private class CreateIndex extends SwingWorker { - - private ProgressHandle progress; - - CreateIndex(){}; - - @Override - protected Object doInBackground() throws Exception { - progress = ProgressHandleFactory.createHandle("Indexing " + name); - - /** We need proper cancel support in TSK to make the task cancellable - new Cancellable() { - Override - public boolean cancel() { - return CreateIndex.this.cancel(true); - } - }); - */ - progress.start(); - progress.switchToIndeterminate(); - SleuthkitJNI.createLookupIndex(databasePaths.get(0)); - return null; - } - - /* clean up or start the worker threads */ - @Override - protected void done() { - indexing = false; - progress.finish(); - pcs.firePropertyChange(EVENT.INDEXING_DONE.toString(), null, name); - } - } +/* + * Autopsy Forensic Browser + * + * Copyright 2011 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.hashdatabase; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.io.File; +import java.util.List; +import java.util.logging.Level; +import javax.swing.SwingWorker; +import org.netbeans.api.progress.ProgressHandle; +import org.netbeans.api.progress.ProgressHandleFactory; +import org.openide.util.Cancellable; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.SleuthkitJNI; +import org.sleuthkit.datamodel.TskException; + +/** + * Hash database representation of NSRL and Known Bad hash databases + * with indexing capability + * + */ +public class HashDb implements Comparable { + + enum EVENT {INDEXING_DONE }; + private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); + + + public enum DBType{ + NSRL("NSRL"), KNOWN_BAD("Known Bad"); + + private String displayName; + + private DBType(String displayName) { + this.displayName = displayName; + } + + public String getDisplayName() { + return this.displayName; + } + } + + // Suffix added to the end of a database name to get its index file + private static final String INDEX_SUFFIX = "-md5.idx"; + + private String name; + private List databasePaths; // TODO: Length limited to one for now... + private boolean useForIngest; + private boolean showInboxMessages; + private boolean indexing; + private DBType type; + + public HashDb(String name, List databasePaths, boolean useForIngest, boolean showInboxMessages, DBType type) { + this.name = name; + this.databasePaths = databasePaths; + this.useForIngest = useForIngest; + this.showInboxMessages = showInboxMessages; + this.type = type; + this.indexing = false; + } + + void addPropertyChangeListener(PropertyChangeListener pcl) { + pcs.addPropertyChangeListener(pcl); + } + + void removePropertyChangeListener(PropertyChangeListener pcl) { + pcs.removePropertyChangeListener(pcl); + } + + boolean getUseForIngest() { + return useForIngest; + } + + boolean getShowInboxMessages() { + return showInboxMessages; + } + + DBType getDbType() { + return type; + } + + String getName() { + return name; + } + + List getDatabasePaths() { + return databasePaths; + } + + void setUseForIngest(boolean useForIngest) { + this.useForIngest = useForIngest; + } + + void setShowInboxMessages(boolean showInboxMessages) { + this.showInboxMessages = showInboxMessages; + } + + void setName(String name) { + this.name = name; + } + + void setDatabasePaths(List databasePaths) { + this.databasePaths = databasePaths; + } + + void setDbType(DBType type) { + this.type = type; + } + + /** + * Checks if the database exists. + * @return true if a file exists at the database path, else false + */ + boolean databaseExists() { + return databaseFile().exists(); + } + + /** + * Checks if Sleuth Kit can open the index for the database path. + * @return true if the index was found and opened successfully, else false + */ + boolean indexExists() { + try { + return hasIndex(databasePaths.get(0)); // TODO: support multiple paths + } catch (TskException ex) { + Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Error checking if index exists.", ex); + return false; + } + } + + /** + * Gets the database file. + * @return a File initialized with the database path + */ + File databaseFile() { + return new File(databasePaths.get(0)); // TODO: support multiple paths + } + + /** + * Gets the index file + * @return a File initialized with an index path derived from the database + * path + */ + File indexFile() { + return new File(toIndexPath(databasePaths.get(0))); // TODO: support multiple paths + } + + /** + * Checks if the index file is older than the database file + * @return true if there is are files at the index path and the database + * path, and the index file has an older modified-time than the database + * file, else false + */ + boolean isOutdated() { + File i = indexFile(); + File db = databaseFile(); + + return i.exists() && db.exists() && isOlderThan(i, db); + } + + /** + * Checks if the database is being indexed + */ + boolean isIndexing() { + return indexing; + } + + /** + * Returns the status of the HashDb as determined from indexExists(), + * databaseExists(), and isOutdated() + * @return IndexStatus enum according to their definitions + */ + IndexStatus status() { + boolean i = this.indexExists(); + boolean db = this.databaseExists(); + + if(indexing) + return IndexStatus.INDEXING; + if (i) { + if (db) { + return this.isOutdated() ? IndexStatus.INDEX_OUTDATED : IndexStatus.INDEX_CURRENT; + } else { + return IndexStatus.NO_DB; + } + } else { + return db ? IndexStatus.NO_INDEX : IndexStatus.NONE; + } + } + + /** + * Tries to index the database (overwrites any existing index) + * @throws TskException if an error occurs in the SleuthKit bindings + */ + void createIndex() throws TskException { + indexing = true; + CreateIndex creator = new CreateIndex(); + creator.execute(); + } + + /** + * Checks if one file is older than an other + * @param a first file + * @param b second file + * @return true if the first file's last modified data is before the second + * file's last modified date + */ + private static boolean isOlderThan(File a, File b) { + return a.lastModified() < b.lastModified(); + } + + /** + * Determines if a path points to an index by checking the suffix + * @param path + * @return true if index + */ + static boolean isIndexPath(String path) { + return path.endsWith(INDEX_SUFFIX); + } + + /** + * Derives database path from an image path by removing the suffix. + * @param indexPath + * @return + */ + static String toDatabasePath(String indexPath) { + return indexPath.substring(0, indexPath.lastIndexOf(INDEX_SUFFIX)); + } + + /** + * Derives image path from an database path by appending the suffix. + * @param databasePath + * @return + */ + static String toIndexPath(String databasePath) { + return databasePath.concat(INDEX_SUFFIX); + } + + /** + * Calls Sleuth Kit method via JNI to determine whether there is an + * index for the given path + * @param databasePath path Path for the database the index is of + * (database doesn't have to actually exist)' + * @return true if index exists + * @throws TskException if there is an error in the JNI call + */ + static boolean hasIndex(String databasePath) throws TskException { + return SleuthkitJNI.lookupIndexExists(databasePath); + } + + @Override + public int compareTo(HashDb o) { + return this.name.compareTo(o.name); + } + + /* Thread that creates a database's index */ + private class CreateIndex extends SwingWorker { + + private ProgressHandle progress; + + CreateIndex(){}; + + @Override + protected Object doInBackground() throws Exception { + progress = ProgressHandleFactory.createHandle("Indexing " + name); + + /** We need proper cancel support in TSK to make the task cancellable + new Cancellable() { + Override + public boolean cancel() { + return CreateIndex.this.cancel(true); + } + }); + */ + progress.start(); + progress.switchToIndeterminate(); + SleuthkitJNI.createLookupIndex(databasePaths.get(0)); + return null; + } + + /* clean up or start the worker threads */ + @Override + protected void done() { + indexing = false; + progress.finish(); + pcs.firePropertyChange(EVENT.INDEXING_DONE.toString(), null, name); + } + } } \ No newline at end of file diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java index 9ddc638b9e..b0040ff080 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbXML.java @@ -1,425 +1,425 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011 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.hashdatabase; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.logging.Level; -import javax.swing.JFileChooser; -import javax.swing.JOptionPane; -import javax.swing.filechooser.FileNameExtensionFilter; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.PlatformUtil; -import org.sleuthkit.autopsy.coreutils.XMLUtil; -import org.sleuthkit.autopsy.hashdatabase.HashDb.DBType; -import org.sleuthkit.datamodel.SleuthkitJNI; -import org.sleuthkit.datamodel.TskCoreException; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.NodeList; - -public class HashDbXML { - private static final String ROOT_EL = "hash_sets"; - private static final String SET_EL = "hash_set"; - private static final String SET_NAME_ATTR = "name"; - private static final String SET_TYPE_ATTR = "type"; - private static final String SET_USE_FOR_INGEST_ATTR = "use_for_ingest"; - private static final String SET_SHOW_INBOX_MESSAGES = "show_inbox_messages"; - private static final String PATH_EL = "hash_set_path"; - private static final String PATH_NUMBER_ATTR = "number"; - private static final String CUR_HASHSETS_FILE_NAME = "hashsets.xml"; - private static final String XSDFILE = "HashsetsSchema.xsd"; - private static final String ENCODING = "UTF-8"; - private static final String CUR_HASHSET_FILE = PlatformUtil.getUserConfigDirectory() + File.separator + CUR_HASHSETS_FILE_NAME; - private static final String SET_CALC = "hash_calculate"; - private static final String SET_VALUE = "value"; - private static final Logger logger = Logger.getLogger(HashDbXML.class.getName()); - private static HashDbXML currentInstance; - - private List knownBadSets; - private HashDb nsrlSet; - private String xmlFile; - private boolean calculate; - - private HashDbXML(String xmlFile) { - knownBadSets = new ArrayList(); - this.xmlFile = xmlFile; - } - - /** - * get instance for managing the current keyword list of the application - */ - static synchronized HashDbXML getCurrent() { - if (currentInstance == null) { - currentInstance = new HashDbXML(CUR_HASHSET_FILE); - currentInstance.reload(); - } - return currentInstance; - } - - /** - * Get the hash sets - */ - public List getAllSets() { - List ret = new ArrayList(); - if(nsrlSet != null) { - ret.add(nsrlSet); - } - ret.addAll(knownBadSets); - return ret; - } - - /** - * Get the Known Bad sets - */ - public List getKnownBadSets() { - return knownBadSets; - } - - /** - * Get the NSRL set - */ - public HashDb getNSRLSet() { - return nsrlSet; - } - - /** - * Add a known bad hash set - */ - public void addKnownBadSet(HashDb set) { - knownBadSets.add(set); - //save(); - } - - /** - * Add a known bad hash set - */ - public void addKnownBadSet(int index, HashDb set) { - knownBadSets.add(index, set); - //save(); - } - - /** - * Set the NSRL hash set (override old set) - */ - public void setNSRLSet(HashDb set) { - this.nsrlSet = set; - //save(); - } - - /** - * Remove a hash known bad set - */ - public void removeKnownBadSetAt(int index) { - knownBadSets.remove(index); - //save(); - } - - /** - * Remove the NSRL database - */ - public void removeNSRLSet() { - this.nsrlSet = null; - //save(); - } - - /** - * load the file or create new - */ - public void reload() { - boolean created = false; - - //TODO clearing the list causes a bug: we lose track of the state - //whether db is being indexed, we should somehow preserve the state when loading new HashDb objects - - knownBadSets.clear(); - nsrlSet = null; - - if (!this.setsFileExists()) { - //create new if it doesn't exist - save(); - created = true; - } - - //load, if fails to load create new; save regardless - load(); - if (!created) { - //create new if failed to load - save(); - } - } - - /** - * Sets the local variable calculate to the given boolean. - * @param set the state to make calculate - */ - public void setCalculate(boolean set) { - this.calculate = set; - //save(); - } - - /** - * Returns the value of the local boolean calculate. - * @return true if calculate is true, false otherwise - */ - public boolean getCalculate() { - return this.calculate; - } - - /** - * writes out current sets file replacing the last one - */ - public boolean save() { - boolean success = false; - - DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance(); - - try { - DocumentBuilder docBuilder = dbfac.newDocumentBuilder(); - Document doc = docBuilder.newDocument(); - - Element rootEl = doc.createElement(ROOT_EL); - doc.appendChild(rootEl); - - for (HashDb set : knownBadSets) { - String useForIngest = Boolean.toString(set.getUseForIngest()); - String showInboxMessages = Boolean.toString(set.getShowInboxMessages()); - List paths = set.getDatabasePaths(); - String type = DBType.KNOWN_BAD.toString(); - - Element setEl = doc.createElement(SET_EL); - setEl.setAttribute(SET_NAME_ATTR, set.getName()); - setEl.setAttribute(SET_TYPE_ATTR, type); - setEl.setAttribute(SET_USE_FOR_INGEST_ATTR, useForIngest); - setEl.setAttribute(SET_SHOW_INBOX_MESSAGES, showInboxMessages); - - for (int i = 0; i < paths.size(); i++) { - String path = paths.get(i); - Element pathEl = doc.createElement(PATH_EL); - pathEl.setAttribute(PATH_NUMBER_ATTR, Integer.toString(i)); - pathEl.setTextContent(path); - setEl.appendChild(pathEl); - } - rootEl.appendChild(setEl); - } - - if(nsrlSet != null) { - String useForIngest = Boolean.toString(nsrlSet.getUseForIngest()); - String showInboxMessages = Boolean.toString(nsrlSet.getShowInboxMessages()); - List paths = nsrlSet.getDatabasePaths(); - String type = DBType.NSRL.toString(); - - Element setEl = doc.createElement(SET_EL); - setEl.setAttribute(SET_NAME_ATTR, nsrlSet.getName()); - setEl.setAttribute(SET_TYPE_ATTR, type); - setEl.setAttribute(SET_USE_FOR_INGEST_ATTR, useForIngest); - setEl.setAttribute(SET_SHOW_INBOX_MESSAGES, showInboxMessages); - - for (int i = 0; i < paths.size(); i++) { - String path = paths.get(i); - Element pathEl = doc.createElement(PATH_EL); - pathEl.setAttribute(PATH_NUMBER_ATTR, Integer.toString(i)); - pathEl.setTextContent(path); - setEl.appendChild(pathEl); - } - rootEl.appendChild(setEl); - } - - String calcValue = Boolean.toString(calculate); - Element setCalc = doc.createElement(SET_CALC); - setCalc.setAttribute(SET_VALUE, calcValue); - rootEl.appendChild(setCalc); - - success = XMLUtil.saveDoc(HashDbXML.class, xmlFile, ENCODING, doc); - } catch (ParserConfigurationException e) { - logger.log(Level.SEVERE, "Error saving hash sets: can't initialize parser.", e); - } - return success; - } - - /** - * load and parse XML, then dispose - */ - public boolean load() { - final Document doc = XMLUtil.loadDoc(HashDbXML.class, xmlFile, XSDFILE); - if (doc == null) { - return false; - } - - Element root = doc.getDocumentElement(); - if (root == null) { - logger.log(Level.SEVERE, "Error loading hash sets: invalid file format."); - return false; - } - NodeList setsNList = root.getElementsByTagName(SET_EL); - int numSets = setsNList.getLength(); - if(numSets==0) { - logger.log(Level.WARNING, "No element hash_set exists."); - } - for (int i = 0; i < numSets; ++i) { - Element setEl = (Element) setsNList.item(i); - final String name = setEl.getAttribute(SET_NAME_ATTR); - final String type = setEl.getAttribute(SET_TYPE_ATTR); - final String useForIngest = setEl.getAttribute(SET_USE_FOR_INGEST_ATTR); - final String showInboxMessages = setEl.getAttribute(SET_SHOW_INBOX_MESSAGES); - Boolean useForIngestBool = Boolean.parseBoolean(useForIngest); - Boolean showInboxMessagesBool = Boolean.parseBoolean(showInboxMessages); - List paths = new ArrayList(); - - // Parse all paths - NodeList pathsNList = setEl.getElementsByTagName(PATH_EL); - final int numPaths = pathsNList.getLength(); - for (int j = 0; j < numPaths; ++j) { - Element pathEl = (Element) pathsNList.item(j); - String number = pathEl.getAttribute(PATH_NUMBER_ATTR); - String path = pathEl.getTextContent(); - - // If either the database or it's index exist - File database = new File(path); - File index = new File(HashDb.toIndexPath(path)); - if(database.exists() || index.exists()) { - paths.add(path); - } else { - // Ask for new path - int ret = JOptionPane.showConfirmDialog(null, "Database " + name + " could not be found at location\n" - + path + "\n" - + " Would you like to search for the file?", "Missing Database", JOptionPane.YES_NO_OPTION); - if (ret == JOptionPane.YES_OPTION) { - String filePath = searchForFile(name); - if(filePath!=null) { - paths.add(filePath); - } - } - } - } - - // Check everything was properly set - if(name.isEmpty()) { - logger.log(Level.WARNING, "Name was not set for hash_set at index {0}.", i); - } - if(type.isEmpty()) { - logger.log(Level.SEVERE, "Type was not set for hash_set at index {0}, cannot make instance of HashDb class.", i); - return false; // exit because this causes a fatal error - } - if(useForIngest.isEmpty()) { - logger.log(Level.WARNING, "UseForIngest was not set for hash_set at index {0}.", i); - } - if(showInboxMessages.isEmpty()) { - logger.log(Level.WARNING, "ShowInboxMessages was not set for hash_set at index {0}.", i); - } - - if(paths.isEmpty()) { - logger.log(Level.WARNING, "No paths were set for hash_set at index {0}. Removing the database.", i); - } else { - // No paths for this entry, the user most likely declined to search for them - DBType typeDBType = DBType.valueOf(type); - HashDb set = new HashDb(name, paths, useForIngestBool, showInboxMessagesBool, typeDBType); - - if(typeDBType == DBType.KNOWN_BAD) { - knownBadSets.add(set); - } else if(typeDBType == DBType.NSRL) { - this.nsrlSet = set; - } - } - } - - NodeList calcList = root.getElementsByTagName(SET_CALC); - int numCalc = calcList.getLength(); // Shouldn't be more than 1 - if(numCalc==0) { - logger.log(Level.WARNING, "No element hash_calculate exists."); - } - for(int i=0; i 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.hashdatabase; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import javax.swing.JFileChooser; +import javax.swing.JOptionPane; +import javax.swing.filechooser.FileNameExtensionFilter; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.autopsy.coreutils.PlatformUtil; +import org.sleuthkit.autopsy.coreutils.XMLUtil; +import org.sleuthkit.autopsy.hashdatabase.HashDb.DBType; +import org.sleuthkit.datamodel.SleuthkitJNI; +import org.sleuthkit.datamodel.TskCoreException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +public class HashDbXML { + private static final String ROOT_EL = "hash_sets"; + private static final String SET_EL = "hash_set"; + private static final String SET_NAME_ATTR = "name"; + private static final String SET_TYPE_ATTR = "type"; + private static final String SET_USE_FOR_INGEST_ATTR = "use_for_ingest"; + private static final String SET_SHOW_INBOX_MESSAGES = "show_inbox_messages"; + private static final String PATH_EL = "hash_set_path"; + private static final String PATH_NUMBER_ATTR = "number"; + private static final String CUR_HASHSETS_FILE_NAME = "hashsets.xml"; + private static final String XSDFILE = "HashsetsSchema.xsd"; + private static final String ENCODING = "UTF-8"; + private static final String CUR_HASHSET_FILE = PlatformUtil.getUserConfigDirectory() + File.separator + CUR_HASHSETS_FILE_NAME; + private static final String SET_CALC = "hash_calculate"; + private static final String SET_VALUE = "value"; + private static final Logger logger = Logger.getLogger(HashDbXML.class.getName()); + private static HashDbXML currentInstance; + + private List knownBadSets; + private HashDb nsrlSet; + private String xmlFile; + private boolean calculate; + + private HashDbXML(String xmlFile) { + knownBadSets = new ArrayList(); + this.xmlFile = xmlFile; + } + + /** + * get instance for managing the current keyword list of the application + */ + static synchronized HashDbXML getCurrent() { + if (currentInstance == null) { + currentInstance = new HashDbXML(CUR_HASHSET_FILE); + currentInstance.reload(); + } + return currentInstance; + } + + /** + * Get the hash sets + */ + public List getAllSets() { + List ret = new ArrayList(); + if(nsrlSet != null) { + ret.add(nsrlSet); + } + ret.addAll(knownBadSets); + return ret; + } + + /** + * Get the Known Bad sets + */ + public List getKnownBadSets() { + return knownBadSets; + } + + /** + * Get the NSRL set + */ + public HashDb getNSRLSet() { + return nsrlSet; + } + + /** + * Add a known bad hash set + */ + public void addKnownBadSet(HashDb set) { + knownBadSets.add(set); + //save(); + } + + /** + * Add a known bad hash set + */ + public void addKnownBadSet(int index, HashDb set) { + knownBadSets.add(index, set); + //save(); + } + + /** + * Set the NSRL hash set (override old set) + */ + public void setNSRLSet(HashDb set) { + this.nsrlSet = set; + //save(); + } + + /** + * Remove a hash known bad set + */ + public void removeKnownBadSetAt(int index) { + knownBadSets.remove(index); + //save(); + } + + /** + * Remove the NSRL database + */ + public void removeNSRLSet() { + this.nsrlSet = null; + //save(); + } + + /** + * load the file or create new + */ + public void reload() { + boolean created = false; + + //TODO clearing the list causes a bug: we lose track of the state + //whether db is being indexed, we should somehow preserve the state when loading new HashDb objects + + knownBadSets.clear(); + nsrlSet = null; + + if (!this.setsFileExists()) { + //create new if it doesn't exist + save(); + created = true; + } + + //load, if fails to load create new; save regardless + load(); + if (!created) { + //create new if failed to load + save(); + } + } + + /** + * Sets the local variable calculate to the given boolean. + * @param set the state to make calculate + */ + public void setCalculate(boolean set) { + this.calculate = set; + //save(); + } + + /** + * Returns the value of the local boolean calculate. + * @return true if calculate is true, false otherwise + */ + public boolean getCalculate() { + return this.calculate; + } + + /** + * writes out current sets file replacing the last one + */ + public boolean save() { + boolean success = false; + + DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance(); + + try { + DocumentBuilder docBuilder = dbfac.newDocumentBuilder(); + Document doc = docBuilder.newDocument(); + + Element rootEl = doc.createElement(ROOT_EL); + doc.appendChild(rootEl); + + for (HashDb set : knownBadSets) { + String useForIngest = Boolean.toString(set.getUseForIngest()); + String showInboxMessages = Boolean.toString(set.getShowInboxMessages()); + List paths = set.getDatabasePaths(); + String type = DBType.KNOWN_BAD.toString(); + + Element setEl = doc.createElement(SET_EL); + setEl.setAttribute(SET_NAME_ATTR, set.getName()); + setEl.setAttribute(SET_TYPE_ATTR, type); + setEl.setAttribute(SET_USE_FOR_INGEST_ATTR, useForIngest); + setEl.setAttribute(SET_SHOW_INBOX_MESSAGES, showInboxMessages); + + for (int i = 0; i < paths.size(); i++) { + String path = paths.get(i); + Element pathEl = doc.createElement(PATH_EL); + pathEl.setAttribute(PATH_NUMBER_ATTR, Integer.toString(i)); + pathEl.setTextContent(path); + setEl.appendChild(pathEl); + } + rootEl.appendChild(setEl); + } + + if(nsrlSet != null) { + String useForIngest = Boolean.toString(nsrlSet.getUseForIngest()); + String showInboxMessages = Boolean.toString(nsrlSet.getShowInboxMessages()); + List paths = nsrlSet.getDatabasePaths(); + String type = DBType.NSRL.toString(); + + Element setEl = doc.createElement(SET_EL); + setEl.setAttribute(SET_NAME_ATTR, nsrlSet.getName()); + setEl.setAttribute(SET_TYPE_ATTR, type); + setEl.setAttribute(SET_USE_FOR_INGEST_ATTR, useForIngest); + setEl.setAttribute(SET_SHOW_INBOX_MESSAGES, showInboxMessages); + + for (int i = 0; i < paths.size(); i++) { + String path = paths.get(i); + Element pathEl = doc.createElement(PATH_EL); + pathEl.setAttribute(PATH_NUMBER_ATTR, Integer.toString(i)); + pathEl.setTextContent(path); + setEl.appendChild(pathEl); + } + rootEl.appendChild(setEl); + } + + String calcValue = Boolean.toString(calculate); + Element setCalc = doc.createElement(SET_CALC); + setCalc.setAttribute(SET_VALUE, calcValue); + rootEl.appendChild(setCalc); + + success = XMLUtil.saveDoc(HashDbXML.class, xmlFile, ENCODING, doc); + } catch (ParserConfigurationException e) { + logger.log(Level.SEVERE, "Error saving hash sets: can't initialize parser.", e); + } + return success; + } + + /** + * load and parse XML, then dispose + */ + public boolean load() { + final Document doc = XMLUtil.loadDoc(HashDbXML.class, xmlFile, XSDFILE); + if (doc == null) { + return false; + } + + Element root = doc.getDocumentElement(); + if (root == null) { + logger.log(Level.SEVERE, "Error loading hash sets: invalid file format."); + return false; + } + NodeList setsNList = root.getElementsByTagName(SET_EL); + int numSets = setsNList.getLength(); + if(numSets==0) { + logger.log(Level.WARNING, "No element hash_set exists."); + } + for (int i = 0; i < numSets; ++i) { + Element setEl = (Element) setsNList.item(i); + final String name = setEl.getAttribute(SET_NAME_ATTR); + final String type = setEl.getAttribute(SET_TYPE_ATTR); + final String useForIngest = setEl.getAttribute(SET_USE_FOR_INGEST_ATTR); + final String showInboxMessages = setEl.getAttribute(SET_SHOW_INBOX_MESSAGES); + Boolean useForIngestBool = Boolean.parseBoolean(useForIngest); + Boolean showInboxMessagesBool = Boolean.parseBoolean(showInboxMessages); + List paths = new ArrayList(); + + // Parse all paths + NodeList pathsNList = setEl.getElementsByTagName(PATH_EL); + final int numPaths = pathsNList.getLength(); + for (int j = 0; j < numPaths; ++j) { + Element pathEl = (Element) pathsNList.item(j); + String number = pathEl.getAttribute(PATH_NUMBER_ATTR); + String path = pathEl.getTextContent(); + + // If either the database or it's index exist + File database = new File(path); + File index = new File(HashDb.toIndexPath(path)); + if(database.exists() || index.exists()) { + paths.add(path); + } else { + // Ask for new path + int ret = JOptionPane.showConfirmDialog(null, "Database " + name + " could not be found at location\n" + + path + "\n" + + " Would you like to search for the file?", "Missing Database", JOptionPane.YES_NO_OPTION); + if (ret == JOptionPane.YES_OPTION) { + String filePath = searchForFile(name); + if(filePath!=null) { + paths.add(filePath); + } + } + } + } + + // Check everything was properly set + if(name.isEmpty()) { + logger.log(Level.WARNING, "Name was not set for hash_set at index {0}.", i); + } + if(type.isEmpty()) { + logger.log(Level.SEVERE, "Type was not set for hash_set at index {0}, cannot make instance of HashDb class.", i); + return false; // exit because this causes a fatal error + } + if(useForIngest.isEmpty()) { + logger.log(Level.WARNING, "UseForIngest was not set for hash_set at index {0}.", i); + } + if(showInboxMessages.isEmpty()) { + logger.log(Level.WARNING, "ShowInboxMessages was not set for hash_set at index {0}.", i); + } + + if(paths.isEmpty()) { + logger.log(Level.WARNING, "No paths were set for hash_set at index {0}. Removing the database.", i); + } else { + // No paths for this entry, the user most likely declined to search for them + DBType typeDBType = DBType.valueOf(type); + HashDb set = new HashDb(name, paths, useForIngestBool, showInboxMessagesBool, typeDBType); + + if(typeDBType == DBType.KNOWN_BAD) { + knownBadSets.add(set); + } else if(typeDBType == DBType.NSRL) { + this.nsrlSet = set; + } + } + } + + NodeList calcList = root.getElementsByTagName(SET_CALC); + int numCalc = calcList.getLength(); // Shouldn't be more than 1 + if(numCalc==0) { + logger.log(Level.WARNING, "No element hash_calculate exists."); + } + for(int i=0; i Date: Thu, 7 Nov 2013 14:24:46 -0500 Subject: [PATCH 077/169] Made more of API for HashDatabase module classes public and fixed report wizard bug --- .../autopsy/report/ReportVisualPanel1.java | 2 +- .../autopsy/hashdatabase/HashDb.java | 21 ++++++++++--------- .../autopsy/hashdatabase/HashDbManager.java | 2 +- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel1.java b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel1.java index 972bb3eb0e..a9da09980a 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel1.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel1.java @@ -238,7 +238,7 @@ public final class ReportVisualPanel1 extends JPanel implements ListSelectionLis boolean generalModuleSelected = false; if (module instanceof GeneralReportModule) { JPanel generalPanel = ((GeneralReportModule) module).getConfigurationPanel(); - panel = (generalPanel == null) ? new JPanel() : panel; + panel = (generalPanel == null) ? new JPanel() : generalPanel; generalModuleSelected = true; } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index eaea16b7d6..bf30eec738 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -108,27 +108,27 @@ public class HashDb implements Comparable { return this.displayName.compareTo(o.displayName); } - void addPropertyChangeListener(PropertyChangeListener pcl) { + public void addPropertyChangeListener(PropertyChangeListener pcl) { propertyChangeSupport.addPropertyChangeListener(pcl); } - void removePropertyChangeListener(PropertyChangeListener pcl) { + public void removePropertyChangeListener(PropertyChangeListener pcl) { propertyChangeSupport.removePropertyChangeListener(pcl); } - String getDisplayName() { + public String getDisplayName() { return displayName; } - String getDatabasePath() { + public String getDatabasePath() { return databasePath; } - KnownFilesType getKnownFilesType() { + public KnownFilesType getKnownFilesType() { return type; } - boolean getUseForIngest() { + public boolean getUseForIngest() { return useForIngest; } @@ -136,7 +136,7 @@ public class HashDb implements Comparable { this.useForIngest = useForIngest; } - boolean getShowInboxMessages() { + public boolean getShowInboxMessages() { return showInboxMessages; } @@ -144,7 +144,7 @@ public class HashDb implements Comparable { this.showInboxMessages = showInboxMessages; } - boolean hasLookupIndex() { + public boolean hasLookupIndex() { try { return SleuthkitJNI.hashDatabaseHasLookupIndex(handle); } @@ -154,7 +154,7 @@ public class HashDb implements Comparable { } } - boolean hasTextLookupIndexOnly() throws TskCoreException { + public boolean hasTextLookupIndexOnly() throws TskCoreException { return SleuthkitJNI.hashDatabaseHasLegacyLookupIndexOnly(handle); } @@ -208,6 +208,7 @@ public class HashDb implements Comparable { * @param databasePath * @return */ + // RJCTODO: Thought I got rid of this... static String toIndexPath(String databasePath) { return databasePath.concat(INDEX_FILE_EXTENSION); } @@ -216,7 +217,7 @@ public class HashDb implements Comparable { return indexing; } - IndexStatus getStatus() throws TskCoreException { + public IndexStatus getStatus() throws TskCoreException { IndexStatus status = IndexStatus.NO_INDEX; if (indexing) { diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java index 40016af622..b02326a437 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java @@ -210,7 +210,7 @@ public class HashDbManager { return null; } - + // public HashDb getHashSetAt(int index) // RJCTODO: Get rid of this From be995438255fc3e618a2c14634f473ce329b75a6 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 7 Nov 2013 20:26:39 -0500 Subject: [PATCH 078/169] Made HashDbConfigPanel more public --- .../org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java index e24ac3a7a1..fe62d2839d 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java @@ -44,11 +44,11 @@ import org.sleuthkit.datamodel.TskCoreException; /** * Instances of this class provide a UI for managing the hash sets configuration. */ -final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel { +public final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel { private HashDbManager hashSetManager = HashDbManager.getInstance(); private HashSetTableModel hashSetTableModel = new HashSetTableModel(); - HashDbConfigPanel() { + public HashDbConfigPanel() { initComponents(); customizeComponents(); updateComponentsForNoSelection(); From e71159cf2f3d3340e51eb7549326d1d6ce084b09 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 8 Nov 2013 10:25:21 -0500 Subject: [PATCH 079/169] Line endings --- KeywordSearch/manifest.mf | 18 +- KeywordSearch/nbproject/project.properties | 12 +- RecentActivity/manifest.mf | 20 +- RecentActivity/nbproject/project.properties | 14 +- SevenZip/manifest.mf | 12 +- Testing/manifest.mf | 12 +- .../autopsy/testing/Bundle.properties | 2 +- Timeline/manifest.mf | 14 +- thunderbirdparser/manifest.mf | 14 +- .../nbproject/project.properties | 12 +- update_versions.py | 1878 ++++++++--------- 11 files changed, 1004 insertions(+), 1004 deletions(-) diff --git a/KeywordSearch/manifest.mf b/KeywordSearch/manifest.mf index dd9e48a200..e309652025 100644 --- a/KeywordSearch/manifest.mf +++ b/KeywordSearch/manifest.mf @@ -1,9 +1,9 @@ -Manifest-Version: 1.0 -AutoUpdate-Show-In-Client: true -OpenIDE-Module: org.sleuthkit.autopsy.keywordsearch/5 -OpenIDE-Module-Implementation-Version: 9 -OpenIDE-Module-Install: org/sleuthkit/autopsy/keywordsearch/Installer.class -OpenIDE-Module-Layer: org/sleuthkit/autopsy/keywordsearch/layer.xml -OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/keywordsearch/Bundle.properties -OpenIDE-Module-Requires: org.openide.windows.WindowManager - +Manifest-Version: 1.0 +AutoUpdate-Show-In-Client: true +OpenIDE-Module: org.sleuthkit.autopsy.keywordsearch/5 +OpenIDE-Module-Implementation-Version: 9 +OpenIDE-Module-Install: org/sleuthkit/autopsy/keywordsearch/Installer.class +OpenIDE-Module-Layer: org/sleuthkit/autopsy/keywordsearch/layer.xml +OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/keywordsearch/Bundle.properties +OpenIDE-Module-Requires: org.openide.windows.WindowManager + diff --git a/KeywordSearch/nbproject/project.properties b/KeywordSearch/nbproject/project.properties index 140caac79c..4f3228693f 100644 --- a/KeywordSearch/nbproject/project.properties +++ b/KeywordSearch/nbproject/project.properties @@ -1,6 +1,6 @@ -javac.source=1.7 -javac.compilerargs=-Xlint -Xlint:-serial -license.file=../LICENSE-2.0.txt -nbm.homepage=http://www.sleuthkit.org/autopsy/ -nbm.needs.restart=true -spec.version.base=3.2 +javac.source=1.7 +javac.compilerargs=-Xlint -Xlint:-serial +license.file=../LICENSE-2.0.txt +nbm.homepage=http://www.sleuthkit.org/autopsy/ +nbm.needs.restart=true +spec.version.base=3.2 diff --git a/RecentActivity/manifest.mf b/RecentActivity/manifest.mf index 14b58804be..b6f0a41ec0 100644 --- a/RecentActivity/manifest.mf +++ b/RecentActivity/manifest.mf @@ -1,10 +1,10 @@ -Manifest-Version: 1.0 -OpenIDE-Module: org.sleuthkit.autopsy.recentactivity/5 -OpenIDE-Module-Implementation-Version: 9 -OpenIDE-Module-Layer: org/sleuthkit/autopsy/recentactivity/layer.xml -OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/recentactivity/Bundle.properties -OpenIDE-Module-Requires: - org.openide.modules.InstalledFileLocator, - org.openide.windows.TopComponent$Registry, - org.openide.windows.WindowManager - +Manifest-Version: 1.0 +OpenIDE-Module: org.sleuthkit.autopsy.recentactivity/5 +OpenIDE-Module-Implementation-Version: 9 +OpenIDE-Module-Layer: org/sleuthkit/autopsy/recentactivity/layer.xml +OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/recentactivity/Bundle.properties +OpenIDE-Module-Requires: + org.openide.modules.InstalledFileLocator, + org.openide.windows.TopComponent$Registry, + org.openide.windows.WindowManager + diff --git a/RecentActivity/nbproject/project.properties b/RecentActivity/nbproject/project.properties index 4ce77193f7..2cb871f415 100644 --- a/RecentActivity/nbproject/project.properties +++ b/RecentActivity/nbproject/project.properties @@ -1,7 +1,7 @@ -file.reference.gson-2.1.jar=release/modules/ext/gson-2.1.jar -javac.source=1.7 -javac.compilerargs=-Xlint -Xlint:-serial -license.file=../LICENSE-2.0.txt -nbm.homepage=http://www.sleuthkit.org/autopsy/ -nbm.needs.restart=true -spec.version.base=3.0 +file.reference.gson-2.1.jar=release/modules/ext/gson-2.1.jar +javac.source=1.7 +javac.compilerargs=-Xlint -Xlint:-serial +license.file=../LICENSE-2.0.txt +nbm.homepage=http://www.sleuthkit.org/autopsy/ +nbm.needs.restart=true +spec.version.base=3.0 diff --git a/SevenZip/manifest.mf b/SevenZip/manifest.mf index 9989549bec..ca53e48be8 100644 --- a/SevenZip/manifest.mf +++ b/SevenZip/manifest.mf @@ -1,6 +1,6 @@ -Manifest-Version: 1.0 -OpenIDE-Module: org.sleuthkit.autopsy.sevenzip/1 -OpenIDE-Module-Implementation-Version: 3 -OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/sevenzip/Bundle.properties - - +Manifest-Version: 1.0 +OpenIDE-Module: org.sleuthkit.autopsy.sevenzip/1 +OpenIDE-Module-Implementation-Version: 3 +OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/sevenzip/Bundle.properties + + diff --git a/Testing/manifest.mf b/Testing/manifest.mf index 53c457afbb..381f4bb133 100644 --- a/Testing/manifest.mf +++ b/Testing/manifest.mf @@ -1,6 +1,6 @@ -Manifest-Version: 1.0 -AutoUpdate-Show-In-Client: false -OpenIDE-Module: org.sleuthkit.autopsy.testing/3 -OpenIDE-Module-Implementation-Version: 7 -OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/testing/Bundle.properties - +Manifest-Version: 1.0 +AutoUpdate-Show-In-Client: false +OpenIDE-Module: org.sleuthkit.autopsy.testing/3 +OpenIDE-Module-Implementation-Version: 7 +OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/testing/Bundle.properties + diff --git a/Testing/src/org/sleuthkit/autopsy/testing/Bundle.properties b/Testing/src/org/sleuthkit/autopsy/testing/Bundle.properties index 023a96d380..125ec1c485 100644 --- a/Testing/src/org/sleuthkit/autopsy/testing/Bundle.properties +++ b/Testing/src/org/sleuthkit/autopsy/testing/Bundle.properties @@ -1 +1 @@ -OpenIDE-Module-Name=Testing +OpenIDE-Module-Name=Testing diff --git a/Timeline/manifest.mf b/Timeline/manifest.mf index 3210242336..6cc867f901 100644 --- a/Timeline/manifest.mf +++ b/Timeline/manifest.mf @@ -1,7 +1,7 @@ -Manifest-Version: 1.0 -OpenIDE-Module: org.sleuthkit.autopsy.timeline/1 -OpenIDE-Module-Layer: org/sleuthkit/autopsy/timeline/layer.xml -OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/timeline/Bundle.properties -OpenIDE-Module-Requires: org.openide.windows.WindowManager -OpenIDE-Module-Implementation-Version: 3 - +Manifest-Version: 1.0 +OpenIDE-Module: org.sleuthkit.autopsy.timeline/1 +OpenIDE-Module-Layer: org/sleuthkit/autopsy/timeline/layer.xml +OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/timeline/Bundle.properties +OpenIDE-Module-Requires: org.openide.windows.WindowManager +OpenIDE-Module-Implementation-Version: 3 + diff --git a/thunderbirdparser/manifest.mf b/thunderbirdparser/manifest.mf index c16a2f4c01..fc34c0e90a 100644 --- a/thunderbirdparser/manifest.mf +++ b/thunderbirdparser/manifest.mf @@ -1,7 +1,7 @@ -Manifest-Version: 1.0 -AutoUpdate-Show-In-Client: true -OpenIDE-Module: org.sleuthkit.autopsy.thunderbirdparser/3 -OpenIDE-Module-Implementation-Version: 9 -OpenIDE-Module-Layer: org/sleuthkit/autopsy/thunderbirdparser/layer.xml -OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/thunderbirdparser/Bundle.properties - +Manifest-Version: 1.0 +AutoUpdate-Show-In-Client: true +OpenIDE-Module: org.sleuthkit.autopsy.thunderbirdparser/3 +OpenIDE-Module-Implementation-Version: 9 +OpenIDE-Module-Layer: org/sleuthkit/autopsy/thunderbirdparser/layer.xml +OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/thunderbirdparser/Bundle.properties + diff --git a/thunderbirdparser/nbproject/project.properties b/thunderbirdparser/nbproject/project.properties index 6a243df466..0735c621fa 100644 --- a/thunderbirdparser/nbproject/project.properties +++ b/thunderbirdparser/nbproject/project.properties @@ -1,6 +1,6 @@ -javac.source=1.7 -javac.compilerargs=-Xlint -Xlint:-serial -license.file=../LICENSE-2.0.txt -nbm.homepage=http://www.sleuthkit.org/autopsy/ -nbm.needs.restart=true -spec.version.base=1.2 +javac.source=1.7 +javac.compilerargs=-Xlint -Xlint:-serial +license.file=../LICENSE-2.0.txt +nbm.homepage=http://www.sleuthkit.org/autopsy/ +nbm.needs.restart=true +spec.version.base=1.2 diff --git a/update_versions.py b/update_versions.py index 2883021c9f..fa228d0cca 100644 --- a/update_versions.py +++ b/update_versions.py @@ -1,939 +1,939 @@ -# -# Autopsy Forensic Browser -# -# Copyright 2012-2013 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. - - -####################### -# This script exists to help us determine update the library -# versions appropriately. See this page for version details. -# -# http://wiki.sleuthkit.org/index.php?title=Autopsy_3_Module_Versions -# -# The basic idea is that this script uses javadoc/jdiff to -# compare the current state of the source code to the last -# tag and identifies if APIs were removed, added, etc. -# -# When run from the Autopsy build script, this script will: -# - Clone Autopsy and checkout to the previous release tag -# as found in the NEWS.txt file -# - Auto-discover all modules and packages -# - Run jdiff, comparing the current and previous modules -# - Use jdiff's output to determine if each module -# a) has no changes -# b) has backwards compatible changes -# c) has backwards incompatible changes -# - Based off it's compatibility, updates each module's -# a) Major version -# b) Specification version -# c) Implementation version -# - Updates the dependencies on each module depending on the -# updated version numbers -# -# Optionally, when run from the command line, one can provide the -# desired tag to compare the current version to, the directory for -# the current version of Autopsy, and whether to automatically -# update the version numbers and dependencies. -# ------------------------------------------------------------ - -import errno -import os -import shutil -import stat -import subprocess -import sys -import traceback -from os import remove, close -from shutil import move -from tempfile import mkstemp -from xml.dom.minidom import parse, parseString - -# Jdiff return codes. Described in more detail further on -NO_CHANGES = 100 -COMPATIBLE = 101 -NON_COMPATIBLE = 102 -ERROR = 1 - -# An Autopsy module object -class Module: - # Initialize it with a name, return code, and version numbers - def __init__(self, name=None, ret=None, versions=None): - self.name = name - self.ret = ret - self.versions = versions - # As a string, the module should be it's name - def __str__(self): - return self.name - def __repr__(self): - return self.name - # When compared to another module, the two are equal if the names are the same - def __cmp__(self, other): - if isinstance(other, Module): - if self.name == other.name: - return 0 - elif self.name < other.name: - return -1 - else: - return 1 - return 1 - def __eq__(self, other): - if isinstance(other, Module): - if self.name == other.name: - return True - return False - def set_name(self, name): - self.name = name - def set_ret(self, ret): - self.ret = ret - def set_versions(self, versions): - self.versions = versions - def spec(self): - return self.versions[0] - def impl(self): - return self.versions[1] - def release(self): - return self.versions[2] - -# Representation of the Specification version number -class Spec: - # Initialize specification number, where num is a string like x.y - def __init__(self, num): - self.third = None - spec_nums = num.split(".") - if len(spec_nums) == 3: - final = spec_nums[2] - self.third = int(final) - - l, r = spec_nums[0], spec_nums[1] - - self.left = int(l) - self.right = int(r) - - def __str__(self): - return self.get() - def __cmp__(self, other): - if isinstance(other, Spec): - if self.left == other.left: - if self.right == other.right: - return 0 - if self.right < other.right: - return -1 - return 1 - if self.left < other.left: - return -1 - return 1 - elif isinstance(other, str): - l, r = other.split(".") - if self.left == int(l): - if self.right == int(r): - return 0 - if self.right < int(r): - return -1 - return 1 - if self.left < int(l): - return -1 - return 1 - return -1 - - def overflow(self): - return str(self.left + 1) + ".0" - def increment(self): - return str(self.left) + "." + str(self.right + 1) - def get(self): - spec_str = str(self.left) + "." + str(self.right) - if self.third is not None: - spec_str += "." + str(self.final) - return spec_str - def set(self, num): - if isinstance(num, str): - l, r = num.split(".") - self.left = int(l) - self.right = int(r) - elif isinstance(num, Spec): - self.left = num.left - self.right = num.right - return self - -# ================================ # -# Core Functions # -# ================================ # - -# Given a list of modules and the names for each version, compare -# the generated jdiff XML for each module and output the jdiff -# JavaDocs. -# -# modules: the list of all modules both versions have in common -# apiname_tag: the api name of the previous version, most likely the tag -# apiname_cur: the api name of the current version, most likely "Current" -# -# returns the exit code from the modified jdiff.jar -# return code 1 = error in jdiff -# return code 100 = no changes -# return code 101 = compatible changes -# return code 102 = incompatible changes -def compare_xml(module, apiname_tag, apiname_cur): - global docdir - make_dir(docdir) - null_file = fix_path(os.path.abspath("./thirdparty/jdiff/v-custom/lib/Null.java")) - jdiff = fix_path(os.path.abspath("./thirdparty/jdiff/v-custom/jdiff.jar")) - oldapi = fix_path("build/jdiff-xml/" + apiname_tag + "-" + module.name) - newapi = fix_path("build/jdiff-xml/" + apiname_cur + "-" + module.name) - docs = fix_path(docdir + "/" + module.name) - # Comments are strange. They look for a file with additional user comments in a - # directory like docs/user_comments_for_xyz. The problem being that xyz is the - # path to the new/old api. So xyz turns into multiple directories for us. - # i.e. user_comments_for_build/jdiff-xml/[tag name]-[module name]_to_build/jdiff-xml - comments = fix_path(docs + "/user_comments_for_build") - jdiff_com = fix_path(comments + "/jdiff-xml") - tag_comments = fix_path(jdiff_com + "/" + apiname_tag + "-" + module.name + "_to_build") - jdiff_tag_com = fix_path(tag_comments + "/jdiff-xml") - - if not os.path.exists(jdiff): - print("JDIFF doesn't exist.") - - make_dir(docs) - make_dir(comments) - make_dir(jdiff_com) - make_dir(tag_comments) - make_dir(jdiff_tag_com) - make_dir("jdiff-logs") - log = open("jdiff-logs/COMPARE-" + module.name + ".log", "w") - cmd = ["javadoc", - "-doclet", "jdiff.JDiff", - "-docletpath", jdiff, - "-d", docs, - "-oldapi", oldapi, - "-newapi", newapi, - "-script", - null_file] - jdiff = subprocess.Popen(cmd, stdout=log, stderr=log) - jdiff.wait() - log.close() - code = jdiff.returncode - print("Compared XML for " + module.name) - if code == NO_CHANGES: - print(" No API changes") - elif code == COMPATIBLE: - print(" API Changes are backwards compatible") - elif code == NON_COMPATIBLE: - print(" API Changes are not backwards compatible") - else: - print(" *Error in XML, most likely an empty module") - sys.stdout.flush() - return code - -# Generate the jdiff xml for the given module -# path: path to the autopsy source -# module: Module object -# name: api name for jdiff -def gen_xml(path, modules, name): - for module in modules: - # If its the regression test, the source is in the "test" dir - if module.name == "Testing": - src = os.path.join(path, module.name, "test", "qa-functional", "src") - else: - src = os.path.join(path, module.name, "src") - # xerces = os.path.abspath("./lib/xerces.jar") - xml_out = fix_path(os.path.abspath("./build/jdiff-xml/" + name + "-" + module.name)) - jdiff = fix_path(os.path.abspath("./thirdparty/jdiff/v-custom/jdiff.jar")) - make_dir("build/jdiff-xml") - make_dir("jdiff-logs") - log = open("jdiff-logs/GEN_XML-" + name + "-" + module.name + ".log", "w") - cmd = ["javadoc", - "-doclet", "jdiff.JDiff", - "-docletpath", jdiff, # ;" + xerces, <-- previous problems required this - "-apiname", xml_out, # leaving it in just in case it's needed once again - "-sourcepath", fix_path(src)] - cmd = cmd + get_packages(src) - jdiff = subprocess.Popen(cmd, stdout=log, stderr=log) - jdiff.wait() - log.close() - print("Generated XML for " + name + " " + module.name) - sys.stdout.flush() - -# Find all the modules in the given path -def find_modules(path): - modules = [] - # Step into each folder in the given path and - # see if it has manifest.mf - if so, it's a module - for dir in os.listdir(path): - directory = os.path.join(path, dir) - if os.path.isdir(directory): - for file in os.listdir(directory): - if file == "manifest.mf": - modules.append(Module(dir, None, None)) - return modules - -# Detects the differences between the source and tag modules -def module_diff(source_modules, tag_modules): - added_modules = [x for x in source_modules if x not in tag_modules] - removed_modules = [x for x in tag_modules if x not in source_modules] - similar_modules = [x for x in source_modules if x in tag_modules] - - added_modules = (added_modules if added_modules else []) - removed_modules = (removed_modules if removed_modules else []) - similar_modules = (similar_modules if similar_modules else []) - return similar_modules, added_modules, removed_modules - -# Reads the previous tag from NEWS.txt -def get_tag(sourcepath): - news = open(sourcepath + "/NEWS.txt", "r") - second_instance = False - for line in news: - if "----------------" in line: - if second_instance: - ver = line.split("VERSION ")[1] - ver = ver.split(" -")[0] - return ("autopsy-" + ver).strip() - else: - second_instance = True - continue - news.close() - - -# ========================================== # -# Dependency Functions # -# ========================================== # - -# Write a new XML file, copying all the lines from projectxml -# and replacing the specification version for the code-name-base base -# with the supplied specification version spec -def set_dep_spec(projectxml, base, spec): - print(" Updating Specification version..") - orig = open(projectxml, "r") - f, abs_path = mkstemp() - new_file = open(abs_path, "w") - found_base = False - spacing = " " - sopen = "" - sclose = "\n" - for line in orig: - if base in line: - found_base = True - if found_base and sopen in line: - update = spacing + sopen + str(spec) + sclose - new_file.write(update) - else: - new_file.write(line) - new_file.close() - close(f) - orig.close() - remove(projectxml) - move(abs_path, projectxml) - -# Write a new XML file, copying all the lines from projectxml -# and replacing the release version for the code-name-base base -# with the supplied release version -def set_dep_release(projectxml, base, release): - print(" Updating Release version..") - orig = open(projectxml, "r") - f, abs_path = mkstemp() - new_file = open(abs_path, "w") - found_base = False - spacing = " " - ropen = "" - rclose = "\n" - for line in orig: - if base in line: - found_base = True - if found_base and ropen in line: - update = spacing + ropen + str(release) + rclose - new_file.write(update) - else: - new_file.write(line) - new_file.close() - close(f) - orig.close() - remove(projectxml) - move(abs_path, projectxml) - -# Return the dependency versions in the XML dependency node -def get_dep_versions(dep): - run_dependency = dep.getElementsByTagName("run-dependency")[0] - release_version = run_dependency.getElementsByTagName("release-version") - if release_version: - release_version = getTagText(release_version[0].childNodes) - specification_version = run_dependency.getElementsByTagName("specification-version") - if specification_version: - specification_version = getTagText(specification_version[0].childNodes) - return int(release_version), Spec(specification_version) - -# Given a code-name-base, see if it corresponds with any of our modules -def get_module_from_base(modules, code_name_base): - for module in modules: - if "org.sleuthkit.autopsy." + module.name.lower() == code_name_base: - return module - return None # If it didn't match one of our modules - -# Check the text between two XML tags -def getTagText(nodelist): - for node in nodelist: - if node.nodeType == node.TEXT_NODE: - return node.data - -# Check the projectxml for a dependency on any module in modules -def check_for_dependencies(projectxml, modules): - dom = parse(projectxml) - dep_list = dom.getElementsByTagName("dependency") - for dep in dep_list: - code_name_base = dep.getElementsByTagName("code-name-base")[0] - code_name_base = getTagText(code_name_base.childNodes) - module = get_module_from_base(modules, code_name_base) - if module: - print(" Found dependency on " + module.name) - release, spec = get_dep_versions(dep) - if release != module.release() and module.release() is not None: - set_dep_release(projectxml, code_name_base, module.release()) - else: print(" Release version is correct") - if spec != module.spec() and module.spec() is not None: - set_dep_spec(projectxml, code_name_base, module.spec()) - else: print(" Specification version is correct") - -# Given the module and the source directory, return -# the paths to the manifest and project properties files -def get_dependency_file(module, source): - projectxml = os.path.join(source, module.name, "nbproject", "project.xml") - if os.path.isfile(projectxml): - return projectxml - -# Verify/Update the dependencies for each module, basing the dependency -# version number off the versions in each module -def update_dependencies(modules, source): - for module in modules: - print("Checking the dependencies for " + module.name + "...") - projectxml = get_dependency_file(module, source) - if projectxml == None: - print(" Error finding project xml file") - else: - other = [x for x in modules] - check_for_dependencies(projectxml, other) - sys.stdout.flush() - -# ======================================== # -# Versioning Functions # -# ======================================== # - -# Return the specification version in the given project.properties/manifest.mf file -def get_specification(project, manifest): - try: - # Try to find it in the project file - # it will be there if impl version is set to append automatically - f = open(project, 'r') - for line in f: - if "spec.version.base" in line: - return Spec(line.split("=")[1].strip()) - f.close() - # If not found there, try the manifest file - f = open(manifest, 'r') - for line in f: - if "OpenIDE-Module-Specification-Version:" in line: - return Spec(line.split(": ")[1].strip()) - except Exception as e: - print("Error parsing Specification version for") - print(project) - print(e) - -# Set the specification version in the given project properties file -# but if it can't be found there, set it in the manifest file -def set_specification(project, manifest, num): - try: - # First try the project file - f = open(project, 'r') - for line in f: - if "spec.version.base" in line: - f.close() - replace(project, line, "spec.version.base=" + str(num) + "\n") - return - f.close() - # If it's not there, try the manifest file - f = open(manifest, 'r') - for line in f: - if "OpenIDE-Module-Specification-Version:" in line: - f.close() - replace(manifest, line, "OpenIDE-Module-Specification-Version: " + str(num) + "\n") - return - # Otherwise we're out of luck - print(" Error finding the Specification version to update") - print(" " + manifest) - f.close() - except: - print(" Error incrementing Specification version for") - print(" " + project) - -# Return the implementation version in the given manifest.mf file -def get_implementation(manifest): - try: - f = open(manifest, 'r') - for line in f: - if "OpenIDE-Module-Implementation-Version" in line: - return int(line.split(": ")[1].strip()) - f.close() - except: - print("Error parsing Implementation version for") - print(manifest) - -# Set the implementation version in the given manifest file -def set_implementation(manifest, num): - try: - f = open(manifest, 'r') - for line in f: - if "OpenIDE-Module-Implementation-Version" in line: - f.close() - replace(manifest, line, "OpenIDE-Module-Implementation-Version: " + str(num) + "\n") - return - # If it isn't there, add it - f.close() - write_implementation(manifest, num) - except: - print(" Error incrementing Implementation version for") - print(" " + manifest) - -# Rewrite the manifest file to include the implementation version -def write_implementation(manifest, num): - f = open(manifest, "r") - contents = f.read() - contents = contents[:-2] + "OpenIDE-Module-Implementation-Version: " + str(num) + "\n\n" - f.close() - f = open(manifest, "w") - f.write(contents) - f.close() - -# Return the release version in the given manifest.mf file -def get_release(manifest): - try: - f = open(manifest, 'r') - for line in f: - if "OpenIDE-Module:" in line: - return int(line.split("/")[1].strip()) - f.close() - except: - #print("Error parsing Release version for") - #print(manifest) - return 0 - -# Set the release version in the given manifest file -def set_release(manifest, num): - try: - f = open(manifest, 'r') - for line in f: - if "OpenIDE-Module:" in line: - f.close() - index = line.index('/') - len(line) + 1 - newline = line[:index] + str(num) - replace(manifest, line, newline + "\n") - return - print(" Error finding the release version to update") - print(" " + manifest) - f.close() - except: - print(" Error incrementing release version for") - print(" " + manifest) - -# Given the module and the source directory, return -# the paths to the manifest and project properties files -def get_version_files(module, source): - manifest = os.path.join(source, module.name, "manifest.mf") - project = os.path.join(source, module.name, "nbproject", "project.properties") - if os.path.isfile(manifest) and os.path.isfile(project): - return manifest, project - -# Returns a the current version numbers for the module in source -def get_versions(module, source): - manifest, project = get_version_files(module, source) - if manifest == None or project == None: - print(" Error finding manifeset and project properties files") - return - spec = get_specification(project, manifest) - impl = get_implementation(manifest) - release = get_release(manifest) - return [spec, impl, release] - -# Update the version numbers for every module in modules -def update_versions(modules, source): - for module in modules: - versions = module.versions - manifest, project = get_version_files(module, source) - print("Updating " + module.name + "...") - if manifest == None or project == None: - print(" Error finding manifeset and project properties files") - return - if module.ret == COMPATIBLE: - versions = [versions[0].set(versions[0].increment()), versions[1] + 1, versions[2]] - set_specification(project, manifest, versions[0]) - set_implementation(manifest, versions[1]) - module.set_versions(versions) - elif module.ret == NON_COMPATIBLE: - versions = [versions[0].set(versions[0].overflow()), versions[1] + 1, versions[2] + 1] - set_specification(project, manifest, versions[0]) - set_implementation(manifest, versions[1]) - set_release(manifest, versions[2]) - module.set_versions(versions) - elif module.ret == NO_CHANGES: - versions = [versions[0], versions[1] + 1, versions[2]] - set_implementation(manifest, versions[1]) - module.set_versions(versions) - elif module.ret == None: - versions = [Spec("1.0"), 1, 1] - set_specification(project, manifest, versions[0]) - set_implementation(manifest, versions[1]) - set_release(manifest, versions[2]) - module.set_versions(versions) - sys.stdout.flush() - -# Given a list of the added modules, remove the modules -# which have the correct 'new module default' version number -def remove_correct_added(modules): - correct = [x for x in modules] - for module in modules: - if module.spec() == "1.0" or module.spec() == "0.0": - if module.impl() == 1: - if module.release() == 1 or module.release() == 0: - correct.remove(module) - return correct - -# ==================================== # -# Helper Functions # -# ==================================== # - -# Replace pattern with subst in given file -def replace(file, pattern, subst): - #Create temp file - fh, abs_path = mkstemp() - new_file = open(abs_path,'w') - old_file = open(file) - for line in old_file: - new_file.write(line.replace(pattern, subst)) - #close temp file - new_file.close() - close(fh) - old_file.close() - #Remove original file - remove(file) - #Move new file - move(abs_path, file) - -# Given a list of modules print the version numbers that need changing -def print_version_updates(modules): - f = open("gen_version.txt", "a") - for module in modules: - versions = module.versions - if module.ret == COMPATIBLE: - output = (module.name + ":\n") - output += ("\tSpecification:\t" + str(versions[0]) + "\t->\t" + str(versions[0].increment()) + "\n") - output += ("\tImplementation:\t" + str(versions[1]) + "\t->\t" + str(versions[1] + 1) + "\n") - output += ("\tRelease:\tNo Change.\n") - output += ("\n") - print(output) - sys.stdout.flush() - f.write(output) - elif module.ret == NON_COMPATIBLE: - output = (module.name + ":\n") - output += ("\tSpecification:\t" + str(versions[0]) + "\t->\t" + str(versions[0].overflow()) + "\n") - output += ("\tImplementation:\t" + str(versions[1]) + "\t->\t" + str(versions[1] + 1) + "\n") - output += ("\tRelease:\t" + str(versions[2]) + "\t->\t" + str(versions[2] + 1) + "\n") - output += ("\n") - print(output) - sys.stdout.flush() - f.write(output) - elif module.ret == ERROR: - output = (module.name + ":\n") - output += ("\t*Unable to detect necessary changes\n") - output += ("\tSpecification:\t" + str(versions[0]) + "\n") - output += ("\tImplementation:\t" + str(versions[1]) + "\n") - output += ("\tRelease:\t\t" + str(versions[2]) + "\n") - output += ("\n") - print(output) - f.write(output) - sys.stdout.flush() - elif module.ret == NO_CHANGES: - output = (module.name + ":\n") - if versions[1] is None: - output += ("\tImplementation: None\n") - else: - output += ("\tImplementation:\t" + str(versions[1]) + "\t->\t" + str(versions[1] + 1) + "\n") - output += ("\n") - print(output) - sys.stdout.flush() - f.write(output) - elif module.ret is None: - output = ("Added " + module.name + ":\n") - if module.spec() != "1.0" and module.spec() != "0.0": - output += ("\tSpecification:\t" + str(module.spec()) + "\t->\t" + "1.0\n") - output += ("\n") - if module.impl() != 1: - output += ("\tImplementation:\t" + str(module.impl()) + "\t->\t" + "1\n") - output += ("\n") - if module.release() != 1 and module.release() != 0: - output += ("Release:\t\t" + str(module.release()) + "\t->\t" + "1\n") - output += ("\n") - print(output) - sys.stdout.flush() - f.write(output) - sys.stdout.flush() - f.close() - -# Changes cygwin paths to Windows -def fix_path(path): - if "cygdrive" in path: - new_path = path[11:] - return "C:/" + new_path - else: - return path - -# Print a 'title' -def printt(title): - print("\n" + title) - lines = "" - for letter in title: - lines += "-" - print(lines) - sys.stdout.flush() - -# Get a list of package names in the given path -# The path is expected to be of the form {base}/module/src -# -# NOTE: We currently only check for packages of the form -# org.sleuthkit.autopsy.x -# If we add other namespaces for commercial modules we will -# have to add a check here -def get_packages(path): - packages = [] - package_path = os.path.join(path, "org", "sleuthkit", "autopsy") - for folder in os.listdir(package_path): - package_string = "org.sleuthkit.autopsy." - packages.append(package_string + folder) - return packages - -# Create the given directory, if it doesn't already exist -def make_dir(dir): - try: - if not os.path.isdir(dir): - os.mkdir(dir) - if os.path.isdir(dir): - return True - return False - except: - print("Exception thrown when creating directory") - return False - -# Delete the given directory, and make sure it is deleted -def del_dir(dir): - try: - if os.path.isdir(dir): - shutil.rmtree(dir, ignore_errors=False, onerror=handleRemoveReadonly) - if os.path.isdir(dir): - return False - else: - return True - return True - except: - print("Exception thrown when deleting directory") - traceback.print_exc() - return False - -# Handle any permisson errors thrown by shutil.rmtree -def handleRemoveReadonly(func, path, exc): - excvalue = exc[1] - if func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES: - os.chmod(path, stat.S_IRWXU| stat.S_IRWXG| stat.S_IRWXO) # 0777 - func(path) - else: - raise - -# Run git clone and git checkout for the tag -def do_git(tag, tag_dir): - try: - printt("Cloning Autopsy tag " + tag + " into dir " + tag_dir + " (this could take a while)...") - subprocess.call(["git", "clone", "https://github.com/sleuthkit/autopsy.git", tag_dir], - stdout=subprocess.PIPE) - printt("Checking out tag " + tag + "...") - subprocess.call(["git", "checkout", tag], - stdout=subprocess.PIPE, - cwd=tag_dir) - return True - except Exception as ex: - print("Error cloning and checking out Autopsy: ", sys.exc_info()[0]) - print(str(ex)) - print("The terminal you are using most likely does not recognize git commands.") - return False - -# Get the flags from argv -def args(): - try: - sys.argv.pop(0) - while sys.argv: - arg = sys.argv.pop(0) - if arg == "-h" or arg == "--help": - return 1 - elif arg == "-t" or arg == "--tag": - global tag - tag = sys.argv.pop(0) - elif arg == "-s" or arg == "--source": - global source - source = sys.argv.pop(0) - elif arg == "-d" or arg == "--dir": - global docdir - docdir = sys.argv.pop(0) - elif arg == "-a" or arg == "--auto": - global dry - dry = False - else: - raise Exception() - except: - pass - -# Print script run info -def printinfo(): - global tag - global source - global docdir - global dry - printt("Release script information:") - if source is None: - source = fix_path(os.path.abspath(".")) - print("Using source directory:\n " + source) - if tag is None: - tag = get_tag(source) - print("Checking out to tag:\n " + tag) - if docdir is None: - docdir = fix_path(os.path.abspath("./jdiff-javadocs")) - print("Generating jdiff JavaDocs in:\n " + docdir) - if dry is True: - print("Dry run: will not auto-update version numbers") - sys.stdout.flush() - -# Print the script's usage/help -def usage(): - return \ - """ - USAGE: - Compares the API of the current Autopsy source code with a previous - tagged version. By default, it will detect the previous tag from - the NEWS file and will not update the versions in the source code. - - OPTIONAL FLAGS: - -t --tag Specify a previous tag to compare to. - Otherwise the NEWS file will be used. - - -d --dir The output directory for the jdiff JavaDocs. If no - directory is given, the default is jdiff-javadocs/{module}. - - -s --source The directory containing Autopsy's source code. - - -a --auto Automatically update version numbers (not dry). - - -h --help Prints this usage. - """ - -# ==================================== # -# Main Functionality # -# ==================================== # - -# Where the magic happens -def main(): - global tag; global source; global docdir; global dry - tag = None; source = None; docdir = None; dry = True - - ret = args() - if ret: - print(usage()) - return 0 - printinfo() - - # ----------------------------------------------- - # 1) Clone Autopsy, checkout to given tag/commit - # 2) Get the modules in the clone and the source - # 3) Generate the xml comparison - # ----------------------------------------------- - if not del_dir("./build/" + tag): - print("\n\n=========================================") - print(" Failed to delete previous Autopsy clone.") - print(" Unable to continue...") - print("=========================================") - return 1 - tag_dir = os.path.abspath("./build/" + tag) - if not do_git(tag, tag_dir): - return 1 - sys.stdout.flush() - - tag_modules = find_modules(tag_dir) - source_modules = find_modules(source) - - printt("Generating jdiff XML reports...") - apiname_tag = tag - apiname_cur = "current" - gen_xml(tag_dir, tag_modules, apiname_tag) - gen_xml(source, source_modules, apiname_cur) - - printt("Deleting cloned Autopsy directory...") - print("Clone successfully deleted" if del_dir(tag_dir) else "Failed to delete clone") - sys.stdout.flush() - - # ----------------------------------------------------- - # 1) Seperate modules into added, similar, and removed - # 2) Compare XML for each module - # ----------------------------------------------------- - printt("Comparing modules found...") - similar_modules, added_modules, removed_modules = module_diff(source_modules, tag_modules) - if added_modules or removed_modules: - for m in added_modules: - print("+ Added " + m.name) - sys.stdout.flush() - for m in removed_modules: - print("- Removed " + m.name) - sys.stdout.flush() - else: - print("No added or removed modules") - sys.stdout.flush() - - printt("Comparing jdiff outputs...") - for module in similar_modules: - module.set_ret(compare_xml(module, apiname_tag, apiname_cur)) - print("Refer to the jdiff-javadocs folder for more details") - - # ------------------------------------------------------------ - # 1) Do versioning - # 2) Auto-update version numbers in files and the_modules list - # 3) Auto-update dependencies - # ------------------------------------------------------------ - printt("Auto-detecting version numbers and changes...") - for module in added_modules: - module.set_versions(get_versions(module, source)) - for module in similar_modules: - module.set_versions(get_versions(module, source)) - - added_modules = remove_correct_added(added_modules) - the_modules = similar_modules + added_modules - print_version_updates(the_modules) - - if not dry: - printt("Auto-updating version numbers...") - update_versions(the_modules, source) - print("All auto-updates complete") - - printt("Detecting and auto-updating dependencies...") - update_dependencies(the_modules, source) - - printt("Deleting jdiff XML...") - xml_dir = os.path.abspath("./build/jdiff-xml") - print("XML successfully deleted" if del_dir(xml_dir) else "Failed to delete XML") - - print("\n--- Script completed successfully ---") - return 0 - -# Start off the script -if __name__ == "__main__": - sys.exit(main()) +# +# Autopsy Forensic Browser +# +# Copyright 2012-2013 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. + + +####################### +# This script exists to help us determine update the library +# versions appropriately. See this page for version details. +# +# http://wiki.sleuthkit.org/index.php?title=Autopsy_3_Module_Versions +# +# The basic idea is that this script uses javadoc/jdiff to +# compare the current state of the source code to the last +# tag and identifies if APIs were removed, added, etc. +# +# When run from the Autopsy build script, this script will: +# - Clone Autopsy and checkout to the previous release tag +# as found in the NEWS.txt file +# - Auto-discover all modules and packages +# - Run jdiff, comparing the current and previous modules +# - Use jdiff's output to determine if each module +# a) has no changes +# b) has backwards compatible changes +# c) has backwards incompatible changes +# - Based off it's compatibility, updates each module's +# a) Major version +# b) Specification version +# c) Implementation version +# - Updates the dependencies on each module depending on the +# updated version numbers +# +# Optionally, when run from the command line, one can provide the +# desired tag to compare the current version to, the directory for +# the current version of Autopsy, and whether to automatically +# update the version numbers and dependencies. +# ------------------------------------------------------------ + +import errno +import os +import shutil +import stat +import subprocess +import sys +import traceback +from os import remove, close +from shutil import move +from tempfile import mkstemp +from xml.dom.minidom import parse, parseString + +# Jdiff return codes. Described in more detail further on +NO_CHANGES = 100 +COMPATIBLE = 101 +NON_COMPATIBLE = 102 +ERROR = 1 + +# An Autopsy module object +class Module: + # Initialize it with a name, return code, and version numbers + def __init__(self, name=None, ret=None, versions=None): + self.name = name + self.ret = ret + self.versions = versions + # As a string, the module should be it's name + def __str__(self): + return self.name + def __repr__(self): + return self.name + # When compared to another module, the two are equal if the names are the same + def __cmp__(self, other): + if isinstance(other, Module): + if self.name == other.name: + return 0 + elif self.name < other.name: + return -1 + else: + return 1 + return 1 + def __eq__(self, other): + if isinstance(other, Module): + if self.name == other.name: + return True + return False + def set_name(self, name): + self.name = name + def set_ret(self, ret): + self.ret = ret + def set_versions(self, versions): + self.versions = versions + def spec(self): + return self.versions[0] + def impl(self): + return self.versions[1] + def release(self): + return self.versions[2] + +# Representation of the Specification version number +class Spec: + # Initialize specification number, where num is a string like x.y + def __init__(self, num): + self.third = None + spec_nums = num.split(".") + if len(spec_nums) == 3: + final = spec_nums[2] + self.third = int(final) + + l, r = spec_nums[0], spec_nums[1] + + self.left = int(l) + self.right = int(r) + + def __str__(self): + return self.get() + def __cmp__(self, other): + if isinstance(other, Spec): + if self.left == other.left: + if self.right == other.right: + return 0 + if self.right < other.right: + return -1 + return 1 + if self.left < other.left: + return -1 + return 1 + elif isinstance(other, str): + l, r = other.split(".") + if self.left == int(l): + if self.right == int(r): + return 0 + if self.right < int(r): + return -1 + return 1 + if self.left < int(l): + return -1 + return 1 + return -1 + + def overflow(self): + return str(self.left + 1) + ".0" + def increment(self): + return str(self.left) + "." + str(self.right + 1) + def get(self): + spec_str = str(self.left) + "." + str(self.right) + if self.third is not None: + spec_str += "." + str(self.final) + return spec_str + def set(self, num): + if isinstance(num, str): + l, r = num.split(".") + self.left = int(l) + self.right = int(r) + elif isinstance(num, Spec): + self.left = num.left + self.right = num.right + return self + +# ================================ # +# Core Functions # +# ================================ # + +# Given a list of modules and the names for each version, compare +# the generated jdiff XML for each module and output the jdiff +# JavaDocs. +# +# modules: the list of all modules both versions have in common +# apiname_tag: the api name of the previous version, most likely the tag +# apiname_cur: the api name of the current version, most likely "Current" +# +# returns the exit code from the modified jdiff.jar +# return code 1 = error in jdiff +# return code 100 = no changes +# return code 101 = compatible changes +# return code 102 = incompatible changes +def compare_xml(module, apiname_tag, apiname_cur): + global docdir + make_dir(docdir) + null_file = fix_path(os.path.abspath("./thirdparty/jdiff/v-custom/lib/Null.java")) + jdiff = fix_path(os.path.abspath("./thirdparty/jdiff/v-custom/jdiff.jar")) + oldapi = fix_path("build/jdiff-xml/" + apiname_tag + "-" + module.name) + newapi = fix_path("build/jdiff-xml/" + apiname_cur + "-" + module.name) + docs = fix_path(docdir + "/" + module.name) + # Comments are strange. They look for a file with additional user comments in a + # directory like docs/user_comments_for_xyz. The problem being that xyz is the + # path to the new/old api. So xyz turns into multiple directories for us. + # i.e. user_comments_for_build/jdiff-xml/[tag name]-[module name]_to_build/jdiff-xml + comments = fix_path(docs + "/user_comments_for_build") + jdiff_com = fix_path(comments + "/jdiff-xml") + tag_comments = fix_path(jdiff_com + "/" + apiname_tag + "-" + module.name + "_to_build") + jdiff_tag_com = fix_path(tag_comments + "/jdiff-xml") + + if not os.path.exists(jdiff): + print("JDIFF doesn't exist.") + + make_dir(docs) + make_dir(comments) + make_dir(jdiff_com) + make_dir(tag_comments) + make_dir(jdiff_tag_com) + make_dir("jdiff-logs") + log = open("jdiff-logs/COMPARE-" + module.name + ".log", "w") + cmd = ["javadoc", + "-doclet", "jdiff.JDiff", + "-docletpath", jdiff, + "-d", docs, + "-oldapi", oldapi, + "-newapi", newapi, + "-script", + null_file] + jdiff = subprocess.Popen(cmd, stdout=log, stderr=log) + jdiff.wait() + log.close() + code = jdiff.returncode + print("Compared XML for " + module.name) + if code == NO_CHANGES: + print(" No API changes") + elif code == COMPATIBLE: + print(" API Changes are backwards compatible") + elif code == NON_COMPATIBLE: + print(" API Changes are not backwards compatible") + else: + print(" *Error in XML, most likely an empty module") + sys.stdout.flush() + return code + +# Generate the jdiff xml for the given module +# path: path to the autopsy source +# module: Module object +# name: api name for jdiff +def gen_xml(path, modules, name): + for module in modules: + # If its the regression test, the source is in the "test" dir + if module.name == "Testing": + src = os.path.join(path, module.name, "test", "qa-functional", "src") + else: + src = os.path.join(path, module.name, "src") + # xerces = os.path.abspath("./lib/xerces.jar") + xml_out = fix_path(os.path.abspath("./build/jdiff-xml/" + name + "-" + module.name)) + jdiff = fix_path(os.path.abspath("./thirdparty/jdiff/v-custom/jdiff.jar")) + make_dir("build/jdiff-xml") + make_dir("jdiff-logs") + log = open("jdiff-logs/GEN_XML-" + name + "-" + module.name + ".log", "w") + cmd = ["javadoc", + "-doclet", "jdiff.JDiff", + "-docletpath", jdiff, # ;" + xerces, <-- previous problems required this + "-apiname", xml_out, # leaving it in just in case it's needed once again + "-sourcepath", fix_path(src)] + cmd = cmd + get_packages(src) + jdiff = subprocess.Popen(cmd, stdout=log, stderr=log) + jdiff.wait() + log.close() + print("Generated XML for " + name + " " + module.name) + sys.stdout.flush() + +# Find all the modules in the given path +def find_modules(path): + modules = [] + # Step into each folder in the given path and + # see if it has manifest.mf - if so, it's a module + for dir in os.listdir(path): + directory = os.path.join(path, dir) + if os.path.isdir(directory): + for file in os.listdir(directory): + if file == "manifest.mf": + modules.append(Module(dir, None, None)) + return modules + +# Detects the differences between the source and tag modules +def module_diff(source_modules, tag_modules): + added_modules = [x for x in source_modules if x not in tag_modules] + removed_modules = [x for x in tag_modules if x not in source_modules] + similar_modules = [x for x in source_modules if x in tag_modules] + + added_modules = (added_modules if added_modules else []) + removed_modules = (removed_modules if removed_modules else []) + similar_modules = (similar_modules if similar_modules else []) + return similar_modules, added_modules, removed_modules + +# Reads the previous tag from NEWS.txt +def get_tag(sourcepath): + news = open(sourcepath + "/NEWS.txt", "r") + second_instance = False + for line in news: + if "----------------" in line: + if second_instance: + ver = line.split("VERSION ")[1] + ver = ver.split(" -")[0] + return ("autopsy-" + ver).strip() + else: + second_instance = True + continue + news.close() + + +# ========================================== # +# Dependency Functions # +# ========================================== # + +# Write a new XML file, copying all the lines from projectxml +# and replacing the specification version for the code-name-base base +# with the supplied specification version spec +def set_dep_spec(projectxml, base, spec): + print(" Updating Specification version..") + orig = open(projectxml, "r") + f, abs_path = mkstemp() + new_file = open(abs_path, "w") + found_base = False + spacing = " " + sopen = "" + sclose = "\n" + for line in orig: + if base in line: + found_base = True + if found_base and sopen in line: + update = spacing + sopen + str(spec) + sclose + new_file.write(update) + else: + new_file.write(line) + new_file.close() + close(f) + orig.close() + remove(projectxml) + move(abs_path, projectxml) + +# Write a new XML file, copying all the lines from projectxml +# and replacing the release version for the code-name-base base +# with the supplied release version +def set_dep_release(projectxml, base, release): + print(" Updating Release version..") + orig = open(projectxml, "r") + f, abs_path = mkstemp() + new_file = open(abs_path, "w") + found_base = False + spacing = " " + ropen = "" + rclose = "\n" + for line in orig: + if base in line: + found_base = True + if found_base and ropen in line: + update = spacing + ropen + str(release) + rclose + new_file.write(update) + else: + new_file.write(line) + new_file.close() + close(f) + orig.close() + remove(projectxml) + move(abs_path, projectxml) + +# Return the dependency versions in the XML dependency node +def get_dep_versions(dep): + run_dependency = dep.getElementsByTagName("run-dependency")[0] + release_version = run_dependency.getElementsByTagName("release-version") + if release_version: + release_version = getTagText(release_version[0].childNodes) + specification_version = run_dependency.getElementsByTagName("specification-version") + if specification_version: + specification_version = getTagText(specification_version[0].childNodes) + return int(release_version), Spec(specification_version) + +# Given a code-name-base, see if it corresponds with any of our modules +def get_module_from_base(modules, code_name_base): + for module in modules: + if "org.sleuthkit.autopsy." + module.name.lower() == code_name_base: + return module + return None # If it didn't match one of our modules + +# Check the text between two XML tags +def getTagText(nodelist): + for node in nodelist: + if node.nodeType == node.TEXT_NODE: + return node.data + +# Check the projectxml for a dependency on any module in modules +def check_for_dependencies(projectxml, modules): + dom = parse(projectxml) + dep_list = dom.getElementsByTagName("dependency") + for dep in dep_list: + code_name_base = dep.getElementsByTagName("code-name-base")[0] + code_name_base = getTagText(code_name_base.childNodes) + module = get_module_from_base(modules, code_name_base) + if module: + print(" Found dependency on " + module.name) + release, spec = get_dep_versions(dep) + if release != module.release() and module.release() is not None: + set_dep_release(projectxml, code_name_base, module.release()) + else: print(" Release version is correct") + if spec != module.spec() and module.spec() is not None: + set_dep_spec(projectxml, code_name_base, module.spec()) + else: print(" Specification version is correct") + +# Given the module and the source directory, return +# the paths to the manifest and project properties files +def get_dependency_file(module, source): + projectxml = os.path.join(source, module.name, "nbproject", "project.xml") + if os.path.isfile(projectxml): + return projectxml + +# Verify/Update the dependencies for each module, basing the dependency +# version number off the versions in each module +def update_dependencies(modules, source): + for module in modules: + print("Checking the dependencies for " + module.name + "...") + projectxml = get_dependency_file(module, source) + if projectxml == None: + print(" Error finding project xml file") + else: + other = [x for x in modules] + check_for_dependencies(projectxml, other) + sys.stdout.flush() + +# ======================================== # +# Versioning Functions # +# ======================================== # + +# Return the specification version in the given project.properties/manifest.mf file +def get_specification(project, manifest): + try: + # Try to find it in the project file + # it will be there if impl version is set to append automatically + f = open(project, 'r') + for line in f: + if "spec.version.base" in line: + return Spec(line.split("=")[1].strip()) + f.close() + # If not found there, try the manifest file + f = open(manifest, 'r') + for line in f: + if "OpenIDE-Module-Specification-Version:" in line: + return Spec(line.split(": ")[1].strip()) + except Exception as e: + print("Error parsing Specification version for") + print(project) + print(e) + +# Set the specification version in the given project properties file +# but if it can't be found there, set it in the manifest file +def set_specification(project, manifest, num): + try: + # First try the project file + f = open(project, 'r') + for line in f: + if "spec.version.base" in line: + f.close() + replace(project, line, "spec.version.base=" + str(num) + "\n") + return + f.close() + # If it's not there, try the manifest file + f = open(manifest, 'r') + for line in f: + if "OpenIDE-Module-Specification-Version:" in line: + f.close() + replace(manifest, line, "OpenIDE-Module-Specification-Version: " + str(num) + "\n") + return + # Otherwise we're out of luck + print(" Error finding the Specification version to update") + print(" " + manifest) + f.close() + except: + print(" Error incrementing Specification version for") + print(" " + project) + +# Return the implementation version in the given manifest.mf file +def get_implementation(manifest): + try: + f = open(manifest, 'r') + for line in f: + if "OpenIDE-Module-Implementation-Version" in line: + return int(line.split(": ")[1].strip()) + f.close() + except: + print("Error parsing Implementation version for") + print(manifest) + +# Set the implementation version in the given manifest file +def set_implementation(manifest, num): + try: + f = open(manifest, 'r') + for line in f: + if "OpenIDE-Module-Implementation-Version" in line: + f.close() + replace(manifest, line, "OpenIDE-Module-Implementation-Version: " + str(num) + "\n") + return + # If it isn't there, add it + f.close() + write_implementation(manifest, num) + except: + print(" Error incrementing Implementation version for") + print(" " + manifest) + +# Rewrite the manifest file to include the implementation version +def write_implementation(manifest, num): + f = open(manifest, "r") + contents = f.read() + contents = contents[:-2] + "OpenIDE-Module-Implementation-Version: " + str(num) + "\n\n" + f.close() + f = open(manifest, "w") + f.write(contents) + f.close() + +# Return the release version in the given manifest.mf file +def get_release(manifest): + try: + f = open(manifest, 'r') + for line in f: + if "OpenIDE-Module:" in line: + return int(line.split("/")[1].strip()) + f.close() + except: + #print("Error parsing Release version for") + #print(manifest) + return 0 + +# Set the release version in the given manifest file +def set_release(manifest, num): + try: + f = open(manifest, 'r') + for line in f: + if "OpenIDE-Module:" in line: + f.close() + index = line.index('/') - len(line) + 1 + newline = line[:index] + str(num) + replace(manifest, line, newline + "\n") + return + print(" Error finding the release version to update") + print(" " + manifest) + f.close() + except: + print(" Error incrementing release version for") + print(" " + manifest) + +# Given the module and the source directory, return +# the paths to the manifest and project properties files +def get_version_files(module, source): + manifest = os.path.join(source, module.name, "manifest.mf") + project = os.path.join(source, module.name, "nbproject", "project.properties") + if os.path.isfile(manifest) and os.path.isfile(project): + return manifest, project + +# Returns a the current version numbers for the module in source +def get_versions(module, source): + manifest, project = get_version_files(module, source) + if manifest == None or project == None: + print(" Error finding manifeset and project properties files") + return + spec = get_specification(project, manifest) + impl = get_implementation(manifest) + release = get_release(manifest) + return [spec, impl, release] + +# Update the version numbers for every module in modules +def update_versions(modules, source): + for module in modules: + versions = module.versions + manifest, project = get_version_files(module, source) + print("Updating " + module.name + "...") + if manifest == None or project == None: + print(" Error finding manifeset and project properties files") + return + if module.ret == COMPATIBLE: + versions = [versions[0].set(versions[0].increment()), versions[1] + 1, versions[2]] + set_specification(project, manifest, versions[0]) + set_implementation(manifest, versions[1]) + module.set_versions(versions) + elif module.ret == NON_COMPATIBLE: + versions = [versions[0].set(versions[0].overflow()), versions[1] + 1, versions[2] + 1] + set_specification(project, manifest, versions[0]) + set_implementation(manifest, versions[1]) + set_release(manifest, versions[2]) + module.set_versions(versions) + elif module.ret == NO_CHANGES: + versions = [versions[0], versions[1] + 1, versions[2]] + set_implementation(manifest, versions[1]) + module.set_versions(versions) + elif module.ret == None: + versions = [Spec("1.0"), 1, 1] + set_specification(project, manifest, versions[0]) + set_implementation(manifest, versions[1]) + set_release(manifest, versions[2]) + module.set_versions(versions) + sys.stdout.flush() + +# Given a list of the added modules, remove the modules +# which have the correct 'new module default' version number +def remove_correct_added(modules): + correct = [x for x in modules] + for module in modules: + if module.spec() == "1.0" or module.spec() == "0.0": + if module.impl() == 1: + if module.release() == 1 or module.release() == 0: + correct.remove(module) + return correct + +# ==================================== # +# Helper Functions # +# ==================================== # + +# Replace pattern with subst in given file +def replace(file, pattern, subst): + #Create temp file + fh, abs_path = mkstemp() + new_file = open(abs_path,'w') + old_file = open(file) + for line in old_file: + new_file.write(line.replace(pattern, subst)) + #close temp file + new_file.close() + close(fh) + old_file.close() + #Remove original file + remove(file) + #Move new file + move(abs_path, file) + +# Given a list of modules print the version numbers that need changing +def print_version_updates(modules): + f = open("gen_version.txt", "a") + for module in modules: + versions = module.versions + if module.ret == COMPATIBLE: + output = (module.name + ":\n") + output += ("\tSpecification:\t" + str(versions[0]) + "\t->\t" + str(versions[0].increment()) + "\n") + output += ("\tImplementation:\t" + str(versions[1]) + "\t->\t" + str(versions[1] + 1) + "\n") + output += ("\tRelease:\tNo Change.\n") + output += ("\n") + print(output) + sys.stdout.flush() + f.write(output) + elif module.ret == NON_COMPATIBLE: + output = (module.name + ":\n") + output += ("\tSpecification:\t" + str(versions[0]) + "\t->\t" + str(versions[0].overflow()) + "\n") + output += ("\tImplementation:\t" + str(versions[1]) + "\t->\t" + str(versions[1] + 1) + "\n") + output += ("\tRelease:\t" + str(versions[2]) + "\t->\t" + str(versions[2] + 1) + "\n") + output += ("\n") + print(output) + sys.stdout.flush() + f.write(output) + elif module.ret == ERROR: + output = (module.name + ":\n") + output += ("\t*Unable to detect necessary changes\n") + output += ("\tSpecification:\t" + str(versions[0]) + "\n") + output += ("\tImplementation:\t" + str(versions[1]) + "\n") + output += ("\tRelease:\t\t" + str(versions[2]) + "\n") + output += ("\n") + print(output) + f.write(output) + sys.stdout.flush() + elif module.ret == NO_CHANGES: + output = (module.name + ":\n") + if versions[1] is None: + output += ("\tImplementation: None\n") + else: + output += ("\tImplementation:\t" + str(versions[1]) + "\t->\t" + str(versions[1] + 1) + "\n") + output += ("\n") + print(output) + sys.stdout.flush() + f.write(output) + elif module.ret is None: + output = ("Added " + module.name + ":\n") + if module.spec() != "1.0" and module.spec() != "0.0": + output += ("\tSpecification:\t" + str(module.spec()) + "\t->\t" + "1.0\n") + output += ("\n") + if module.impl() != 1: + output += ("\tImplementation:\t" + str(module.impl()) + "\t->\t" + "1\n") + output += ("\n") + if module.release() != 1 and module.release() != 0: + output += ("Release:\t\t" + str(module.release()) + "\t->\t" + "1\n") + output += ("\n") + print(output) + sys.stdout.flush() + f.write(output) + sys.stdout.flush() + f.close() + +# Changes cygwin paths to Windows +def fix_path(path): + if "cygdrive" in path: + new_path = path[11:] + return "C:/" + new_path + else: + return path + +# Print a 'title' +def printt(title): + print("\n" + title) + lines = "" + for letter in title: + lines += "-" + print(lines) + sys.stdout.flush() + +# Get a list of package names in the given path +# The path is expected to be of the form {base}/module/src +# +# NOTE: We currently only check for packages of the form +# org.sleuthkit.autopsy.x +# If we add other namespaces for commercial modules we will +# have to add a check here +def get_packages(path): + packages = [] + package_path = os.path.join(path, "org", "sleuthkit", "autopsy") + for folder in os.listdir(package_path): + package_string = "org.sleuthkit.autopsy." + packages.append(package_string + folder) + return packages + +# Create the given directory, if it doesn't already exist +def make_dir(dir): + try: + if not os.path.isdir(dir): + os.mkdir(dir) + if os.path.isdir(dir): + return True + return False + except: + print("Exception thrown when creating directory") + return False + +# Delete the given directory, and make sure it is deleted +def del_dir(dir): + try: + if os.path.isdir(dir): + shutil.rmtree(dir, ignore_errors=False, onerror=handleRemoveReadonly) + if os.path.isdir(dir): + return False + else: + return True + return True + except: + print("Exception thrown when deleting directory") + traceback.print_exc() + return False + +# Handle any permisson errors thrown by shutil.rmtree +def handleRemoveReadonly(func, path, exc): + excvalue = exc[1] + if func in (os.rmdir, os.remove) and excvalue.errno == errno.EACCES: + os.chmod(path, stat.S_IRWXU| stat.S_IRWXG| stat.S_IRWXO) # 0777 + func(path) + else: + raise + +# Run git clone and git checkout for the tag +def do_git(tag, tag_dir): + try: + printt("Cloning Autopsy tag " + tag + " into dir " + tag_dir + " (this could take a while)...") + subprocess.call(["git", "clone", "https://github.com/sleuthkit/autopsy.git", tag_dir], + stdout=subprocess.PIPE) + printt("Checking out tag " + tag + "...") + subprocess.call(["git", "checkout", tag], + stdout=subprocess.PIPE, + cwd=tag_dir) + return True + except Exception as ex: + print("Error cloning and checking out Autopsy: ", sys.exc_info()[0]) + print(str(ex)) + print("The terminal you are using most likely does not recognize git commands.") + return False + +# Get the flags from argv +def args(): + try: + sys.argv.pop(0) + while sys.argv: + arg = sys.argv.pop(0) + if arg == "-h" or arg == "--help": + return 1 + elif arg == "-t" or arg == "--tag": + global tag + tag = sys.argv.pop(0) + elif arg == "-s" or arg == "--source": + global source + source = sys.argv.pop(0) + elif arg == "-d" or arg == "--dir": + global docdir + docdir = sys.argv.pop(0) + elif arg == "-a" or arg == "--auto": + global dry + dry = False + else: + raise Exception() + except: + pass + +# Print script run info +def printinfo(): + global tag + global source + global docdir + global dry + printt("Release script information:") + if source is None: + source = fix_path(os.path.abspath(".")) + print("Using source directory:\n " + source) + if tag is None: + tag = get_tag(source) + print("Checking out to tag:\n " + tag) + if docdir is None: + docdir = fix_path(os.path.abspath("./jdiff-javadocs")) + print("Generating jdiff JavaDocs in:\n " + docdir) + if dry is True: + print("Dry run: will not auto-update version numbers") + sys.stdout.flush() + +# Print the script's usage/help +def usage(): + return \ + """ + USAGE: + Compares the API of the current Autopsy source code with a previous + tagged version. By default, it will detect the previous tag from + the NEWS file and will not update the versions in the source code. + + OPTIONAL FLAGS: + -t --tag Specify a previous tag to compare to. + Otherwise the NEWS file will be used. + + -d --dir The output directory for the jdiff JavaDocs. If no + directory is given, the default is jdiff-javadocs/{module}. + + -s --source The directory containing Autopsy's source code. + + -a --auto Automatically update version numbers (not dry). + + -h --help Prints this usage. + """ + +# ==================================== # +# Main Functionality # +# ==================================== # + +# Where the magic happens +def main(): + global tag; global source; global docdir; global dry + tag = None; source = None; docdir = None; dry = True + + ret = args() + if ret: + print(usage()) + return 0 + printinfo() + + # ----------------------------------------------- + # 1) Clone Autopsy, checkout to given tag/commit + # 2) Get the modules in the clone and the source + # 3) Generate the xml comparison + # ----------------------------------------------- + if not del_dir("./build/" + tag): + print("\n\n=========================================") + print(" Failed to delete previous Autopsy clone.") + print(" Unable to continue...") + print("=========================================") + return 1 + tag_dir = os.path.abspath("./build/" + tag) + if not do_git(tag, tag_dir): + return 1 + sys.stdout.flush() + + tag_modules = find_modules(tag_dir) + source_modules = find_modules(source) + + printt("Generating jdiff XML reports...") + apiname_tag = tag + apiname_cur = "current" + gen_xml(tag_dir, tag_modules, apiname_tag) + gen_xml(source, source_modules, apiname_cur) + + printt("Deleting cloned Autopsy directory...") + print("Clone successfully deleted" if del_dir(tag_dir) else "Failed to delete clone") + sys.stdout.flush() + + # ----------------------------------------------------- + # 1) Seperate modules into added, similar, and removed + # 2) Compare XML for each module + # ----------------------------------------------------- + printt("Comparing modules found...") + similar_modules, added_modules, removed_modules = module_diff(source_modules, tag_modules) + if added_modules or removed_modules: + for m in added_modules: + print("+ Added " + m.name) + sys.stdout.flush() + for m in removed_modules: + print("- Removed " + m.name) + sys.stdout.flush() + else: + print("No added or removed modules") + sys.stdout.flush() + + printt("Comparing jdiff outputs...") + for module in similar_modules: + module.set_ret(compare_xml(module, apiname_tag, apiname_cur)) + print("Refer to the jdiff-javadocs folder for more details") + + # ------------------------------------------------------------ + # 1) Do versioning + # 2) Auto-update version numbers in files and the_modules list + # 3) Auto-update dependencies + # ------------------------------------------------------------ + printt("Auto-detecting version numbers and changes...") + for module in added_modules: + module.set_versions(get_versions(module, source)) + for module in similar_modules: + module.set_versions(get_versions(module, source)) + + added_modules = remove_correct_added(added_modules) + the_modules = similar_modules + added_modules + print_version_updates(the_modules) + + if not dry: + printt("Auto-updating version numbers...") + update_versions(the_modules, source) + print("All auto-updates complete") + + printt("Detecting and auto-updating dependencies...") + update_dependencies(the_modules, source) + + printt("Deleting jdiff XML...") + xml_dir = os.path.abspath("./build/jdiff-xml") + print("XML successfully deleted" if del_dir(xml_dir) else "Failed to delete XML") + + print("\n--- Script completed successfully ---") + return 0 + +# Start off the script +if __name__ == "__main__": + sys.exit(main()) From 5cb0dcaf75b275a0f901404914ae517aa1d4aa04 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 8 Nov 2013 11:16:41 -0500 Subject: [PATCH 080/169] Added TaskManager getContentTagsByContent API --- .../autopsy/casemodule/services/TagsManager.java | 15 +++++++++++++++ .../org/netbeans/core/startup/Bundle.properties | 2 +- .../core/windows/view/ui/Bundle.properties | 2 +- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 3562887438..4f125ac5fe 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -269,6 +269,21 @@ public class TagsManager implements Closeable { return tskCase.getContentTagsByTagName(tagName); } + /** + * Gets content tags count by content. + * @param [in] content The content of interest. + * @return A list, possibly empty, of the tags that have been applied to the artifact. + * @throws TskCoreException + */ + public synchronized List getContentTagsByContent(Content content) throws TskCoreException { + // @@@ This is a work around to be removed when database access on the EDT is correctly synchronized. + if (!tagNamesInitialized) { + getExistingTagNames(); + } + + return tskCase.getContentTagsByContent(content); + } + /** * Tags a blackboard artifact object. * @param [in] artifact The blackboard artifact to tag. diff --git a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties index ea31e2447b..c79e98565e 100644 --- a/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties +++ b/branding/core/core.jar/org/netbeans/core/startup/Bundle.properties @@ -1,5 +1,5 @@ #Updated by build script -#Fri, 18 Oct 2013 23:25:14 -0400 +#Fri, 08 Nov 2013 11:12:24 -0500 LBL_splash_window_title=Starting Autopsy SPLASH_HEIGHT=288 SPLASH_WIDTH=538 diff --git a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties index 5b961ec43f..266f776266 100644 --- a/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties +++ b/branding/modules/org-netbeans-core-windows.jar/org/netbeans/core/windows/view/ui/Bundle.properties @@ -1,5 +1,5 @@ #Updated by build script -#Fri, 18 Oct 2013 23:25:14 -0400 +#Fri, 08 Nov 2013 11:12:24 -0500 CTL_MainWindow_Title=Autopsy 3.0.8 CTL_MainWindow_Title_No_Project=Autopsy 3.0.8 From aa7456667831b9af28182a352eae1ea22419d9cc Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 8 Nov 2013 16:17:58 -0500 Subject: [PATCH 081/169] Added discard() method to HashDbConfigPanel --- .../org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java index fe62d2839d..fac3bf68fa 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java @@ -211,6 +211,10 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio hashSetManager.save(); } + public void discard() { + HashDbManager.getInstance().loadLastSavedConfiguration(); + } + /** * Removes a list of HashDbs from the dialog panel that do not have a companion -md5.idx file. * Occurs when user clicks "No" to the dialog popup box. From d1f3be1fba0d8617e7e9a8810e5764e3129b28a7 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 8 Nov 2013 16:27:32 -0500 Subject: [PATCH 082/169] Updated hash database module for TSK API changes --- .../autopsy/hashdatabase/HashDb.java | 4 ++++ .../autopsy/hashdatabase/HashDbManager.java | 19 ++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index bf30eec738..57a570d2d7 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -265,4 +265,8 @@ public class HashDb implements Comparable { propertyChangeSupport.firePropertyChange(Event.INDEXING_DONE.toString(), null, displayName); } } + + public void close() throws TskCoreException { + SleuthkitJNI.closeHashDatabase(handle); + } } \ No newline at end of file diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java index b02326a437..0ad9646e59 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java @@ -262,15 +262,28 @@ public class HashDbManager { * cancellation of configuration panels. */ public void loadLastSavedConfiguration() { + if (nsrlHashSet != null) { + try { + nsrlHashSet.close(); + } + catch (TskCoreException ex) { + // RJCTODO: Log + } + nsrlHashSet = null; + } + try { - SleuthkitJNI.closeHashDatabases(); + for (HashDb hashSet : knownBadHashSets) { + hashSet.close(); + } } catch (TskCoreException ex) { // RJCTODO: Log } - nsrlHashSet = null; - knownBadHashSets.clear(); + knownBadHashSets.clear(); + + if (hashSetsConfigurationFileExists()) { readHashSetsConfigurationFromDisk(); } From 6341a48e13be1593aed5a4fc36df0e34268c3df2 Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Fri, 8 Nov 2013 19:28:53 -0500 Subject: [PATCH 083/169] Added more regression tests to testHashDbJni(). --- .../autopsy/testing/RegressionTest.java | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java b/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java index af3ebc35c6..df53d00e40 100644 --- a/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java +++ b/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java @@ -96,7 +96,7 @@ public class RegressionTest extends TestCase { NbModuleSuite.Configuration conf = NbModuleSuite.createConfiguration(RegressionTest.class). clusters(".*"). enableModules(".*"); - conf = conf.addTest("testHashDbJni", + conf = conf.addTest("testHashDbJni" "testNewCaseWizardOpen", "testNewCaseWizard", "testStartAddDataSource", @@ -135,12 +135,30 @@ public class RegressionTest extends TestCase { try { String hashfn = "regtestHash.kdb"; - String md5hash = "b8c51089ebcdf9f11154a021438f5bd6"; + //String md5hash = "b8c51089ebcdf9f11154a021438f5bd6"; + String md5hash = "2c875b03541ffa970679986b48dca943"; String md5hash2 = "cb4aca35f3fd54aacf96da9cd9acadb8"; String md5hashBad = "35b299c6fcf47ece375b3221bdc16969"; - + +// logger.info("Opening existing kdb file..."); +// int handle = SleuthkitJNI.openHashDatabase(hashfn); +// logger.info("handle = " + handle); + logger.info("Creating hash db " + hashfn); int handle = SleuthkitJNI.createHashDatabase(hashfn); + logger.info("handle = " + handle); + + logger.info("hashDatabaseCanBeReindexed?"); + boolean retIndexable = SleuthkitJNI.hashDatabaseCanBeReindexed(handle); + logger.info("return value = " + Boolean.toString(retIndexable)); + + logger.info("getHashDatabasePath?"); + String retDbpath = SleuthkitJNI.getHashDatabasePath(handle); + logger.info("return value = " + retDbpath); + + logger.info("getHashDatabaseIndexPath?"); + String retIndexDbpath = SleuthkitJNI.getHashDatabaseIndexPath(handle); + logger.info("return value = " + retIndexDbpath); logger.info("Adding hash " + md5hash); SleuthkitJNI.addToHashDatabase("", md5hash, "", "", handle); @@ -155,6 +173,13 @@ public class RegressionTest extends TestCase { logger.info("Querying for unknown hash " + md5hashBad); TskData.FileKnown k2 = SleuthkitJNI.lookupInHashDatabase(md5hashBad, handle); logger.info("Query result: " + k2.toString()); + + logger.info("Test: hashDatabaseHasLookupIndex() "); + boolean b = SleuthkitJNI.hashDatabaseHasLookupIndex(handle); + logger.info("Result: " + Boolean.toString(b)); + + + } catch (TskException ex) { logger.log(Level.WARNING, "Database creation error: ", ex); From 68c857f587fa41ef826d96e0c145ad41296df92c Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Sat, 9 Nov 2013 11:41:50 -0500 Subject: [PATCH 084/169] Update HashDb class for SleuthkitJNI API change --- .../src/org/sleuthkit/autopsy/hashdatabase/HashDb.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index 57a570d2d7..561334a99c 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -192,12 +192,7 @@ public class HashDb implements Comparable { AbstractFile file = (AbstractFile)content; // TODO: Add support for SHA-1 and SHA-256 hashes. if (null != file.getMd5Hash()) { - if (type == KnownFilesType.NSRL) { - result = SleuthkitJNI.lookupInNSRLDatabase(file.getMd5Hash()); - } - else { - result = SleuthkitJNI.lookupInHashDatabase(file.getMd5Hash(), handle); - } + result = SleuthkitJNI.lookupInHashDatabase(file.getMd5Hash(), handle); } } return result; From fe610119fea80535096867f3430ef016c5ccf898 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Sat, 9 Nov 2013 11:42:56 -0500 Subject: [PATCH 085/169] Added DataModelActionsFactory class --- .../datamodel/DataModelActionsFactory.java | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100755 Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java new file mode 100755 index 0000000000..0426a61aa7 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java @@ -0,0 +1,147 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2013 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.datamodel; + +import java.util.ArrayList; +import java.util.List; +import javax.swing.Action; +import org.sleuthkit.autopsy.actions.AddBlackboardArtifactTagAction; +import org.sleuthkit.autopsy.actions.AddContentTagAction; +import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; +import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; +import org.sleuthkit.autopsy.directorytree.ExtractAction; +import org.sleuthkit.autopsy.directorytree.HashSearchAction; +import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; +import org.sleuthkit.autopsy.directorytree.ViewContextAction; +import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.DerivedFile; +import org.sleuthkit.datamodel.Directory; +import org.sleuthkit.datamodel.File; +import org.sleuthkit.datamodel.LayoutFile; +import org.sleuthkit.datamodel.LocalFile; +import org.sleuthkit.datamodel.VirtualDirectory; + +/** + * This class provides methods for creating sets of actions for data model objects. + */ +class DataModelActionsFactory { + static List getActions(File file) { + List actions = new ArrayList<>(); + actions.add(new ViewContextAction("View File in Directory", file)); + final FileNode fileNode = new FileNode(file); + actions.add(null); // creates a menu separator + actions.add(new NewWindowViewAction("View in New Window", fileNode)); + actions.add(new ExternalViewerAction("Open in External Viewer", fileNode)); + actions.add(null); // creates a menu separator + actions.add(ExtractAction.getInstance()); + actions.add(new HashSearchAction("Search for files with the same MD5 hash", fileNode)); + actions.add(null); // creates a menu separator + actions.add(AddContentTagAction.getInstance()); + actions.add(AddBlackboardArtifactTagAction.getInstance()); + actions.addAll(ContextMenuExtensionPoint.getActions()); + return actions; + } + + static List getActions(LayoutFile file) { + List actions = new ArrayList<>(); + actions.add(new ViewContextAction("View File in Directory", file)); + LayoutFileNode layoutFileNode = new LayoutFileNode(file); + actions.add(null); // creates a menu separator + actions.add(new NewWindowViewAction("View in New Window", layoutFileNode)); + actions.add(new ExternalViewerAction("Open in External Viewer", layoutFileNode)); + actions.add(null); // creates a menu separator + actions.add(ExtractAction.getInstance());// + actions.add(null); // creates a menu separator + actions.add(AddContentTagAction.getInstance()); + actions.add(AddBlackboardArtifactTagAction.getInstance()); + actions.addAll(ContextMenuExtensionPoint.getActions()); + return actions; + } + + static List getActions(Directory directory) { + List actions = new ArrayList<>(); + actions.add(new ViewContextAction("View File in Directory", directory)); + DirectoryNode directoryNode = new DirectoryNode(directory); + actions.add(null); // creates a menu separator + actions.add(new NewWindowViewAction("View in New Window", directoryNode)); + actions.add(new ExternalViewerAction("Open in External Viewer", directoryNode)); + actions.add(null); // creates a menu separator + actions.add(ExtractAction.getInstance()); + actions.add(null); // creates a menu separator + actions.add(AddContentTagAction.getInstance()); + actions.add(AddBlackboardArtifactTagAction.getInstance()); + actions.addAll(ContextMenuExtensionPoint.getActions()); // RJCTODO: Separator should not be added by provider + return actions; + } + + static List getActions(VirtualDirectory directory) { + List actions = new ArrayList<>(); + actions.add(new ViewContextAction("View File in Directory", directory)); + VirtualDirectoryNode directoryNode = new VirtualDirectoryNode(directory); + actions.add(null); // creates a menu separator + actions.add(new NewWindowViewAction("View in New Window", directoryNode)); + actions.add(new ExternalViewerAction("Open in External Viewer", directoryNode)); + actions.add(null); // creates a menu separator + actions.add(ExtractAction.getInstance()); + actions.add(null); // creates a menu separator + actions.add(AddContentTagAction.getInstance()); + actions.add(AddBlackboardArtifactTagAction.getInstance()); + actions.addAll(ContextMenuExtensionPoint.getActions()); + return actions; + } + + static List getActions(LocalFile file) { + List actions = new ArrayList<>(); + actions.add(new ViewContextAction("View File in Directory", file)); + final LocalFileNode localFileNode = new LocalFileNode(file); + actions.add(null); // creates a menu separator + actions.add(new NewWindowViewAction("View in New Window", localFileNode)); + actions.add(new ExternalViewerAction("Open in External Viewer", localFileNode)); + actions.add(null); // creates a menu separator + actions.add(ExtractAction.getInstance()); + actions.add(null); // creates a menu separator + actions.add(AddContentTagAction.getInstance()); + actions.add(AddBlackboardArtifactTagAction.getInstance()); + actions.addAll(ContextMenuExtensionPoint.getActions()); + return actions; + } + + static List getActions(DerivedFile file) { + List actions = new ArrayList<>(); + actions.add(new ViewContextAction("View File in Directory", file)); + final LocalFileNode localFileNode = new LocalFileNode(file); + actions.add(null); // creates a menu separator + actions.add(new NewWindowViewAction("View in New Window", localFileNode)); + actions.add(new ExternalViewerAction("Open in External Viewer", localFileNode)); + actions.add(null); // creates a menu separator + actions.add(ExtractAction.getInstance()); + actions.add(null); // creates a menu separator + actions.add(AddContentTagAction.getInstance()); + actions.add(AddBlackboardArtifactTagAction.getInstance()); + actions.addAll(ContextMenuExtensionPoint.getActions()); + return actions; + } + + static List getActions(AbstractFile file) { + List actions = new ArrayList<>(); + actions.add(new ViewContextAction("View File in Directory", file)); + // RJCTODO + return actions; + } +} \ No newline at end of file From cec71c909ad3f60aa6f3faf47eb9aeccc0bf1a60 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Sat, 9 Nov 2013 11:52:12 -0500 Subject: [PATCH 086/169] Added getActions(Content content) to DataModelActionsFactory --- .../datamodel/DataModelActionsFactory.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java index 0426a61aa7..27f6b328a0 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java @@ -30,6 +30,7 @@ import org.sleuthkit.autopsy.directorytree.HashSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.DerivedFile; import org.sleuthkit.datamodel.Directory; import org.sleuthkit.datamodel.File; @@ -41,6 +42,30 @@ import org.sleuthkit.datamodel.VirtualDirectory; * This class provides methods for creating sets of actions for data model objects. */ class DataModelActionsFactory { + static List getActions(Content content) { + if (content instanceof File) { + return getActions((File)content); + } + else if (content instanceof LayoutFile) { + return getActions((LayoutFile)content); + } + else if (content instanceof Directory) { + return getActions((Directory)content); + } + else if (content instanceof VirtualDirectory) { + return getActions((VirtualDirectory)content); + } + else if (content instanceof LocalFile) { + return getActions((LocalFile)content); + } + else if (content instanceof DerivedFile) { + return getActions((DerivedFile)content); + } + else { + return new ArrayList<>(); + } + } + static List getActions(File file) { List actions = new ArrayList<>(); actions.add(new ViewContextAction("View File in Directory", file)); From b82816009ebdbd4a48390d72186d665569c969b8 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Sun, 10 Nov 2013 19:31:34 -0500 Subject: [PATCH 087/169] Restored selection of menu actions for tag nodes --- .../sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java | 3 ++- Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java | 3 ++- .../sleuthkit/autopsy/directorytree/DataResultFilterNode.java | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java index b01247efb1..d88e72bf84 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java @@ -76,7 +76,8 @@ public class BlackboardArtifactTagNode extends DisplayableItemNode { @Override public Action[] getActions(boolean context) { - List actions = new ArrayList<>(); + List actions = DataModelActionsFactory.getActions(tag.getContent()); // RJCTODO: Get extra stuff from Tags + actions.add(null); // Adds a menu item separator. actions.add(DeleteBlackboardArtifactTagAction.getInstance()); return actions.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java index ef0cb06d68..fa3aa97eba 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java @@ -75,7 +75,8 @@ public class ContentTagNode extends DisplayableItemNode { @Override public Action[] getActions(boolean context) { - List actions = new ArrayList<>(); + List actions = DataModelActionsFactory.getActions(tag.getContent()); + actions.add(null); // Adds a menu item separator. actions.add(DeleteContentTagAction.getInstance()); return actions.toArray(new Action[0]); } diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java index 369525542a..cd52f171b8 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/DataResultFilterNode.java @@ -171,6 +171,8 @@ public class DataResultFilterNode extends FilterNode { //set up actions for artifact node based on its Content object //TODO all actions need to be consolidated in single place! //they should be set in individual Node subclass and using a utility to get Actions per Content sub-type + // TODO UPDATE: There is now a DataModelActionsFactory utility; also tags are no longer artifacts so conditionals + // can be removed. List actions = new ArrayList<>(); From a537d0457ba8593f5db34f3c82b85dc825f12f4c Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Sun, 10 Nov 2013 20:03:51 -0500 Subject: [PATCH 088/169] Modified DataModelActionsFactory to deal with artifact source content --- .../datamodel/BlackboardArtifactTagNode.java | 3 +- .../autopsy/datamodel/ContentTagNode.java | 3 +- .../datamodel/DataModelActionsFactory.java | 69 ++++++++++--------- 3 files changed, 39 insertions(+), 36 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java index d88e72bf84..bb45253a5e 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java @@ -18,7 +18,6 @@ */ package org.sleuthkit.autopsy.datamodel; -import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -76,7 +75,7 @@ public class BlackboardArtifactTagNode extends DisplayableItemNode { @Override public Action[] getActions(boolean context) { - List actions = DataModelActionsFactory.getActions(tag.getContent()); // RJCTODO: Get extra stuff from Tags + List actions = DataModelActionsFactory.getActions(tag.getContent(), true); actions.add(null); // Adds a menu item separator. actions.add(DeleteBlackboardArtifactTagAction.getInstance()); return actions.toArray(new Action[0]); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java index fa3aa97eba..3817bb3c9a 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java @@ -19,7 +19,6 @@ package org.sleuthkit.autopsy.datamodel; -import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -75,7 +74,7 @@ public class ContentTagNode extends DisplayableItemNode { @Override public Action[] getActions(boolean context) { - List actions = DataModelActionsFactory.getActions(tag.getContent()); + List actions = DataModelActionsFactory.getActions(tag.getContent(), false); actions.add(null); // Adds a menu item separator. actions.add(DeleteContentTagAction.getInstance()); return actions.toArray(new Action[0]); diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java index 27f6b328a0..4b79b6059a 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java @@ -42,33 +42,33 @@ import org.sleuthkit.datamodel.VirtualDirectory; * This class provides methods for creating sets of actions for data model objects. */ class DataModelActionsFactory { - static List getActions(Content content) { + static List getActions(Content content, boolean isArtifactSource) { if (content instanceof File) { - return getActions((File)content); + return getActions((File)content, isArtifactSource); } else if (content instanceof LayoutFile) { - return getActions((LayoutFile)content); + return getActions((LayoutFile)content, isArtifactSource); } else if (content instanceof Directory) { - return getActions((Directory)content); + return getActions((Directory)content, isArtifactSource); } else if (content instanceof VirtualDirectory) { - return getActions((VirtualDirectory)content); + return getActions((VirtualDirectory)content, isArtifactSource); } else if (content instanceof LocalFile) { - return getActions((LocalFile)content); + return getActions((LocalFile)content, isArtifactSource); } else if (content instanceof DerivedFile) { - return getActions((DerivedFile)content); + return getActions((DerivedFile)content, isArtifactSource); } else { return new ArrayList<>(); } } - static List getActions(File file) { + static List getActions(File file, boolean isArtifactSource) { List actions = new ArrayList<>(); - actions.add(new ViewContextAction("View File in Directory", file)); + actions.add(new ViewContextAction((isArtifactSource ? "View Source File in Directory" : "View File in Directory"), file)); final FileNode fileNode = new FileNode(file); actions.add(null); // creates a menu separator actions.add(new NewWindowViewAction("View in New Window", fileNode)); @@ -78,14 +78,16 @@ class DataModelActionsFactory { actions.add(new HashSearchAction("Search for files with the same MD5 hash", fileNode)); actions.add(null); // creates a menu separator actions.add(AddContentTagAction.getInstance()); - actions.add(AddBlackboardArtifactTagAction.getInstance()); + if (isArtifactSource) { + actions.add(AddBlackboardArtifactTagAction.getInstance()); + } actions.addAll(ContextMenuExtensionPoint.getActions()); return actions; } - static List getActions(LayoutFile file) { + static List getActions(LayoutFile file, boolean isArtifactSource) { List actions = new ArrayList<>(); - actions.add(new ViewContextAction("View File in Directory", file)); + actions.add(new ViewContextAction((isArtifactSource ? "View Source File in Directory" : "View File in Directory"), file)); LayoutFileNode layoutFileNode = new LayoutFileNode(file); actions.add(null); // creates a menu separator actions.add(new NewWindowViewAction("View in New Window", layoutFileNode)); @@ -94,14 +96,16 @@ class DataModelActionsFactory { actions.add(ExtractAction.getInstance());// actions.add(null); // creates a menu separator actions.add(AddContentTagAction.getInstance()); - actions.add(AddBlackboardArtifactTagAction.getInstance()); + if (isArtifactSource) { + actions.add(AddBlackboardArtifactTagAction.getInstance()); + } actions.addAll(ContextMenuExtensionPoint.getActions()); return actions; } - static List getActions(Directory directory) { + static List getActions(Directory directory, boolean isArtifactSource) { List actions = new ArrayList<>(); - actions.add(new ViewContextAction("View File in Directory", directory)); + actions.add(new ViewContextAction((isArtifactSource ? "View Source File in Directory" : "View File in Directory"), directory)); DirectoryNode directoryNode = new DirectoryNode(directory); actions.add(null); // creates a menu separator actions.add(new NewWindowViewAction("View in New Window", directoryNode)); @@ -110,14 +114,16 @@ class DataModelActionsFactory { actions.add(ExtractAction.getInstance()); actions.add(null); // creates a menu separator actions.add(AddContentTagAction.getInstance()); - actions.add(AddBlackboardArtifactTagAction.getInstance()); + if (isArtifactSource) { + actions.add(AddBlackboardArtifactTagAction.getInstance()); + } actions.addAll(ContextMenuExtensionPoint.getActions()); // RJCTODO: Separator should not be added by provider return actions; } - static List getActions(VirtualDirectory directory) { + static List getActions(VirtualDirectory directory, boolean isArtifactSource) { List actions = new ArrayList<>(); - actions.add(new ViewContextAction("View File in Directory", directory)); + actions.add(new ViewContextAction((isArtifactSource ? "View Source File in Directory" : "View File in Directory"), directory)); VirtualDirectoryNode directoryNode = new VirtualDirectoryNode(directory); actions.add(null); // creates a menu separator actions.add(new NewWindowViewAction("View in New Window", directoryNode)); @@ -126,14 +132,16 @@ class DataModelActionsFactory { actions.add(ExtractAction.getInstance()); actions.add(null); // creates a menu separator actions.add(AddContentTagAction.getInstance()); - actions.add(AddBlackboardArtifactTagAction.getInstance()); + if (isArtifactSource) { + actions.add(AddBlackboardArtifactTagAction.getInstance()); + } actions.addAll(ContextMenuExtensionPoint.getActions()); return actions; } - static List getActions(LocalFile file) { + static List getActions(LocalFile file, boolean isArtifactSource) { List actions = new ArrayList<>(); - actions.add(new ViewContextAction("View File in Directory", file)); + actions.add(new ViewContextAction((isArtifactSource ? "View Source File in Directory" : "View File in Directory"), file)); final LocalFileNode localFileNode = new LocalFileNode(file); actions.add(null); // creates a menu separator actions.add(new NewWindowViewAction("View in New Window", localFileNode)); @@ -142,14 +150,16 @@ class DataModelActionsFactory { actions.add(ExtractAction.getInstance()); actions.add(null); // creates a menu separator actions.add(AddContentTagAction.getInstance()); - actions.add(AddBlackboardArtifactTagAction.getInstance()); + if (isArtifactSource) { + actions.add(AddBlackboardArtifactTagAction.getInstance()); + } actions.addAll(ContextMenuExtensionPoint.getActions()); return actions; } - static List getActions(DerivedFile file) { + static List getActions(DerivedFile file, boolean isArtifactSource) { List actions = new ArrayList<>(); - actions.add(new ViewContextAction("View File in Directory", file)); + actions.add(new ViewContextAction((isArtifactSource ? "View Source File in Directory" : "View File in Directory"), file)); final LocalFileNode localFileNode = new LocalFileNode(file); actions.add(null); // creates a menu separator actions.add(new NewWindowViewAction("View in New Window", localFileNode)); @@ -158,15 +168,10 @@ class DataModelActionsFactory { actions.add(ExtractAction.getInstance()); actions.add(null); // creates a menu separator actions.add(AddContentTagAction.getInstance()); - actions.add(AddBlackboardArtifactTagAction.getInstance()); + if (isArtifactSource) { + actions.add(AddBlackboardArtifactTagAction.getInstance()); + } actions.addAll(ContextMenuExtensionPoint.getActions()); return actions; - } - - static List getActions(AbstractFile file) { - List actions = new ArrayList<>(); - actions.add(new ViewContextAction("View File in Directory", file)); - // RJCTODO - return actions; } } \ No newline at end of file From 6c407691ad31785006c8424ea4206761349c2850 Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Mon, 11 Nov 2013 14:22:15 -0500 Subject: [PATCH 089/169] Delete test kdb file (if it exists) before starting a new test. --- .../sleuthkit/autopsy/testing/RegressionTest.java | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java b/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java index df53d00e40..77a0371aa5 100644 --- a/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java +++ b/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java @@ -29,6 +29,7 @@ import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.nio.file.Files; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -97,7 +98,7 @@ public class RegressionTest extends TestCase { clusters(".*"). enableModules(".*"); conf = conf.addTest("testHashDbJni" - "testNewCaseWizardOpen", + , "testNewCaseWizardOpen", "testNewCaseWizard", "testStartAddDataSource", "testConfigureIngest1", @@ -144,6 +145,15 @@ public class RegressionTest extends TestCase { // int handle = SleuthkitJNI.openHashDatabase(hashfn); // logger.info("handle = " + handle); + // Make sure we start with a clean slate + File f = new File(hashfn); + if (f.exists()) { + if (!f.delete()) { + // Probably a file permission issue + logger.warning("Cleaning test file failed."); + } + } + logger.info("Creating hash db " + hashfn); int handle = SleuthkitJNI.createHashDatabase(hashfn); logger.info("handle = " + handle); From a4fc68b5a86ddb70e32329286618fa1869a2ca31 Mon Sep 17 00:00:00 2001 From: raman-bt Date: Wed, 13 Nov 2013 09:14:26 -0500 Subject: [PATCH 090/169] Changed the label on the message box in ProgressPanel to be more generic and read "Status" instead of "Currently Adding:" Any kind of progress messages may be displayed in the box, instead of simply the name of file/folder being added. --- .../autopsy/casemodule/AddImageTask.java | 9 ++++-- .../AddImageWizardAddingProgressPanel.java | 4 +-- .../AddImageWizardAddingProgressVisual.form | 10 +++--- .../AddImageWizardAddingProgressVisual.java | 32 +++++++++---------- .../AddImageWizardIngestConfigPanel.java | 17 ---------- .../autopsy/casemodule/AddLocalFilesTask.java | 2 +- .../autopsy/casemodule/Bundle.properties | 2 +- .../DSPProgressMonitor.java | 2 +- 8 files changed, 32 insertions(+), 46 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java index ff0a90a9c2..ed2ef603b6 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java @@ -93,9 +93,12 @@ public class AddImageTask implements Runnable { public void run() { try { while (!Thread.currentThread().isInterrupted()) { - - progressMonitor.setText(process.currentDirectory()); - + String currDir = process.currentDirectory(); + if (currDir != null) { + if (!currDir.isEmpty() ) { + progressMonitor.setProgressText("Adding: " + currDir); + } + } Thread.sleep(2 * 1000); } return; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java index 7e1bd20464..476bbdd1df 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressPanel.java @@ -83,12 +83,12 @@ class AddImageWizardAddingProgressPanel implements WizardDescriptor.FinishablePa } @Override - public void setText(final String text) { + public void setProgressText(final String text) { // update the progress UI asynchronously EventQueue.invokeLater(new Runnable() { @Override public void run() { - getComponent().setCurrentDirText(text); + getComponent().setProgressMsgText(text); } }); } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressVisual.form b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressVisual.form index 53febaf0bf..9f3068809b 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressVisual.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressVisual.form @@ -142,7 +142,7 @@ - + @@ -158,7 +158,7 @@ - + @@ -185,7 +185,7 @@ - + @@ -196,11 +196,11 @@ - + - + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressVisual.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressVisual.java index a95ad671f2..f0e10fa1e2 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressVisual.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardAddingProgressVisual.java @@ -71,7 +71,7 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel { donePanel.setVisible(false); viewLogButton.setVisible(false); //match visual background of panel - this.TextArea_CurrentDirectory.setBackground(this.getBackground()); + this.progressTextArea.setBackground(this.getBackground()); } @@ -95,10 +95,10 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel { /** * Updates the currently processing directory * - * @param dir the text to update with + * @param msg the text to update with */ - public void setCurrentDirText(String dir) { - this.TextArea_CurrentDirectory.setText(dir); + public void setProgressMsgText(String msg) { + this.progressTextArea.setText(msg); } /** @@ -140,7 +140,7 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel { inProgressPanel = new javax.swing.JPanel(); progressBar = new javax.swing.JProgressBar(); progressLabel = new javax.swing.JLabel(); - TextArea_CurrentDirectory = new javax.swing.JTextArea(); + progressTextArea = new javax.swing.JTextArea(); subTitle2Label = new javax.swing.JLabel(); subTitle1Label = new javax.swing.JLabel(); @@ -193,14 +193,14 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel { org.openide.awt.Mnemonics.setLocalizedText(progressLabel, org.openide.util.NbBundle.getMessage(AddImageWizardAddingProgressVisual.class, "AddImageWizardAddingProgressVisual.progressLabel.text")); // NOI18N progressLabel.setPreferredSize(null); - TextArea_CurrentDirectory.setEditable(false); - TextArea_CurrentDirectory.setBackground(new java.awt.Color(240, 240, 240)); - TextArea_CurrentDirectory.setLineWrap(true); - TextArea_CurrentDirectory.setRows(5); - TextArea_CurrentDirectory.setWrapStyleWord(true); - TextArea_CurrentDirectory.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), org.openide.util.NbBundle.getMessage(AddImageWizardAddingProgressVisual.class, "AddImageWizardAddingProgressVisual.TextArea_CurrentDirectory.border.title"))); // NOI18N - TextArea_CurrentDirectory.setCursor(new java.awt.Cursor(java.awt.Cursor.TEXT_CURSOR)); - TextArea_CurrentDirectory.setFocusable(false); + progressTextArea.setEditable(false); + progressTextArea.setBackground(new java.awt.Color(240, 240, 240)); + progressTextArea.setLineWrap(true); + progressTextArea.setRows(5); + progressTextArea.setWrapStyleWord(true); + progressTextArea.setBorder(javax.swing.BorderFactory.createTitledBorder(javax.swing.BorderFactory.createEtchedBorder(), org.openide.util.NbBundle.getMessage(AddImageWizardAddingProgressVisual.class, "AddImageWizardAddingProgressVisual.progressTextArea.border.title"))); // NOI18N + progressTextArea.setCursor(new java.awt.Cursor(java.awt.Cursor.TEXT_CURSOR)); + progressTextArea.setFocusable(false); org.openide.awt.Mnemonics.setLocalizedText(subTitle2Label, org.openide.util.NbBundle.getMessage(AddImageWizardAddingProgressVisual.class, "AddImageWizardAddingProgressVisual.subTitle2Label.text")); // NOI18N @@ -216,7 +216,7 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel { .addComponent(subTitle2Label) .addComponent(progressLabel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(subTitle1Label, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(TextArea_CurrentDirectory) + .addComponent(progressTextArea) .addComponent(progressBar, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addGap(0, 8, Short.MAX_VALUE)) ); @@ -229,7 +229,7 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(TextArea_CurrentDirectory, javax.swing.GroupLayout.PREFERRED_SIZE, 91, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(progressTextArea, javax.swing.GroupLayout.PREFERRED_SIZE, 91, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(progressLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE) .addContainerGap()) @@ -268,12 +268,12 @@ public class AddImageWizardAddingProgressVisual extends javax.swing.JPanel { dialog.setVisible(true); }//GEN-LAST:event_viewLogButtonActionPerformed // Variables declaration - do not modify//GEN-BEGIN:variables - protected javax.swing.JTextArea TextArea_CurrentDirectory; protected javax.swing.JPanel donePanel; protected javax.swing.JPanel inProgressPanel; private javax.swing.JPanel loadingPanel; private javax.swing.JProgressBar progressBar; protected javax.swing.JLabel progressLabel; + protected javax.swing.JTextArea progressTextArea; protected javax.swing.JLabel statusLabel; protected javax.swing.JLabel subTitle1Label; protected javax.swing.JLabel subTitle2Label; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java index 917ff4316e..4e7ed87ab6 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageWizardIngestConfigPanel.java @@ -22,36 +22,19 @@ package org.sleuthkit.autopsy.casemodule; import org.sleuthkit.autopsy.ingest.IngestConfigurator; import java.awt.Color; import java.awt.Component; -import java.awt.EventQueue; import java.awt.Window; -import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.logging.Level; import javax.swing.JButton; import javax.swing.JOptionPane; -import javax.swing.JProgressBar; import javax.swing.SwingUtilities; -import javax.swing.SwingWorker; import javax.swing.event.ChangeListener; import org.openide.WizardDescriptor; import org.openide.util.HelpCtx; import org.openide.util.Lookup; -import org.sleuthkit.autopsy.casemodule.services.FileManager; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.autopsy.coreutils.PlatformUtil; -import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; -import org.sleuthkit.datamodel.FileSystem; -import org.sleuthkit.datamodel.Image; -import org.sleuthkit.datamodel.SleuthkitCase; -import org.sleuthkit.datamodel.SleuthkitJNI.CaseDbHandle.AddImageProcess; -import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.datamodel.TskDataException; -import org.sleuthkit.datamodel.TskException; -import org.sleuthkit.datamodel.Volume; -import org.sleuthkit.datamodel.VolumeSystem; import org.sleuthkit.autopsy.corecomponentinterfaces.DSPCallback; import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor; /** diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddLocalFilesTask.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddLocalFilesTask.java index 7d6a3c0668..34b7a32089 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddLocalFilesTask.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddLocalFilesTask.java @@ -178,7 +178,7 @@ public class AddLocalFilesTask implements Runnable { @Override public void fileAdded(final AbstractFile newFile) { if (count++ % 10 == 0) { - progressMonitor.setText(newFile.getParentPath() + "/" + newFile.getName()); + progressMonitor.setProgressText("Adding: " + newFile.getParentPath() + "/" + newFile.getName()); } } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties index 53aba1d053..1c20ec4025 100644 --- a/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/Bundle.properties @@ -138,7 +138,6 @@ AddImageWizardChooseDataSourceVisual.jLabel2.text=jLabel2 AddImageWizardChooseDataSourceVisual.nextLabel.text= Press 'Next' to analyze the input data, extract volume and file system data, and populate a local database. AddImageWizardChooseDataSourceVisual.imgInfoLabel.text=Enter Data Source Information: AddImageWizardAddingProgressVisual.progressLabel.text= -AddImageWizardAddingProgressVisual.TextArea_CurrentDirectory.border.title=Currently Adding: AddImageWizardAddingProgressVisual.viewLogButton.text=View Log AddImageWizardAddingProgressVisual.titleLabel.text=Adding Data Source AddImageWizardAddingProgressVisual.subTitle1Label.text=File system information is being added to a local database. File analysis will start when this finishes. @@ -153,3 +152,4 @@ LocalDiskPanel.noFatOrphansCheckbox.text=Ignore orphan files in FAT file systems LocalDiskPanel.descLabel.text=(faster results, although some data will not be searched) MissingImageDialog.browseButton.text=Browse MissingImageDialog.pathNameTextField.text= +AddImageWizardAddingProgressVisual.progressTextArea.border.title=Status diff --git a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DSPProgressMonitor.java b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DSPProgressMonitor.java index c68574eeb2..88d6b5e04c 100644 --- a/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DSPProgressMonitor.java +++ b/Core/src/org/sleuthkit/autopsy/corecomponentinterfaces/DSPProgressMonitor.java @@ -29,5 +29,5 @@ public interface DSPProgressMonitor { void setProgress(int progress); - void setText(String text); + void setProgressText(String text); } From 178179a4628041b93e1429968d59622c212c4483 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 13 Nov 2013 18:40:25 -0500 Subject: [PATCH 091/169] Correct implementation of indexing for hash databases --- .../datamodel/DataModelActionsFactory.java | 57 ++++++++------- .../autopsy/report/ReportGenerator.java | 24 ++++++- .../autopsy/report/ReportModule.java | 23 +++--- .../autopsy/report/ReportProgressPanel.java | 66 ++++++++--------- .../autopsy/hashdatabase/IndexStatus.java | 70 ------------------- 5 files changed, 94 insertions(+), 146 deletions(-) delete mode 100644 HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/IndexStatus.java diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java index 4b79b6059a..0840894017 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java @@ -29,7 +29,6 @@ import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction; -import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.DerivedFile; import org.sleuthkit.datamodel.Directory; @@ -41,31 +40,13 @@ import org.sleuthkit.datamodel.VirtualDirectory; /** * This class provides methods for creating sets of actions for data model objects. */ +// TODO: All of the methods below that deal with classes derived from AbstractFile are the same except for the creation of wrapper nodes to pass to actions. +// 1. Do the types of the wrapper nodes really need to vary? If not, it would mean a single +// static List getActions(AbstrctFile file, boolean isArtifactSource) +// method could be implemented. If the different nodes are necessary, is it merely because of some misuse of the Visitor pattern somewhere? +// 2. All of this would be much improved by not constructing nodes with actions, but this might be necessary with pushing of nodes rather than use of lookups to +// handle selections. class DataModelActionsFactory { - static List getActions(Content content, boolean isArtifactSource) { - if (content instanceof File) { - return getActions((File)content, isArtifactSource); - } - else if (content instanceof LayoutFile) { - return getActions((LayoutFile)content, isArtifactSource); - } - else if (content instanceof Directory) { - return getActions((Directory)content, isArtifactSource); - } - else if (content instanceof VirtualDirectory) { - return getActions((VirtualDirectory)content, isArtifactSource); - } - else if (content instanceof LocalFile) { - return getActions((LocalFile)content, isArtifactSource); - } - else if (content instanceof DerivedFile) { - return getActions((DerivedFile)content, isArtifactSource); - } - else { - return new ArrayList<>(); - } - } - static List getActions(File file, boolean isArtifactSource) { List actions = new ArrayList<>(); actions.add(new ViewContextAction((isArtifactSource ? "View Source File in Directory" : "View File in Directory"), file)); @@ -173,5 +154,29 @@ class DataModelActionsFactory { } actions.addAll(ContextMenuExtensionPoint.getActions()); return actions; - } + } + + static List getActions(Content content, boolean isArtifactSource) { + if (content instanceof File) { + return getActions((File)content, isArtifactSource); + } + else if (content instanceof LayoutFile) { + return getActions((LayoutFile)content, isArtifactSource); + } + else if (content instanceof Directory) { + return getActions((Directory)content, isArtifactSource); + } + else if (content instanceof VirtualDirectory) { + return getActions((VirtualDirectory)content, isArtifactSource); + } + else if (content instanceof LocalFile) { + return getActions((LocalFile)content, isArtifactSource); + } + else if (content instanceof DerivedFile) { + return getActions((DerivedFile)content, isArtifactSource); + } + else { + return new ArrayList<>(); + } + } } \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java index a31be8d299..f8041d406e 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportGenerator.java @@ -115,7 +115,13 @@ public class ReportGenerator { for (Entry entry : tableModuleStates.entrySet()) { if (entry.getValue()) { TableReportModule module = entry.getKey(); - tableProgress.put(module, panel.addReport(module.getName(), reportPath + module.getFilePath())); + String moduleFilePath = module.getFilePath(); + if (moduleFilePath != null) { + tableProgress.put(module, panel.addReport(module.getName(), reportPath + moduleFilePath)); + } + else { + tableProgress.put(module, panel.addReport(module.getName(), null)); + } } } } @@ -124,7 +130,13 @@ public class ReportGenerator { for (Entry entry : generalModuleStates.entrySet()) { if (entry.getValue()) { GeneralReportModule module = entry.getKey(); - generalProgress.put(module, panel.addReport(module.getName(), reportPath + module.getFilePath())); + String moduleFilePath = module.getFilePath(); + if (moduleFilePath != null) { + generalProgress.put(module, panel.addReport(module.getName(), reportPath + moduleFilePath)); + } + else { + generalProgress.put(module, panel.addReport(module.getName(), null)); + } } } } @@ -133,7 +145,13 @@ public class ReportGenerator { for(Entry entry : fileListModuleStates.entrySet()) { if (entry.getValue()) { FileReportModule module = entry.getKey(); - fileProgress.put(module, panel.addReport(module.getName(), reportPath + module.getFilePath())); + String moduleFilePath = module.getFilePath(); + if (moduleFilePath != null) { + fileProgress.put(module, panel.addReport(module.getName(), reportPath + moduleFilePath)); + } + else { + fileProgress.put(module, panel.addReport(module.getName(), null)); + } } } } diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportModule.java b/Core/src/org/sleuthkit/autopsy/report/ReportModule.java index d01b994985..2a3a677b29 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportModule.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportModule.java @@ -23,37 +23,30 @@ package org.sleuthkit.autopsy.report; /** - * Interface extended by TableReportModule and GeneralReportModule. - * Contains vital report information to be used by every report. + * Interface got report modules that plug in to the reporting infrastructure. */ public interface ReportModule { /** - * Returns a basic string name for the report. What is 'officially' titled. - * - * @return the report name + * Get the name of the report this module generates. */ public String getName(); /** - * Returns a one line user friendly description of the type of report this - * module generates - * @return user-friendly report description + * Gets a one-line, user friendly description of the type of report this + * module generates. */ public String getDescription(); /** - * Returns the extension that is used for the report - * - * @return String the extension the file will be saved as - * + * Gets the extension of the report file, if any, generated by this module. + * @return File name extension, may be null. */ public String getExtension(); /** - * Returns the path to the main (or only) file for the report. - * - * @return String path to the report file + * Gets the path of the report file, if any, generated by this module. + * @return File path, may be null. */ public String getFilePath(); } \ No newline at end of file diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.java b/Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.java index 452fd28d7e..bcb876424b 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.java @@ -58,46 +58,48 @@ public class ReportProgressPanel extends javax.swing.JPanel { processingLabel.setText("Queuing..."); STATUS = ReportStatus.QUEUING; - // Add the "link" effect to the pathLabel - final String linkPath = reportPath; - pathLabel.addMouseListener(new MouseListener() { + if (reportPath != null) { + // Add the "link" effect to the pathLabel + final String linkPath = reportPath; + pathLabel.addMouseListener(new MouseListener() { - @Override - public void mouseClicked(MouseEvent e) { - } + @Override + public void mouseClicked(MouseEvent e) { + } - @Override - public void mousePressed(MouseEvent e) { - } + @Override + public void mousePressed(MouseEvent e) { + } - @Override - public void mouseReleased(MouseEvent e) { - File file = new File(linkPath); - try { - Desktop.getDesktop().open(file); - } catch (IOException ex) { - } catch (IllegalArgumentException ex) { + @Override + public void mouseReleased(MouseEvent e) { + File file = new File(linkPath); try { - // try to open the parent path if the file doens't exist - Desktop.getDesktop().open(file.getParentFile()); - } catch (IOException ex1) { + Desktop.getDesktop().open(file); + } catch (IOException ex) { + } catch (IllegalArgumentException ex) { + try { + // try to open the parent path if the file doens't exist + Desktop.getDesktop().open(file.getParentFile()); + } catch (IOException ex1) { + } } } - } - @Override - public void mouseEntered(MouseEvent e) { - pathLabel.setForeground(Color.DARK_GRAY); - setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); - } + @Override + public void mouseEntered(MouseEvent e) { + pathLabel.setForeground(Color.DARK_GRAY); + setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); + } - @Override - public void mouseExited(MouseEvent e) { - pathLabel.setForeground(Color.BLACK); - setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - } - - }); + @Override + public void mouseExited(MouseEvent e) { + pathLabel.setForeground(Color.BLACK); + setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + } + + }); + } } /** diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/IndexStatus.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/IndexStatus.java deleted file mode 100644 index c48ecdab9b..0000000000 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/IndexStatus.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Autopsy Forensic Browser - * - * Copyright 2011 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.hashdatabase; - -/** - * The status of a HashDb as determined from its indexExists(), - * databaseExists(), and isOutdated() methods - * @author pmartel - */ -enum IndexStatus { - - /** - * The index exists but the database does not. This indicates a text index - * without an accompanying text database. - */ - INDEX_ONLY("Index only"), - /** - * The database exists but the index does not. This indicates a text database - * with no index. - */ - NO_INDEX("No index"), - /** - * The index is currently being generated. - */ - INDEXING("Index is currently being generated"), - /** - * The index is generated. - */ - INDEXED("Indexed"), - /** - * An error occurred while determining status. - */ - UNKNOWN("Error determining status"); - private String message; - - /** - * @param message Short description of the state represented - */ - private IndexStatus(String message) { - this.message = message; - } - - /** - * Get status message - * @return a short description of the state represented - */ - String message() { - return this.message; - } - - public static boolean isIngestible(IndexStatus status) { - return status == INDEX_ONLY || status == INDEXED; - } -} From 85d631500180fa4f0d0f36d3bf371171bf21da1a Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 13 Nov 2013 18:40:54 -0500 Subject: [PATCH 092/169] Correct implementation of indexing for hash databases --- .../AddContentToHashDbAction.java | 49 +- .../autopsy/hashdatabase/Bundle.properties | 30 +- .../autopsy/hashdatabase/HashDb.java | 174 ++++--- .../hashdatabase/HashDbConfigPanel.form | 105 +++-- .../hashdatabase/HashDbConfigPanel.java | 276 +++++++----- .../HashDbCreateDatabaseDialog.form | 10 +- .../HashDbCreateDatabaseDialog.java | 32 +- .../HashDbImportDatabaseDialog.form | 10 +- .../HashDbImportDatabaseDialog.java | 38 +- .../hashdatabase/HashDbIngestModule.java | 94 ++-- .../autopsy/hashdatabase/HashDbManager.java | 425 +++++++----------- .../hashdatabase/HashDbSimpleConfigPanel.form | 75 ++-- .../hashdatabase/HashDbSimpleConfigPanel.java | 326 +++++++------- .../autopsy/hashdatabase/ModalNoButtons.java | 43 +- 14 files changed, 849 insertions(+), 838 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java index 4b58c3c4b2..3387128e28 100755 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java @@ -107,23 +107,11 @@ public class AddContentToHashDbAction extends AbstractAction implements Presente List hashDatabases = HashDbManager.getInstance().getKnownBadHashSets(); if (!hashDatabases.isEmpty()) { for (final HashDb database : HashDbManager.getInstance().getUpdateableHashSets()) { - JMenuItem databaseItem = add(database.getDisplayName()); + JMenuItem databaseItem = add(database.getHashSetName()); databaseItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { - Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); - for (AbstractFile file : selectedFiles) { - String md5Hash = file.getMd5Hash(); - if (null != md5Hash) { - try { - database.add(file); - } - catch (TskCoreException ex) { - Logger.getLogger(AddContentToHashDbAction.class.getName()).log(Level.SEVERE, "Error adding to hash database", ex); - JOptionPane.showMessageDialog(null, "Unable to add " + file.getName() + " to hash database.", "Add to Hash Database Error", JOptionPane.ERROR_MESSAGE); - } - } - } + addContentToHashSet(database); } }); } @@ -132,6 +120,39 @@ public class AddContentToHashDbAction extends AbstractAction implements Presente JMenuItem empty = new JMenuItem("No hash databases"); empty.setEnabled(false); add(empty); + } + + // Add a "New Hash Set..." menu item. + addSeparator(); + JMenuItem newHashSetItem = new JMenuItem("New Hash Set..."); + newHashSetItem.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + HashDb hashDb = new HashDbCreateDatabaseDialog().doDialog(); + if (null != hashDb) { + HashDbManager hashSetManager = HashDbManager.getInstance(); + hashSetManager.addHashSet(hashDb); + hashSetManager.save(); + addContentToHashSet(hashDb); + } + } + }); + add(newHashSetItem); + } + + private void addContentToHashSet(HashDb hashSet) { + Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); + for (AbstractFile file : selectedFiles) { + String md5Hash = file.getMd5Hash(); + if (null != md5Hash) { + try { + hashSet.add(file); + } + catch (TskCoreException ex) { + Logger.getLogger(AddContentToHashDbAction.class.getName()).log(Level.SEVERE, "Error adding to hash database", ex); + JOptionPane.showMessageDialog(null, "Unable to add " + file.getName() + " to hash database.", "Add to Hash Database Error", JOptionPane.ERROR_MESSAGE); + } + } } } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties index 60bee53079..891a9e4358 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/Bundle.properties @@ -22,33 +22,27 @@ HashDbSearchPanel.errorField.text=Error: Not all files have been hashed. HashDbSearchPanel.saveBox.text=Remember Hashes HashDbSearchPanel.cancelButton.text=Cancel OpenIDE-Module-Short-Description=Hash Database Ingest Module and hash db tools -ModalNoButtons.CURRENTLYON_LABEL.text=Currently Indexing x of y -ModalNoButtons.GO_GET_COFFEE_LABEL.text=Hash databases are currently being indexed, this may take some time. -ModalNoButtons.CURRENTDB_LABEL.text=(CurrentDb) -ModalNoButtons.CANCEL_BUTTON.text=Cancel HashDbImportDatabaseDialog.sendInboxMessagesCheckbox.text=Enable sending messages to inbox during ingest HashDbImportDatabaseDialog.useForIngestCheckbox.text=Enable for ingest -HashDbImportDatabaseDialog.jLabel1.text=Display name of database: +HashDbImportDatabaseDialog.jLabel1.text=Hash Set Name: HashDbImportDatabaseDialog.databaseNameTextField.text= HashDbImportDatabaseDialog.databasePathTextField.text= HashDbImportDatabaseDialog.browseButton.text=Browse -HashDbImportDatabaseDialog.nsrlRadioButton.text=NSRL HashDbImportDatabaseDialog.knownBadRadioButton.text=Known Bad HashDbImportDatabaseDialog.jLabel2.text=Type of database: HashDbImportDatabaseDialog.okButton.text=OK HashDbImportDatabaseDialog.cancelButton.text=Cancel HashDbCreateDatabaseDialog.jLabel2.text=Type of database: HashDbCreateDatabaseDialog.knownBadRadioButton.text=Known Bad -HashDbCreateDatabaseDialog.nsrlRadioButton.text=NSRL HashDbCreateDatabaseDialog.browseButton.text=Browse HashDbCreateDatabaseDialog.databasePathTextField.text= HashDbCreateDatabaseDialog.cancelButton.text=Cancel HashDbCreateDatabaseDialog.sendInboxMessagesCheckbox.text=Enable sending messages to inbox during ingest HashDbCreateDatabaseDialog.okButton.text=OK HashDbCreateDatabaseDialog.useForIngestCheckbox.text=Enable for ingest -HashDbCreateDatabaseDialog.jLabel1.text=Display name of database: +HashDbCreateDatabaseDialog.jLabel1.text=Hash Set Name: HashDbCreateDatabaseDialog.databaseNameTextField.text= -HashDbConfigPanel.nameLabel.text=Name: +HashDbConfigPanel.nameLabel.text=Hash Set Name: HashDbConfigPanel.hashDbNameLabel.text=No database selected HashDbConfigPanel.hashDatabasesLabel.text=Hash Databases: HashDbConfigPanel.hashDbLocationLabel.text=No database selected @@ -59,7 +53,7 @@ HashDbConfigPanel.jLabel4.text=Location: HashDbConfigPanel.jLabel2.text=Name: HashDbConfigPanel.optionsLabel.text=Options HashDbConfigPanel.typeLabel.text=Type: -HashDbConfigPanel.locationLabel.text=Location: +HashDbConfigPanel.locationLabel.text=Database Path: HashDbConfigPanel.hashDbIndexStatusLabel.text=No database selected HashDbConfigPanel.hashDbTypeLabel.text=No database selected HashDbConfigPanel.indexButton.text=Index @@ -67,10 +61,18 @@ HashDbConfigPanel.indexLabel.text=Index Status: HashDbConfigPanel.showInboxMessagesCheckBox.text=Enable sending messages to inbox during ingest HashDbConfigPanel.useForIngestCheckbox.text=Enable for ingest HashDbConfigPanel.informationLabel.text=Information -HashDbSimpleConfigPanel.nsrlDbLabelVal.text=- HashDbSimpleConfigPanel.calcHashesButton.text=Calculate hashes even if no hash database is selected -HashDbSimpleConfigPanel.jLabel1.text=Enable known bad databases for ingest: -HashDbSimpleConfigPanel.nsrlDbLabel.text=NSRL Database: HashDbConfigPanel.newDatabaseButton.text=New Database HashDbConfigPanel.importDatabaseButton.text=Import Database -HashDbConfigPanel.deleteDatabaseButton.text=Delete Database \ No newline at end of file +HashDbConfigPanel.deleteDatabaseButton.text=Delete Database +HashDbConfigPanel.indexPathLabelLabel.text=Index Path: +HashDbConfigPanel.indexPathLabel.text=No database selected +ModalNoButtons.CURRENTDB_LABEL.text=(CurrentDb) +ModalNoButtons.CURRENTLYON_LABEL.text=Currently Indexing x of y +ModalNoButtons.GO_GET_COFFEE_LABEL.text=Hash databases are currently being indexed, this may take some time. +ModalNoButtons.cancelButton.text=Cancel +ModalNoButtons.CANCEL_BUTTON.text=Cancel +HashDbSimpleConfigPanel.knownBadHashDbsLabel.text=Enable known bad databases for ingest: +HashDbSimpleConfigPanel.knownHashDbsLabel.text=Enable known hash databases for ingest: +HashDbImportDatabaseDialog.knownRadioButton.text=Known (NSRL or other) +HashDbCreateDatabaseDialog.knownRadioButton.text=Known (NSRL or other) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index 561334a99c..6f2d91c804 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -20,9 +20,12 @@ package org.sleuthkit.autopsy.hashdatabase; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; +import java.util.logging.Level; +import javax.swing.JOptionPane; import javax.swing.SwingWorker; import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandleFactory; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.SleuthkitJNI; @@ -30,16 +33,23 @@ import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; /** - * Instances of this class represent the hash databases underlying known files - * hash sets. + * Instances of this class represent hash databases used to classify files as + * known or know bad. */ -public class HashDb implements Comparable { +public class HashDb { + /** + * Property change events published by hash database objects. + */ public enum Event { INDEXING_DONE } + /** + * The classification to apply to files whose hashes are stored in the + * hash database. + */ public enum KnownFilesType{ - NSRL("NSRL"), + KNOWN("Known"), KNOWN_BAD("Known Bad"); private String displayName; @@ -48,84 +58,90 @@ public class HashDb implements Comparable { this.displayName = displayName; } - String getDisplayName() { + public String getDisplayName() { return this.displayName; } } - + + private int handle; + private KnownFilesType knownFilesType; + private String databasePath; + private String indexPath; + private String hashSetName; + private boolean useForIngest; + private boolean sendHitMessages; + private boolean indexing; + private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this); + /** * Opens an existing hash database. - * @param hashSetName Hash set name used to represent the hash database in user interface components. - * @param databasePath Full path to the database file to be created. The file name component of the path must have a ".kdb" extension. + * @param hashSetName Name used to represent the hash database in user interface components. + * @param selectedFilePath Full path to either a hash database file or a hash database index file. * @param useForIngest A flag indicating whether or not the hash database should be used during ingest. - * @param showInboxMessages A flag indicating whether hash set hit messages should be sent to the application inbox. - * @param knownType The known files type of the database. + * @param sendHitMessages A flag indicating whether hash set hit messages should be sent to the application in box. + * @param knownFilesType The classification to apply to files whose hashes are stored in the hash database. * @return A HashDb object representation of the new hash database. * @throws TskCoreException */ - public static HashDb openHashDatabase(String hashSetName, String databasePath, boolean useForIngest, boolean showInboxMessages, KnownFilesType knownType) throws TskCoreException { - return new HashDb(SleuthkitJNI.openHashDatabase(databasePath), hashSetName, databasePath, useForIngest, showInboxMessages, knownType); + public static HashDb openHashDatabase(String hashSetName, String selectedFilePath, boolean useForIngest, boolean sendHitMessages, KnownFilesType knownFilesType) throws TskCoreException { + int handle = SleuthkitJNI.openHashDatabase(selectedFilePath); + return new HashDb(handle, SleuthkitJNI.getHashDatabasePath(handle), SleuthkitJNI.getHashDatabaseIndexPath(handle), hashSetName, useForIngest, sendHitMessages, knownFilesType); } /** * Creates a new hash database. - * @param hashSetName Name used to represent the database in user interface components. + * @param hashSetName Hash set name used to represent the hash database in user interface components. * @param databasePath Full path to the database file to be created. The file name component of the path must have a ".kdb" extension. * @param useForIngest A flag indicating whether or not the data base should be used during the file ingest process. * @param showInboxMessages A flag indicating whether messages indicating lookup hits should be sent to the application in box. - * @param knownType The known files type of the database. + * @param hashSetType The type of hash set to associate with the database. * @return A HashDb object representation of the opened hash database. * @throws TskCoreException */ - public static HashDb createHashDatabase(String hashSetName, String databasePath, boolean useForIngest, boolean showInboxMessages, KnownFilesType type) throws TskCoreException { - return new HashDb(SleuthkitJNI.createHashDatabase(databasePath), hashSetName, databasePath, useForIngest, showInboxMessages, type); + public static HashDb createHashDatabase(String hashSetName, String databasePath, boolean useForIngest, boolean showInboxMessages, KnownFilesType knownFilesType) throws TskCoreException { + int handle = SleuthkitJNI.createHashDatabase(databasePath); + return new HashDb(handle, SleuthkitJNI.getHashDatabasePath(handle), SleuthkitJNI.getHashDatabaseIndexPath(handle), hashSetName, useForIngest, showInboxMessages, knownFilesType); } - - private static final String INDEX_FILE_EXTENSION = ".kdb"; - private static final String LEGACY_INDEX_FILE_EXTENSION = "-md5.idx"; - - private final PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this); - private String displayName; - private String databasePath; - private boolean useForIngest; - private boolean showInboxMessages; - private KnownFilesType type; - private int handle; - private boolean indexing; - - HashDb(int handle, String name, String databasePath, boolean useForIngest, boolean showInboxMessages, KnownFilesType type) { - this.displayName = name; + + private HashDb(int handle, String databasePath, String indexPath, String name, boolean useForIngest, boolean sendHitMessages, KnownFilesType knownFilesType) { this.databasePath = databasePath; + this.indexPath = indexPath; + this.hashSetName = name; this.useForIngest = useForIngest; - this.showInboxMessages = showInboxMessages; - this.type = type; + this.sendHitMessages = sendHitMessages; + this.knownFilesType = knownFilesType; this.handle = handle; this.indexing = false; } - @Override - public int compareTo(HashDb o) { - return this.displayName.compareTo(o.displayName); - } - + /** + * Adds a listener for the events defined in HashDb.Event. + */ public void addPropertyChangeListener(PropertyChangeListener pcl) { propertyChangeSupport.addPropertyChangeListener(pcl); } + /** + * Removes a listener for the events defined in HashDb.Event. + */ public void removePropertyChangeListener(PropertyChangeListener pcl) { propertyChangeSupport.removePropertyChangeListener(pcl); } - public String getDisplayName() { - return displayName; + public String getHashSetName() { + return hashSetName; } public String getDatabasePath() { return databasePath; } + public String getIndexPath() { + return indexPath; + } + public KnownFilesType getKnownFilesType() { - return type; + return knownFilesType; } public boolean getUseForIngest() { @@ -137,24 +153,23 @@ public class HashDb implements Comparable { } public boolean getShowInboxMessages() { - return showInboxMessages; + return sendHitMessages; } void setShowInboxMessages(boolean showInboxMessages) { - this.showInboxMessages = showInboxMessages; + this.sendHitMessages = showInboxMessages; + } + + // RJCTODO: Add comments + public boolean hasLookupIndex() throws TskCoreException { + return SleuthkitJNI.hashDatabaseHasLookupIndex(handle); } - public boolean hasLookupIndex() { - try { - return SleuthkitJNI.hashDatabaseHasLookupIndex(handle); - } - catch (TskCoreException ex) { - // RJCTODO - return false; - } + public boolean canBeReindexed() throws TskCoreException { + return SleuthkitJNI.hashDatabaseCanBeReindexed(handle); } - - public boolean hasTextLookupIndexOnly() throws TskCoreException { + + public boolean hasIndexOnly() throws TskCoreException { return SleuthkitJNI.hashDatabaseHasLegacyLookupIndexOnly(handle); } @@ -197,59 +212,40 @@ public class HashDb implements Comparable { } return result; } - - /** - * Derives index path from an database path by appending the suffix. - * @param databasePath - * @return - */ - // RJCTODO: Thought I got rid of this... - static String toIndexPath(String databasePath) { - return databasePath.concat(INDEX_FILE_EXTENSION); - } - + boolean isIndexing() { return indexing; } - public IndexStatus getStatus() throws TskCoreException { - IndexStatus status = IndexStatus.NO_INDEX; - - if (indexing) { - status = IndexStatus.INDEXING; - } - else if (hasLookupIndex()) { - if (hasTextLookupIndexOnly()) { - status = IndexStatus.INDEX_ONLY; - } - else { - status = IndexStatus.INDEXED; - } - } - - return status; - } - // Tries to index the database (overwrites any existing index) using a // SwingWorker. - void createIndex() throws TskCoreException { - CreateIndex creator = new CreateIndex(); + void createIndex(boolean deleteIndexFile) { + CreateIndex creator = new CreateIndex(deleteIndexFile); creator.execute(); } private class CreateIndex extends SwingWorker { private ProgressHandle progress; + private boolean deleteIndexFile; - CreateIndex() { + CreateIndex(boolean deleteIndexFile) { + this.deleteIndexFile = deleteIndexFile; }; @Override - protected Object doInBackground() throws Exception { + protected Object doInBackground() { indexing = true; - progress = ProgressHandleFactory.createHandle("Indexing " + displayName); + progress = ProgressHandleFactory.createHandle("Indexing " + hashSetName); progress.start(); progress.switchToIndeterminate(); - SleuthkitJNI.createLookupIndexForHashDatabase(handle); // RJCTODO: There is nobody to catch, fix this. + try { + SleuthkitJNI.createLookupIndexForHashDatabase(handle, deleteIndexFile); + indexPath = SleuthkitJNI.getHashDatabaseIndexPath(handle); + } + catch (TskCoreException ex) { + Logger.getLogger(HashDb.class.getName()).log(Level.SEVERE, "Error indexing hash database", ex); + JOptionPane.showMessageDialog(null, "Error indexing hash database for " + getHashSetName() + ".", "Hash Database Index Error", JOptionPane.ERROR_MESSAGE); + } return null; } @@ -257,7 +253,7 @@ public class HashDb implements Comparable { protected void done() { indexing = false; progress.finish(); - propertyChangeSupport.firePropertyChange(Event.INDEXING_DONE.toString(), null, displayName); + propertyChangeSupport.firePropertyChange(Event.INDEXING_DONE.toString(), null, hashSetName); } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.form index 1d841ad64a..2cef194731 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.form @@ -64,48 +64,46 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -115,7 +113,7 @@ - + @@ -139,29 +137,34 @@ - - - - - - + - + - - + + - + + + + + + + + + + + - + @@ -402,5 +405,19 @@ + + + + + + + + + + + + + + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java index fac3bf68fa..34f9bca200 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbConfigPanel.java @@ -27,6 +27,7 @@ import java.beans.PropertyChangeListener; import java.io.File; import java.util.ArrayList; import java.util.List; +import java.util.logging.Level; import javax.swing.JComponent; import javax.swing.JOptionPane; import javax.swing.JTable; @@ -37,16 +38,18 @@ import javax.swing.table.AbstractTableModel; import javax.swing.table.TableCellRenderer; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; import org.sleuthkit.autopsy.coreutils.Logger; -import static org.sleuthkit.autopsy.hashdatabase.IndexStatus.NO_INDEX; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.TskCoreException; /** - * Instances of this class provide a UI for managing the hash sets configuration. + * Instances of this class provide a comprehensive UI for managing the hash sets configuration. */ public final class HashDbConfigPanel extends javax.swing.JPanel implements OptionsPanel { + private static final String NO_SELECTION_TEXT = "No database selected"; + private static final String ERROR_GETTING_INDEX_STATUS = "Error occurred getting status"; + private static final String LEGACY_INDEX_FILE_EXTENSION = "-md5.idx"; private HashDbManager hashSetManager = HashDbManager.getInstance(); - private HashSetTableModel hashSetTableModel = new HashSetTableModel(); + private HashSetTableModel hashSetTableModel = new HashSetTableModel(); public HashDbConfigPanel() { initComponents(); @@ -84,15 +87,16 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio private void updateComponentsForNoSelection() { boolean ingestIsRunning = IngestManager.getDefault().isIngestRunning(); - // Update labels. - hashDbLocationLabel.setText("No database selected"); - hashDbNameLabel.setText("No database selected"); - hashDbIndexStatusLabel.setText("No database selected"); - hashDbTypeLabel.setText("No database selected"); + // Update descriptive labels. + hashDbNameLabel.setText(NO_SELECTION_TEXT); + hashDbTypeLabel.setText(NO_SELECTION_TEXT); + hashDbLocationLabel.setText(NO_SELECTION_TEXT); + indexPathLabel.setText(NO_SELECTION_TEXT); // Update indexing components. - indexButton.setText("Index"); + hashDbIndexStatusLabel.setText(NO_SELECTION_TEXT); hashDbIndexStatusLabel.setForeground(Color.black); + indexButton.setText("Index"); indexButton.setEnabled(false); // Update ingest options. @@ -115,54 +119,56 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio private void updateComponentsForSelection(HashDb db) { boolean ingestIsRunning = IngestManager.getDefault().isIngestRunning(); - // Update labels. - hashDbLocationLabel.setToolTipText(db.getDatabasePath()); - if (db.getDatabasePath().length() > 50){ - String shortenedPath = db.getDatabasePath(); - shortenedPath = shortenedPath.substring(0, 10 + shortenedPath.substring(10).indexOf(File.separator) + 1) + "..." + shortenedPath.substring((shortenedPath.length() - 20) + shortenedPath.substring(shortenedPath.length() - 20).indexOf(File.separator)); - hashDbLocationLabel.setText(shortenedPath); - } - else { - hashDbLocationLabel.setText(db.getDatabasePath()); - } - hashDbNameLabel.setText(db.getDisplayName()); + // Update descriptive labels. + hashDbNameLabel.setText(db.getHashSetName()); hashDbTypeLabel.setText(db.getKnownFilesType().getDisplayName()); - + hashDbLocationLabel.setText(shortenPath(db.getDatabasePath())); + indexPathLabel.setText(shortenPath(db.getIndexPath())); + // Update indexing components. - IndexStatus status = IndexStatus.UNKNOWN; try { - status = db.getStatus(); + if (db.isIndexing()) { + indexButton.setText("Indexing"); + hashDbIndexStatusLabel.setText("Index is currently being generated"); + hashDbIndexStatusLabel.setForeground(Color.black); + indexButton.setEnabled(false); + } + else if (db.hasLookupIndex()) { + if (db.hasIndexOnly()) { + hashDbIndexStatusLabel.setText("Index only"); + } + else if (db.getIndexPath().endsWith(LEGACY_INDEX_FILE_EXTENSION)) { + hashDbIndexStatusLabel.setText("Indexed (old format)"); + } + else { + hashDbIndexStatusLabel.setText("Indexed"); + } + hashDbIndexStatusLabel.setForeground(Color.black); + if (db.canBeReindexed()) { + indexButton.setText("Re-Index"); + indexButton.setEnabled(true); + } + else { + indexButton.setText("Index"); + indexButton.setEnabled(false); + } + } + else { + hashDbIndexStatusLabel.setText("No index"); + hashDbIndexStatusLabel.setForeground(Color.red); + indexButton.setText("Index"); + indexButton.setEnabled(true); + } } catch (TskCoreException ex) { - // RJCTODO - // Logger.getLogger(HashDbIngestModule.class.getName()) - } - hashDbIndexStatusLabel.setText(status.message()); - switch (status) { - case NO_INDEX: - indexButton.setText("Index"); - hashDbIndexStatusLabel.setForeground(Color.red); - indexButton.setEnabled(true); - break; - case INDEXING: - indexButton.setText("Indexing"); - hashDbIndexStatusLabel.setForeground(Color.black); - indexButton.setEnabled(false); - break; - case UNKNOWN: - indexButton.setText("Index"); - hashDbIndexStatusLabel.setForeground(Color.red); - indexButton.setEnabled(false); - break; - case INDEXED: - // TODO: Restore ability to re-index an indexed database. - case INDEX_ONLY: - default: - indexButton.setText("Index"); - hashDbIndexStatusLabel.setForeground(Color.black); - indexButton.setEnabled(false); - break; - } + Logger.getLogger(HashDbConfigPanel.class.getName()).log(Level.SEVERE, "Error getting index state of hash database", ex); + hashDbIndexStatusLabel.setText(ERROR_GETTING_INDEX_STATUS); + hashDbIndexStatusLabel.setForeground(Color.red); + indexButton.setText("Index"); + indexButton.setEnabled(false); + } + + // Diable the indexing button if ingest is in progress. if (ingestIsRunning) { indexButton.setEnabled(false); } @@ -184,6 +190,14 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio ingestWarningLabel.setVisible(ingestIsRunning); } + private static String shortenPath(String path) { + String shortenedPath = path; + if (shortenedPath.length() > 50){ + shortenedPath = shortenedPath.substring(0, 10 + shortenedPath.substring(10).indexOf(File.separator) + 1) + "..." + shortenedPath.substring((shortenedPath.length() - 20) + shortenedPath.substring(shortenedPath.length() - 20).indexOf(File.separator)); + } + return shortenedPath; + } + @Override public void load() { hashSetTable.clearSelection(); @@ -195,8 +209,13 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio //Checking for for any unindexed databases List unindexed = new ArrayList<>(); for (HashDb hashSet : hashSetManager.getAllHashSets()) { - if (!hashSet.hasLookupIndex()) { - unindexed.add(hashSet); + try { + if (!hashSet.hasLookupIndex()) { + unindexed.add(hashSet); + } + } + catch (TskCoreException ex) { + Logger.getLogger(HashDbConfigPanel.class.getName()).log(Level.SEVERE, "Error getting index info for hash database", ex); } } @@ -237,7 +256,7 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio String total = ""; String message; for(HashDb hdb : unindexed){ - total+= "\n" + hdb.getDisplayName(); + total+= "\n" + hdb.getHashSetName(); } if(plural){ message = "The following databases are not indexed, would you like to index them now? \n " + total; @@ -326,11 +345,17 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio @Override public Object getValueAt(int rowIndex, int columnIndex) { - return hashSets.get(rowIndex).getDisplayName(); + return hashSets.get(rowIndex).getHashSetName(); } private boolean indexExists(int rowIndex){ - return hashSets.get(rowIndex).hasLookupIndex(); + try { + return hashSets.get(rowIndex).hasLookupIndex(); + } + catch (TskCoreException ex) { + Logger.getLogger(HashSetTableModel.class.getName()).log(Level.SEVERE, "Error getting index info for hash database", ex); + return false; + } } @Override @@ -359,7 +384,7 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio int getIndexByName(String name) { for (int i = 0; i < hashSets.size(); ++i) { - if (hashSets.get(i).getDisplayName().equals(name)) { + if (hashSets.get(i).getHashSetName().equals(name)) { return i; } } @@ -410,6 +435,8 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio informationSeparator = new javax.swing.JSeparator(); optionsSeparator = new javax.swing.JSeparator(); newDatabaseButton = new javax.swing.JButton(); + indexPathLabelLabel = new javax.swing.JLabel(); + indexPathLabel = new javax.swing.JLabel(); org.openide.awt.Mnemonics.setLocalizedText(jLabel2, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.jLabel2.text")); // NOI18N @@ -520,6 +547,10 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio } }); + org.openide.awt.Mnemonics.setLocalizedText(indexPathLabelLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.indexPathLabelLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(indexPathLabel, org.openide.util.NbBundle.getMessage(HashDbConfigPanel.class, "HashDbConfigPanel.indexPathLabel.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( @@ -531,44 +562,44 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio .addGroup(layout.createSequentialGroup() .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 275, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(informationLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(informationSeparator)) - .addGroup(layout.createSequentialGroup() - .addComponent(optionsLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(optionsSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 324, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(ingestWarningLabel) - .addGroup(layout.createSequentialGroup() + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addGap(10, 10, 10) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(nameLabel) - .addComponent(locationLabel) - .addComponent(typeLabel)) - .addGap(40, 40, 40)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addComponent(indexLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 66, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18))) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(hashDbTypeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(hashDbLocationLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(hashDbIndexStatusLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(hashDbNameLabel))) + .addComponent(nameLabel) + .addGap(53, 53, 53) + .addComponent(hashDbNameLabel)) .addComponent(useForIngestCheckbox) .addComponent(showInboxMessagesCheckBox) - .addComponent(indexButton, javax.swing.GroupLayout.PREFERRED_SIZE, 75, javax.swing.GroupLayout.PREFERRED_SIZE))))) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(locationLabel) + .addComponent(indexButton, javax.swing.GroupLayout.PREFERRED_SIZE, 120, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(typeLabel) + .addComponent(indexLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 66, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(indexPathLabelLabel)) + .addGap(10, 10, 10) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(hashDbTypeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 241, Short.MAX_VALUE) + .addComponent(hashDbLocationLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(indexPathLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(hashDbIndexStatusLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))) + .addGroup(layout.createSequentialGroup() + .addComponent(optionsLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(optionsSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 324, javax.swing.GroupLayout.PREFERRED_SIZE)))) .addGroup(layout.createSequentialGroup() .addComponent(newDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(importDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(deleteDatabaseButton, javax.swing.GroupLayout.PREFERRED_SIZE, 133, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addContainerGap(40, Short.MAX_VALUE)) + .addGap(24, 24, 24)) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -587,25 +618,29 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(nameLabel) .addComponent(hashDbNameLabel)) - .addGap(5, 5, 5) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(locationLabel) - .addComponent(hashDbLocationLabel)) - .addGap(5, 5, 5) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(typeLabel) .addComponent(hashDbTypeLabel)) - .addGap(5, 5, 5) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(hashDbIndexStatusLabel) - .addComponent(indexLabel)) - .addGap(5, 5, 5) + .addComponent(locationLabel) + .addComponent(hashDbLocationLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(indexPathLabelLabel) + .addComponent(indexPathLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(indexLabel) + .addComponent(hashDbIndexStatusLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(indexButton) .addGap(18, 18, 18) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(optionsLabel) .addComponent(optionsSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 6, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGap(18, 18, 18) .addComponent(useForIngestCheckbox) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(showInboxMessagesCheckBox) @@ -624,34 +659,33 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio }// //GEN-END:initComponents private void indexButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_indexButtonActionPerformed - final HashDb hashDbToBeIndexed = ((HashSetTable)hashSetTable).getSelection(); - if (hashDbToBeIndexed != null) { - // Add a listener for the INDEXING_DONE event. The listener will update - // the UI. - hashDbToBeIndexed.addPropertyChangeListener(new PropertyChangeListener() { - @Override - public void propertyChange(PropertyChangeEvent evt) { - if (evt.getPropertyName().equals(HashDb.Event.INDEXING_DONE.toString())) { - HashDb selectedHashDb = ((HashSetTable)hashSetTable).getSelection(); - if (selectedHashDb != null && hashDbToBeIndexed != null && hashDbToBeIndexed.equals(selectedHashDb)) { - updateComponents(); - } - hashSetTableModel.refreshDisplay(); + final HashDb hashDb = ((HashSetTable)hashSetTable).getSelection(); + assert hashDb != null; + + // Add a listener for the INDEXING_DONE event. This listener will update + // the UI. + hashDb.addPropertyChangeListener(new PropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent evt) { + if (evt.getPropertyName().equals(HashDb.Event.INDEXING_DONE.toString())) { + HashDb selectedHashDb = ((HashSetTable)hashSetTable).getSelection(); + if (selectedHashDb != null && hashDb != null && hashDb.equals(selectedHashDb)) { + updateComponents(); } - } - }); - - // Display a modal dialog box to kick off the indexing on a worker thread - // and try to persuade the user to wait for the indexing task to finish. - // TODO: This defeats the purpose of doing the indexing on a worker thread. - // The user may also cancel the dialog and change the hash sets configuration. - // That should be fine, as long as the indexing DB is not deleted, which - // shu;d be able to be controlled. - ModalNoButtons indexDialog = new ModalNoButtons(this, new Frame(), hashDbToBeIndexed); - indexDialog.setLocationRelativeTo(null); - indexDialog.setVisible(true); - indexDialog.setModal(true); - } + hashSetTableModel.refreshDisplay(); + } + } + }); + + // Display a modal dialog box to kick off the indexing on a worker thread + // and try to persuade the user to wait for the indexing task to finish. + // TODO: If the user waits, this defeats the purpose of doing the indexing on a worker thread. + // But if the user cancels the dialog, other operations on the database + // may be attempted when it is not in a suitable state. + ModalNoButtons indexDialog = new ModalNoButtons(this, new Frame(), hashDb); + indexDialog.setLocationRelativeTo(null); + indexDialog.setVisible(true); + indexDialog.setModal(true); }//GEN-LAST:event_indexButtonActionPerformed private void deleteDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteDatabaseButtonActionPerformed @@ -694,7 +728,7 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio if (hashDb != null) { hashSetManager.addHashSet(hashDb); hashSetTableModel.refreshModel(); - ((HashSetTable)hashSetTable).selectRowByName(hashDb.getDisplayName()); + ((HashSetTable)hashSetTable).selectRowByName(hashDb.getHashSetName()); } }//GEN-LAST:event_importDatabaseButtonActionPerformed @@ -703,7 +737,7 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio if (null != hashDb) { hashSetManager.addHashSet(hashDb); hashSetTableModel.refreshModel(); - ((HashSetTable)hashSetTable).selectRowByName(hashDb.getDisplayName()); + ((HashSetTable)hashSetTable).selectRowByName(hashDb.getHashSetName()); } }//GEN-LAST:event_newDatabaseButtonActionPerformed @@ -718,6 +752,8 @@ public final class HashDbConfigPanel extends javax.swing.JPanel implements Optio private javax.swing.JButton importDatabaseButton; private javax.swing.JButton indexButton; private javax.swing.JLabel indexLabel; + private javax.swing.JLabel indexPathLabel; + private javax.swing.JLabel indexPathLabelLabel; private javax.swing.JLabel informationLabel; private javax.swing.JSeparator informationSeparator; private javax.swing.JLabel ingestWarningLabel; diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.form index 1342083256..f788dcff2d 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.form @@ -59,7 +59,7 @@ - + @@ -90,7 +90,7 @@ - + @@ -145,18 +145,18 @@ - + - + - + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java index 1a69551f0b..3203a3ccd3 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java @@ -97,7 +97,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { cancelButton = new javax.swing.JButton(); databasePathTextField = new javax.swing.JTextField(); browseButton = new javax.swing.JButton(); - nsrlRadioButton = new javax.swing.JRadioButton(); + knownRadioButton = new javax.swing.JRadioButton(); knownBadRadioButton = new javax.swing.JRadioButton(); jLabel1 = new javax.swing.JLabel(); databaseNameTextField = new javax.swing.JTextField(); @@ -130,12 +130,12 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { } }); - buttonGroup1.add(nsrlRadioButton); - org.openide.awt.Mnemonics.setLocalizedText(nsrlRadioButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.nsrlRadioButton.text")); // NOI18N - nsrlRadioButton.setEnabled(false); - nsrlRadioButton.addActionListener(new java.awt.event.ActionListener() { + buttonGroup1.add(knownRadioButton); + org.openide.awt.Mnemonics.setLocalizedText(knownRadioButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.knownRadioButton.text")); // NOI18N + knownRadioButton.setEnabled(false); + knownRadioButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - nsrlRadioButtonActionPerformed(evt); + knownRadioButtonActionPerformed(evt); } }); @@ -195,7 +195,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { .addGap(10, 10, 10) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(knownBadRadioButton) - .addComponent(nsrlRadioButton)) + .addComponent(knownRadioButton)) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -217,7 +217,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jLabel2) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(nsrlRadioButton) + .addComponent(knownRadioButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(knownBadRadioButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) @@ -238,12 +238,12 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { try { fileChooser.setSelectedFile(new File("hash.kdb")); if (fileChooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) { - File databaseFile = fileChooser.getSelectedFile(); + File databaseFile = fileChooser.getSelectedFile(); databasePathTextField.setText(databaseFile.getCanonicalPath()); databaseNameTextField.setText(FilenameUtils.removeExtension(databaseFile.getName())); if (databaseNameTextField.getText().toLowerCase().contains("nsrl")) { - nsrlRadioButton.setSelected(true); - nsrlRadioButtonActionPerformed(null); + knownRadioButton.setSelected(true); + knownRadioButtonActionPerformed(null); } } } @@ -252,10 +252,10 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { } }//GEN-LAST:event_browseButtonActionPerformed - private void nsrlRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nsrlRadioButtonActionPerformed + private void knownRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_knownRadioButtonActionPerformed sendInboxMessagesCheckbox.setSelected(false); sendInboxMessagesCheckbox.setEnabled(false); - }//GEN-LAST:event_nsrlRadioButtonActionPerformed + }//GEN-LAST:event_knownRadioButtonActionPerformed private void knownBadRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_knownBadRadioButtonActionPerformed sendInboxMessagesCheckbox.setSelected(true); @@ -277,8 +277,8 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { } KnownFilesType type; - if(nsrlRadioButton.isSelected()) { - type = KnownFilesType.NSRL; + if(knownRadioButton.isSelected()) { + type = KnownFilesType.KNOWN; } else { type = KnownFilesType.KNOWN_BAD; } @@ -308,7 +308,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JRadioButton knownBadRadioButton; - private javax.swing.JRadioButton nsrlRadioButton; + private javax.swing.JRadioButton knownRadioButton; private javax.swing.JButton okButton; private javax.swing.JCheckBox sendInboxMessagesCheckbox; private javax.swing.JCheckBox useForIngestCheckbox; diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.form index e6473a9688..5cb8ef9c34 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.form @@ -59,7 +59,7 @@ - + @@ -90,7 +90,7 @@ - + @@ -145,17 +145,17 @@ - + - + - + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java index 8dc8e459ed..d4cea65dbb 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbImportDatabaseDialog.java @@ -79,7 +79,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { cancelButton = new javax.swing.JButton(); databasePathTextField = new javax.swing.JTextField(); browseButton = new javax.swing.JButton(); - nsrlRadioButton = new javax.swing.JRadioButton(); + knownRadioButton = new javax.swing.JRadioButton(); knownBadRadioButton = new javax.swing.JRadioButton(); jLabel1 = new javax.swing.JLabel(); databaseNameTextField = new javax.swing.JTextField(); @@ -112,11 +112,11 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { } }); - buttonGroup1.add(nsrlRadioButton); - org.openide.awt.Mnemonics.setLocalizedText(nsrlRadioButton, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.nsrlRadioButton.text")); // NOI18N - nsrlRadioButton.addActionListener(new java.awt.event.ActionListener() { + buttonGroup1.add(knownRadioButton); + org.openide.awt.Mnemonics.setLocalizedText(knownRadioButton, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.knownRadioButton.text")); // NOI18N + knownRadioButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - nsrlRadioButtonActionPerformed(evt); + knownRadioButtonActionPerformed(evt); } }); @@ -176,7 +176,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { .addGap(10, 10, 10) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(knownBadRadioButton) - .addComponent(nsrlRadioButton)) + .addComponent(knownRadioButton)) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -198,7 +198,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jLabel2) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(nsrlRadioButton) + .addComponent(knownRadioButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(knownBadRadioButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) @@ -221,6 +221,10 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { try { databasePathTextField.setText(databaseFile.getCanonicalPath()); databaseNameTextField.setText(FilenameUtils.removeExtension(databaseFile.getName())); + if (databaseNameTextField.getText().toLowerCase().contains("nsrl")) { + knownRadioButton.setSelected(true); + knownRadioButtonActionPerformed(null); + } } catch (IOException ex) { Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.SEVERE, "Failed to get path of selected database", ex); @@ -228,10 +232,10 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { } }//GEN-LAST:event_browseButtonActionPerformed - private void nsrlRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_nsrlRadioButtonActionPerformed + private void knownRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_knownRadioButtonActionPerformed sendInboxMessagesCheckbox.setSelected(false); sendInboxMessagesCheckbox.setEnabled(false); - }//GEN-LAST:event_nsrlRadioButtonActionPerformed + }//GEN-LAST:event_knownRadioButtonActionPerformed private void knownBadRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_knownBadRadioButtonActionPerformed sendInboxMessagesCheckbox.setSelected(true); @@ -244,18 +248,18 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed if(databasePathTextField.getText().isEmpty()) { - JOptionPane.showMessageDialog(this, "Database path cannot be empty."); + JOptionPane.showMessageDialog(this, "Hash database file path cannot be empty."); return; } if(databaseNameTextField.getText().isEmpty()) { - JOptionPane.showMessageDialog(this, "Database display name cannot be empty."); + JOptionPane.showMessageDialog(this, "Hash set name cannot be empty."); return; } File file = new File(databasePathTextField.getText()); if (!file.exists()) { - JOptionPane.showMessageDialog(this, "Selected database does not exist."); + JOptionPane.showMessageDialog(this, "Selected hash database does not exist."); return; } @@ -270,8 +274,8 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { } KnownFilesType type; - if (nsrlRadioButton.isSelected()) { - type = KnownFilesType.NSRL; + if (knownRadioButton.isSelected()) { + type = KnownFilesType.KNOWN; } else { type = KnownFilesType.KNOWN_BAD; @@ -279,10 +283,6 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { try { selectedHashDb = HashDb.openHashDatabase(databaseNameTextField.getText(), filePath, useForIngestCheckbox.isSelected(), sendInboxMessagesCheckbox.isSelected(), type); - - -// if (!selectedHashDb.hasTextLookupIndexOnly()) - } catch (TskCoreException ex) { Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.WARNING, "Failed to open hash database at " + filePath, ex); @@ -305,7 +305,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JRadioButton knownBadRadioButton; - private javax.swing.JRadioButton nsrlRadioButton; + private javax.swing.JRadioButton knownRadioButton; private javax.swing.JButton okButton; private javax.swing.JCheckBox sendInboxMessagesCheckbox; private javax.swing.JCheckBox useForIngestCheckbox; diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java index 17125cb262..547bf38273 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java @@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.hashdatabase; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; +import java.util.List; import java.util.logging.Level; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; @@ -37,6 +38,7 @@ import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE; import org.sleuthkit.datamodel.Hash; import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskException; @@ -52,8 +54,8 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { private static int messageId = 0; private int knownBadCount = 0; private boolean calcHashesIsSet; - private HashDb nsrlHashSet; - private ArrayList knownBadHashSets = new ArrayList<>(); + private List knownBadHashSets = new ArrayList<>(); + private List knownHashSets = new ArrayList<>(); static long calctime = 0; static long lookuptime = 0; private final Hash hasher = new Hash(); @@ -124,31 +126,38 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { public void init(IngestModuleInit initContext) { services = IngestServices.getDefault(); skCase = Case.getCurrentCase().getSleuthkitCase(); - HashDbManager hashDbManager = HashDbManager.getInstance(); - nsrlHashSet = null; - knownBadHashSets.clear(); + HashDbManager hashDbManager = HashDbManager.getInstance(); + getHashSetsUsableForIngest(hashDbManager.getKnownBadHashSets(), knownBadHashSets); + getHashSetsUsableForIngest(hashDbManager.getKnownHashSets(), knownHashSets); calcHashesIsSet = hashDbManager.shouldAlwaysCalculateHashes(); - HashDb nsrl = hashDbManager.getNSRLHashSet(); - if (nsrl != null && nsrl.getUseForIngest() && nsrl.hasLookupIndex()) { - nsrlHashSet = nsrl; - } - - for (HashDb db : hashDbManager.getKnownBadHashSets()) { - if (db.getUseForIngest() && db.hasLookupIndex()) { - knownBadHashSets.add(db); - } - } - - if (nsrlHashSet == null) { - services.postMessage(IngestMessage.createWarningMessage(++messageId, this, "No NSRL database set", "Known file search will not be executed.")); + if (knownHashSets.isEmpty()) { + services.postMessage(IngestMessage.createWarningMessage(++messageId, this, "No known hash database set", "Known file search will not be executed.")); } if (knownBadHashSets.isEmpty()) { - services.postMessage(IngestMessage.createWarningMessage(++messageId, this, "No known bad database set", "Known bad file search will not be executed.")); + services.postMessage(IngestMessage.createWarningMessage(++messageId, this, "No known bad hash database set", "Known bad file search will not be executed.")); } } + private void getHashSetsUsableForIngest(List hashDbs, List hashDbsForIngest) { + assert hashDbs != null; + assert hashDbsForIngest != null; + hashDbsForIngest.clear(); + for (HashDb db : hashDbs) { + if (db.getUseForIngest()) { + try { + if (db.hasLookupIndex()) { + hashDbsForIngest.add(db); + } + } + catch (TskCoreException ex) { + logger.log(Level.WARNING, "Error get index status for hash database at " +db.getDatabasePath(), ex); + } + } + } + } + @Override public boolean hasBackgroundJobsRunning() { return false; @@ -166,7 +175,7 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { private ProcessResult processFile(AbstractFile file) { // bail out if we have no hashes set - if ((nsrlHashSet == null) && (knownBadHashSets.isEmpty()) && (calcHashesIsSet == false)) { + if ((knownHashSets.isEmpty()) && (knownBadHashSets.isEmpty()) && (calcHashesIsSet == false)) { return ProcessResult.OK; } @@ -213,33 +222,38 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { "Error encountered while setting known bad state for " + name + ".")); ret = ProcessResult.ERROR; } - String hashSetName = db.getDisplayName(); + String hashSetName = db.getHashSetName(); processBadFile(file, md5Hash, hashSetName, db.getShowInboxMessages()); } } - // only do NSRL if we didn't find a known bad - if (!foundBad && nsrlHashSet != null) { - try { - long lookupstart = System.currentTimeMillis(); - status = nsrlHashSet.lookUp(file); - lookuptime += (System.currentTimeMillis() - lookupstart); - } catch (TskException ex) { - logger.log(Level.WARNING, "Couldn't lookup NSRL hash for file " + name + " - see sleuthkit log for details", ex); - services.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestModule.this, "Hash Lookup Error: " + name, - "Error encountered while looking up NSRL hash value for " + name + ".")); - ret = ProcessResult.ERROR; - } - - if (status.equals(TskData.FileKnown.KNOWN)) { + // If the file is not in the known bad sets, search for it in the known sets. + // Any hit is sufficient to classify it as known, and there is no need to create + // a hit artifact or send a message to the application inbox. + if (!foundBad) { + for (HashDb db : knownHashSets) { try { - skCase.setKnown(file, TskData.FileKnown.KNOWN); + long lookupstart = System.currentTimeMillis(); + status = db.lookUp(file); + lookuptime += (System.currentTimeMillis() - lookupstart); } catch (TskException ex) { - logger.log(Level.WARNING, "Couldn't set known state for file " + name + " - see sleuthkit log for details", ex); + logger.log(Level.WARNING, "Couldn't lookup known hash for file " + name + " - see sleuthkit log for details", ex); services.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestModule.this, "Hash Lookup Error: " + name, - "Error encountered while setting known (NSRL) state for " + name + ".")); + "Error encountered while looking up known hash value for " + name + ".")); ret = ProcessResult.ERROR; } + + if (status.equals(TskData.FileKnown.KNOWN)) { + try { + skCase.setKnown(file, TskData.FileKnown.KNOWN); + break; + } catch (TskException ex) { + logger.log(Level.WARNING, "Couldn't set known state for file " + name + " - see sleuthkit log for details", ex); + services.postMessage(IngestMessage.createErrorMessage(++messageId, HashDbIngestModule.this, "Hash Lookup Error: " + name, + "Error encountered while setting known state for " + name + ".")); + ret = ProcessResult.ERROR; + } + } } } @@ -292,7 +306,7 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { @Override public void complete() { - if ((!knownBadHashSets.isEmpty()) || (nsrlHashSet != null)) { + if ((!knownBadHashSets.isEmpty()) || (!knownHashSets.isEmpty())) { StringBuilder detailsSb = new StringBuilder(); //details detailsSb.append(""); @@ -306,7 +320,7 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { detailsSb.append("

Databases Used:

\n
    "); for (HashDb db : knownBadHashSets) { - detailsSb.append("
  • ").append(db.getDisplayName()).append("
  • \n"); + detailsSb.append("
  • ").append(db.getHashSetName()).append("
  • \n"); } detailsSb.append("
"); diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java index 0ad9646e59..e71882b4de 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java @@ -34,16 +34,14 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.XMLUtil; import org.sleuthkit.autopsy.hashdatabase.HashDb.KnownFilesType; -import org.sleuthkit.datamodel.SleuthkitJNI; import org.sleuthkit.datamodel.TskCoreException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; /** - * This class is a singleton that manages the configuration of the hash databases - * that serve as hash sets for the identification of known files, known good files, - * and known bad files. + * This class is a singleton that manages the set of hash databases + * used to classify files as known or known bad. */ public class HashDbManager { private static final String ROOT_EL = "hash_sets"; @@ -61,7 +59,8 @@ public class HashDbManager { private static final String SET_VALUE = "value"; private static final Logger logger = Logger.getLogger(HashDbManager.class.getName()); private static HashDbManager instance; - private String xmlFile = PlatformUtil.getUserConfigDirectory() + File.separator + CUR_HASHSETS_FILE_NAME; + private String xmlFilePath = PlatformUtil.getUserConfigDirectory() + File.separator + CUR_HASHSETS_FILE_NAME; + private List knownHashSets = new ArrayList<>(); private List knownBadHashSets = new ArrayList<>(); private HashDb nsrlHashSet; private boolean alwaysCalculateHashes; @@ -83,102 +82,34 @@ public class HashDbManager { } /** - * Adds a hash set to the configuration as the designated National Software - * Reference Library (NSRL) hash set. Assumes that the hash set previously - * designated as NSRL set, if any, is not being indexed. Does not save the - * configuration. + * Adds a hash database to the configuration. Does not check for duplication + * of hash set names and does not save the configuration - the configuration + * is only saved on demand to support cancellation of configuration panels. */ - public void setNSRLHashSet(HashDb set) { - if (nsrlHashSet != null) { - // RJCTODO: When the closeHashDatabase() API exists, close the existing database - } - nsrlHashSet = set; - } - - /** - * Gets the hash set from the configuration, if any, that is designated as - * the National Software Reference Library (NSRL) hash set. - * @return A HashDb object representing the hash set or null. - */ - public HashDb getNSRLHashSet() { - return nsrlHashSet; - } - - /** - * Removes the hash set designated as the National Software Reference - * Library (NSRL) hash set from the configuration. Does not save the - * configuration. - */ - public void removeNSRLHashSet() { - if (nsrlHashSet != null) { - // RJCTODO: When the closeHashDatabase() API exists, close the existing database - } - nsrlHashSet = null; - } - - /** - * Adds a hash set to the configuration as a known bad files hash set. Does - * not check for duplication of sets and does not save the configuration. - */ - public void addKnownBadHashSet(HashDb set) { - knownBadHashSets.add(set); - } - - /** - * Gets the configured known bad files hash sets. - * @return A list, possibly empty, of HashDb objects. - */ - public List getKnownBadHashSets() { - return Collections.unmodifiableList(knownBadHashSets); - } - - /** - * Adds a hash set to the configuration. If the hash set is designated as - * the National Software Reference Library (NSRL) hash set, it is assumed - * the the hash set previously designated as the NSRL set, if any, is not - * being indexed. Does not check for duplication of sets and does not save - * the configuration. - */ - public void addHashSet(HashDb hashSet) { - if (hashSet.getKnownFilesType() == HashDb.KnownFilesType.NSRL) { - setNSRLHashSet(hashSet); + public void addHashSet(HashDb hashDb) { + if (hashDb.getKnownFilesType() == HashDb.KnownFilesType.KNOWN) { + knownHashSets.add(hashDb); } else { - addKnownBadHashSet(hashSet); + knownBadHashSets.add(hashDb); } } /** - * Removes a hash set from the hash sets configuration. + * Removes a hash database from the configuration. Does not save the + * configuration - the configuration is only saved on demand to support + * cancellation of configuration panels. */ - public void removeHashSet(HashDb hashSetToRemove) { - if (nsrlHashSet != null && nsrlHashSet.equals(hashSetToRemove)) { - removeNSRLHashSet(); + public void removeHashSet(HashDb hashDb) { + try { + hashDb.close(); } - else { - knownBadHashSets.remove(hashSetToRemove); - // RJCTODO: Close HashDb + catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Error closing hash database at " + hashDb.getDatabasePath(), ex); } - } - - /** - * Gets the configured known files hash sets that accept updates. - * @return A list, possibly empty, of HashDb objects. - */ - public List getUpdateableHashSets() { - ArrayList updateableDbs = new ArrayList<>(); - for (HashDb db : knownBadHashSets) { - try { - if (db.isUpdateable()) { - updateableDbs.add(db); - } - } - catch (TskCoreException ex) { - logger.log(Level.SEVERE, "Error checking updateable status of " + db.getDatabasePath(), ex); - } - } - return Collections.unmodifiableList(updateableDbs); - } + knownHashSets.remove(hashDb); + knownBadHashSets.remove(hashDb); + } /** * Gets all of the configured hash sets. @@ -187,56 +118,57 @@ public class HashDbManager { */ public List getAllHashSets() { List hashDbs = new ArrayList<>(); - if (nsrlHashSet != null) { - hashDbs.add(nsrlHashSet); - } + hashDbs.addAll(knownHashSets); hashDbs.addAll(knownBadHashSets); return Collections.unmodifiableList(hashDbs); - } + } - /** Gets the configured hash set, if any, with a given name. - * @return A HashDb object or null. - */ - public HashDb getHashSetByName(String name) { - if (nsrlHashSet != null && nsrlHashSet.getDisplayName().equals(name)) { - return nsrlHashSet; - } - - for (HashDb hashSet : knownBadHashSets) { - if (hashSet.getDisplayName().equals(name)) { - return hashSet; - } - } - - return null; - } - -// public HashDb getHashSetAt(int index) - - // RJCTODO: Get rid of this - /** - * Adds a hash set to the configuration as a known bad files hash set. The - * set is added to the internal known bad sets collection at the index - * specified by the caller. Does not save the configuration. + /** + * Gets the configured known files hash sets. + * @return A list, possibly empty, of HashDb objects. */ - public void addKnownBadSet(int index, HashDb set) { - knownBadHashSets.add(index, set); + public List getKnownHashSets() { + return Collections.unmodifiableList(knownHashSets); + } + + /** + * Gets the configured known bad files hash sets. + * @return A list, possibly empty, of HashDb objects. + */ + public List getKnownBadHashSets() { + return Collections.unmodifiableList(knownBadHashSets); + } + + /** + * Gets all of the configured hash sets that accept updates. + * @return A list, possibly empty, of HashDb objects. + */ + public List getUpdateableHashSets() { + List updateableDbs = getUpdateableHashSets(knownHashSets); + updateableDbs.addAll(getUpdateableHashSets(knownBadHashSets)); + return Collections.unmodifiableList(updateableDbs); } - // RJCTODO: Get rid of this - /** - * Removes the known bad files hash set from the internal known bad files - * hash sets collection at the specified index. Does not save the configuration. - */ - public void removeKnownBadSetAt(int index) { - knownBadHashSets.remove(index); + private List getUpdateableHashSets(List hashDbs) { + ArrayList updateableDbs = new ArrayList<>(); + for (HashDb db : hashDbs) { + try { + if (db.isUpdateable()) { + updateableDbs.add(db); + } + } + catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Error checking updateable status of hash database at " + db.getDatabasePath(), ex); + } + } + return Collections.unmodifiableList(updateableDbs); } /** - * Sets the value for the flag indicates whether hashes should be calculated + * Sets the value for the flag that indicates whether hashes should be calculated * for content even if no hash databases are configured. */ - public void setShouldAlwaysCalculateHashes(boolean alwaysCalculateHashes) { + public void alwaysCalculateHashes(boolean alwaysCalculateHashes) { this.alwaysCalculateHashes = alwaysCalculateHashes; } @@ -261,112 +193,86 @@ public class HashDbManager { * Restores the last saved hash sets configuration. This supports * cancellation of configuration panels. */ - public void loadLastSavedConfiguration() { - if (nsrlHashSet != null) { - try { - nsrlHashSet.close(); - } - catch (TskCoreException ex) { - // RJCTODO: Log - } - nsrlHashSet = null; - } - - try { - for (HashDb hashSet : knownBadHashSets) { - hashSet.close(); - } - } - catch (TskCoreException ex) { - // RJCTODO: Log - } - - knownBadHashSets.clear(); - - + public void loadLastSavedConfiguration() { + closeHashDatabases(knownHashSets); + closeHashDatabases(knownBadHashSets); + if (hashSetsConfigurationFileExists()) { readHashSetsConfigurationFromDisk(); } } - + + private void closeHashDatabases(List hashDbs) { + String dbPath = ""; + try { + for (HashDb db : hashDbs) { + dbPath = db.getDatabasePath(); + db.close(); + } + } + catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Error closing hash database at " + dbPath, ex); + } + hashDbs.clear(); + } + private boolean hashSetsConfigurationFileExists() { - File f = new File(xmlFile); + File f = new File(xmlFilePath); return f.exists() && f.canRead() && f.canWrite(); } private boolean writeHashSetConfigurationToDisk() { boolean success = false; - DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance(); - try { DocumentBuilder docBuilder = dbfac.newDocumentBuilder(); Document doc = docBuilder.newDocument(); - Element rootEl = doc.createElement(ROOT_EL); doc.appendChild(rootEl); - // TODO: Remove all the multiple database paths stuff, it was a mistake. - for (HashDb set : knownBadHashSets) { - String useForIngest = Boolean.toString(set.getUseForIngest()); - String showInboxMessages = Boolean.toString(set.getShowInboxMessages()); - List paths = Collections.singletonList(set.getDatabasePath()); - String type = KnownFilesType.KNOWN_BAD.toString(); - - Element setEl = doc.createElement(SET_EL); - setEl.setAttribute(SET_NAME_ATTR, set.getDisplayName()); - setEl.setAttribute(SET_TYPE_ATTR, type); - setEl.setAttribute(SET_USE_FOR_INGEST_ATTR, useForIngest); - setEl.setAttribute(SET_SHOW_INBOX_MESSAGES, showInboxMessages); - - for (int i = 0; i < paths.size(); i++) { - String path = paths.get(i); - Element pathEl = doc.createElement(PATH_EL); - pathEl.setAttribute(PATH_NUMBER_ATTR, Integer.toString(i)); - pathEl.setTextContent(path); - setEl.appendChild(pathEl); - } - rootEl.appendChild(setEl); - } + writeHashDbsToDisk(doc, rootEl, knownHashSets); + writeHashDbsToDisk(doc, rootEl, knownBadHashSets); - // TODO: Remove all the multiple database paths stuff. - if(nsrlHashSet != null) { - String useForIngest = Boolean.toString(nsrlHashSet.getUseForIngest()); - String showInboxMessages = Boolean.toString(nsrlHashSet.getShowInboxMessages()); - List paths = Collections.singletonList(nsrlHashSet.getDatabasePath()); - String type = KnownFilesType.NSRL.toString(); - - Element setEl = doc.createElement(SET_EL); - setEl.setAttribute(SET_NAME_ATTR, nsrlHashSet.getDisplayName()); - setEl.setAttribute(SET_TYPE_ATTR, type); - setEl.setAttribute(SET_USE_FOR_INGEST_ATTR, useForIngest); - setEl.setAttribute(SET_SHOW_INBOX_MESSAGES, showInboxMessages); - - for (int i = 0; i < paths.size(); i++) { - String path = paths.get(i); - Element pathEl = doc.createElement(PATH_EL); - pathEl.setAttribute(PATH_NUMBER_ATTR, Integer.toString(i)); - pathEl.setTextContent(path); - setEl.appendChild(pathEl); - } - rootEl.appendChild(setEl); - } - String calcValue = Boolean.toString(alwaysCalculateHashes); Element setCalc = doc.createElement(SET_CALC); setCalc.setAttribute(SET_VALUE, calcValue); rootEl.appendChild(setCalc); - success = XMLUtil.saveDoc(HashDbManager.class, xmlFile, ENCODING, doc); + success = XMLUtil.saveDoc(HashDbManager.class, xmlFilePath, ENCODING, doc); } catch (ParserConfigurationException e) { - logger.log(Level.SEVERE, "Error saving hash sets: can't initialize parser.", e); + logger.log(Level.SEVERE, "Error saving hash databases", e); } return success; } + private static void writeHashDbsToDisk(Document doc, Element rootEl, List hashDbs) { + for (HashDb db : hashDbs) { + Element setEl = doc.createElement(SET_EL); + setEl.setAttribute(SET_NAME_ATTR, db.getHashSetName()); + setEl.setAttribute(SET_TYPE_ATTR, db.getKnownFilesType().toString()); + setEl.setAttribute(SET_USE_FOR_INGEST_ATTR, Boolean.toString(db.getUseForIngest())); + setEl.setAttribute(SET_SHOW_INBOX_MESSAGES, Boolean.toString(db.getShowInboxMessages())); + Element pathEl = doc.createElement(PATH_EL); + pathEl.setTextContent(db.getDatabasePath()); + setEl.appendChild(pathEl); + + // TODO: Multiple database paths stuff. +// List paths = Collections.singletonList(db.getDatabasePath()); +// for (int i = 0; i < paths.size(); i++) { +// String path = paths.get(i); +// Element pathEl = doc.createElement(PATH_EL); +// pathEl.setAttribute(PATH_NUMBER_ATTR, Integer.toString(i)); +// pathEl.setTextContent(path); +// setEl.appendChild(pathEl); +// } + rootEl.appendChild(setEl); + } + } + + // TODO: The return value from this function is never checked. Failure is not indicated to the user. Is this desired? private boolean readHashSetsConfigurationFromDisk() { - final Document doc = XMLUtil.loadDoc(HashDbManager.class, xmlFile, XSDFILE); + final Document doc = XMLUtil.loadDoc(HashDbManager.class, xmlFilePath, XSDFILE); if (doc == null) { return false; } @@ -376,11 +282,13 @@ public class HashDbManager { logger.log(Level.SEVERE, "Error loading hash sets: invalid file format."); return false; } + NodeList setsNList = root.getElementsByTagName(SET_EL); int numSets = setsNList.getLength(); - if(numSets==0) { + if(numSets == 0) { logger.log(Level.WARNING, "No element hash_set exists."); } + for (int i = 0; i < numSets; ++i) { Element setEl = (Element) setsNList.item(i); final String name = setEl.getAttribute(SET_NAME_ATTR); @@ -389,102 +297,89 @@ public class HashDbManager { final String showInboxMessages = setEl.getAttribute(SET_SHOW_INBOX_MESSAGES); Boolean useForIngestBool = Boolean.parseBoolean(useForIngest); Boolean showInboxMessagesBool = Boolean.parseBoolean(showInboxMessages); - List paths = new ArrayList<>(); - // TODO: Remove all the multiple database paths stuff. - // RJCTODO: Rework this to do a search a bit differently, or simply indicate the file is missing... + String path = null; NodeList pathsNList = setEl.getElementsByTagName(PATH_EL); - final int numPaths = pathsNList.getLength(); - for (int j = 0; j < numPaths; ++j) { - Element pathEl = (Element) pathsNList.item(j); - String number = pathEl.getAttribute(PATH_NUMBER_ATTR); - String path = pathEl.getTextContent(); - - // If either the database or it's index exist + if (pathsNList.getLength() > 0) { + // Shouldn't be more than 1 + Element pathEl = (Element) pathsNList.item(0); + path = pathEl.getTextContent(); File database = new File(path); - File index = new File(HashDb.toIndexPath(path)); - if(database.exists() || index.exists()) { - paths.add(path); - } else { - // Ask for new path - int ret = JOptionPane.showConfirmDialog(null, "Database " + name + " could not be found at location\n" - + path + "\n" - + " Would you like to search for the file?", "Missing Database", JOptionPane.YES_NO_OPTION); - if (ret == JOptionPane.YES_OPTION) { - String filePath = searchForFile(name); - if(filePath!=null) { - paths.add(filePath); - } - } + if(!database.exists() && JOptionPane.showConfirmDialog(null, "Database " + name + " could not be found at location\n" + path + "\nWould you like to search for the file?", "Missing Database", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION) { + path = searchForFile(); } } - // Check everything was properly set +// for (int j = 0; j < numPaths; ++j) { +// Element pathEl = (Element) pathsNList.item(j); +// String path = pathEl.getTextContent(); +// +// File database = new File(path); +// if(database.exists()) { +// paths.add(path); +// } else { +// // Ask for new path +// int ret = JOptionPane.showConfirmDialog(null, "Database " + name + " could not be found at location\n" +// + path + "\n" +// + " Would you like to search for the file?", "Missing Database", JOptionPane.YES_NO_OPTION); +// if (ret == JOptionPane.YES_OPTION) { +// String filePath = searchForFile(); +// if(filePath!=null) { +// paths.add(filePath); +// } +// } +// } +// } +// if(name.isEmpty()) { logger.log(Level.WARNING, "Name was not set for hash_set at index {0}.", i); } + if(type.isEmpty()) { logger.log(Level.SEVERE, "Type was not set for hash_set at index {0}, cannot make instance of HashDb class.", i); - return false; // exit because this causes a fatal error + return false; } + if(useForIngest.isEmpty()) { logger.log(Level.WARNING, "UseForIngest was not set for hash_set at index {0}.", i); } + if(showInboxMessages.isEmpty()) { logger.log(Level.WARNING, "ShowInboxMessages was not set for hash_set at index {0}.", i); } - if(paths.isEmpty()) { - // No paths for this entry, the user most likely declined to search for them - logger.log(Level.WARNING, "No paths were set for hash_set at index {0}. Removing the database.", i); + if(path == null) { + logger.log(Level.WARNING, "No path for hash_set at index {0}, cannot make instance of HashDb class.", i); } else { - KnownFilesType typeDBType = KnownFilesType.valueOf(type); try { - HashDb db = HashDb.openHashDatabase(name, paths.get(0), useForIngestBool, showInboxMessagesBool, typeDBType); - if (typeDBType == KnownFilesType.NSRL) { - setNSRLHashSet(db); - } - else { - addKnownBadHashSet(db); - } + addHashSet(HashDb.openHashDatabase(name, path, useForIngestBool, showInboxMessagesBool, KnownFilesType.valueOf(type))); } catch (TskCoreException ex) { Logger.getLogger(HashDbManager.class.getName()).log(Level.SEVERE, "Error opening hash database", ex); - JOptionPane.showMessageDialog(null, "Unable to open " + paths.get(0) + " hash database.", "Open Hash Database Error", JOptionPane.ERROR_MESSAGE); + JOptionPane.showMessageDialog(null, "Unable to open " + path + " hash database.", "Open Hash Database Error", JOptionPane.ERROR_MESSAGE); } } } NodeList calcList = root.getElementsByTagName(SET_CALC); - int numCalc = calcList.getLength(); // Shouldn't be more than 1 - if(numCalc==0) { + if (calcList.getLength() > 0) { + Element calcEl = (Element) calcList.item(0); // Shouldn't be more than 1 + final String value = calcEl.getAttribute(SET_VALUE); + alwaysCalculateHashes = Boolean.parseBoolean(value); + } + else { logger.log(Level.WARNING, "No element hash_calculate exists."); } - for(int i=0; i + - - - - - - - + + + - - + + @@ -40,18 +37,17 @@ - - - - - + + - + + + - + - + @@ -71,7 +67,7 @@ - + @@ -82,17 +78,17 @@ - + - + - + - + @@ -103,12 +99,39 @@ - + - - + + + + - + + + + + + + + + + + + +
+ + + + + + + + + + + + + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.java index f33040b36b..776a417a99 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.java @@ -22,6 +22,7 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.List; import javax.swing.JOptionPane; +import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableColumn; @@ -29,96 +30,146 @@ import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.TskCoreException; /** - * Instances of this class are used as a file ingest module configuration panel - * by the known files hash set lookup file ingest module. + * Instances of this class provide a simplified UI for managing the hash sets configuration. */ public class HashDbSimpleConfigPanel extends javax.swing.JPanel { - private HashTableModel knownBadTableModel; - private HashDb nsrl; + private HashDbsTableModel knownTableModel; + private HashDbsTableModel knownBadTableModel; public HashDbSimpleConfigPanel() { - knownBadTableModel = new HashTableModel(); + knownTableModel = new HashDbsTableModel(HashDbManager.getInstance().getKnownHashSets()); + knownBadTableModel = new HashDbsTableModel(HashDbManager.getInstance().getKnownBadHashSets()); initComponents(); customizeComponents(); } - - private void reloadCalc() { - final HashDbManager xmlHandle = HashDbManager.getInstance(); - final HashDb nsrlDb = xmlHandle.getNSRLHashSet(); - final boolean nsrlUsed = nsrlDb != null && nsrlDb.getUseForIngest()== true && nsrlDb.hasLookupIndex(); - final List knowns = xmlHandle.getKnownBadHashSets(); - final boolean knownExists = !knowns.isEmpty(); - boolean knownUsed = false; - if (knownExists) { - for (HashDb known : knowns) { - if (known.getUseForIngest() == true) { - knownUsed = true; - break; - } - } - } - if (!nsrlUsed && !knownUsed ) { - calcHashesButton.setEnabled(true); - calcHashesButton.setSelected(true); - xmlHandle.setShouldAlwaysCalculateHashes(true); - } else { - calcHashesButton.setEnabled(false); - calcHashesButton.setSelected(false); - xmlHandle.setShouldAlwaysCalculateHashes(false); - } - } - private void customizeComponents() { - final HashDbManager xmlHandle = HashDbManager.getInstance(); + customizeHashDbsTable(jScrollPane1, knownHashTable, knownTableModel); + customizeHashDbsTable(jScrollPane2, knownBadHashTable, knownBadTableModel); + + // Add a listener to the always calculate hashes checkbox component. + // The listener passes the user's selection on to the hash database manager. calcHashesButton.addActionListener( new ActionListener() { - @Override public void actionPerformed(ActionEvent e) { - if(calcHashesButton.isSelected()) { - xmlHandle.setShouldAlwaysCalculateHashes(true); - } else { - xmlHandle.setShouldAlwaysCalculateHashes(false); - } + HashDbManager.getInstance().alwaysCalculateHashes(calcHashesButton.isSelected()); } }); - notableHashTable.setModel(knownBadTableModel); - - notableHashTable.setTableHeader(null); - notableHashTable.setRowSelectionAllowed(false); - //customize column witdhs - final int width1 = jScrollPane1.getPreferredSize().width; - notableHashTable.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN); - TableColumn column1; - for (int i = 0; i < notableHashTable.getColumnCount(); i++) { - column1 = notableHashTable.getColumnModel().getColumn(i); + refreshComponents(); + } + + private void customizeHashDbsTable(JScrollPane scrollPane, JTable table, HashDbsTableModel tableModel) { + table.setModel(tableModel); + table.setTableHeader(null); + table.setRowSelectionAllowed(false); + + final int width1 = scrollPane.getPreferredSize().width; + knownHashTable.setAutoResizeMode(JTable.AUTO_RESIZE_NEXT_COLUMN); + TableColumn column; + for (int i = 0; i < table.getColumnCount(); i++) { + column = table.getColumnModel().getColumn(i); if (i == 0) { - column1.setPreferredWidth(((int) (width1 * 0.07))); + column.setPreferredWidth(((int) (width1 * 0.07))); } else { - column1.setPreferredWidth(((int) (width1 * 0.92))); + column.setPreferredWidth(((int) (width1 * 0.92))); + } + } + } + + private void refreshComponents() { + refreshAlwaysCalcHashesComponents(); + knownBadTableModel.refresh(); + } + + private void refreshAlwaysCalcHashesComponents() { + boolean noHashDbsConfiguredForIngest = true; + for (HashDb hashDb : HashDbManager.getInstance().getAllHashSets()) { + try { + if (hashDb.getUseForIngest()== true && hashDb.hasLookupIndex()) { + noHashDbsConfiguredForIngest = false; + break; + } + } + catch (TskCoreException ex) { + // RJCTODO + } + } + + // If there are no hash databases configured for use during file ingest, + // default to always calculating hashes of the files. + if (noHashDbsConfiguredForIngest) { + calcHashesButton.setEnabled(true); + calcHashesButton.setSelected(true); + HashDbManager.getInstance().alwaysCalculateHashes(true); + } else { + calcHashesButton.setEnabled(false); + calcHashesButton.setSelected(false); + HashDbManager.getInstance().alwaysCalculateHashes(false); + } + } + + private class HashDbsTableModel extends AbstractTableModel { + private final List hashDbs; + + HashDbsTableModel(List hashDbs) { + this.hashDbs = hashDbs; + } + + private void refresh() { + fireTableDataChanged(); + } + + @Override + public int getRowCount() { + return hashDbs.size(); + } + + @Override + public int getColumnCount() { + return 2; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + HashDb db = hashDbs.get(rowIndex); + if (columnIndex == 0) { + return db.getUseForIngest(); + } else { + return db.getHashSetName(); } } - reloadSets(); - } - - private void reloadSets() { - nsrl = HashDbManager.getInstance().getNSRLHashSet(); - - if (nsrl == null || nsrl.getUseForIngest() == false) { - nsrlDbLabelVal.setText("Disabled"); + @Override + public boolean isCellEditable(int rowIndex, int columnIndex) { + return !IngestManager.getDefault().isIngestRunning() && columnIndex == 0; } - else if (nsrl.hasLookupIndex() == false) { - nsrlDbLabelVal.setText("Disabled (No index)"); - } - else { - nsrlDbLabelVal.setText("Enabled"); + + @Override + public void setValueAt(Object aValue, int rowIndex, int columnIndex) { + if(columnIndex == 0) { + HashDb db = hashDbs.get(rowIndex); + boolean dbHasIndex = false; + try { + dbHasIndex = db.hasLookupIndex(); + } + catch (TskCoreException ex) { + // RJCTODO + } + if(((Boolean) getValueAt(rowIndex, columnIndex)) || dbHasIndex) { + db.setUseForIngest((Boolean) aValue); + } + else { + JOptionPane.showMessageDialog(HashDbSimpleConfigPanel.this, "Hash databases must be indexed before they can be used for ingest"); + } + refreshComponents(); + } } - reloadCalc(); - - knownBadTableModel.resync(); + @Override + public Class getColumnClass(int c) { + return getValueAt(0, c).getClass(); + } } /** This method is called from within the constructor to @@ -131,26 +182,40 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel { private void initComponents() { jScrollPane1 = new javax.swing.JScrollPane(); - notableHashTable = new javax.swing.JTable(); - jLabel1 = new javax.swing.JLabel(); - nsrlDbLabel = new javax.swing.JLabel(); + knownHashTable = new javax.swing.JTable(); + knownBadHashDbsLabel = new javax.swing.JLabel(); + knownHashDbsLabel = new javax.swing.JLabel(); calcHashesButton = new javax.swing.JCheckBox(); - nsrlDbLabelVal = new javax.swing.JLabel(); + jScrollPane2 = new javax.swing.JScrollPane(); + knownBadHashTable = new javax.swing.JTable(); jScrollPane1.setBorder(javax.swing.BorderFactory.createEtchedBorder()); - notableHashTable.setBackground(new java.awt.Color(240, 240, 240)); - notableHashTable.setShowHorizontalLines(false); - notableHashTable.setShowVerticalLines(false); - jScrollPane1.setViewportView(notableHashTable); + knownHashTable.setBackground(new java.awt.Color(240, 240, 240)); + knownHashTable.setShowHorizontalLines(false); + knownHashTable.setShowVerticalLines(false); + jScrollPane1.setViewportView(knownHashTable); - jLabel1.setText(org.openide.util.NbBundle.getMessage(HashDbSimpleConfigPanel.class, "HashDbSimpleConfigPanel.jLabel1.text")); // NOI18N + knownBadHashDbsLabel.setText(org.openide.util.NbBundle.getMessage(HashDbSimpleConfigPanel.class, "HashDbSimpleConfigPanel.knownBadHashDbsLabel.text")); // NOI18N - nsrlDbLabel.setText(org.openide.util.NbBundle.getMessage(HashDbSimpleConfigPanel.class, "HashDbSimpleConfigPanel.nsrlDbLabel.text")); // NOI18N + knownHashDbsLabel.setText(org.openide.util.NbBundle.getMessage(HashDbSimpleConfigPanel.class, "HashDbSimpleConfigPanel.knownHashDbsLabel.text")); // NOI18N calcHashesButton.setText(org.openide.util.NbBundle.getMessage(HashDbSimpleConfigPanel.class, "HashDbSimpleConfigPanel.calcHashesButton.text")); // NOI18N - nsrlDbLabelVal.setText(org.openide.util.NbBundle.getMessage(HashDbSimpleConfigPanel.class, "HashDbSimpleConfigPanel.nsrlDbLabelVal.text")); // NOI18N + jScrollPane2.setBorder(javax.swing.BorderFactory.createEtchedBorder()); + + knownBadHashTable.setBackground(new java.awt.Color(240, 240, 240)); + knownBadHashTable.setModel(new javax.swing.table.DefaultTableModel( + new Object [][] { + + }, + new String [] { + + } + )); + knownBadHashTable.setShowHorizontalLines(false); + knownBadHashTable.setShowVerticalLines(false); + jScrollPane2.setViewportView(knownBadHashTable); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); @@ -159,109 +224,40 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) .addGroup(layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(nsrlDbLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(nsrlDbLabelVal, javax.swing.GroupLayout.PREFERRED_SIZE, 105, javax.swing.GroupLayout.PREFERRED_SIZE)) - .addComponent(jLabel1, javax.swing.GroupLayout.Alignment.LEADING)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(knownHashDbsLabel) + .addComponent(knownBadHashDbsLabel)) .addGap(0, 0, Short.MAX_VALUE)) - .addComponent(calcHashesButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE)) + .addComponent(jScrollPane2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) + .addComponent(calcHashesButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() - .addGap(7, 7, 7) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(nsrlDbLabel) - .addComponent(nsrlDbLabelVal)) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(knownHashDbsLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jLabel1) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 103, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGap(18, 18, 18) + .addComponent(knownBadHashDbsLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 73, Short.MAX_VALUE) + .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 103, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(calcHashesButton) - .addContainerGap()) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); }// //GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JCheckBox calcHashesButton; - private javax.swing.JLabel jLabel1; private javax.swing.JScrollPane jScrollPane1; - private javax.swing.JTable notableHashTable; - private javax.swing.JLabel nsrlDbLabel; - private javax.swing.JLabel nsrlDbLabelVal; + private javax.swing.JScrollPane jScrollPane2; + private javax.swing.JLabel knownBadHashDbsLabel; + private javax.swing.JTable knownBadHashTable; + private javax.swing.JLabel knownHashDbsLabel; + private javax.swing.JTable knownHashTable; // End of variables declaration//GEN-END:variables - - private class HashTableModel extends AbstractTableModel { - - private HashDbManager xmlHandle = HashDbManager.getInstance(); - - private void resync() { - fireTableDataChanged(); - } - - @Override - public int getRowCount() { - int size = xmlHandle.getKnownBadHashSets().size(); - return size == 0 ? 1 : size; - } - - @Override - public int getColumnCount() { - return 2; - } - - @Override - public Object getValueAt(int rowIndex, int columnIndex) { - if (xmlHandle.getKnownBadHashSets().isEmpty()) { - if (columnIndex == 0) { - return ""; - } else { - return "Disabled"; - } - } else { - HashDb db = xmlHandle.getKnownBadHashSets().get(rowIndex); - if (columnIndex == 0) { - return db.getUseForIngest(); - } else { - return db.getDisplayName(); - } - } - } - - @Override - public boolean isCellEditable(int rowIndex, int columnIndex) { - return !IngestManager.getDefault().isIngestRunning() && columnIndex == 0; - } - - @Override - public void setValueAt(Object aValue, int rowIndex, int columnIndex) { - if(columnIndex == 0){ - HashDb db = xmlHandle.getKnownBadHashSets().get(rowIndex); - IndexStatus status = IndexStatus.NO_INDEX; - try { - status = db.getStatus(); - } - catch (TskCoreException ex) { - // RJCTODO - } - if(((Boolean) getValueAt(rowIndex, columnIndex)) || IndexStatus.isIngestible(status)) { - db.setUseForIngest((Boolean) aValue); - } else { - JOptionPane.showMessageDialog(HashDbSimpleConfigPanel.this, "Databases must be indexed before they can be used for ingest"); - } - reloadSets(); - } - } - - @Override - public Class getColumnClass(int c) { - return getValueAt(0, c).getClass(); - } - } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java index 61e55c07b3..432a4011f2 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/ModalNoButtons.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011 - 2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,12 +21,13 @@ package org.sleuthkit.autopsy.hashdatabase; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import javax.swing.JOptionPane; import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.datamodel.TskException; +import org.sleuthkit.datamodel.TskCoreException; /** * This class exists as a stop-gap measure to force users to have an indexed database. @@ -40,6 +41,7 @@ import org.sleuthkit.datamodel.TskException; */ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListener { + private static final String INDEX_FILE_EXTENSION = ".kdb"; List unindexed; HashDb toIndex; HashDbConfigPanel hdbmp; @@ -165,7 +167,6 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen * @param evt mouse click event */ private void CANCEL_BUTTONMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_CANCEL_BUTTONMouseClicked - // TODO add your handling code here: String message = "You are about to exit out of indexing your hash databases. \n" + "The generated index will be left unusable. If you choose to continue,\n " + "please delete the corresponding -md5.idx file in the hash folder.\n" @@ -173,7 +174,7 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen int res = JOptionPane.showConfirmDialog(this, message, "Unfinished Indexing", JOptionPane.YES_NO_OPTION); if(res == JOptionPane.YES_OPTION){ - List remove = new ArrayList(); + List remove = new ArrayList<>(); if(this.toIndex == null){ remove = this.unindexed; } @@ -203,17 +204,13 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen */ private void indexThis() { this.INDEXING_PROGBAR.setIndeterminate(true); - currentDb = this.toIndex.getDisplayName(); + currentDb = this.toIndex.getHashSetName(); this.CURRENTDB_LABEL.setText("(" + currentDb + ")"); this.length = 1; this.CURRENTLYON_LABEL.setText("Currently indexing 1 database"); if (!this.toIndex.isIndexing()) { this.toIndex.addPropertyChangeListener(this); - try { - this.toIndex.createIndex(); - } catch (TskException se) { - Logger.getLogger(ModalNoButtons.class.getName()).log(Level.WARNING, "Error making TSK index", se); - } + this.toIndex.createIndex(okToDeleteOldIndexFile(toIndex)); } } @@ -224,16 +221,12 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen length = this.unindexed.size(); this.INDEXING_PROGBAR.setIndeterminate(true); for (HashDb db : this.unindexed) { - currentDb = db.getDisplayName(); + currentDb = db.getHashSetName(); this.CURRENTDB_LABEL.setText("(" + currentDb + ")"); this.CURRENTLYON_LABEL.setText("Currently indexing 1 of " + length); if (!db.isIndexing()) { db.addPropertyChangeListener(this); - try { - db.createIndex(); - } catch (TskException e) { - Logger.getLogger(ModalNoButtons.class.getName()).log(Level.WARNING, "Error making TSK index", e); - } + db.createIndex(okToDeleteOldIndexFile(db)); } } } @@ -263,4 +256,22 @@ class ModalNoButtons extends javax.swing.JDialog implements PropertyChangeListen } } } + + private boolean okToDeleteOldIndexFile(HashDb hashDb) { + boolean deleteOldIndexFile = true; + try { + if (hashDb.hasLookupIndex()) { + String indexPath = hashDb.getIndexPath(); + File indexFile = new File(indexPath); + if (!indexPath.endsWith(INDEX_FILE_EXTENSION)) { + deleteOldIndexFile = JOptionPane.showConfirmDialog(this, "Updating index file format, delete " + indexFile.getName() + " file that uses the old file format?", "Delete Obsolete Index File", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION; + } + } + } + catch (TskCoreException ex) { + Logger.getLogger(HashDbConfigPanel.class.getName()).log(Level.SEVERE, "Error getting index info for hash database", ex); + JOptionPane.showMessageDialog(null, "Error gettting index information for " + hashDb.getHashSetName() + " hash database. Cannot perform indexing operation.", "Hash Database Index Status Error", JOptionPane.ERROR_MESSAGE); + } + return deleteOldIndexFile; + } } From 24bbd79de6b63d2f466e4b171df581560e5f6bf4 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 13 Nov 2013 19:02:39 -0500 Subject: [PATCH 093/169] Clean up for hash db API work --- .../autopsy/datamodel/DataModelActionsFactory.java | 2 +- .../src/org/sleuthkit/autopsy/hashdatabase/HashDb.java | 1 - .../org/sleuthkit/autopsy/hashdatabase/HashDbManager.java | 2 -- .../autopsy/hashdatabase/HashDbSimpleConfigPanel.java | 6 ++++-- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java b/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java index 0840894017..6660d61868 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java @@ -98,7 +98,7 @@ class DataModelActionsFactory { if (isArtifactSource) { actions.add(AddBlackboardArtifactTagAction.getInstance()); } - actions.addAll(ContextMenuExtensionPoint.getActions()); // RJCTODO: Separator should not be added by provider + actions.addAll(ContextMenuExtensionPoint.getActions()); return actions; } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index 6f2d91c804..90eec76191 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -160,7 +160,6 @@ public class HashDb { this.sendHitMessages = showInboxMessages; } - // RJCTODO: Add comments public boolean hasLookupIndex() throws TskCoreException { return SleuthkitJNI.hashDatabaseHasLookupIndex(handle); } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java index e71882b4de..a29a5df11c 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java @@ -51,7 +51,6 @@ public class HashDbManager { private static final String SET_USE_FOR_INGEST_ATTR = "use_for_ingest"; private static final String SET_SHOW_INBOX_MESSAGES = "show_inbox_messages"; private static final String PATH_EL = "hash_set_path"; - private static final String PATH_NUMBER_ATTR = "number"; private static final String CUR_HASHSETS_FILE_NAME = "hashsets.xml"; private static final String XSDFILE = "HashsetsSchema.xsd"; private static final String ENCODING = "UTF-8"; @@ -62,7 +61,6 @@ public class HashDbManager { private String xmlFilePath = PlatformUtil.getUserConfigDirectory() + File.separator + CUR_HASHSETS_FILE_NAME; private List knownHashSets = new ArrayList<>(); private List knownBadHashSets = new ArrayList<>(); - private HashDb nsrlHashSet; private boolean alwaysCalculateHashes; /** diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.java index 776a417a99..8e89741f2a 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.java @@ -21,11 +21,13 @@ package org.sleuthkit.autopsy.hashdatabase; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.List; +import java.util.logging.Level; import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.table.AbstractTableModel; import javax.swing.table.TableColumn; +import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.TskCoreException; @@ -92,7 +94,7 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel { } } catch (TskCoreException ex) { - // RJCTODO + Logger.getLogger(HashDbSimpleConfigPanel.class.getName()).log(Level.SEVERE, "Error getting info for hash database at " + hashDb.getDatabasePath(), ex); } } @@ -154,7 +156,7 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel { dbHasIndex = db.hasLookupIndex(); } catch (TskCoreException ex) { - // RJCTODO + Logger.getLogger(HashDbSimpleConfigPanel.class.getName()).log(Level.SEVERE, "Error getting info for hash database at " + db.getDatabasePath(), ex); } if(((Boolean) getValueAt(rowIndex, columnIndex)) || dbHasIndex) { db.setUseForIngest((Boolean) aValue); From af631469a379b370b6e16f26459e4c3b86340c28 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 13 Nov 2013 19:11:55 -0500 Subject: [PATCH 094/169] Fixed bug in HashDbManager --- .../src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java index a29a5df11c..a1c73d1cd8 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java @@ -159,7 +159,7 @@ public class HashDbManager { logger.log(Level.SEVERE, "Error checking updateable status of hash database at " + db.getDatabasePath(), ex); } } - return Collections.unmodifiableList(updateableDbs); + return updateableDbs; } /** From 0258dfbf896d3428b2b0e8dda5f36805aed632b6 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 13 Nov 2013 19:13:45 -0500 Subject: [PATCH 095/169] Removed commented out code in HashDbManager --- .../autopsy/hashdatabase/HashDbManager.java | 31 ------------------- 1 file changed, 31 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java index a1c73d1cd8..1c7fb82a22 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java @@ -254,16 +254,6 @@ public class HashDbManager { Element pathEl = doc.createElement(PATH_EL); pathEl.setTextContent(db.getDatabasePath()); setEl.appendChild(pathEl); - - // TODO: Multiple database paths stuff. -// List paths = Collections.singletonList(db.getDatabasePath()); -// for (int i = 0; i < paths.size(); i++) { -// String path = paths.get(i); -// Element pathEl = doc.createElement(PATH_EL); -// pathEl.setAttribute(PATH_NUMBER_ATTR, Integer.toString(i)); -// pathEl.setTextContent(path); -// setEl.appendChild(pathEl); -// } rootEl.appendChild(setEl); } } @@ -308,27 +298,6 @@ public class HashDbManager { } } -// for (int j = 0; j < numPaths; ++j) { -// Element pathEl = (Element) pathsNList.item(j); -// String path = pathEl.getTextContent(); -// -// File database = new File(path); -// if(database.exists()) { -// paths.add(path); -// } else { -// // Ask for new path -// int ret = JOptionPane.showConfirmDialog(null, "Database " + name + " could not be found at location\n" -// + path + "\n" -// + " Would you like to search for the file?", "Missing Database", JOptionPane.YES_NO_OPTION); -// if (ret == JOptionPane.YES_OPTION) { -// String filePath = searchForFile(); -// if(filePath!=null) { -// paths.add(filePath); -// } -// } -// } -// } -// if(name.isEmpty()) { logger.log(Level.WARNING, "Name was not set for hash_set at index {0}.", i); } From b3856fd0d1ed22c33bd35143c05684024c06725e Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 13 Nov 2013 19:35:31 -0500 Subject: [PATCH 096/169] Fix for bug in handling of null file path/ext code for report modules --- .../autopsy/report/ReportProgressPanel.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.java b/Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.java index bcb876424b..c131923155 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.java @@ -48,18 +48,18 @@ public class ReportProgressPanel extends javax.swing.JPanel { } private void customInit(String reportName, String reportPath) { - reportLabel.setText(reportName); - pathLabel.setText("" + shortenPath(reportPath) + ""); - pathLabel.setToolTipText(reportPath); - reportProgressBar.setIndeterminate(true); reportProgressBar.setMaximum(100); - + + reportLabel.setText(reportName); processingLabel.setText("Queuing..."); STATUS = ReportStatus.QUEUING; if (reportPath != null) { - // Add the "link" effect to the pathLabel + pathLabel.setText("" + shortenPath(reportPath) + ""); + pathLabel.setToolTipText(reportPath); + + // Add the "link" effect to the pathLabel final String linkPath = reportPath; pathLabel.addMouseListener(new MouseListener() { From 36292599b04d9d2d610cf326bd02d0bbea63b361 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Wed, 13 Nov 2013 19:54:05 -0500 Subject: [PATCH 097/169] Cosmetic UI fix to report generator handling of reports without files --- Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.java b/Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.java index c131923155..af083db23d 100644 --- a/Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.java +++ b/Core/src/org/sleuthkit/autopsy/report/ReportProgressPanel.java @@ -100,6 +100,9 @@ public class ReportProgressPanel extends javax.swing.JPanel { }); } + else { + pathLabel.setText("No report file"); + } } /** From 4ceca1becf80e75d83428cf1ef83d324571cb967 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 14 Nov 2013 09:54:10 -0500 Subject: [PATCH 098/169] Fix for bug when storing path of index only hash databases --- .../autopsy/hashdatabase/HashDbManager.java | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java index 1c7fb82a22..687903e96b 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbManager.java @@ -251,10 +251,22 @@ public class HashDbManager { setEl.setAttribute(SET_TYPE_ATTR, db.getKnownFilesType().toString()); setEl.setAttribute(SET_USE_FOR_INGEST_ATTR, Boolean.toString(db.getUseForIngest())); setEl.setAttribute(SET_SHOW_INBOX_MESSAGES, Boolean.toString(db.getShowInboxMessages())); - Element pathEl = doc.createElement(PATH_EL); - pathEl.setTextContent(db.getDatabasePath()); - setEl.appendChild(pathEl); - rootEl.appendChild(setEl); + String path = null; + try { + if (db.hasIndexOnly()) { + path = db.getIndexPath(); + } + else { + path = db.getDatabasePath(); + } + Element pathEl = doc.createElement(PATH_EL); + pathEl.setTextContent(path); + setEl.appendChild(pathEl); + rootEl.appendChild(setEl); + } + catch (TskCoreException ex) { + logger.log(Level.SEVERE, "Error getting path of hash database " + db.getHashSetName() + ", unable to save configuration", ex); + } } } From 4f004e44c22e28c8b58accf65acdaa2de6cf6f41 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Thu, 14 Nov 2013 13:10:10 -0500 Subject: [PATCH 099/169] Updated hash database code and its clients to use new comment feature of API --- .../filesearch/KnownStatusSearchFilter.java | 4 +-- .../AddContentToHashDbAction.java | 3 +- .../autopsy/hashdatabase/HashDb.java | 35 ++++++++++++++++--- .../hashdatabase/HashDbIngestModule.java | 10 ++++-- 4 files changed, 41 insertions(+), 11 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java b/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java index e790852a39..501a13c440 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchFilter.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * - * Copyright 2011 Basis Technology Corp. + * Copyright 2011 - 2013 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -55,7 +55,7 @@ class KnownStatusSearchFilter extends AbstractFileSearchFilter Date: Thu, 14 Nov 2013 17:16:43 -0500 Subject: [PATCH 100/169] Improved UI compnents sizing for hash db simlpe panel --- .../hashdatabase/HashDbSimpleConfigPanel.form | 12 ++++++------ .../hashdatabase/HashDbSimpleConfigPanel.java | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.form index 65ae8ca857..f25f5bdc32 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.form @@ -28,7 +28,7 @@ - + @@ -40,14 +40,14 @@ - - + + - - + + - + diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.java index 8e89741f2a..f9545bac6d 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.java @@ -233,7 +233,7 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel { .addComponent(knownBadHashDbsLabel)) .addGap(0, 0, Short.MAX_VALUE)) .addComponent(jScrollPane2, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE) - .addComponent(calcHashesButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addComponent(calcHashesButton, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addContainerGap()) ); layout.setVerticalGroup( @@ -242,14 +242,14 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel { .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(knownHashDbsLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 103, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(18, 18, 18) + .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 55, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(knownBadHashDbsLabel) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 103, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 55, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(calcHashesButton) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addContainerGap()) ); }// //GEN-END:initComponents From 7ea6b661ad7ae487dbff46b1973ac15fbde0baed Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 15 Nov 2013 10:48:59 -0500 Subject: [PATCH 101/169] HashDb: Corrected enabling of Known radio buttons and provided for refresh of simple config after advanced config --- .../HashDbCreateDatabaseDialog.form | 1 - .../HashDbCreateDatabaseDialog.java | 1 - .../hashdatabase/HashDbIngestModule.java | 25 +++++++++++++------ .../hashdatabase/HashDbSimpleConfigPanel.java | 6 ++--- 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.form b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.form index f788dcff2d..56cbcf2e03 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.form +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.form @@ -153,7 +153,6 @@ - diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java index 3203a3ccd3..cadbced05d 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbCreateDatabaseDialog.java @@ -132,7 +132,6 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { buttonGroup1.add(knownRadioButton); org.openide.awt.Mnemonics.setLocalizedText(knownRadioButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.knownRadioButton.text")); // NOI18N - knownRadioButton.setEnabled(false); knownRadioButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { knownRadioButtonActionPerformed(evt); diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java index 6c83416fb3..b1a6a96d67 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbIngestModule.java @@ -49,7 +49,8 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { public final static String MODULE_DESCRIPTION = "Identifies known and notables files using supplied hash databases, such as a standard NSRL database."; final public static String MODULE_VERSION = Version.getVersion(); private static final Logger logger = Logger.getLogger(HashDbIngestModule.class.getName()); - private HashDbConfigPanel panel; + private HashDbSimpleConfigPanel simpleConfigPanel; + private HashDbConfigPanel advancedConfigPanel; private IngestServices services; private SleuthkitCase skCase; private static int messageId = 0; @@ -93,7 +94,11 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { @Override public javax.swing.JPanel getSimpleConfiguration(String context) { - return new HashDbSimpleConfigPanel(); + if (simpleConfigPanel == null) { + simpleConfigPanel = new HashDbSimpleConfigPanel(); + } + + return simpleConfigPanel; } @Override @@ -108,18 +113,22 @@ public class HashDbIngestModule extends IngestModuleAbstractFile { @Override public javax.swing.JPanel getAdvancedConfiguration(String context) { - if (panel == null) { - panel = new HashDbConfigPanel(); + if (advancedConfigPanel == null) { + advancedConfigPanel = new HashDbConfigPanel(); } - panel.load(); - return panel; + advancedConfigPanel.load(); + return advancedConfigPanel; } @Override public void saveAdvancedConfiguration() { - if (panel != null) { - panel.store(); + if (advancedConfigPanel != null) { + advancedConfigPanel.store(); + } + + if (simpleConfigPanel != null) { + simpleConfigPanel.refreshComponents(); } } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.java index f9545bac6d..bd8388fc62 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDbSimpleConfigPanel.java @@ -79,9 +79,10 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel { } } - private void refreshComponents() { - refreshAlwaysCalcHashesComponents(); + public void refreshComponents() { + knownTableModel.refresh(); knownBadTableModel.refresh(); + refreshAlwaysCalcHashesComponents(); } private void refreshAlwaysCalcHashesComponents() { @@ -164,7 +165,6 @@ public class HashDbSimpleConfigPanel extends javax.swing.JPanel { else { JOptionPane.showMessageDialog(HashDbSimpleConfigPanel.this, "Hash databases must be indexed before they can be used for ingest"); } - refreshComponents(); } } From 9f7cb9098fde4ba1f917a70963dcf346b11fca3a Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 15 Nov 2013 11:27:37 -0500 Subject: [PATCH 102/169] Changed icons for tags --- .../sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java | 2 +- Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java index bb45253a5e..3503776324 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java @@ -37,7 +37,7 @@ import org.sleuthkit.datamodel.TskCoreException; * either content or blackboard artifact tag nodes. */ public class BlackboardArtifactTagNode extends DisplayableItemNode { - private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; + private static final String ICON_PATH = "org/sleuthkit/autopsy/images/green-tag-icon-16.png"; private final BlackboardArtifactTag tag; public BlackboardArtifactTagNode(BlackboardArtifactTag tag) { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java index 3817bb3c9a..352b040888 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java @@ -37,7 +37,7 @@ import org.sleuthkit.datamodel.TskCoreException; * type, then by tag name. */ public class ContentTagNode extends DisplayableItemNode { - private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; + private static final String ICON_PATH = "org/sleuthkit/autopsy/images/blue-tag-icon-16.png"; private final ContentTag tag; public ContentTagNode(ContentTag tag) { From b7c12a154e8f6132eacc4a3403b1e972a93e5aaa Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 15 Nov 2013 13:50:12 -0500 Subject: [PATCH 103/169] Updated Tags sub-tree nodes to populate path area of DataResultTopComponent --- .../org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java | 3 ++- Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java | 3 ++- Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java | 3 ++- .../autopsy/directorytree/BlackboardArtifactTagTypeNode.java | 3 ++- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java index 37b14bf976..41dad8ac5b 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java @@ -24,6 +24,7 @@ import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; +import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.ContentTag; @@ -40,7 +41,7 @@ public class ContentTagTypeNode extends DisplayableItemNode { private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; public ContentTagTypeNode(TagName tagName) { - super(Children.create(new ContentTagNodeFactory(tagName), true)); + super(Children.create(new ContentTagNodeFactory(tagName), true), Lookups.singleton(tagName.getDisplayName() + " " + DISPLAY_NAME)); long tagsCount = 0; try { diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java index 74b3f195bf..38d140b039 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java @@ -24,6 +24,7 @@ import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; +import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.BlackboardArtifactTagTypeNode; @@ -41,7 +42,7 @@ public class TagNameNode extends DisplayableItemNode { private final TagName tagName; public TagNameNode(TagName tagName) { - super(Children.create(new TagTypeNodeFactory(tagName), true)); + super(Children.create(new TagTypeNodeFactory(tagName), true), Lookups.singleton(tagName.getDisplayName() + " Tags")); this.tagName = tagName; long tagsCount = 0; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java index 635416bc1e..37669308bd 100755 --- a/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java @@ -24,6 +24,7 @@ import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; +import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.TagName; @@ -40,7 +41,7 @@ public class TagsNode extends DisplayableItemNode { private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; public TagsNode() { - super(Children.create(new TagNameNodeFactory(), true)); + super(Children.create(new TagNameNodeFactory(), true), Lookups.singleton(DISPLAY_NAME)); super.setName(DISPLAY_NAME); super.setDisplayName(DISPLAY_NAME); this.setIconBaseWithExtension(ICON_PATH); diff --git a/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java b/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java index 5cedd82e98..067b68a49c 100755 --- a/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java +++ b/Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java @@ -24,6 +24,7 @@ import org.openide.nodes.ChildFactory; import org.openide.nodes.Children; import org.openide.nodes.Node; import org.openide.nodes.Sheet; +import org.openide.util.lookup.Lookups; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactTagNode; @@ -45,7 +46,7 @@ public class BlackboardArtifactTagTypeNode extends DisplayableItemNode { private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; public BlackboardArtifactTagTypeNode(TagName tagName) { - super(Children.create(new BlackboardArtifactTagNodeFactory(tagName), true)); + super(Children.create(new BlackboardArtifactTagNodeFactory(tagName), true), Lookups.singleton(tagName.getDisplayName() + " " + DISPLAY_NAME)); long tagsCount = 0; try { From d17d60c331dace326d425e9f01d2ac1ade7b8166 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 15 Nov 2013 13:56:08 -0500 Subject: [PATCH 104/169] Deleted out of date and unused XSD --- .../autopsy/hashdatabase/HashsetsSchema.xsd | 52 ------------------- 1 file changed, 52 deletions(-) delete mode 100644 HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashsetsSchema.xsd diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashsetsSchema.xsd b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashsetsSchema.xsd deleted file mode 100644 index c278bbd32b..0000000000 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashsetsSchema.xsd +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - From 606f1ae4d5c8b1246b5505f1d96e1bafcce448d3 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 15 Nov 2013 15:13:01 -0500 Subject: [PATCH 105/169] Removed default case name comment when adding to a hash db --- .../autopsy/hashdatabase/AddContentToHashDbAction.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java index 9070858c6b..62a5ddd969 100755 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java @@ -147,7 +147,7 @@ public class AddContentToHashDbAction extends AbstractAction implements Presente String md5Hash = file.getMd5Hash(); if (null != md5Hash) { try { - hashSet.add(file, Case.getCurrentCase().getName()); + hashSet.add(file); } catch (TskCoreException ex) { Logger.getLogger(AddContentToHashDbAction.class.getName()).log(Level.SEVERE, "Error adding to hash database", ex); From 630f165c297f63d8419e53a45f1cd6d374400fad Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Fri, 15 Nov 2013 17:28:17 -0500 Subject: [PATCH 106/169] Remove adding hashes of virtual directories, other small fixes --- .../casemodule/services/TagsManager.java | 24 ++++++++++--------- .../coreutils/ContextMenuExtensionPoint.java | 1 + .../datamodel/VirtualDirectoryNode.java | 2 -- .../ExplorerNodeActionVisitor.java | 1 - .../AddContentToHashDbAction.java | 4 ++-- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index 4f125ac5fe..67788f8300 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -165,7 +165,7 @@ public class TagsManager implements Closeable { * @throws TskCoreException */ public ContentTag addContentTag(Content content, TagName tagName) throws TskCoreException { - return addContentTag(content, tagName, "", 0, content.getSize() - 1); + return addContentTag(content, tagName, "", -1, -1); } /** @@ -177,7 +177,7 @@ public class TagsManager implements Closeable { * @throws TskCoreException */ public ContentTag addContentTag(Content content, TagName tagName, String comment) throws TskCoreException { - return addContentTag(content, tagName, comment, 0, content.getSize() - 1); + return addContentTag(content, tagName, comment, -1, -1); } /** @@ -196,16 +196,18 @@ public class TagsManager implements Closeable { getExistingTagNames(); } - if (beginByteOffset < 0 || beginByteOffset > content.getSize() - 1) { - throw new IllegalArgumentException("beginByteOffset = " + beginByteOffset + " out of content size range (0 - " + (content.getSize() - 1) + ")"); - } + if (beginByteOffset >= 0 && endByteOffset >= 1) { + if (beginByteOffset > content.getSize() - 1) { + throw new IllegalArgumentException("beginByteOffset = " + beginByteOffset + " out of content size range (0 - " + (content.getSize() - 1) + ")"); + } - if (endByteOffset < 0 || endByteOffset > content.getSize() - 1) { - throw new IllegalArgumentException("endByteOffset = " + endByteOffset + " out of content size range (0 - " + (content.getSize() - 1) + ")"); - } - - if (endByteOffset < beginByteOffset) { - throw new IllegalArgumentException("endByteOffset < beginByteOffset"); + if (endByteOffset > content.getSize() - 1) { + throw new IllegalArgumentException("endByteOffset = " + endByteOffset + " out of content size range (0 - " + (content.getSize() - 1) + ")"); + } + + if (endByteOffset < beginByteOffset) { + throw new IllegalArgumentException("endByteOffset < beginByteOffset"); + } } return tskCase.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset); diff --git a/Core/src/org/sleuthkit/autopsy/coreutils/ContextMenuExtensionPoint.java b/Core/src/org/sleuthkit/autopsy/coreutils/ContextMenuExtensionPoint.java index 868a2bafd2..10cb36ac33 100755 --- a/Core/src/org/sleuthkit/autopsy/coreutils/ContextMenuExtensionPoint.java +++ b/Core/src/org/sleuthkit/autopsy/coreutils/ContextMenuExtensionPoint.java @@ -42,6 +42,7 @@ public class ContextMenuExtensionPoint { if (!providerActions.isEmpty()) { actions.add(null); // Separator to set off this provider's actions. actions.addAll(provider.getActions()); + actions.add(null); // Separator to set off this provider's actions. } } return actions; diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java index 6a9f5c7645..d1a66fd25c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/VirtualDirectoryNode.java @@ -28,7 +28,6 @@ import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; -import org.sleuthkit.autopsy.actions.AddContentTagAction; import org.sleuthkit.datamodel.VirtualDirectory; import org.sleuthkit.datamodel.TskData; @@ -82,7 +81,6 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode visit(final VirtualDirectory d) { List actions = new ArrayList<>(); actions.add(ExtractAction.getInstance()); - actions.add(AddContentTagAction.getInstance()); actions.addAll(ContextMenuExtensionPoint.getActions()); return actions; } diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java index 3387128e28..bef2c3e889 100755 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java @@ -104,9 +104,9 @@ public class AddContentToHashDbAction extends AbstractAction implements Presente // Get the current set of updateable hash databases and add each // one as a menu item. - List hashDatabases = HashDbManager.getInstance().getKnownBadHashSets(); + List hashDatabases = HashDbManager.getInstance().getUpdateableHashSets(); if (!hashDatabases.isEmpty()) { - for (final HashDb database : HashDbManager.getInstance().getUpdateableHashSets()) { + for (final HashDb database : hashDatabases) { JMenuItem databaseItem = add(database.getHashSetName()); databaseItem.addActionListener(new ActionListener() { @Override From 4d0788dc222b2356630a5d6516e95002abe58146 Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Fri, 15 Nov 2013 22:50:16 -0500 Subject: [PATCH 107/169] Add In Hashset column (no data yet). --- .../autopsy/datamodel/AbstractAbstractFileNode.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java index eed0c43ea3..940f5b25ee 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java @@ -146,6 +146,12 @@ public abstract class AbstractAbstractFileNode extends A return "Known"; } }, + HASHSETS { + @Override + public String toString() { + return "In Hashsets"; + } + }, MD5HASH { @Override public String toString() { @@ -188,6 +194,7 @@ public abstract class AbstractAbstractFileNode extends A map.put(AbstractFilePropertyType.TYPE_DIR.toString(), content.getDirType().getLabel()); map.put(AbstractFilePropertyType.TYPE_META.toString(), content.getMetaType().toString()); map.put(AbstractFilePropertyType.KNOWN.toString(), content.getKnown().getName()); + map.put(AbstractFilePropertyType.HASHSETS.toString(), ""); map.put(AbstractFilePropertyType.MD5HASH.toString(), content.getMd5Hash() == null ? "" : content.getMd5Hash()); } From e585d612e797c2032e491df98da4f689efd64849 Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Fri, 15 Nov 2013 23:30:12 -0500 Subject: [PATCH 108/169] Populate the In Hashsets column (empty string if there were no hits for that file). --- .../datamodel/AbstractAbstractFileNode.java | 2 +- .../autopsy/datamodel/HashsetHits.java | 37 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java index 940f5b25ee..eb9001575c 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/AbstractAbstractFileNode.java @@ -194,7 +194,7 @@ public abstract class AbstractAbstractFileNode extends A map.put(AbstractFilePropertyType.TYPE_DIR.toString(), content.getDirType().getLabel()); map.put(AbstractFilePropertyType.TYPE_META.toString(), content.getMetaType().toString()); map.put(AbstractFilePropertyType.KNOWN.toString(), content.getKnown().getName()); - map.put(AbstractFilePropertyType.HASHSETS.toString(), ""); + map.put(AbstractFilePropertyType.HASHSETS.toString(), HashsetHits.getList(content.getSleuthkitCase(), content.getId())); map.put(AbstractFilePropertyType.MD5HASH.toString(), content.getMd5Hash() == null ? "" : content.getMd5Hash()); } diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java index ca15f6d2e7..8ed1bcc750 100644 --- a/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/HashsetHits.java @@ -94,6 +94,43 @@ public class HashsetHits implements AutopsyVisitableItem { } } + static public String getList(SleuthkitCase skCase, long objId) { + ResultSet rs = null; + String strList = ""; + + try { + int setNameId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID(); + int artId = BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID(); + String query = "SELECT value_text,blackboard_attributes.artifact_id,attribute_type_id " + + "FROM blackboard_attributes,blackboard_artifacts WHERE " + + "attribute_type_id=" + setNameId + + " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id" + + " AND blackboard_artifacts.artifact_type_id=" + artId + + " AND blackboard_artifacts.obj_id=" + objId; + rs = skCase.runQuery(query); + int i = 0; + while (rs.next()) { + if (i++ > 0) { + strList += ", "; + } + strList += rs.getString("value_text"); + } + + } catch (SQLException ex) { + logger.log(Level.WARNING, "SQL Exception occurred: ", ex); + } + finally { + if (rs != null) { + try { + skCase.closeRunQuery(rs); + } catch (SQLException ex) { + logger.log(Level.WARNING, "Error closing result set after getting hashset hits", ex); + } + } + } + return strList; + } + @Override public T accept(AutopsyItemVisitor v) { return v.visit(this); From 01bc909c20e1cafad3cdafea25c4b284358227b1 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 18 Nov 2013 14:43:46 -0500 Subject: [PATCH 109/169] Updated the labels in KnownStatusSearchPanel fro multiple known databases --- .../org/sleuthkit/autopsy/filesearch/Bundle.properties | 2 +- .../autopsy/filesearch/KnownStatusSearchPanel.form | 5 ++++- .../autopsy/filesearch/KnownStatusSearchPanel.java | 10 ++++++++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties b/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties index 4bf164e3de..afeec73469 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/filesearch/Bundle.properties @@ -24,7 +24,7 @@ FileSearchTopComponent.dateCheckBox1.text=Date: FileSearchTopComponent.dateFiltersButton1.text=Date Filters KnownStatusSearchPanel.knownCheckBox.text=Known Status: KnownStatusSearchPanel.knownBadOptionCheckBox.text=Known bad -KnownStatusSearchPanel.knownOptionCheckBox.text=Known (NSRL) +KnownStatusSearchPanel.knownOptionCheckBox.text=Known (NSRL or other) KnownStatusSearchPanel.unknownOptionCheckBox.text=Unknown DateSearchPanel.dateCheckBox.text=Date: DateSearchPanel.jLabel4.text=Timezone: diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchPanel.form b/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchPanel.form index 8eb2e5fe2c..3237a70996 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchPanel.form +++ b/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchPanel.form @@ -1,4 +1,4 @@ - +
@@ -64,6 +64,9 @@
+ + +
diff --git a/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchPanel.java b/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchPanel.java index 28475e690c..e78d81a43c 100644 --- a/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchPanel.java +++ b/Core/src/org/sleuthkit/autopsy/filesearch/KnownStatusSearchPanel.java @@ -74,6 +74,11 @@ class KnownStatusSearchPanel extends javax.swing.JPanel { knownOptionCheckBox.setSelected(true); knownOptionCheckBox.setText(org.openide.util.NbBundle.getMessage(KnownStatusSearchPanel.class, "KnownStatusSearchPanel.knownOptionCheckBox.text")); // NOI18N + knownOptionCheckBox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + knownOptionCheckBoxActionPerformed(evt); + } + }); knownBadOptionCheckBox.setSelected(true); knownBadOptionCheckBox.setText(org.openide.util.NbBundle.getMessage(KnownStatusSearchPanel.class, "KnownStatusSearchPanel.knownBadOptionCheckBox.text")); // NOI18N @@ -102,6 +107,11 @@ class KnownStatusSearchPanel extends javax.swing.JPanel { .addComponent(knownBadOptionCheckBox)) ); }// //GEN-END:initComponents + + private void knownOptionCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_knownOptionCheckBoxActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_knownOptionCheckBoxActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JCheckBox knownBadOptionCheckBox; private javax.swing.JCheckBox knownCheckBox; From 630bf46074a3d159224c405b6d09503b31bfb401 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 18 Nov 2013 15:04:41 -0500 Subject: [PATCH 110/169] Updated HashDb for chnage in hash datbases API (accepting nulls in place of empty strings) --- .../src/org/sleuthkit/autopsy/hashdatabase/HashDb.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java index e7d743c79d..ec6e84435f 100644 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/HashDb.java @@ -187,7 +187,7 @@ public class HashDb { * @throws TskCoreException */ public void add(Content content) throws TskCoreException { - add(content, ""); + add(content, null); } /** @@ -204,7 +204,7 @@ public class HashDb { AbstractFile file = (AbstractFile)content; // TODO: Add support for SHA-1 and SHA-256 hashes. if (null != file.getMd5Hash()) { - SleuthkitJNI.addToHashDatabase(file.getName(), file.getMd5Hash(), "", "", comment, handle); + SleuthkitJNI.addToHashDatabase(file.getName(), file.getMd5Hash(), null, null, comment, handle); } } } From 91c9bd2036b3ad55afee660082210c4fc09ee0ec Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 18 Nov 2013 15:25:31 -0500 Subject: [PATCH 111/169] Removed superfluous import from AddContentToHashDbAction --- .../sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java | 1 - 1 file changed, 1 deletion(-) diff --git a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java index 5ed63cd59a..bef2c3e889 100755 --- a/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java +++ b/HashDatabase/src/org/sleuthkit/autopsy/hashdatabase/AddContentToHashDbAction.java @@ -31,7 +31,6 @@ import javax.swing.JOptionPane; import org.openide.util.Utilities; import org.openide.util.Lookup; import org.openide.util.actions.Presenter; -import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.ingest.IngestConfigurator; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; From 7147cbce155550f64531f228e480d6e7665effb5 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 18 Nov 2013 15:40:20 -0500 Subject: [PATCH 112/169] Fixed hang of GetTagNameDialog when user types in an existing tag name --- Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java index 2100d83ae2..fb0d50ddc4 100644 --- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java +++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java @@ -299,6 +299,9 @@ public class GetTagNameDialog extends JDialog { tagName = null; } } + else { + dispose(); + } } }//GEN-LAST:event_okButtonActionPerformed From ec72bb7a81f7665d60eadcfad13d856317790ad9 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 18 Nov 2013 17:36:39 -0500 Subject: [PATCH 113/169] Added code to AddContentTagAction to handle current and parent directory entries --- .../autopsy/actions/AddContentTagAction.java | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java index fa762cb7bd..70c8f9ee3e 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java @@ -25,6 +25,7 @@ import org.openide.util.Utilities; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.datamodel.AbstractFile; +import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; @@ -58,6 +59,35 @@ public class AddContentTagAction extends AddTagAction { Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); for (AbstractFile file : selectedFiles) { try { + // Handle the special cases of "." and ".." directory entries. + if (file.getName().equals(".")) { + Content parentFile = file.getParent(); + if (parentFile instanceof AbstractFile) { + file = (AbstractFile)parentFile; + } + else { + JOptionPane.showMessageDialog(null, "Unable to tag " + parentFile.getName() + ", not a regular file.", "Cannot Apply Tag", JOptionPane.WARNING_MESSAGE); + continue; + } + } + else if (file.getName().equals("..")) { + Content parentFile = file.getParent(); + if (parentFile instanceof AbstractFile) { + parentFile = (AbstractFile)((AbstractFile)parentFile).getParent(); + if (parentFile instanceof AbstractFile) { + file = (AbstractFile)parentFile; + } + else { + JOptionPane.showMessageDialog(null, "Unable to tag " + parentFile.getName() + ", not a regular file.", "Cannot Apply Tag", JOptionPane.WARNING_MESSAGE); + continue; + } + } + else { + JOptionPane.showMessageDialog(null, "Unable to tag " + parentFile.getName() + ", not a regular file.", "Cannot Apply Tag", JOptionPane.WARNING_MESSAGE); + continue; + } + } + Case.getCurrentCase().getServices().getTagsManager().addContentTag(file, tagName, comment); } catch (TskCoreException ex) { From caef10a69b6825785ef7dcfe605e65ea5c0d4a6e Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Mon, 18 Nov 2013 18:04:53 -0500 Subject: [PATCH 114/169] Added code to AddContentTagAction to handle current and parent directory entries --- .../org/sleuthkit/autopsy/actions/AddContentTagAction.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java index 70c8f9ee3e..8760ed364f 100755 --- a/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java +++ b/Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java @@ -59,7 +59,7 @@ public class AddContentTagAction extends AddTagAction { Collection selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class); for (AbstractFile file : selectedFiles) { try { - // Handle the special cases of "." and ".." directory entries. + // Handle the special cases of current (".") and parent ("..") directory entries. if (file.getName().equals(".")) { Content parentFile = file.getParent(); if (parentFile instanceof AbstractFile) { @@ -95,5 +95,5 @@ public class AddContentTagAction extends AddTagAction { JOptionPane.showMessageDialog(null, "Unable to tag " + file.getName() + ".", "Tagging Error", JOptionPane.ERROR_MESSAGE); } } - } + } } \ No newline at end of file From 4207869db99f3bb9d611d6f533ae67b093d39b78 Mon Sep 17 00:00:00 2001 From: "Samuel H. Kenyon" Date: Mon, 18 Nov 2013 18:35:03 -0500 Subject: [PATCH 115/169] Revert Autopsy regression test of JNI HashDB which is now tested in the TSK JNI unit test. --- .../autopsy/testing/RegressionTest.java | 77 +------------------ 1 file changed, 2 insertions(+), 75 deletions(-) diff --git a/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java b/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java index 77a0371aa5..b7c798e4ea 100644 --- a/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java +++ b/Testing/test/qa-functional/src/org/sleuthkit/autopsy/testing/RegressionTest.java @@ -29,7 +29,6 @@ import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.nio.file.Files; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -61,9 +60,6 @@ import org.netbeans.junit.NbModuleSuite; import org.openide.util.Exceptions; import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.keywordsearch.*; -import org.sleuthkit.datamodel.SleuthkitJNI; -import org.sleuthkit.datamodel.TskData; -import org.sleuthkit.datamodel.TskException; /** * This test expects the following system properties to be set: img_path: The @@ -97,8 +93,7 @@ public class RegressionTest extends TestCase { NbModuleSuite.Configuration conf = NbModuleSuite.createConfiguration(RegressionTest.class). clusters(".*"). enableModules(".*"); - conf = conf.addTest("testHashDbJni" - , "testNewCaseWizardOpen", + conf = conf.addTest("testNewCaseWizardOpen", "testNewCaseWizard", "testStartAddDataSource", "testConfigureIngest1", @@ -108,8 +103,7 @@ public class RegressionTest extends TestCase { "testAddSourceWizard1", "testIngest", "testGenerateReportToolbar", - "testGenerateReportButton" - ); + "testGenerateReportButton"); return NbModuleSuite.create(conf); @@ -131,73 +125,6 @@ public class RegressionTest extends TestCase { public void tearDown() { } - public void testHashDbJni() { - logger.info("HashDb JNI"); - try - { - String hashfn = "regtestHash.kdb"; - //String md5hash = "b8c51089ebcdf9f11154a021438f5bd6"; - String md5hash = "2c875b03541ffa970679986b48dca943"; - String md5hash2 = "cb4aca35f3fd54aacf96da9cd9acadb8"; - String md5hashBad = "35b299c6fcf47ece375b3221bdc16969"; - -// logger.info("Opening existing kdb file..."); -// int handle = SleuthkitJNI.openHashDatabase(hashfn); -// logger.info("handle = " + handle); - - // Make sure we start with a clean slate - File f = new File(hashfn); - if (f.exists()) { - if (!f.delete()) { - // Probably a file permission issue - logger.warning("Cleaning test file failed."); - } - } - - logger.info("Creating hash db " + hashfn); - int handle = SleuthkitJNI.createHashDatabase(hashfn); - logger.info("handle = " + handle); - - logger.info("hashDatabaseCanBeReindexed?"); - boolean retIndexable = SleuthkitJNI.hashDatabaseCanBeReindexed(handle); - logger.info("return value = " + Boolean.toString(retIndexable)); - - logger.info("getHashDatabasePath?"); - String retDbpath = SleuthkitJNI.getHashDatabasePath(handle); - logger.info("return value = " + retDbpath); - - logger.info("getHashDatabaseIndexPath?"); - String retIndexDbpath = SleuthkitJNI.getHashDatabaseIndexPath(handle); - logger.info("return value = " + retIndexDbpath); - - logger.info("Adding hash " + md5hash); - SleuthkitJNI.addToHashDatabase("", md5hash, "", "", handle); - - logger.info("Adding hash " + md5hash2); - SleuthkitJNI.addToHashDatabase("", md5hash2, "", "", handle); - - logger.info("Querying for known hash " + md5hash); - TskData.FileKnown k = SleuthkitJNI.lookupInHashDatabase(md5hash, handle); - logger.info("Query result: " + k.toString()); - - logger.info("Querying for unknown hash " + md5hashBad); - TskData.FileKnown k2 = SleuthkitJNI.lookupInHashDatabase(md5hashBad, handle); - logger.info("Query result: " + k2.toString()); - - logger.info("Test: hashDatabaseHasLookupIndex() "); - boolean b = SleuthkitJNI.hashDatabaseHasLookupIndex(handle); - logger.info("Result: " + Boolean.toString(b)); - - - - - } catch (TskException ex) { - logger.log(Level.WARNING, "Database creation error: ", ex); - logger.info("A TskException occurred."); - return; - } - } - public void testNewCaseWizardOpen() { logger.info("New Case"); NbDialogOperator nbdo = new NbDialogOperator("Welcome"); From 9ac0c310ea1af8c5f8d3eae6c00903319b0d9d64 Mon Sep 17 00:00:00 2001 From: Richard Cordovano Date: Tue, 19 Nov 2013 18:17:34 -0500 Subject: [PATCH 116/169] Normalization of line endings --- Core/manifest.mf | 20 +- ExifParser/manifest.mf | 12 +- HashDatabase/manifest.mf | 14 +- HashDatabase/nbproject/project.properties | 12 +- .../autopsy/keywordsearch/Bundle.properties | 182 +- .../docs/keywordsearch-about.html | 162 +- test/README.txt | 26 +- test/script/Emailer.py | 98 +- test/script/regression.py | 3708 ++++++++--------- test/script/srcupdater.py | 374 +- 10 files changed, 2304 insertions(+), 2304 deletions(-) diff --git a/Core/manifest.mf b/Core/manifest.mf index 31bfec73de..7aa34c46dc 100644 --- a/Core/manifest.mf +++ b/Core/manifest.mf @@ -1,10 +1,10 @@ -Manifest-Version: 1.0 -OpenIDE-Module: org.sleuthkit.autopsy.core/9 -OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/core/Bundle.properties -OpenIDE-Module-Layer: org/sleuthkit/autopsy/core/layer.xml -OpenIDE-Module-Implementation-Version: 9 -OpenIDE-Module-Requires: org.openide.windows.WindowManager, org.netbeans.api.javahelp.Help -AutoUpdate-Show-In-Client: true -AutoUpdate-Essential-Module: true -OpenIDE-Module-Install: org/sleuthkit/autopsy/core/Installer.class - +Manifest-Version: 1.0 +OpenIDE-Module: org.sleuthkit.autopsy.core/9 +OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/core/Bundle.properties +OpenIDE-Module-Layer: org/sleuthkit/autopsy/core/layer.xml +OpenIDE-Module-Implementation-Version: 9 +OpenIDE-Module-Requires: org.openide.windows.WindowManager, org.netbeans.api.javahelp.Help +AutoUpdate-Show-In-Client: true +AutoUpdate-Essential-Module: true +OpenIDE-Module-Install: org/sleuthkit/autopsy/core/Installer.class + diff --git a/ExifParser/manifest.mf b/ExifParser/manifest.mf index dbf05fee2f..44ad288f51 100644 --- a/ExifParser/manifest.mf +++ b/ExifParser/manifest.mf @@ -1,6 +1,6 @@ -Manifest-Version: 1.0 -AutoUpdate-Show-In-Client: true -OpenIDE-Module: org.sleuthkit.autopsy.exifparser/3 -OpenIDE-Module-Implementation-Version: 9 -OpenIDE-Module-Layer: org/sleuthkit/autopsy/exifparser/layer.xml -OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/exifparser/Bundle.properties +Manifest-Version: 1.0 +AutoUpdate-Show-In-Client: true +OpenIDE-Module: org.sleuthkit.autopsy.exifparser/3 +OpenIDE-Module-Implementation-Version: 9 +OpenIDE-Module-Layer: org/sleuthkit/autopsy/exifparser/layer.xml +OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/exifparser/Bundle.properties diff --git a/HashDatabase/manifest.mf b/HashDatabase/manifest.mf index ba201a294c..b8c105413c 100644 --- a/HashDatabase/manifest.mf +++ b/HashDatabase/manifest.mf @@ -1,7 +1,7 @@ -Manifest-Version: 1.0 -AutoUpdate-Show-In-Client: true -OpenIDE-Module: org.sleuthkit.autopsy.hashdatabase/3 -OpenIDE-Module-Implementation-Version: 9 -OpenIDE-Module-Layer: org/sleuthkit/autopsy/hashdatabase/layer.xml -OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/hashdatabase/Bundle.properties - +Manifest-Version: 1.0 +AutoUpdate-Show-In-Client: true +OpenIDE-Module: org.sleuthkit.autopsy.hashdatabase/3 +OpenIDE-Module-Implementation-Version: 9 +OpenIDE-Module-Layer: org/sleuthkit/autopsy/hashdatabase/layer.xml +OpenIDE-Module-Localizing-Bundle: org/sleuthkit/autopsy/hashdatabase/Bundle.properties + diff --git a/HashDatabase/nbproject/project.properties b/HashDatabase/nbproject/project.properties index 88f75855cb..e633758f8a 100644 --- a/HashDatabase/nbproject/project.properties +++ b/HashDatabase/nbproject/project.properties @@ -1,6 +1,6 @@ -javac.source=1.7 -javac.compilerargs=-Xlint -Xlint:-serial -license.file=../LICENSE-2.0.txt -nbm.homepage=http://www.sleuthkit.org/autopsy/ -nbm.needs.restart=true -spec.version.base=1.3 +javac.source=1.7 +javac.compilerargs=-Xlint -Xlint:-serial +license.file=../LICENSE-2.0.txt +nbm.homepage=http://www.sleuthkit.org/autopsy/ +nbm.needs.restart=true +spec.version.base=1.3 diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties index 65dbef957c..2d260d1242 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/Bundle.properties @@ -1,91 +1,91 @@ -OpenIDE-Module-Display-Category=Ingest Module -OpenIDE-Module-Long-Description=\ - Keyword Search ingest module.\n\n\ - The module indexes files found in the disk image at ingest time. \ - It then periodically runs the search on the indexed files using one or more keyword lists (containing pure words and/or regular expressions) and posts results.\n\n\ - The module also contains additional tools integrated in the main GUI, such as keyword list configuration, keyword seach bar in the top-right corner, extracted text viewer and search results viewer showing highlighted keywords found. -OpenIDE-Module-Name=KeywordSearch -ListBundleName=Keyword Lists -ListBundleConfig=Keyword List Configuration -IndexProgressPanel.statusText.text=Status text -IndexProgressPanel.cancelButton.text=Cancel -ExtractedContentPanel.hitLabel.text=Matches on page: -ExtractedContentPanel.hitCountLabel.text=- -ExtractedContentPanel.hitOfLabel.text=of -ExtractedContentPanel.hitTotalLabel.text=- -ExtractedContentPanel.hitButtonsLabel.text=Match -ExtractedContentPanel.hitPreviousButton.text= -ExtractedContentPanel.hitNextButton.text= -ExtractedContentPanel.copyMenuItem.text=Copy -ExtractedContentPanel.selectAllMenuItem.text=Select All -KeywordSearchEditListPanel.saveListButton.text=Copy List -KeywordSearchEditListPanel.addWordField.text= -KeywordSearchEditListPanel.addWordButton.text=Add -KeywordSearchEditListPanel.chRegex.text=Regular Expression -KeywordSearchEditListPanel.deleteWordButton.text=Remove Selected -KeywordSearchEditListPanel.cutMenuItem.text=Cut -KeywordSearchEditListPanel.selectAllMenuItem.text=Select All -KeywordSearchEditListPanel.pasteMenuItem.text=Paste -KeywordSearchEditListPanel.copyMenuItem.text=Copy -KeywordSearchEditListPanel.exportButton.text=Export List -KeywordSearchEditListPanel.deleteListButton.text=Delete List -KeywordSearchListsManagementPanel.newListButton.text=New List -KeywordSearchEditListPanel.useForIngestCheckbox.text=Enable for ingest -KeywordSearchListsManagementPanel.importButton.text=Import List -KeywordSearchPanel.searchBox.text=Search... -KeywordSearchPanel.regExCheckboxMenuItem.text=Use Regular Expressions -KeywordSearchPanel.settingsLabel.text= -KeywordSearchListsViewerPanel.searchAddButton.text=Search -KeywordSearchListsViewerPanel.manageListsButton.text=Manage Lists -KeywordSearchListsViewerPanel.ingestIndexLabel.text=Files Indexed: -KeywordSearchEditListPanel.selectorsCombo.toolTipText=Regular Expression selector type (optional) -KeywordSearchPanel.searchButton.text= -KeywordSearchPanel.cutMenuItem.text=Cut -KeywordSearchPanel.copyMenuItem.text=Copy -KeywordSearchPanel.pasteMenuItem.text=Paste -KeywordSearchPanel.selectAllMenuItem.text=Select All -ExtractedContentPanel.pageButtonsLabel.text=Page -ExtractedContentPanel.pageNextButton.text= -ExtractedContentPanel.pagePreviousButton.actionCommand=pagePreviousButton -ExtractedContentPanel.pagePreviousButton.text= -ExtractedContentPanel.pagesLabel.text=Page: -ExtractedContentPanel.pageOfLabel.text=of -ExtractedContentPanel.pageCurLabel.text=- -ExtractedContentPanel.pageTotalLabel.text=- -ExtractedContentPanel.hitLabel.toolTipText= -KeywordSearchEditListPanel.ingestMessagesCheckbox.text=Enable sending messages to inbox during ingest -KeywordSearchEditListPanel.ingestMessagesCheckbox.toolTipText=Send messages during triage / ingest when hits on keyword from this list occur -KeywordSearchConfigurationPanel2.skipNSRLCheckBox.text=Do not add files in NSRL (known files) to keyword index during ingest -KeywordSearchConfigurationPanel2.skipNSRLCheckBox.toolTipText=Requires Hash DB service to had run previously, or be selected for next ingest. -KeywordSearchConfigurationPanel2.filesIndexedValue.text=- -KeywordSearchConfigurationPanel2.filesIndexedLabel.text=Files in keyword index: -KeywordSearchIngestSimplePanel.languagesLabel.text=Scripts enabled for string extraction from unknown file types: -KeywordSearchIngestSimplePanel.languagesValLabel.text=- -KeywordSearchIngestSimplePanel.languagesLabel.toolTipText=Scripts enabled for string extraction from unknown file types. Changes can be done in Advanced Settings. -KeywordSearchIngestSimplePanel.languagesValLabel.toolTipText= -KeywordSearchConfigurationPanel3.languagesLabel.text=Enabled scripts (languages): -KeywordSearchConfigurationPanel2.chunksLabel.text=Chunks in keyword index: -KeywordSearchConfigurationPanel2.chunksValLabel.text=- -KeywordSearchConfigurationPanel3.enableUTF8Checkbox.text=Enable UTF8 text extraction -KeywordSearchConfigurationPanel3.enableUTF16Checkbox.text=Enable UTF16LE and UTF16BE string extraction -KeywordSearchEditListPanel.keywordOptionsLabel.text=Keyword Options -KeywordSearchEditListPanel.listOptionsLabel.text=List Options -KeywordSearchConfigurationPanel3.ingestSettingsLabel.text=Ingest settings for string extraction from unknown file types (changes effective on next ingest): -KeywordSearchConfigurationPanel2.settingsLabel.text=Settings -KeywordSearchConfigurationPanel2.informationLabel.text=Information -KeywordSearchListsManagementPanel.keywordListsLabel.text=Keyword Lists: -KeywordSearchEditListPanel.keywordsLabel.text=Keywords: -KeywordSearchConfigurationPanel2.timeRadioButton1.toolTipText=20 mins. (fastest ingest time) -KeywordSearchConfigurationPanel2.timeRadioButton1.text=20 minutes (slowest feedback, fastest ingest) -KeywordSearchConfigurationPanel2.timeRadioButton2.toolTipText=10 minutes (faster overall ingest time than default) -KeywordSearchConfigurationPanel2.timeRadioButton2.text=10 minutes (slower feedback, faster ingest) -KeywordSearchConfigurationPanel2.timeRadioButton3.toolTipText=5 minutes (overall ingest time will be longer) -KeywordSearchConfigurationPanel2.timeRadioButton3.text=5 minutes (default) -KeywordSearchIngestSimplePanel.encodingsLabel.text=Encodings: -KeywordSearchIngestSimplePanel.keywordSearchEncodings.text=- -KeywordSearchIngestSimplePanel.titleLabel.text=Select keyword lists to enable during ingest: -OpenIDE-Module-Short-Description=Keyword Search ingest module, extracted text viewer and keyword search tools -KeywordSearchListsViewerPanel.manageListsButton.toolTipText=Manage keyword lists, their settings and associated keywords. The settings are shared among all cases. -KeywordSearchConfigurationPanel2.frequencyLabel.text=Results update frequency during ingest: -KeywordSearchConfigurationPanel2.timeRadioButton4.text_1=1 minute (faster feedback, longest ingest) -KeywordSearchConfigurationPanel2.timeRadioButton4.toolTipText=1 minute (overall ingest time will be longest) +OpenIDE-Module-Display-Category=Ingest Module +OpenIDE-Module-Long-Description=\ + Keyword Search ingest module.\n\n\ + The module indexes files found in the disk image at ingest time. \ + It then periodically runs the search on the indexed files using one or more keyword lists (containing pure words and/or regular expressions) and posts results.\n\n\ + The module also contains additional tools integrated in the main GUI, such as keyword list configuration, keyword seach bar in the top-right corner, extracted text viewer and search results viewer showing highlighted keywords found. +OpenIDE-Module-Name=KeywordSearch +ListBundleName=Keyword Lists +ListBundleConfig=Keyword List Configuration +IndexProgressPanel.statusText.text=Status text +IndexProgressPanel.cancelButton.text=Cancel +ExtractedContentPanel.hitLabel.text=Matches on page: +ExtractedContentPanel.hitCountLabel.text=- +ExtractedContentPanel.hitOfLabel.text=of +ExtractedContentPanel.hitTotalLabel.text=- +ExtractedContentPanel.hitButtonsLabel.text=Match +ExtractedContentPanel.hitPreviousButton.text= +ExtractedContentPanel.hitNextButton.text= +ExtractedContentPanel.copyMenuItem.text=Copy +ExtractedContentPanel.selectAllMenuItem.text=Select All +KeywordSearchEditListPanel.saveListButton.text=Copy List +KeywordSearchEditListPanel.addWordField.text= +KeywordSearchEditListPanel.addWordButton.text=Add +KeywordSearchEditListPanel.chRegex.text=Regular Expression +KeywordSearchEditListPanel.deleteWordButton.text=Remove Selected +KeywordSearchEditListPanel.cutMenuItem.text=Cut +KeywordSearchEditListPanel.selectAllMenuItem.text=Select All +KeywordSearchEditListPanel.pasteMenuItem.text=Paste +KeywordSearchEditListPanel.copyMenuItem.text=Copy +KeywordSearchEditListPanel.exportButton.text=Export List +KeywordSearchEditListPanel.deleteListButton.text=Delete List +KeywordSearchListsManagementPanel.newListButton.text=New List +KeywordSearchEditListPanel.useForIngestCheckbox.text=Enable for ingest +KeywordSearchListsManagementPanel.importButton.text=Import List +KeywordSearchPanel.searchBox.text=Search... +KeywordSearchPanel.regExCheckboxMenuItem.text=Use Regular Expressions +KeywordSearchPanel.settingsLabel.text= +KeywordSearchListsViewerPanel.searchAddButton.text=Search +KeywordSearchListsViewerPanel.manageListsButton.text=Manage Lists +KeywordSearchListsViewerPanel.ingestIndexLabel.text=Files Indexed: +KeywordSearchEditListPanel.selectorsCombo.toolTipText=Regular Expression selector type (optional) +KeywordSearchPanel.searchButton.text= +KeywordSearchPanel.cutMenuItem.text=Cut +KeywordSearchPanel.copyMenuItem.text=Copy +KeywordSearchPanel.pasteMenuItem.text=Paste +KeywordSearchPanel.selectAllMenuItem.text=Select All +ExtractedContentPanel.pageButtonsLabel.text=Page +ExtractedContentPanel.pageNextButton.text= +ExtractedContentPanel.pagePreviousButton.actionCommand=pagePreviousButton +ExtractedContentPanel.pagePreviousButton.text= +ExtractedContentPanel.pagesLabel.text=Page: +ExtractedContentPanel.pageOfLabel.text=of +ExtractedContentPanel.pageCurLabel.text=- +ExtractedContentPanel.pageTotalLabel.text=- +ExtractedContentPanel.hitLabel.toolTipText= +KeywordSearchEditListPanel.ingestMessagesCheckbox.text=Enable sending messages to inbox during ingest +KeywordSearchEditListPanel.ingestMessagesCheckbox.toolTipText=Send messages during triage / ingest when hits on keyword from this list occur +KeywordSearchConfigurationPanel2.skipNSRLCheckBox.text=Do not add files in NSRL (known files) to keyword index during ingest +KeywordSearchConfigurationPanel2.skipNSRLCheckBox.toolTipText=Requires Hash DB service to had run previously, or be selected for next ingest. +KeywordSearchConfigurationPanel2.filesIndexedValue.text=- +KeywordSearchConfigurationPanel2.filesIndexedLabel.text=Files in keyword index: +KeywordSearchIngestSimplePanel.languagesLabel.text=Scripts enabled for string extraction from unknown file types: +KeywordSearchIngestSimplePanel.languagesValLabel.text=- +KeywordSearchIngestSimplePanel.languagesLabel.toolTipText=Scripts enabled for string extraction from unknown file types. Changes can be done in Advanced Settings. +KeywordSearchIngestSimplePanel.languagesValLabel.toolTipText= +KeywordSearchConfigurationPanel3.languagesLabel.text=Enabled scripts (languages): +KeywordSearchConfigurationPanel2.chunksLabel.text=Chunks in keyword index: +KeywordSearchConfigurationPanel2.chunksValLabel.text=- +KeywordSearchConfigurationPanel3.enableUTF8Checkbox.text=Enable UTF8 text extraction +KeywordSearchConfigurationPanel3.enableUTF16Checkbox.text=Enable UTF16LE and UTF16BE string extraction +KeywordSearchEditListPanel.keywordOptionsLabel.text=Keyword Options +KeywordSearchEditListPanel.listOptionsLabel.text=List Options +KeywordSearchConfigurationPanel3.ingestSettingsLabel.text=Ingest settings for string extraction from unknown file types (changes effective on next ingest): +KeywordSearchConfigurationPanel2.settingsLabel.text=Settings +KeywordSearchConfigurationPanel2.informationLabel.text=Information +KeywordSearchListsManagementPanel.keywordListsLabel.text=Keyword Lists: +KeywordSearchEditListPanel.keywordsLabel.text=Keywords: +KeywordSearchConfigurationPanel2.timeRadioButton1.toolTipText=20 mins. (fastest ingest time) +KeywordSearchConfigurationPanel2.timeRadioButton1.text=20 minutes (slowest feedback, fastest ingest) +KeywordSearchConfigurationPanel2.timeRadioButton2.toolTipText=10 minutes (faster overall ingest time than default) +KeywordSearchConfigurationPanel2.timeRadioButton2.text=10 minutes (slower feedback, faster ingest) +KeywordSearchConfigurationPanel2.timeRadioButton3.toolTipText=5 minutes (overall ingest time will be longer) +KeywordSearchConfigurationPanel2.timeRadioButton3.text=5 minutes (default) +KeywordSearchIngestSimplePanel.encodingsLabel.text=Encodings: +KeywordSearchIngestSimplePanel.keywordSearchEncodings.text=- +KeywordSearchIngestSimplePanel.titleLabel.text=Select keyword lists to enable during ingest: +OpenIDE-Module-Short-Description=Keyword Search ingest module, extracted text viewer and keyword search tools +KeywordSearchListsViewerPanel.manageListsButton.toolTipText=Manage keyword lists, their settings and associated keywords. The settings are shared among all cases. +KeywordSearchConfigurationPanel2.frequencyLabel.text=Results update frequency during ingest: +KeywordSearchConfigurationPanel2.timeRadioButton4.text_1=1 minute (faster feedback, longest ingest) +KeywordSearchConfigurationPanel2.timeRadioButton4.toolTipText=1 minute (overall ingest time will be longest) diff --git a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/docs/keywordsearch-about.html b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/docs/keywordsearch-about.html index ec2a45f056..b4290c98de 100644 --- a/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/docs/keywordsearch-about.html +++ b/KeywordSearch/src/org/sleuthkit/autopsy/keywordsearch/docs/keywordsearch-about.html @@ -1,81 +1,81 @@ - - - - - Keyword Search - - - - -

Keyword Search

-

- Autopsy ships a keyword search module, which provides the ingest capability - and also supports a manual text search mode. -

-

The keyword search ingest module extracts text from the files on the image being ingested and adds them to the index that can then be searched.

-

- Autopsy tries its best to extract maximum amount of text from the files being indexed. - First, the indexing will try to extract text from supported file formats, such as pure text file format, MS Office Documents, PDF files, Email files, and many others. - If the file is not supported by the standard text extractor, Autopsy will fallback to string extraction algorithm. - String extraction on unknown file formats or arbitrary binary files can often still extract a good amount of text from the file, often good enough to provide additional clues. - However, string extraction will not be able to extract text strings from binary files that have been encrypted. -

-

- Autopsy ships with some built-in lists that define regular expressions and enable user to search for Phone Numbers, IP addresses, URLs and E-mail addresses. - However, enabling some of these very general lists can produce a very large number of hits, many of them can be false-positives. -

-

- Once files are in the index, they can be searched quickly for specific keywords, regular expressions, - or using keyword search lists that can contain a mixture of keywords and regular expressions. - Search queries can be executed automatically by the ingest during the ingest run, or at the end of the ingest, depending on the current settings and the time it takes to ingest the image. -

-

Search queries can also be executed manually by the user at any time, as long as there are some files already indexed and ready to be searched.

-

- Keyword search module will save the search results regardless whether the search is performed by the ingest process, or manually by the user. - The saved results are available in the Directory Tree in the left hand side panel. -

-

- To see keyword search results in real-time while ingest is running, add keyword lists using the - Keyword Search Configuration Dialog - and select the "Use during ingest" check box. - You can select "Enable sending messages to inbox during ingest" per list, if the hits on that list should be reported in the Inbox, which is recommended for very specific searches. -

-

- See (Ingest) - for more information on ingest in general. -

-

- Once there are files in the index, the Keyword Search Bar - will be available for use to manually search at any time. -

- - - + + + + + Keyword Search + + + + +

Keyword Search

+

+ Autopsy ships a keyword search module, which provides the ingest capability + and also supports a manual text search mode. +

+

The keyword search ingest module extracts text from the files on the image being ingested and adds them to the index that can then be searched.

+

+ Autopsy tries its best to extract maximum amount of text from the files being indexed. + First, the indexing will try to extract text from supported file formats, such as pure text file format, MS Office Documents, PDF files, Email files, and many others. + If the file is not supported by the standard text extractor, Autopsy will fallback to string extraction algorithm. + String extraction on unknown file formats or arbitrary binary files can often still extract a good amount of text from the file, often good enough to provide additional clues. + However, string extraction will not be able to extract text strings from binary files that have been encrypted. +

+

+ Autopsy ships with some built-in lists that define regular expressions and enable user to search for Phone Numbers, IP addresses, URLs and E-mail addresses. + However, enabling some of these very general lists can produce a very large number of hits, many of them can be false-positives. +

+

+ Once files are in the index, they can be searched quickly for specific keywords, regular expressions, + or using keyword search lists that can contain a mixture of keywords and regular expressions. + Search queries can be executed automatically by the ingest during the ingest run, or at the end of the ingest, depending on the current settings and the time it takes to ingest the image. +

+

Search queries can also be executed manually by the user at any time, as long as there are some files already indexed and ready to be searched.

+

+ Keyword search module will save the search results regardless whether the search is performed by the ingest process, or manually by the user. + The saved results are available in the Directory Tree in the left hand side panel. +

+

+ To see keyword search results in real-time while ingest is running, add keyword lists using the + Keyword Search Configuration Dialog + and select the "Use during ingest" check box. + You can select "Enable sending messages to inbox during ingest" per list, if the hits on that list should be reported in the Inbox, which is recommended for very specific searches. +

+

+ See (Ingest) + for more information on ingest in general. +

+

+ Once there are files in the index, the Keyword Search Bar + will be available for use to manually search at any time. +

+ + + diff --git a/test/README.txt b/test/README.txt index d0064b4f95..854f5e1a33 100644 --- a/test/README.txt +++ b/test/README.txt @@ -1,13 +1,13 @@ -This folder contains the data and scripts required to run regression tests -for Autopsy. There is a 'Testing' folder in the root directory that contains -the Java code that drives Autopsy to perform the tests. - -To run these tests: -- You will need python3. We run this from within Cygwin. -- Download the input images by typing 'ant test-download-imgs' in the root Autopsy folder. - This will place images in 'test/input'. -- Run 'python3 regression.py' from inside of the 'test/scripts' folder. -- Alternatively, run 'python3 regression.py -l [CONFIGFILE] to run the tests on a specified - list of images using a configuration file. See config.xml in the 'test/scripts' folder to - see configuration file formatting. -- Run 'python3 regression.py -h' to see other options. +This folder contains the data and scripts required to run regression tests +for Autopsy. There is a 'Testing' folder in the root directory that contains +the Java code that drives Autopsy to perform the tests. + +To run these tests: +- You will need python3. We run this from within Cygwin. +- Download the input images by typing 'ant test-download-imgs' in the root Autopsy folder. + This will place images in 'test/input'. +- Run 'python3 regression.py' from inside of the 'test/scripts' folder. +- Alternatively, run 'python3 regression.py -l [CONFIGFILE] to run the tests on a specified + list of images using a configuration file. See config.xml in the 'test/scripts' folder to + see configuration file formatting. +- Run 'python3 regression.py -h' to see other options. diff --git a/test/script/Emailer.py b/test/script/Emailer.py index 5d12e6afa3..7e661e12ea 100644 --- a/test/script/Emailer.py +++ b/test/script/Emailer.py @@ -1,49 +1,49 @@ -import smtplib -from email.mime.image import MIMEImage -from email.mime.multipart import MIMEMultipart -from email.mime.text import MIMEText -from email.mime.base import MIMEBase -from email import encoders -import xml -from xml.dom.minidom import parse, parseString - -def send_email(to, server, subj, body, attachments): - """Send an email with the given information. - - Args: - to: a String, the email address to send the email to - server: a String, the mail server to send from - subj: a String, the subject line of the message - body: a String, the body of the message - attachments: a listof_pathto_File, the attachements to include - """ - msg = MIMEMultipart() - msg['Subject'] = subj - # me == the sender's email address - # family = the list of all recipients' email addresses - msg['From'] = 'AutopsyTest' - msg['To'] = to - msg.preamble = 'This is a test' - container = MIMEText(body, 'plain') - msg.attach(container) - Build_email(msg, attachments) - s = smtplib.SMTP(server) - try: - print('Sending Email') - s.sendmail(msg['From'], msg['To'], msg.as_string()) - except Exception as e: - print(str(e)) - s.quit() - -def Build_email(msg, attachments): - for file in attachments: - part = MIMEBase('application', "octet-stream") - atach = open(file, "rb") - attch = atach.read() - noml = file.split("\\") - nom = noml[len(noml)-1] - part.set_payload(attch) - encoders.encode_base64(part) - part.add_header('Content-Disposition', 'attachment; filename="' + nom + '"') - msg.attach(part) - +import smtplib +from email.mime.image import MIMEImage +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText +from email.mime.base import MIMEBase +from email import encoders +import xml +from xml.dom.minidom import parse, parseString + +def send_email(to, server, subj, body, attachments): + """Send an email with the given information. + + Args: + to: a String, the email address to send the email to + server: a String, the mail server to send from + subj: a String, the subject line of the message + body: a String, the body of the message + attachments: a listof_pathto_File, the attachements to include + """ + msg = MIMEMultipart() + msg['Subject'] = subj + # me == the sender's email address + # family = the list of all recipients' email addresses + msg['From'] = 'AutopsyTest' + msg['To'] = to + msg.preamble = 'This is a test' + container = MIMEText(body, 'plain') + msg.attach(container) + Build_email(msg, attachments) + s = smtplib.SMTP(server) + try: + print('Sending Email') + s.sendmail(msg['From'], msg['To'], msg.as_string()) + except Exception as e: + print(str(e)) + s.quit() + +def Build_email(msg, attachments): + for file in attachments: + part = MIMEBase('application', "octet-stream") + atach = open(file, "rb") + attch = atach.read() + noml = file.split("\\") + nom = noml[len(noml)-1] + part.set_payload(attch) + encoders.encode_base64(part) + part.add_header('Content-Disposition', 'attachment; filename="' + nom + '"') + msg.attach(part) + diff --git a/test/script/regression.py b/test/script/regression.py index b2ad319963..6c640823ed 100644 --- a/test/script/regression.py +++ b/test/script/regression.py @@ -1,1854 +1,1854 @@ -#!/usr/bin/python -# -*- coding: utf_8 -*- - - # Autopsy Forensic Browser - # - # Copyright 2013 Basis Technology Corp. - # - # 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. -from tskdbdiff import TskDbDiff, TskDbDiffException -import codecs -import datetime -import logging -import os -import re -import shutil -import socket -import sqlite3 -import subprocess -import sys -from sys import platform as _platform -import time -import traceback -import xml -from time import localtime, strftime -from xml.dom.minidom import parse, parseString -import smtplib -from email.mime.image import MIMEImage -from email.mime.multipart import MIMEMultipart -from email.mime.text import MIMEText -import re -import zipfile -import zlib -import Emailer -import srcupdater -from regression_utils import * - -# -# Please read me... -# -# This is the regression testing Python script. -# It uses an ant command to run build.xml for RegressionTest.java -# -# The code is cleanly sectioned and commented. -# Please follow the current formatting. -# It is a long and potentially confusing script. -# -# Variable, function, and class names are written in Python conventions: -# this_is_a_variable this_is_a_function() ThisIsAClass -# -# - - -# Data Definitions: -# -# pathto_X: A path to type X. -# ConfigFile: An XML file formatted according to the template in myconfig.xml -# ParsedConfig: A dom object that represents a ConfigFile -# SQLCursor: A cursor recieved from a connection to an SQL database -# Nat: A Natural Number -# Image: An image -# - -# Enumeration of database types used for the simplification of generating database paths -DBType = enum('OUTPUT', 'GOLD', 'BACKUP') - -# Common filename of the output and gold databases (although they are in different directories -DB_FILENAME = "autopsy.db" - -# Backup database filename -BACKUP_DB_FILENAME = "autopsy_backup.db" - -# TODO: Double check this purpose statement -# Folder name for gold standard database testing -AUTOPSY_TEST_CASE = "AutopsyTestCase" - -# TODO: Double check this purpose statement -# The filename of the log to store error messages -COMMON_LOG = "AutopsyErrors.txt" - -Day = 0 - -#----------------------# -# Main # -#----------------------# -def main(): - """Parse the command-line arguments, create the configuration, and run the tests.""" - args = Args() - parse_result = args.parse() - test_config = TestConfiguration(args) - # The arguments were given wrong: - if not parse_result: - return - if(not args.fr): - antin = ["ant"] - antin.append("-f") - antin.append(os.path.join("..","..","build.xml")) - antin.append("test-download-imgs") - if SYS is OS.CYGWIN: - subprocess.call(antin) - elif SYS is OS.WIN: - theproc = subprocess.Popen(antin, shell = True, stdout=subprocess.PIPE) - theproc.communicate() - # Otherwise test away! - TestRunner.run_tests(test_config) - - -class TestRunner(object): - """A collection of functions to run the regression tests.""" - - def run_tests(test_config): - """Run the tests specified by the main TestConfiguration. - - Executes the AutopsyIngest for each image and dispatches the results based on - the mode (rebuild or testing) - """ - test_data_list = [ TestData(image, test_config) for image in test_config.images ] - - Reports.html_add_images(test_config.html_log, test_config.images) - - logres =[] - for test_data in test_data_list: - Errors.clear_print_logs() - Errors.set_testing_phase(test_data.image) - if not (test_config.args.rebuild or os.path.exists(test_data.gold_archive)): - msg = "Gold standard doesn't exist, skipping image:" - Errors.print_error(msg) - Errors.print_error(test_data.gold_archive) - continue - TestRunner._run_autopsy_ingest(test_data) - - if test_config.args.rebuild: - TestRunner.rebuild(test_data) - else: - logres.append(TestRunner._run_test(test_data)) - test_data.printout = Errors.printout - test_data.printerror = Errors.printerror - - Reports.write_html_foot(test_config.html_log) - # TODO: move this elsewhere - if (len(logres)>0): - for lm in logres: - for ln in lm: - Errors.add_email_msg(ln) - - # TODO: possibly worth putting this in a sub method - if all([ test_data.overall_passed for test_data in test_data_list ]): - Errors.add_email_msg("All images passed.\n") - else: - msg = "The following images failed:\n" - for test_data in test_data_list: - if not test_data.overall_passed: - msg += "\t" + test_data.image + "\n" - Errors.add_email_msg(msg) - html = open(test_config.html_log) - Errors.add_email_attachment(html.name) - html.close() - - if test_config.email_enabled: - Emailer.send_email(test_config.mail_to, test_config.mail_server, - test_config.mail_subject, Errors.email_body, Errors.email_attachs) - - def _run_autopsy_ingest(test_data): - """Run Autopsy ingest for the image in the given TestData. - - Also generates the necessary logs for rebuilding or diff. - - Args: - test_data: the TestData to run the ingest on. - """ - if image_type(test_data.image_file) == IMGTYPE.UNKNOWN: - Errors.print_error("Error: Image type is unrecognized:") - Errors.print_error(test_data.image_file + "\n") - return - - logging.debug("--------------------") - logging.debug(test_data.image_name) - logging.debug("--------------------") - TestRunner._run_ant(test_data) - time.sleep(2) # Give everything a second to process - - try: - # Dump the database before we diff or use it for rebuild - TskDbDiff.dump_output_db(test_data.get_db_path(DBType.OUTPUT), test_data.get_db_dump_path(DBType.OUTPUT), - test_data.get_sorted_data_path(DBType.OUTPUT)) - except sqlite3.OperationalError as e: - print("Ingest did not run properly.", - "Make sure no other instances of Autopsy are open and try again.") - sys.exit() - - # merges logs into a single log for later diff / rebuild - copy_logs(test_data) - Logs.generate_log_data(test_data) - - TestRunner._handle_solr(test_data) - TestRunner._handle_exception(test_data) - - #TODO: figure out return type of _run_test (logres) - def _run_test(test_data): - """Compare the results of the output to the gold standard. - - Args: - test_data: the TestData - - Returns: - logres? - """ - TestRunner._extract_gold(test_data) - - # Look for core exceptions - # @@@ Should be moved to TestResultsDiffer, but it didn't know about logres -- need to look into that - logres = Logs.search_common_log("TskCoreException", test_data) - - TestResultsDiffer.run_diff(test_data) - test_data.overall_passed = (test_data.html_report_passed and - test_data.errors_diff_passed and test_data.db_diff_passed) - - Reports.generate_reports(test_data) - if(not test_data.overall_passed): - Errors.add_email_attachment(test_data.common_log_path) - return logres - - def _extract_gold(test_data): - """Extract gold archive file to output/gold/tmp/ - - Args: - test_data: the TestData - """ - extrctr = zipfile.ZipFile(test_data.gold_archive, 'r', compression=zipfile.ZIP_DEFLATED) - extrctr.extractall(test_data.main_config.gold) - extrctr.close - time.sleep(2) - - def _handle_solr(test_data): - """Clean up SOLR index if in keep mode (-k). - - Args: - test_data: the TestData - """ - if not test_data.main_config.args.keep: - if clear_dir(test_data.solr_index): - print_report([], "DELETE SOLR INDEX", "Solr index deleted.") - else: - print_report([], "KEEP SOLR INDEX", "Solr index has been kept.") - - def _handle_exception(test_data): - """If running in exception mode, print exceptions to log. - - Args: - test_data: the TestData - """ - if test_data.main_config.args.exception: - exceptions = search_logs(test_data.main_config.args.exception_string, test_data) - okay = ("No warnings or exceptions found containing text '" + - test_data.main_config.args.exception_string + "'.") - print_report(exceptions, "EXCEPTION", okay) - - def rebuild(test_data): - """Rebuild the gold standard with the given TestData. - - Copies the test-generated database and html report files into the gold directory. - """ - test_config = test_data.main_config - # Errors to print - errors = [] - # Delete the current gold standards - gold_dir = test_config.img_gold - clear_dir(test_config.img_gold) - tmpdir = make_path(gold_dir, test_data.image_name) - dbinpth = test_data.get_db_path(DBType.OUTPUT) - dboutpth = make_path(tmpdir, DB_FILENAME) - dataoutpth = make_path(tmpdir, test_data.image_name + "SortedData.txt") - dbdumpinpth = test_data.get_db_dump_path(DBType.OUTPUT) - dbdumpoutpth = make_path(tmpdir, test_data.image_name + "DBDump.txt") - if not os.path.exists(test_config.img_gold): - os.makedirs(test_config.img_gold) - if not os.path.exists(tmpdir): - os.makedirs(tmpdir) - try: - shutil.copy(dbinpth, dboutpth) - if file_exists(test_data.get_sorted_data_path(DBType.OUTPUT)): - shutil.copy(test_data.get_sorted_data_path(DBType.OUTPUT), dataoutpth) - shutil.copy(dbdumpinpth, dbdumpoutpth) - error_pth = make_path(tmpdir, test_data.image_name+"SortedErrors.txt") - shutil.copy(test_data.sorted_log, error_pth) - except IOError as e: - Errors.print_error(str(e)) - Errors.add_email_message("Not rebuilt properly") - print(str(e)) - print(traceback.format_exc()) - # Rebuild the HTML report - output_html_report_dir = test_data.get_html_report_path(DBType.OUTPUT) - gold_html_report_dir = make_path(tmpdir, "Report") - - try: - shutil.copytree(output_html_report_dir, gold_html_report_dir) - except OSError as e: - errors.append(e.error()) - except Exception as e: - errors.append("Error: Unknown fatal error when rebuilding the gold html report.") - errors.append(str(e) + "\n") - print(traceback.format_exc()) - oldcwd = os.getcwd() - zpdir = gold_dir - os.chdir(zpdir) - os.chdir("..") - img_gold = "tmp" - img_archive = make_path(test_data.image_name+"-archive.zip") - comprssr = zipfile.ZipFile(img_archive, 'w',compression=zipfile.ZIP_DEFLATED) - TestRunner.zipdir(img_gold, comprssr) - comprssr.close() - os.chdir(oldcwd) - del_dir(test_config.img_gold) - okay = "Sucessfully rebuilt all gold standards." - print_report(errors, "REBUILDING", okay) - - def zipdir(path, zip): - for root, dirs, files in os.walk(path): - for file in files: - zip.write(os.path.join(root, file)) - - def _run_ant(test_data): - """Construct and run the ant build command for the given TestData. - - Tests Autopsy by calling RegressionTest.java via the ant build file. - - Args: - test_data: the TestData - """ - test_config = test_data.main_config - # Set up the directories - if dir_exists(test_data.output_path): - shutil.rmtree(test_data.output_path) - os.makedirs(test_data.output_path) - test_data.ant = ["ant"] - test_data.ant.append("-v") - test_data.ant.append("-f") - # case.ant.append(case.build_path) - test_data.ant.append(os.path.join("..","..","Testing","build.xml")) - test_data.ant.append("regression-test") - test_data.ant.append("-l") - test_data.ant.append(test_data.antlog_dir) - test_data.ant.append("-Dimg_path=" + test_data.image_file) - test_data.ant.append("-Dknown_bad_path=" + test_config.known_bad_path) - test_data.ant.append("-Dkeyword_path=" + test_config.keyword_path) - test_data.ant.append("-Dnsrl_path=" + test_config.nsrl_path) - test_data.ant.append("-Dgold_path=" + test_config.gold) - test_data.ant.append("-Dout_path=" + - make_local_path(test_data.output_path)) - test_data.ant.append("-Dignore_unalloc=" + "%s" % test_config.args.unallocated) - test_data.ant.append("-Dtest.timeout=" + str(test_config.timeout)) - - Errors.print_out("Ingesting Image:\n" + test_data.image_file + "\n") - Errors.print_out("CMD: " + " ".join(test_data.ant)) - Errors.print_out("Starting test...\n") - antoutpth = make_local_path(test_data.main_config.output_dir, "antRunOutput.txt") - antout = open(antoutpth, "a") - if SYS is OS.CYGWIN: - subprocess.call(test_data.ant, stdout=subprocess.PIPE) - elif SYS is OS.WIN: - theproc = subprocess.Popen(test_data.ant, shell = True, stdout=subprocess.PIPE) - theproc.communicate() - antout.close() - - -class TestData(object): - """Container for the input and output of a single image. - - Represents data for the test of a single image, including path to the image, - database paths, etc. - - Attributes: - main_config: the global TestConfiguration - ant: a listof_String, the ant command for this TestData - image_file: a pathto_Image, the image for this TestData - image: a String, the image file's name - image_name: a String, the image file's name with a trailing (0) - output_path: pathto_Dir, the output directory for this TestData - autopsy_data_file: a pathto_File, the IMAGE_NAMEAutopsy_data.txt file - warning_log: a pathto_File, the AutopsyLogs.txt file - antlog_dir: a pathto_File, the antlog.txt file - test_dbdump: a pathto_File, the database dump, IMAGENAMEDump.txt - common_log_path: a pathto_File, the IMAGE_NAMECOMMON_LOG file - sorted_log: a pathto_File, the IMAGENAMESortedErrors.txt file - reports_dir: a pathto_Dir, the AutopsyTestCase/Reports folder - gold_data_dir: a pathto_Dir, the gold standard directory - gold_archive: a pathto_File, the gold standard archive - logs_dir: a pathto_Dir, the location where autopsy logs are stored - solr_index: a pathto_Dir, the locatino of the solr index - html_report_passed: a boolean, did the HTML report diff pass? - errors_diff_passed: a boolean, did the error diff pass? - db_diff_passed: a boolean, did the db diff pass? - overall_passed: a boolean, did the test pass? - total_test_time: a String representation of the test duration - start_date: a String representation of this TestData's start date - end_date: a String representation of the TestData's end date - total_ingest_time: a String representation of the total ingest time - artifact_count: a Nat, the number of artifacts - artifact_fail: a Nat, the number of artifact failures - heap_space: a String representation of TODO - service_times: a String representation of TODO - autopsy_version: a String, the version of autopsy that was run - ingest_messages: a Nat, the number of ingest messages - indexed_files: a Nat, the number of files indexed during the ingest - indexed_chunks: a Nat, the number of chunks indexed during the ingest - printerror: a listof_String, the error messages printed during this TestData's test - printout: a listof_String, the messages pritned during this TestData's test - """ - - def __init__(self, image, main_config): - """Init this TestData with it's image and the test configuration. - - Args: - image: the Image to be tested. - main_config: the global TestConfiguration. - """ - # Configuration Data - self.main_config = main_config - self.ant = [] - self.image_file = str(image) - # TODO: This 0 should be be refactored out, but it will require rebuilding and changing of outputs. - self.image = get_image_name(self.image_file) - self.image_name = self.image + "(0)" - # Directory structure and files - self.output_path = make_path(self.main_config.output_dir, self.image_name) - self.autopsy_data_file = make_path(self.output_path, self.image_name + "Autopsy_data.txt") - self.warning_log = make_local_path(self.output_path, "AutopsyLogs.txt") - self.antlog_dir = make_local_path(self.output_path, "antlog.txt") - self.test_dbdump = make_path(self.output_path, self.image_name + - "DBDump.txt") - self.common_log_path = make_local_path(self.output_path, self.image_name + COMMON_LOG) - self.sorted_log = make_local_path(self.output_path, self.image_name + "SortedErrors.txt") - self.reports_dir = make_path(self.output_path, AUTOPSY_TEST_CASE, "Reports") - self.gold_data_dir = make_path(self.main_config.img_gold, self.image_name) - self.gold_archive = make_path(self.main_config.gold, - self.image_name + "-archive.zip") - self.logs_dir = make_path(self.output_path, "logs") - self.solr_index = make_path(self.output_path, AUTOPSY_TEST_CASE, - "ModuleOutput", "KeywordSearch") - # Results and Info - self.html_report_passed = False - self.errors_diff_passed = False - self.db_diff_passed = False - self.overall_passed = False - # Ingest info - self.total_test_time = "" - self.start_date = "" - self.end_date = "" - self.total_ingest_time = "" - self.artifact_count = 0 - self.artifact_fail = 0 - self.heap_space = "" - self.service_times = "" - self.autopsy_version = "" - self.ingest_messages = 0 - self.indexed_files = 0 - self.indexed_chunks = 0 - # Error tracking - self.printerror = [] - self.printout = [] - - def ant_to_string(self): - string = "" - for arg in self.ant: - string += (arg + " ") - return string - - def get_db_path(self, db_type): - """Get the path to the database file that corresponds to the given DBType. - - Args: - DBType: the DBType of the path to be generated. - """ - if(db_type == DBType.GOLD): - db_path = make_path(self.gold_data_dir, DB_FILENAME) - elif(db_type == DBType.OUTPUT): - db_path = make_path(self.main_config.output_dir, self.image_name, AUTOPSY_TEST_CASE, DB_FILENAME) - else: - db_path = make_path(self.main_config.output_dir, self.image_name, AUTOPSY_TEST_CASE, BACKUP_DB_FILENAME) - return db_path - - def get_html_report_path(self, html_type): - """Get the path to the HTML Report folder that corresponds to the given DBType. - - Args: - DBType: the DBType of the path to be generated. - """ - if(html_type == DBType.GOLD): - return make_path(self.gold_data_dir, "Report") - else: - # Autopsy creates an HTML report folder in the form AutopsyTestCase DATE-TIME - # It's impossible to get the exact time the folder was created, but the folder - # we are looking for is the only one in the self.reports_dir folder - html_path = "" - for fs in os.listdir(self.reports_dir): - html_path = make_path(self.reports_dir, fs) - if os.path.isdir(html_path): - break - return make_path(html_path, os.listdir(html_path)[0]) - - def get_sorted_data_path(self, file_type): - """Get the path to the SortedData file that corresponds to the given DBType. - - Args: - file_type: the DBType of the path to be generated - """ - return self._get_path_to_file(file_type, "SortedData.txt") - - def get_sorted_errors_path(self, file_type): - """Get the path to the SortedErrors file that correspodns to the given - DBType. - - Args: - file_type: the DBType of the path to be generated - """ - return self._get_path_to_file(file_type, "SortedErrors.txt") - - def get_db_dump_path(self, file_type): - """Get the path to the DBDump file that corresponds to the given DBType. - - Args: - file_type: the DBType of the path to be generated - """ - return self._get_path_to_file(file_type, "DBDump.txt") - - def _get_path_to_file(self, file_type, file_name): - """Get the path to the specified file with the specified type. - - Args: - file_type: the DBType of the path to be generated - file_name: a String, the filename of the path to be generated - """ - full_filename = self.image_name + file_name - if(file_type == DBType.GOLD): - return make_path(self.gold_data_dir, full_filename) - else: - return make_path(self.output_path, full_filename) - - -class TestConfiguration(object): - """Container for test configuration data. - - The Master Test Configuration. Encapsulates consolidated high level input from - config XML file and command-line arguments. - - Attributes: - args: an Args, the command line arguments - output_dir: a pathto_Dir, the output directory - input_dir: a pathto_Dir, the input directory - gold: a pathto_Dir, the gold directory - img_gold: a pathto_Dir, the temp directory where gold images are unzipped to - csv: a pathto_File, the local csv file - global_csv: a pathto_File, the global csv file - html_log: a pathto_File - known_bad_path: - keyword_path: - nsrl_path: - build_path: a pathto_File, the ant build file which runs the tests - autopsy_version: - ingest_messages: a Nat, number of ingest messages - indexed_files: a Nat, the number of indexed files - indexed_chunks: a Nat, the number of indexed chunks - timer: - images: a listof_Image, the images to be tested - timeout: a Nat, the amount of time before killing the test - ant: a listof_String, the ant command to run the tests - """ - - def __init__(self, args): - """Inits TestConfiguration and loads a config file if available. - - Args: - args: an Args, the command line arguments. - """ - self.args = args - # Paths: - self.output_dir = "" - self.input_dir = make_local_path("..","input") - self.gold = make_path("..", "output", "gold") - self.img_gold = make_path(self.gold, 'tmp') - # Logs: - self.csv = "" - self.global_csv = "" - self.html_log = "" - # Ant info: - self.known_bad_path = make_path(self.input_dir, "notablehashes.txt-md5.idx") - self.keyword_path = make_path(self.input_dir, "notablekeywords.xml") - self.nsrl_path = make_path(self.input_dir, "nsrl.txt-md5.idx") - self.build_path = make_path("..", "build.xml") - # Infinite Testing info - timer = 0 - self.images = [] - # Email info - self.email_enabled = args.email_enabled - self.mail_server = "" - self.mail_to = "" - self.mail_subject = "" - # Set the timeout to something huge - # The entire tester should not timeout before this number in ms - # However it only seems to take about half this time - # And it's very buggy, so we're being careful - self.timeout = 24 * 60 * 60 * 1000 * 1000 - - if not self.args.single: - self._load_config_file(self.args.config_file) - else: - self.images.append(self.args.single_file) - self._init_logs() - #self._init_imgs() - #self._init_build_info() - - - def _load_config_file(self, config_file): - """Updates this TestConfiguration's attributes from the config file. - - Initializes this TestConfiguration by iterating through the XML config file - command-line argument. Populates self.images and optional email configuration - - Args: - config_file: ConfigFile - the configuration file to load - """ - try: - count = 0 - parsed_config = parse(config_file) - logres = [] - counts = {} - if parsed_config.getElementsByTagName("indir"): - self.input_dir = parsed_config.getElementsByTagName("indir")[0].getAttribute("value").encode().decode("utf_8") - if parsed_config.getElementsByTagName("global_csv"): - self.global_csv = parsed_config.getElementsByTagName("global_csv")[0].getAttribute("value").encode().decode("utf_8") - self.global_csv = make_local_path(self.global_csv) - if parsed_config.getElementsByTagName("golddir"): - self.gold = parsed_config.getElementsByTagName("golddir")[0].getAttribute("value").encode().decode("utf_8") - self.img_gold = make_path(self.gold, 'tmp') - - self._init_imgs(parsed_config) - self._init_build_info(parsed_config) - self._init_email_info(parsed_config) - - except IOError as e: - msg = "There was an error loading the configuration file.\n" - msg += "\t" + str(e) - Errors.add_email_msg(msg) - logging.critical(traceback.format_exc()) - print(traceback.format_exc()) - - def _init_logs(self): - """Setup output folder, logs, and reporting infrastructure.""" - if(not dir_exists(make_path("..", "output", "results"))): - os.makedirs(make_path("..", "output", "results",)) - self.output_dir = make_path("..", "output", "results", time.strftime("%Y.%m.%d-%H.%M.%S")) - os.makedirs(self.output_dir) - self.csv = make_local_path(self.output_dir, "CSV.txt") - self.html_log = make_path(self.output_dir, "AutopsyTestCase.html") - log_name = self.output_dir + "\\regression.log" - logging.basicConfig(filename=log_name, level=logging.DEBUG) - - def _init_build_info(self, parsed_config): - """Initializes paths that point to information necessary to run the AutopsyIngest.""" - build_elements = parsed_config.getElementsByTagName("build") - if build_elements: - build_element = build_elements[0] - build_path = build_element.getAttribute("value").encode().decode("utf_8") - self.build_path = build_path - - def _init_imgs(self, parsed_config): - """Initialize the list of images to run tests on.""" - for element in parsed_config.getElementsByTagName("image"): - value = element.getAttribute("value").encode().decode("utf_8") - print ("Image in Config File: " + value) - if file_exists(value): - self.images.append(value) - else: - msg = "File: " + value + " doesn't exist" - Errors.print_error(msg) - Errors.add_email_msg(msg) - image_count = len(self.images) - - # Sanity check to see if there are obvious gold images that we are not testing - gold_count = 0 - for file in os.listdir(self.gold): - if not(file == 'tmp'): - gold_count+=1 - - if (image_count > gold_count): - print("******Alert: There are more input images than gold standards, some images will not be properly tested.\n") - elif (image_count < gold_count): - print("******Alert: There are more gold standards than input images, this will not check all gold Standards.\n") - - def _init_email_info(self, parsed_config): - """Initializes email information dictionary""" - email_elements = parsed_config.getElementsByTagName("email") - if email_elements: - mail_to = email_elements[0] - self.mail_to = mail_to.getAttribute("value").encode().decode("utf_8") - mail_server_elements = parsed_config.getElementsByTagName("mail_server") - if mail_server_elements: - mail_from = mail_server_elements[0] - self.mail_server = mail_from.getAttribute("value").encode().decode("utf_8") - subject_elements = parsed_config.getElementsByTagName("subject") - if subject_elements: - subject = subject_elements[0] - self.mail_subject = subject.getAttribute("value").encode().decode("utf_8") - if self.mail_server and self.mail_to and self.args.email_enabled: - self.email_enabled = True - print("Email will be sent to ", self.mail_to) - else: - print("No email will be sent.") - - -#-------------------------------------------------# -# Functions relating to comparing outputs # -#-------------------------------------------------# -class TestResultsDiffer(object): - """Compares results for a single test.""" - - def run_diff(test_data): - """Compares results for a single test. - - Args: - test_data: the TestData to use. - databaseDiff: TskDbDiff object created based off test_data - """ - try: - output_db = test_data.get_db_path(DBType.OUTPUT) - gold_db = test_data.get_db_path(DBType.GOLD) - output_dir = test_data.output_path - gold_bb_dump = test_data.get_sorted_data_path(DBType.GOLD) - gold_dump = test_data.get_db_dump_path(DBType.GOLD) - test_data.db_diff_pass = all(TskDbDiff(output_db, gold_db, output_dir=output_dir, gold_bb_dump=gold_bb_dump, - gold_dump=gold_dump).run_diff()) - - # Compare Exceptions - # replace is a fucntion that replaces strings of digits with 'd' - # this is needed so dates and times will not cause the diff to fail - replace = lambda file: re.sub(re.compile("\d"), "d", file) - output_errors = test_data.get_sorted_errors_path(DBType.OUTPUT) - gold_errors = test_data.get_sorted_errors_path(DBType.GOLD) - passed = TestResultsDiffer._compare_text(output_errors, gold_errors, - replace) - test_data.errors_diff_passed = passed - - # Compare html output - gold_report_path = test_data.get_html_report_path(DBType.GOLD) - output_report_path = test_data.get_html_report_path(DBType.OUTPUT) - passed = TestResultsDiffer._html_report_diff(gold_report_path, - output_report_path) - test_data.html_report_passed = passed - - # Clean up tmp folder - del_dir(test_data.gold_data_dir) - - except sqlite3.OperationalError as e: - Errors.print_error("Tests failed while running the diff:\n") - Errors.print_error(str(e)) - except TskDbDiffException as e: - Errors.print_error(str(e)) - except Exception as e: - Errors.print_error("Tests failed due to an error, try rebuilding or creating gold standards.\n") - Errors.print_error(str(e) + "\n") - print(traceback.format_exc()) - - def _compare_text(output_file, gold_file, process=None): - """Compare two text files. - - Args: - output_file: a pathto_File, the output text file - gold_file: a pathto_File, the input text file - pre-process: (optional) a function of String -> String that will be - called on each input file before the diff, if specified. - """ - if(not file_exists(output_file)): - return False - output_data = codecs.open(output_file, "r", "utf_8").read() - gold_data = codecs.open(gold_file, "r", "utf_8").read() - - if process is not None: - output_data = process(output_data) - gold_data = process(gold_data) - - if (not(gold_data == output_data)): - diff_path = os.path.splitext(os.path.basename(output_file))[0] - diff_path += "-Diff.txt" - diff_file = codecs.open(diff_path, "wb", "utf_8") - dffcmdlst = ["diff", output_file, gold_file] - subprocess.call(dffcmdlst, stdout = diff_file) - Errors.add_email_attachment(diff_path) - msg = "There was a difference in " - msg += os.path.basename(output_file) + ".\n" - Errors.add_email_msg(msg) - Errors.print_error(msg) - return False - else: - return True - - def _html_report_diff(gold_report_path, output_report_path): - """Compare the output and gold html reports. - - Args: - gold_report_path: a pathto_Dir, the gold HTML report directory - output_report_path: a pathto_Dir, the output HTML report directory - - Returns: - true, if the reports match, false otherwise. - """ - try: - gold_html_files = get_files_by_ext(gold_report_path, ".html") - output_html_files = get_files_by_ext(output_report_path, ".html") - - #ensure both reports have the same number of files and are in the same order - if(len(gold_html_files) != len(output_html_files)): - msg = "The reports did not have the same number or files." - msg += "One of the reports may have been corrupted." - Errors.print_error(msg) - else: - gold_html_files.sort() - output_html_files.sort() - - total = {"Gold": 0, "New": 0} - for gold, output in zip(gold_html_files, output_html_files): - count = TestResultsDiffer._compare_report_files(gold, output) - total["Gold"] += count[0] - total["New"] += count[1] - - okay = "The test report matches the gold report." - errors=["Gold report had " + str(total["Gold"]) +" errors", "New report had " + str(total["New"]) + " errors."] - print_report(errors, "REPORT COMPARISON", okay) - - if total["Gold"] == total["New"]: - return True - else: - Errors.print_error("The reports did not match each other.\n " + errors[0] +" and the " + errors[1]) - return False - except OSError as e: - e.print_error() - return False - except Exception as e: - Errors.print_error("Error: Unknown fatal error comparing reports.") - Errors.print_error(str(e) + "\n") - logging.critical(traceback.format_exc()) - return False - - def _compare_report_files(a_path, b_path): - """Compares the two specified report html files. - - Args: - a_path: a pathto_File, the first html report file - b_path: a pathto_File, the second html report file - - Returns: - a tuple of (Nat, Nat), which represent the length of each - unordered list in the html report files, or (0, 0) if the - lenghts are the same. - """ - a_file = open(a_path) - b_file = open(b_path) - a = a_file.read() - b = b_file.read() - a = a[a.find("
    "):] - b = b[b.find("
      "):] - - a_list = TestResultsDiffer._split(a, 50) - b_list = TestResultsDiffer._split(b, 50) - if not len(a_list) == len(b_list): - ex = (len(a_list), len(b_list)) - return ex - else: - return (0, 0) - - # Split a string into an array of string of the given size - def _split(input, size): - return [input[start:start+size] for start in range(0, len(input), size)] - - -class Reports(object): - def generate_reports(test_data): - """Generate the reports for a single test - - Args: - test_data: the TestData - """ - Reports._generate_html(test_data) - if test_data.main_config.global_csv: - Reports._generate_csv(test_data.main_config.global_csv, test_data) - else: - Reports._generate_csv(test_data.main_config.csv, test_data) - - def _generate_html(test_data): - """Generate the HTML log file.""" - # If the file doesn't exist yet, this is the first test_config to run for - # this test, so we need to make the start of the html log - html_log = test_data.main_config.html_log - if not file_exists(html_log): - Reports.write_html_head() - with open(html_log, "a") as html: - # The image title - title = "

      " + test_data.image_name + " \ - tested on " + socket.gethostname() + "

      \ -

      \ - Errors and Warnings |\ - Information |\ - General Output |\ - Logs\ -

      " - # The script errors found - if not test_data.overall_passed: - ids = 'errors1' - else: - ids = 'errors' - errors = "
      \ -

      Errors and Warnings

      \ -
      " - # For each error we have logged in the test_config - for error in test_data.printerror: - # Replace < and > to avoid any html display errors - errors += "

      " + error.replace("<", "<").replace(">", ">") + "

      " - # If there is a \n, we probably want a
      in the html - if "\n" in error: - errors += "
      " - errors += "
      " - - # Links to the logs - logs = "
      \ -

      Logs

      \ -
      " - logs_path = test_data.logs_dir - for file in os.listdir(logs_path): - logs += "

      " + file + "

      " - logs += "
      " - - # All the testing information - info = "
      \ -

      Information

      \ -
      \ -
" - # The individual elements - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" - info += "" -# info += "" -# info += "" -# info += "" -# info += "" -# info += "" -# info += "" - info += "
Image Path:" + test_data.image_file + "
Image Name:" + test_data.image_name + "
test_config Output Directory:" + test_data.main_config.output_dir + "
Autopsy Version:" + test_data.autopsy_version + "
Heap Space:" + test_data.heap_space + "
Test Start Date:" + test_data.start_date + "
Test End Date:" + test_data.end_date + "
Total Test Time:" + test_data.total_test_time + "
Total Ingest Time:" + test_data.total_ingest_time + "
Exceptions Count:" + str(len(get_exceptions(test_data))) + "
Autopsy OutOfMemoryExceptions:" + str(len(search_logs("OutOfMemoryException", test_data))) + "
Autopsy OutOfMemoryErrors:" + str(len(search_logs("OutOfMemoryError", test_data))) + "
Tika OutOfMemoryErrors/Exceptions:" + str(Reports._get_num_memory_errors("tika", test_data)) + "
Solr OutOfMemoryErrors/Exceptions:" + str(Reports._get_num_memory_errors("solr", test_data)) + "
TskCoreExceptions:" + str(len(search_log_set("autopsy", "TskCoreException", test_data))) + "
TskDataExceptions:" + str(len(search_log_set("autopsy", "TskDataException", test_data))) + "
Ingest Messages Count:" + str(test_data.ingest_messages) + "
Indexed Files Count:" + str(test_data.indexed_files) + "
Indexed File Chunks Count:" + str(test_data.indexed_chunks) + "
Out Of Disk Space:\ -

(will skew other test results)

" + str(len(search_log_set("autopsy", "Stopping ingest due to low disk space on disk", test_data))) + "
TSK Objects Count:" + str(test_data.db_diff_results.output_objs) + "
Artifacts Count:" + str(test_data.db_diff_results.output_artifacts)+ "
Attributes Count:" + str(test_data.db_diff_results.output_attrs) + "
\ -
" - # For all the general print statements in the test_config - output = "
\ -

General Output

\ -
" - # For each printout in the test_config's list - for out in test_data.printout: - output += "

" + out + "

" - # If there was a \n it probably means we want a
in the html - if "\n" in out: - output += "
" - output += "
" - - html.write(title) - html.write(errors) - html.write(info) - html.write(logs) - html.write(output) - - def write_html_head(html_log): - """Write the top of the HTML log file. - - Args: - html_log: a pathto_File, the global HTML log - """ - with open(str(html_log), "a") as html: - head = "\ - \ - AutopsyTesttest_config Output\ - \ - \ - " - html.write(head) - - def write_html_foot(html_log): - """Write the bottom of the HTML log file. - - Args: - html_log: a pathto_File, the global HTML log - """ - with open(html_log, "a") as html: - head = "" - html.write(head) - - def html_add_images(html_log, full_image_names): - """Add all the image names to the HTML log. - - Args: - full_image_names: a listof_String, each representing an image name - html_log: a pathto_File, the global HTML log - """ - # If the file doesn't exist yet, this is the first test_config to run for - # this test, so we need to make the start of the html log - if not file_exists(html_log): - Reports.write_html_head(html_log) - with open(html_log, "a") as html: - links = [] - for full_name in full_image_names: - name = get_image_name(full_name) - links.append("" + name + "") - html.write("

" + (" | ".join(links)) + "

") - - def _generate_csv(csv_path, test_data): - """Generate the CSV log file""" - # If the CSV file hasn't already been generated, this is the - # first run, and we need to add the column names - if not file_exists(csv_path): - Reports.csv_header(csv_path) - # Now add on the fields to a new row - with open(csv_path, "a") as csv: - # Variables that need to be written - vars = [] - vars.append( test_data.image_file ) - vars.append( test_data.image_name ) - vars.append( test_data.main_config.output_dir ) - vars.append( socket.gethostname() ) - vars.append( test_data.autopsy_version ) - vars.append( test_data.heap_space ) - vars.append( test_data.start_date ) - vars.append( test_data.end_date ) - vars.append( test_data.total_test_time ) - vars.append( test_data.total_ingest_time ) - vars.append( test_data.service_times ) - vars.append( str(len(get_exceptions(test_data))) ) - vars.append( str(Reports._get_num_memory_errors("autopsy", test_data)) ) - vars.append( str(Reports._get_num_memory_errors("tika", test_data)) ) - vars.append( str(Reports._get_num_memory_errors("solr", test_data)) ) - vars.append( str(len(search_log_set("autopsy", "TskCoreException", test_data))) ) - vars.append( str(len(search_log_set("autopsy", "TskDataException", test_data))) ) - vars.append( str(test_data.ingest_messages) ) - vars.append( str(test_data.indexed_files) ) - vars.append( str(test_data.indexed_chunks) ) - vars.append( str(len(search_log_set("autopsy", "Stopping ingest due to low disk space on disk", test_data))) ) -# vars.append( str(test_data.db_diff_results.output_objs) ) -# vars.append( str(test_data.db_diff_results.output_artifacts) ) -# vars.append( str(test_data.db_diff_results.output_objs) ) - vars.append( make_local_path("gold", test_data.image_name, DB_FILENAME) ) -# vars.append( test_data.db_diff_results.get_artifact_comparison() ) -# vars.append( test_data.db_diff_results.get_attribute_comparison() ) - vars.append( make_local_path("gold", test_data.image_name, "standard.html") ) - vars.append( str(test_data.html_report_passed) ) - vars.append( test_data.ant_to_string() ) - # Join it together with a ", " - output = "|".join(vars) - output += "\n" - # Write to the log! - csv.write(output) - - def csv_header(csv_path): - """Generate the CSV column names.""" - with open(csv_path, "w") as csv: - titles = [] - titles.append("Image Path") - titles.append("Image Name") - titles.append("Output test_config Directory") - titles.append("Host Name") - titles.append("Autopsy Version") - titles.append("Heap Space Setting") - titles.append("Test Start Date") - titles.append("Test End Date") - titles.append("Total Test Time") - titles.append("Total Ingest Time") - titles.append("Service Times") - titles.append("Autopsy Exceptions") - titles.append("Autopsy OutOfMemoryErrors/Exceptions") - titles.append("Tika OutOfMemoryErrors/Exceptions") - titles.append("Solr OutOfMemoryErrors/Exceptions") - titles.append("TskCoreExceptions") - titles.append("TskDataExceptions") - titles.append("Ingest Messages Count") - titles.append("Indexed Files Count") - titles.append("Indexed File Chunks Count") - titles.append("Out Of Disk Space") -# titles.append("Tsk Objects Count") -# titles.append("Artifacts Count") -# titles.append("Attributes Count") - titles.append("Gold Database Name") -# titles.append("Artifacts Comparison") -# titles.append("Attributes Comparison") - titles.append("Gold Report Name") - titles.append("Report Comparison") - titles.append("Ant Command Line") - output = "|".join(titles) - output += "\n" - csv.write(output) - - def _get_num_memory_errors(type, test_data): - """Get the number of OutOfMemory errors and Exceptions. - - Args: - type: a String representing the type of log to check. - test_data: the TestData to examine. - """ - return (len(search_log_set(type, "OutOfMemoryError", test_data)) + - len(search_log_set(type, "OutOfMemoryException", test_data))) - -class Logs(object): - - def generate_log_data(test_data): - """Find and handle relevent data from the Autopsy logs. - - Args: - test_data: the TestData whose logs to examine - """ - Logs._generate_common_log(test_data) - try: - Logs._fill_ingest_data(test_data) - except Exception as e: - Errors.print_error("Error: Unknown fatal error when filling test_config data.") - Errors.print_error(str(e) + "\n") - logging.critical(traceback.format_exc()) - # If running in verbose mode (-v) - if test_data.main_config.args.verbose: - errors = Logs._report_all_errors() - okay = "No warnings or errors in any log files." - print_report(errors, "VERBOSE", okay) - - def _generate_common_log(test_data): - """Generate the common log, the log of all exceptions and warnings from - each log file generated by Autopsy. - - Args: - test_data: the TestData to generate a log for - """ - try: - logs_path = test_data.logs_dir - common_log = codecs.open(test_data.common_log_path, "w", "utf_8") - warning_log = codecs.open(test_data.warning_log, "w", "utf_8") - common_log.write("--------------------------------------------------\n") - common_log.write(test_data.image_name + "\n") - common_log.write("--------------------------------------------------\n") - rep_path = make_local_path(test_data.main_config.output_dir) - rep_path = rep_path.replace("\\\\", "\\") - for file in os.listdir(logs_path): - log = codecs.open(make_path(logs_path, file), "r", "utf_8") - for line in log: - line = line.replace(rep_path, "test_data") - if line.startswith("Exception"): - common_log.write(file +": " + line) - elif line.startswith("Error"): - common_log.write(file +": " + line) - elif line.startswith("SEVERE"): - common_log.write(file +":" + line) - else: - warning_log.write(file +": " + line) - log.close() - common_log.write("\n") - common_log.close() - print(test_data.sorted_log) - srtcmdlst = ["sort", test_data.common_log_path, "-o", test_data.sorted_log] - subprocess.call(srtcmdlst) - except (OSError, IOError) as e: - Errors.print_error("Error: Unable to generate the common log.") - Errors.print_error(str(e) + "\n") - Errors.print_error(traceback.format_exc()) - logging.critical(traceback.format_exc()) - - def _fill_ingest_data(test_data): - """Fill the TestDatas variables that require the log files. - - Args: - test_data: the TestData to modify - """ - try: - # Open autopsy.log.0 - log_path = make_path(test_data.logs_dir, "autopsy.log.0") - log = open(log_path) - - # Set the TestData start time based off the first line of autopsy.log.0 - # *** If logging time format ever changes this will break *** - test_data.start_date = log.readline().split(" org.")[0] - - # Set the test_data ending time based off the "create" time (when the file was copied) - test_data.end_date = time.ctime(os.path.getmtime(log_path)) - except IOError as e: - Errors.print_error("Error: Unable to open autopsy.log.0.") - Errors.print_error(str(e) + "\n") - logging.warning(traceback.format_exc()) - # Start date must look like: "Jul 16, 2012 12:57:53 PM" - # End date must look like: "Mon Jul 16 13:02:42 2012" - # *** If logging time format ever changes this will break *** - start = datetime.datetime.strptime(test_data.start_date, "%b %d, %Y %I:%M:%S %p") - end = datetime.datetime.strptime(test_data.end_date, "%a %b %d %H:%M:%S %Y") - test_data.total_test_time = str(end - start) - - try: - # Set Autopsy version, heap space, ingest time, and service times - - version_line = search_logs("INFO: Application name: Autopsy, version:", test_data)[0] - test_data.autopsy_version = get_word_at(version_line, 5).rstrip(",") - - test_data.heap_space = search_logs("Heap memory usage:", test_data)[0].rstrip().split(": ")[1] - - ingest_line = search_logs("Ingest (including enqueue)", test_data)[0] - test_data.total_ingest_time = get_word_at(ingest_line, 6).rstrip() - - message_line = search_log_set("autopsy", "Ingest messages count:", test_data)[0] - test_data.ingest_messages = int(message_line.rstrip().split(": ")[2]) - - files_line = search_log_set("autopsy", "Indexed files count:", test_data)[0] - test_data.indexed_files = int(files_line.rstrip().split(": ")[2]) - - chunks_line = search_log_set("autopsy", "Indexed file chunks count:", test_data)[0] - test_data.indexed_chunks = int(chunks_line.rstrip().split(": ")[2]) - except (OSError, IOError) as e: - Errors.print_error("Error: Unable to find the required information to fill test_config data.") - Errors.print_error(str(e) + "\n") - logging.critical(traceback.format_exc()) - print(traceback.format_exc()) - try: - service_lines = search_log("autopsy.log.0", "to process()", test_data) - service_list = [] - for line in service_lines: - words = line.split(" ") - # Kind of forcing our way into getting this data - # If this format changes, the tester will break - i = words.index("secs.") - times = words[i-4] + " " - times += words[i-3] + " " - times += words[i-2] + " " - times += words[i-1] + " " - times += words[i] - service_list.append(times) - test_data.service_times = "; ".join(service_list) - except (OSError, IOError) as e: - Errors.print_error("Error: Unknown fatal error when finding service times.") - Errors.print_error(str(e) + "\n") - logging.critical(traceback.format_exc()) - - def _report_all_errors(): - """Generate a list of all the errors found in the common log. - - Returns: - a listof_String, the errors found in the common log - """ - try: - return get_warnings() + get_exceptions() - except (OSError, IOError) as e: - Errors.print_error("Error: Unknown fatal error when reporting all errors.") - Errors.print_error(str(e) + "\n") - logging.warning(traceback.format_exc()) - - def search_common_log(string, test_data): - """Search the common log for any instances of a given string. - - Args: - string: the String to search for. - test_data: the TestData that holds the log to search. - - Returns: - a listof_String, all the lines that the string is found on - """ - results = [] - log = codecs.open(test_data.common_log_path, "r", "utf_8") - for line in log: - if string in line: - results.append(line) - log.close() - return results - - -def print_report(errors, name, okay): - """Print a report with the specified information. - - Args: - errors: a listof_String, the errors to report. - name: a String, the name of the report. - okay: the String to print when there are no errors. - """ - if errors: - Errors.print_error("--------< " + name + " >----------") - for error in errors: - Errors.print_error(str(error)) - Errors.print_error("--------< / " + name + " >--------\n") - else: - Errors.print_out("-----------------------------------------------------------------") - Errors.print_out("< " + name + " - " + okay + " />") - Errors.print_out("-----------------------------------------------------------------\n") - - -def get_exceptions(test_data): - """Get a list of the exceptions in the autopsy logs. - - Args: - test_data: the TestData to use to find the exceptions. - Returns: - a listof_String, the exceptions found in the logs. - """ - exceptions = [] - logs_path = test_data.logs_dir - results = [] - for file in os.listdir(logs_path): - if "autopsy.log" in file: - log = codecs.open(make_path(logs_path, file), "r", "utf_8") - ex = re.compile("\SException") - er = re.compile("\SError") - for line in log: - if ex.search(line) or er.search(line): - exceptions.append(line) - log.close() - return exceptions - -def get_warnings(test_data): - """Get a list of the warnings listed in the common log. - - Args: - test_data: the TestData to use to find the warnings - - Returns: - listof_String, the warnings found. - """ - warnings = [] - common_log = codecs.open(test_data.warning_log, "r", "utf_8") - for line in common_log: - if "warning" in line.lower(): - warnings.append(line) - common_log.close() - return warnings - -def copy_logs(test_data): - """Copy the Autopsy generated logs to output directory. - - Args: - test_data: the TestData whose logs will be copied - """ - try: - log_dir = os.path.join("..", "..", "Testing","build","test","qa-functional","work","userdir0","var","log") - shutil.copytree(log_dir, test_data.logs_dir) - except OSError as e: - printerror(test_data,"Error: Failed to copy the logs.") - printerror(test_data,str(e) + "\n") - logging.warning(traceback.format_exc()) - -def setDay(): - global Day - Day = int(strftime("%d", localtime())) - -def getLastDay(): - return Day - -def getDay(): - return int(strftime("%d", localtime())) - -def newDay(): - return getLastDay() != getDay() - -#------------------------------------------------------------# -# Exception classes to manage "acceptable" thrown exceptions # -# versus unexpected and fatal exceptions # -#------------------------------------------------------------# - -class FileNotFoundException(Exception): - """ - If a file cannot be found by one of the helper functions, - they will throw a FileNotFoundException unless the purpose - is to return False. - """ - def __init__(self, file): - self.file = file - self.strerror = "FileNotFoundException: " + file - - def print_error(self): - Errors.print_error("Error: File could not be found at:") - Errors.print_error(self.file + "\n") - - def error(self): - error = "Error: File could not be found at:\n" + self.file + "\n" - return error - -class DirNotFoundException(Exception): - """ - If a directory cannot be found by a helper function, - it will throw this exception - """ - def __init__(self, dir): - self.dir = dir - self.strerror = "DirNotFoundException: " + dir - - def print_error(self): - Errors.print_error("Error: Directory could not be found at:") - Errors.print_error(self.dir + "\n") - - def error(self): - error = "Error: Directory could not be found at:\n" + self.dir + "\n" - return error - - -class Errors: - """A class used to manage error reporting. - - Attributes: - printout: a listof_String, the non-error messages that were printed - printerror: a listof_String, the error messages that were printed - email_body: a String, the body of the report email - email_msg_prefix: a String, the prefix for lines added to the email - email_attchs: a listof_pathto_File, the files to be attached to the - report email - """ - printout = [] - printerror = [] - email_body = "" - email_msg_prefix = "Configuration" - email_attachs = [] - - def set_testing_phase(image_name): - """Change the email message prefix to be the given testing phase. - - Args: - image_name: a String, representing the current image being tested - """ - Errors.email_msg_prefix = image_name - - def print_out(msg): - """Print out an informational message. - - Args: - msg: a String, the message to be printed - """ - print(msg) - Errors.printout.append(msg) - - def print_error(msg): - """Print out an error message. - - Args: - msg: a String, the error message to be printed. - """ - print(msg) - Errors.printerror.append(msg) - - def clear_print_logs(): - """Reset the image-specific attributes of the Errors class.""" - Errors.printout = [] - Errors.printerror = [] - - def add_email_msg(msg): - """Add the given message to the body of the report email. - - Args: - msg: a String, the message to be added to the email - """ - Errors.email_body += Errors.email_msg_prefix + ":" + msg - - def add_email_attachment(path): - """Add the given file to be an attachment for the report email - - Args: - file: a pathto_File, the file to add - """ - Errors.email_attachs.append(path) - - -class DiffResults(object): - """Container for the results of the database diff tests. - - Stores artifact, object, and attribute counts and comparisons generated by - TskDbDiff. - - Attributes: - gold_attrs: a Nat, the number of gold attributes - output_attrs: a Nat, the number of output attributes - gold_objs: a Nat, the number of gold objects - output_objs: a Nat, the number of output objects - artifact_comp: a listof_String, describing the differences - attribute_comp: a listof_String, describing the differences - passed: a boolean, did the diff pass? - """ - def __init__(self, tsk_diff): - """Inits a DiffResults - - Args: - tsk_diff: a TskDBDiff - """ - self.gold_attrs = tsk_diff.gold_attributes - self.output_attrs = tsk_diff.autopsy_attributes - self.gold_objs = tsk_diff.gold_objects - self.output_objs = tsk_diff.autopsy_objects - self.artifact_comp = tsk_diff.artifact_comparison - self.attribute_comp = tsk_diff.attribute_comparison - self.gold_artifacts = len(tsk_diff.gold_artifacts) - self.output_artifacts = len(tsk_diff.autopsy_artifacts) - self.passed = tsk_diff.passed - - def get_artifact_comparison(self): - if not self.artifact_comp: - return "All counts matched" - else: - return "; ".join(self.artifact_comp) - - def get_attribute_comparison(self): - if not self.attribute_comp: - return "All counts matched" - list = [] - for error in self.attribute_comp: - list.append(error) - return ";".join(list) - - -#-------------------------------------------------------------# -# Parses argv and stores booleans to match command line input # -#-------------------------------------------------------------# -class Args(object): - """A container for command line options and arguments. - - Attributes: - single: a boolean indicating whether to run in single file mode - single_file: an Image to run the test on - rebuild: a boolean indicating whether to run in rebuild mode - list: a boolean indicating a config file was specified - unallocated: a boolean indicating unallocated space should be ignored - ignore: a boolean indicating the input directory should be ingnored - keep: a boolean indicating whether to keep the SOLR index - verbose: a boolean indicating whether verbose output should be printed - exeception: a boolean indicating whether errors containing exception - exception_string should be printed - exception_sring: a String representing and exception name - fr: a boolean indicating whether gold standard images will be downloaded - """ - def __init__(self): - self.single = False - self.single_file = "" - self.rebuild = False - self.list = False - self.config_file = "" - self.unallocated = False - self.ignore = False - self.keep = False - self.verbose = False - self.exception = False - self.exception_string = "" - self.fr = False - self.email_enabled = False - - def parse(self): - """Get the command line arguments and parse them.""" - nxtproc = [] - nxtproc.append("python3") - nxtproc.append(sys.argv.pop(0)) - while sys.argv: - arg = sys.argv.pop(0) - nxtproc.append(arg) - if(arg == "-f"): - #try: @@@ Commented out until a more specific except statement is added - arg = sys.argv.pop(0) - print("Running on a single file:") - print(path_fix(arg) + "\n") - self.single = True - self.single_file = path_fix(arg) - #except: - # print("Error: No single file given.\n") - # return False - elif(arg == "-r" or arg == "--rebuild"): - print("Running in rebuild mode.\n") - self.rebuild = True - elif(arg == "-l" or arg == "--list"): - try: - arg = sys.argv.pop(0) - nxtproc.append(arg) - print("Running from configuration file:") - print(arg + "\n") - self.list = True - self.config_file = arg - except: - print("Error: No configuration file given.\n") - return False - elif(arg == "-u" or arg == "--unallocated"): - print("Ignoring unallocated space.\n") - self.unallocated = True - elif(arg == "-k" or arg == "--keep"): - print("Keeping the Solr index.\n") - self.keep = True - elif(arg == "-v" or arg == "--verbose"): - print("Running in verbose mode:") - print("Printing all thrown exceptions.\n") - self.verbose = True - elif(arg == "-e" or arg == "--exception"): - try: - arg = sys.argv.pop(0) - nxtproc.append(arg) - print("Running in exception mode: ") - print("Printing all exceptions with the string '" + arg + "'\n") - self.exception = True - self.exception_string = arg - except: - print("Error: No exception string given.") - elif arg == "-h" or arg == "--help": - print(usage()) - return False - elif arg == "-fr" or arg == "--forcerun": - print("Not downloading new images") - self.fr = True - elif arg == "-e" or arg == "-email": - self.email_enabled = True - else: - print(usage()) - return False - # Return the args were sucessfully parsed - return self._sanity_check() - - def _sanity_check(self): - """Check to make sure there are no conflicting arguments and the - specified files exist. - - Returns: - False if there are conflicting arguments or a specified file does - not exist, True otherwise - """ - if self.single and self.list: - print("Cannot run both from config file and on a single file.") - return False - if self.list: - if not file_exists(self.config_file): - print("Configuration file does not exist at:", - self.config_file) - return False - elif self.single: - if not file_exists(self.single_file): - msg = "Image file does not exist at: " + self.single_file - return False - if (not self.single) and (not self.ignore) and (not self.list): - self.config_file = "config.xml" - if not file_exists(self.config_file): - msg = "Configuration file does not exist at: " + self.config_file - return False - - return True - -#### -# Helper Functions -#### -def search_logs(string, test_data): - """Search through all the known log files for a given string. - - Args: - string: the String to search for. - test_data: the TestData that holds the logs to search. - - Returns: - a listof_String, the lines that contained the given String. - """ - logs_path = test_data.logs_dir - results = [] - for file in os.listdir(logs_path): - log = codecs.open(make_path(logs_path, file), "r", "utf_8") - for line in log: - if string in line: - results.append(line) - log.close() - return results - -def search_log(log, string, test_data): - """Search the given log for any instances of a given string. - - Args: - log: a pathto_File, the log to search in - string: the String to search for. - test_data: the TestData that holds the log to search. - - Returns: - a listof_String, all the lines that the string is found on - """ - logs_path = make_path(test_data.logs_dir, log) - try: - results = [] - log = codecs.open(logs_path, "r", "utf_8") - for line in log: - if string in line: - results.append(line) - log.close() - if results: - return results - except: - raise FileNotFoundException(logs_path) - -# Search through all the the logs of the given type -# Types include autopsy, tika, and solr -def search_log_set(type, string, test_data): - """Search through all logs to the given type for the given string. - - Args: - type: the type of log to search in. - string: the String to search for. - test_data: the TestData containing the logs to search. - - Returns: - a listof_String, the lines on which the String was found. - """ - logs_path = test_data.logs_dir - results = [] - for file in os.listdir(logs_path): - if type in file: - log = codecs.open(make_path(logs_path, file), "r", "utf_8") - for line in log: - if string in line: - results.append(line) - log.close() - return results - - -def clear_dir(dir): - """Clears all files from a directory and remakes it. - - Args: - dir: a pathto_Dir, the directory to clear - """ - try: - if dir_exists(dir): - shutil.rmtree(dir) - os.makedirs(dir) - return True; - except OSError as e: - printerror(test_data,"Error: Cannot clear the given directory:") - printerror(test_data,dir + "\n") - print(str(e)) - return False; - -def del_dir(dir): - """Delete the given directory. - - Args: - dir: a pathto_Dir, the directory to delete - """ - try: - if dir_exists(dir): - shutil.rmtree(dir) - return True; - except: - printerror(test_data,"Error: Cannot delete the given directory:") - printerror(test_data,dir + "\n") - return False; - -def get_file_in_dir(dir, ext): - """Returns the first file in the given directory with the given extension. - - Args: - dir: a pathto_Dir, the directory to search - ext: a String, the extension to search for - - Returns: - pathto_File, the file that was found - """ - try: - for file in os.listdir(dir): - if file.endswith(ext): - return make_path(dir, file) - # If nothing has been found, raise an exception - raise FileNotFoundException(dir) - except: - raise DirNotFoundException(dir) - -def find_file_in_dir(dir, name, ext): - """Find the file with the given name in the given directory. - - Args: - dir: a pathto_Dir, the directory to search - name: a String, the basename of the file to search for - ext: a String, the extension of the file to search for - """ - try: - for file in os.listdir(dir): - if file.startswith(name): - if file.endswith(ext): - return make_path(dir, file) - raise FileNotFoundException(dir) - except: - raise DirNotFoundException(dir) - - -class OS: - LINUX, MAC, WIN, CYGWIN = range(4) - - -if __name__ == "__main__": - global SYS - if _platform == "linux" or _platform == "linux2": - SYS = OS.LINUX - elif _platform == "darwin": - SYS = OS.MAC - elif _platform == "win32": - SYS = OS.WIN - elif _platform == "cygwin": - SYS = OS.CYGWIN - - if SYS is OS.WIN or SYS is OS.CYGWIN: - main() - else: - print("We only support Windows and Cygwin at this time.") +#!/usr/bin/python +# -*- coding: utf_8 -*- + + # Autopsy Forensic Browser + # + # Copyright 2013 Basis Technology Corp. + # + # 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. +from tskdbdiff import TskDbDiff, TskDbDiffException +import codecs +import datetime +import logging +import os +import re +import shutil +import socket +import sqlite3 +import subprocess +import sys +from sys import platform as _platform +import time +import traceback +import xml +from time import localtime, strftime +from xml.dom.minidom import parse, parseString +import smtplib +from email.mime.image import MIMEImage +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText +import re +import zipfile +import zlib +import Emailer +import srcupdater +from regression_utils import * + +# +# Please read me... +# +# This is the regression testing Python script. +# It uses an ant command to run build.xml for RegressionTest.java +# +# The code is cleanly sectioned and commented. +# Please follow the current formatting. +# It is a long and potentially confusing script. +# +# Variable, function, and class names are written in Python conventions: +# this_is_a_variable this_is_a_function() ThisIsAClass +# +# + + +# Data Definitions: +# +# pathto_X: A path to type X. +# ConfigFile: An XML file formatted according to the template in myconfig.xml +# ParsedConfig: A dom object that represents a ConfigFile +# SQLCursor: A cursor recieved from a connection to an SQL database +# Nat: A Natural Number +# Image: An image +# + +# Enumeration of database types used for the simplification of generating database paths +DBType = enum('OUTPUT', 'GOLD', 'BACKUP') + +# Common filename of the output and gold databases (although they are in different directories +DB_FILENAME = "autopsy.db" + +# Backup database filename +BACKUP_DB_FILENAME = "autopsy_backup.db" + +# TODO: Double check this purpose statement +# Folder name for gold standard database testing +AUTOPSY_TEST_CASE = "AutopsyTestCase" + +# TODO: Double check this purpose statement +# The filename of the log to store error messages +COMMON_LOG = "AutopsyErrors.txt" + +Day = 0 + +#----------------------# +# Main # +#----------------------# +def main(): + """Parse the command-line arguments, create the configuration, and run the tests.""" + args = Args() + parse_result = args.parse() + test_config = TestConfiguration(args) + # The arguments were given wrong: + if not parse_result: + return + if(not args.fr): + antin = ["ant"] + antin.append("-f") + antin.append(os.path.join("..","..","build.xml")) + antin.append("test-download-imgs") + if SYS is OS.CYGWIN: + subprocess.call(antin) + elif SYS is OS.WIN: + theproc = subprocess.Popen(antin, shell = True, stdout=subprocess.PIPE) + theproc.communicate() + # Otherwise test away! + TestRunner.run_tests(test_config) + + +class TestRunner(object): + """A collection of functions to run the regression tests.""" + + def run_tests(test_config): + """Run the tests specified by the main TestConfiguration. + + Executes the AutopsyIngest for each image and dispatches the results based on + the mode (rebuild or testing) + """ + test_data_list = [ TestData(image, test_config) for image in test_config.images ] + + Reports.html_add_images(test_config.html_log, test_config.images) + + logres =[] + for test_data in test_data_list: + Errors.clear_print_logs() + Errors.set_testing_phase(test_data.image) + if not (test_config.args.rebuild or os.path.exists(test_data.gold_archive)): + msg = "Gold standard doesn't exist, skipping image:" + Errors.print_error(msg) + Errors.print_error(test_data.gold_archive) + continue + TestRunner._run_autopsy_ingest(test_data) + + if test_config.args.rebuild: + TestRunner.rebuild(test_data) + else: + logres.append(TestRunner._run_test(test_data)) + test_data.printout = Errors.printout + test_data.printerror = Errors.printerror + + Reports.write_html_foot(test_config.html_log) + # TODO: move this elsewhere + if (len(logres)>0): + for lm in logres: + for ln in lm: + Errors.add_email_msg(ln) + + # TODO: possibly worth putting this in a sub method + if all([ test_data.overall_passed for test_data in test_data_list ]): + Errors.add_email_msg("All images passed.\n") + else: + msg = "The following images failed:\n" + for test_data in test_data_list: + if not test_data.overall_passed: + msg += "\t" + test_data.image + "\n" + Errors.add_email_msg(msg) + html = open(test_config.html_log) + Errors.add_email_attachment(html.name) + html.close() + + if test_config.email_enabled: + Emailer.send_email(test_config.mail_to, test_config.mail_server, + test_config.mail_subject, Errors.email_body, Errors.email_attachs) + + def _run_autopsy_ingest(test_data): + """Run Autopsy ingest for the image in the given TestData. + + Also generates the necessary logs for rebuilding or diff. + + Args: + test_data: the TestData to run the ingest on. + """ + if image_type(test_data.image_file) == IMGTYPE.UNKNOWN: + Errors.print_error("Error: Image type is unrecognized:") + Errors.print_error(test_data.image_file + "\n") + return + + logging.debug("--------------------") + logging.debug(test_data.image_name) + logging.debug("--------------------") + TestRunner._run_ant(test_data) + time.sleep(2) # Give everything a second to process + + try: + # Dump the database before we diff or use it for rebuild + TskDbDiff.dump_output_db(test_data.get_db_path(DBType.OUTPUT), test_data.get_db_dump_path(DBType.OUTPUT), + test_data.get_sorted_data_path(DBType.OUTPUT)) + except sqlite3.OperationalError as e: + print("Ingest did not run properly.", + "Make sure no other instances of Autopsy are open and try again.") + sys.exit() + + # merges logs into a single log for later diff / rebuild + copy_logs(test_data) + Logs.generate_log_data(test_data) + + TestRunner._handle_solr(test_data) + TestRunner._handle_exception(test_data) + + #TODO: figure out return type of _run_test (logres) + def _run_test(test_data): + """Compare the results of the output to the gold standard. + + Args: + test_data: the TestData + + Returns: + logres? + """ + TestRunner._extract_gold(test_data) + + # Look for core exceptions + # @@@ Should be moved to TestResultsDiffer, but it didn't know about logres -- need to look into that + logres = Logs.search_common_log("TskCoreException", test_data) + + TestResultsDiffer.run_diff(test_data) + test_data.overall_passed = (test_data.html_report_passed and + test_data.errors_diff_passed and test_data.db_diff_passed) + + Reports.generate_reports(test_data) + if(not test_data.overall_passed): + Errors.add_email_attachment(test_data.common_log_path) + return logres + + def _extract_gold(test_data): + """Extract gold archive file to output/gold/tmp/ + + Args: + test_data: the TestData + """ + extrctr = zipfile.ZipFile(test_data.gold_archive, 'r', compression=zipfile.ZIP_DEFLATED) + extrctr.extractall(test_data.main_config.gold) + extrctr.close + time.sleep(2) + + def _handle_solr(test_data): + """Clean up SOLR index if in keep mode (-k). + + Args: + test_data: the TestData + """ + if not test_data.main_config.args.keep: + if clear_dir(test_data.solr_index): + print_report([], "DELETE SOLR INDEX", "Solr index deleted.") + else: + print_report([], "KEEP SOLR INDEX", "Solr index has been kept.") + + def _handle_exception(test_data): + """If running in exception mode, print exceptions to log. + + Args: + test_data: the TestData + """ + if test_data.main_config.args.exception: + exceptions = search_logs(test_data.main_config.args.exception_string, test_data) + okay = ("No warnings or exceptions found containing text '" + + test_data.main_config.args.exception_string + "'.") + print_report(exceptions, "EXCEPTION", okay) + + def rebuild(test_data): + """Rebuild the gold standard with the given TestData. + + Copies the test-generated database and html report files into the gold directory. + """ + test_config = test_data.main_config + # Errors to print + errors = [] + # Delete the current gold standards + gold_dir = test_config.img_gold + clear_dir(test_config.img_gold) + tmpdir = make_path(gold_dir, test_data.image_name) + dbinpth = test_data.get_db_path(DBType.OUTPUT) + dboutpth = make_path(tmpdir, DB_FILENAME) + dataoutpth = make_path(tmpdir, test_data.image_name + "SortedData.txt") + dbdumpinpth = test_data.get_db_dump_path(DBType.OUTPUT) + dbdumpoutpth = make_path(tmpdir, test_data.image_name + "DBDump.txt") + if not os.path.exists(test_config.img_gold): + os.makedirs(test_config.img_gold) + if not os.path.exists(tmpdir): + os.makedirs(tmpdir) + try: + shutil.copy(dbinpth, dboutpth) + if file_exists(test_data.get_sorted_data_path(DBType.OUTPUT)): + shutil.copy(test_data.get_sorted_data_path(DBType.OUTPUT), dataoutpth) + shutil.copy(dbdumpinpth, dbdumpoutpth) + error_pth = make_path(tmpdir, test_data.image_name+"SortedErrors.txt") + shutil.copy(test_data.sorted_log, error_pth) + except IOError as e: + Errors.print_error(str(e)) + Errors.add_email_message("Not rebuilt properly") + print(str(e)) + print(traceback.format_exc()) + # Rebuild the HTML report + output_html_report_dir = test_data.get_html_report_path(DBType.OUTPUT) + gold_html_report_dir = make_path(tmpdir, "Report") + + try: + shutil.copytree(output_html_report_dir, gold_html_report_dir) + except OSError as e: + errors.append(e.error()) + except Exception as e: + errors.append("Error: Unknown fatal error when rebuilding the gold html report.") + errors.append(str(e) + "\n") + print(traceback.format_exc()) + oldcwd = os.getcwd() + zpdir = gold_dir + os.chdir(zpdir) + os.chdir("..") + img_gold = "tmp" + img_archive = make_path(test_data.image_name+"-archive.zip") + comprssr = zipfile.ZipFile(img_archive, 'w',compression=zipfile.ZIP_DEFLATED) + TestRunner.zipdir(img_gold, comprssr) + comprssr.close() + os.chdir(oldcwd) + del_dir(test_config.img_gold) + okay = "Sucessfully rebuilt all gold standards." + print_report(errors, "REBUILDING", okay) + + def zipdir(path, zip): + for root, dirs, files in os.walk(path): + for file in files: + zip.write(os.path.join(root, file)) + + def _run_ant(test_data): + """Construct and run the ant build command for the given TestData. + + Tests Autopsy by calling RegressionTest.java via the ant build file. + + Args: + test_data: the TestData + """ + test_config = test_data.main_config + # Set up the directories + if dir_exists(test_data.output_path): + shutil.rmtree(test_data.output_path) + os.makedirs(test_data.output_path) + test_data.ant = ["ant"] + test_data.ant.append("-v") + test_data.ant.append("-f") + # case.ant.append(case.build_path) + test_data.ant.append(os.path.join("..","..","Testing","build.xml")) + test_data.ant.append("regression-test") + test_data.ant.append("-l") + test_data.ant.append(test_data.antlog_dir) + test_data.ant.append("-Dimg_path=" + test_data.image_file) + test_data.ant.append("-Dknown_bad_path=" + test_config.known_bad_path) + test_data.ant.append("-Dkeyword_path=" + test_config.keyword_path) + test_data.ant.append("-Dnsrl_path=" + test_config.nsrl_path) + test_data.ant.append("-Dgold_path=" + test_config.gold) + test_data.ant.append("-Dout_path=" + + make_local_path(test_data.output_path)) + test_data.ant.append("-Dignore_unalloc=" + "%s" % test_config.args.unallocated) + test_data.ant.append("-Dtest.timeout=" + str(test_config.timeout)) + + Errors.print_out("Ingesting Image:\n" + test_data.image_file + "\n") + Errors.print_out("CMD: " + " ".join(test_data.ant)) + Errors.print_out("Starting test...\n") + antoutpth = make_local_path(test_data.main_config.output_dir, "antRunOutput.txt") + antout = open(antoutpth, "a") + if SYS is OS.CYGWIN: + subprocess.call(test_data.ant, stdout=subprocess.PIPE) + elif SYS is OS.WIN: + theproc = subprocess.Popen(test_data.ant, shell = True, stdout=subprocess.PIPE) + theproc.communicate() + antout.close() + + +class TestData(object): + """Container for the input and output of a single image. + + Represents data for the test of a single image, including path to the image, + database paths, etc. + + Attributes: + main_config: the global TestConfiguration + ant: a listof_String, the ant command for this TestData + image_file: a pathto_Image, the image for this TestData + image: a String, the image file's name + image_name: a String, the image file's name with a trailing (0) + output_path: pathto_Dir, the output directory for this TestData + autopsy_data_file: a pathto_File, the IMAGE_NAMEAutopsy_data.txt file + warning_log: a pathto_File, the AutopsyLogs.txt file + antlog_dir: a pathto_File, the antlog.txt file + test_dbdump: a pathto_File, the database dump, IMAGENAMEDump.txt + common_log_path: a pathto_File, the IMAGE_NAMECOMMON_LOG file + sorted_log: a pathto_File, the IMAGENAMESortedErrors.txt file + reports_dir: a pathto_Dir, the AutopsyTestCase/Reports folder + gold_data_dir: a pathto_Dir, the gold standard directory + gold_archive: a pathto_File, the gold standard archive + logs_dir: a pathto_Dir, the location where autopsy logs are stored + solr_index: a pathto_Dir, the locatino of the solr index + html_report_passed: a boolean, did the HTML report diff pass? + errors_diff_passed: a boolean, did the error diff pass? + db_diff_passed: a boolean, did the db diff pass? + overall_passed: a boolean, did the test pass? + total_test_time: a String representation of the test duration + start_date: a String representation of this TestData's start date + end_date: a String representation of the TestData's end date + total_ingest_time: a String representation of the total ingest time + artifact_count: a Nat, the number of artifacts + artifact_fail: a Nat, the number of artifact failures + heap_space: a String representation of TODO + service_times: a String representation of TODO + autopsy_version: a String, the version of autopsy that was run + ingest_messages: a Nat, the number of ingest messages + indexed_files: a Nat, the number of files indexed during the ingest + indexed_chunks: a Nat, the number of chunks indexed during the ingest + printerror: a listof_String, the error messages printed during this TestData's test + printout: a listof_String, the messages pritned during this TestData's test + """ + + def __init__(self, image, main_config): + """Init this TestData with it's image and the test configuration. + + Args: + image: the Image to be tested. + main_config: the global TestConfiguration. + """ + # Configuration Data + self.main_config = main_config + self.ant = [] + self.image_file = str(image) + # TODO: This 0 should be be refactored out, but it will require rebuilding and changing of outputs. + self.image = get_image_name(self.image_file) + self.image_name = self.image + "(0)" + # Directory structure and files + self.output_path = make_path(self.main_config.output_dir, self.image_name) + self.autopsy_data_file = make_path(self.output_path, self.image_name + "Autopsy_data.txt") + self.warning_log = make_local_path(self.output_path, "AutopsyLogs.txt") + self.antlog_dir = make_local_path(self.output_path, "antlog.txt") + self.test_dbdump = make_path(self.output_path, self.image_name + + "DBDump.txt") + self.common_log_path = make_local_path(self.output_path, self.image_name + COMMON_LOG) + self.sorted_log = make_local_path(self.output_path, self.image_name + "SortedErrors.txt") + self.reports_dir = make_path(self.output_path, AUTOPSY_TEST_CASE, "Reports") + self.gold_data_dir = make_path(self.main_config.img_gold, self.image_name) + self.gold_archive = make_path(self.main_config.gold, + self.image_name + "-archive.zip") + self.logs_dir = make_path(self.output_path, "logs") + self.solr_index = make_path(self.output_path, AUTOPSY_TEST_CASE, + "ModuleOutput", "KeywordSearch") + # Results and Info + self.html_report_passed = False + self.errors_diff_passed = False + self.db_diff_passed = False + self.overall_passed = False + # Ingest info + self.total_test_time = "" + self.start_date = "" + self.end_date = "" + self.total_ingest_time = "" + self.artifact_count = 0 + self.artifact_fail = 0 + self.heap_space = "" + self.service_times = "" + self.autopsy_version = "" + self.ingest_messages = 0 + self.indexed_files = 0 + self.indexed_chunks = 0 + # Error tracking + self.printerror = [] + self.printout = [] + + def ant_to_string(self): + string = "" + for arg in self.ant: + string += (arg + " ") + return string + + def get_db_path(self, db_type): + """Get the path to the database file that corresponds to the given DBType. + + Args: + DBType: the DBType of the path to be generated. + """ + if(db_type == DBType.GOLD): + db_path = make_path(self.gold_data_dir, DB_FILENAME) + elif(db_type == DBType.OUTPUT): + db_path = make_path(self.main_config.output_dir, self.image_name, AUTOPSY_TEST_CASE, DB_FILENAME) + else: + db_path = make_path(self.main_config.output_dir, self.image_name, AUTOPSY_TEST_CASE, BACKUP_DB_FILENAME) + return db_path + + def get_html_report_path(self, html_type): + """Get the path to the HTML Report folder that corresponds to the given DBType. + + Args: + DBType: the DBType of the path to be generated. + """ + if(html_type == DBType.GOLD): + return make_path(self.gold_data_dir, "Report") + else: + # Autopsy creates an HTML report folder in the form AutopsyTestCase DATE-TIME + # It's impossible to get the exact time the folder was created, but the folder + # we are looking for is the only one in the self.reports_dir folder + html_path = "" + for fs in os.listdir(self.reports_dir): + html_path = make_path(self.reports_dir, fs) + if os.path.isdir(html_path): + break + return make_path(html_path, os.listdir(html_path)[0]) + + def get_sorted_data_path(self, file_type): + """Get the path to the SortedData file that corresponds to the given DBType. + + Args: + file_type: the DBType of the path to be generated + """ + return self._get_path_to_file(file_type, "SortedData.txt") + + def get_sorted_errors_path(self, file_type): + """Get the path to the SortedErrors file that correspodns to the given + DBType. + + Args: + file_type: the DBType of the path to be generated + """ + return self._get_path_to_file(file_type, "SortedErrors.txt") + + def get_db_dump_path(self, file_type): + """Get the path to the DBDump file that corresponds to the given DBType. + + Args: + file_type: the DBType of the path to be generated + """ + return self._get_path_to_file(file_type, "DBDump.txt") + + def _get_path_to_file(self, file_type, file_name): + """Get the path to the specified file with the specified type. + + Args: + file_type: the DBType of the path to be generated + file_name: a String, the filename of the path to be generated + """ + full_filename = self.image_name + file_name + if(file_type == DBType.GOLD): + return make_path(self.gold_data_dir, full_filename) + else: + return make_path(self.output_path, full_filename) + + +class TestConfiguration(object): + """Container for test configuration data. + + The Master Test Configuration. Encapsulates consolidated high level input from + config XML file and command-line arguments. + + Attributes: + args: an Args, the command line arguments + output_dir: a pathto_Dir, the output directory + input_dir: a pathto_Dir, the input directory + gold: a pathto_Dir, the gold directory + img_gold: a pathto_Dir, the temp directory where gold images are unzipped to + csv: a pathto_File, the local csv file + global_csv: a pathto_File, the global csv file + html_log: a pathto_File + known_bad_path: + keyword_path: + nsrl_path: + build_path: a pathto_File, the ant build file which runs the tests + autopsy_version: + ingest_messages: a Nat, number of ingest messages + indexed_files: a Nat, the number of indexed files + indexed_chunks: a Nat, the number of indexed chunks + timer: + images: a listof_Image, the images to be tested + timeout: a Nat, the amount of time before killing the test + ant: a listof_String, the ant command to run the tests + """ + + def __init__(self, args): + """Inits TestConfiguration and loads a config file if available. + + Args: + args: an Args, the command line arguments. + """ + self.args = args + # Paths: + self.output_dir = "" + self.input_dir = make_local_path("..","input") + self.gold = make_path("..", "output", "gold") + self.img_gold = make_path(self.gold, 'tmp') + # Logs: + self.csv = "" + self.global_csv = "" + self.html_log = "" + # Ant info: + self.known_bad_path = make_path(self.input_dir, "notablehashes.txt-md5.idx") + self.keyword_path = make_path(self.input_dir, "notablekeywords.xml") + self.nsrl_path = make_path(self.input_dir, "nsrl.txt-md5.idx") + self.build_path = make_path("..", "build.xml") + # Infinite Testing info + timer = 0 + self.images = [] + # Email info + self.email_enabled = args.email_enabled + self.mail_server = "" + self.mail_to = "" + self.mail_subject = "" + # Set the timeout to something huge + # The entire tester should not timeout before this number in ms + # However it only seems to take about half this time + # And it's very buggy, so we're being careful + self.timeout = 24 * 60 * 60 * 1000 * 1000 + + if not self.args.single: + self._load_config_file(self.args.config_file) + else: + self.images.append(self.args.single_file) + self._init_logs() + #self._init_imgs() + #self._init_build_info() + + + def _load_config_file(self, config_file): + """Updates this TestConfiguration's attributes from the config file. + + Initializes this TestConfiguration by iterating through the XML config file + command-line argument. Populates self.images and optional email configuration + + Args: + config_file: ConfigFile - the configuration file to load + """ + try: + count = 0 + parsed_config = parse(config_file) + logres = [] + counts = {} + if parsed_config.getElementsByTagName("indir"): + self.input_dir = parsed_config.getElementsByTagName("indir")[0].getAttribute("value").encode().decode("utf_8") + if parsed_config.getElementsByTagName("global_csv"): + self.global_csv = parsed_config.getElementsByTagName("global_csv")[0].getAttribute("value").encode().decode("utf_8") + self.global_csv = make_local_path(self.global_csv) + if parsed_config.getElementsByTagName("golddir"): + self.gold = parsed_config.getElementsByTagName("golddir")[0].getAttribute("value").encode().decode("utf_8") + self.img_gold = make_path(self.gold, 'tmp') + + self._init_imgs(parsed_config) + self._init_build_info(parsed_config) + self._init_email_info(parsed_config) + + except IOError as e: + msg = "There was an error loading the configuration file.\n" + msg += "\t" + str(e) + Errors.add_email_msg(msg) + logging.critical(traceback.format_exc()) + print(traceback.format_exc()) + + def _init_logs(self): + """Setup output folder, logs, and reporting infrastructure.""" + if(not dir_exists(make_path("..", "output", "results"))): + os.makedirs(make_path("..", "output", "results",)) + self.output_dir = make_path("..", "output", "results", time.strftime("%Y.%m.%d-%H.%M.%S")) + os.makedirs(self.output_dir) + self.csv = make_local_path(self.output_dir, "CSV.txt") + self.html_log = make_path(self.output_dir, "AutopsyTestCase.html") + log_name = self.output_dir + "\\regression.log" + logging.basicConfig(filename=log_name, level=logging.DEBUG) + + def _init_build_info(self, parsed_config): + """Initializes paths that point to information necessary to run the AutopsyIngest.""" + build_elements = parsed_config.getElementsByTagName("build") + if build_elements: + build_element = build_elements[0] + build_path = build_element.getAttribute("value").encode().decode("utf_8") + self.build_path = build_path + + def _init_imgs(self, parsed_config): + """Initialize the list of images to run tests on.""" + for element in parsed_config.getElementsByTagName("image"): + value = element.getAttribute("value").encode().decode("utf_8") + print ("Image in Config File: " + value) + if file_exists(value): + self.images.append(value) + else: + msg = "File: " + value + " doesn't exist" + Errors.print_error(msg) + Errors.add_email_msg(msg) + image_count = len(self.images) + + # Sanity check to see if there are obvious gold images that we are not testing + gold_count = 0 + for file in os.listdir(self.gold): + if not(file == 'tmp'): + gold_count+=1 + + if (image_count > gold_count): + print("******Alert: There are more input images than gold standards, some images will not be properly tested.\n") + elif (image_count < gold_count): + print("******Alert: There are more gold standards than input images, this will not check all gold Standards.\n") + + def _init_email_info(self, parsed_config): + """Initializes email information dictionary""" + email_elements = parsed_config.getElementsByTagName("email") + if email_elements: + mail_to = email_elements[0] + self.mail_to = mail_to.getAttribute("value").encode().decode("utf_8") + mail_server_elements = parsed_config.getElementsByTagName("mail_server") + if mail_server_elements: + mail_from = mail_server_elements[0] + self.mail_server = mail_from.getAttribute("value").encode().decode("utf_8") + subject_elements = parsed_config.getElementsByTagName("subject") + if subject_elements: + subject = subject_elements[0] + self.mail_subject = subject.getAttribute("value").encode().decode("utf_8") + if self.mail_server and self.mail_to and self.args.email_enabled: + self.email_enabled = True + print("Email will be sent to ", self.mail_to) + else: + print("No email will be sent.") + + +#-------------------------------------------------# +# Functions relating to comparing outputs # +#-------------------------------------------------# +class TestResultsDiffer(object): + """Compares results for a single test.""" + + def run_diff(test_data): + """Compares results for a single test. + + Args: + test_data: the TestData to use. + databaseDiff: TskDbDiff object created based off test_data + """ + try: + output_db = test_data.get_db_path(DBType.OUTPUT) + gold_db = test_data.get_db_path(DBType.GOLD) + output_dir = test_data.output_path + gold_bb_dump = test_data.get_sorted_data_path(DBType.GOLD) + gold_dump = test_data.get_db_dump_path(DBType.GOLD) + test_data.db_diff_pass = all(TskDbDiff(output_db, gold_db, output_dir=output_dir, gold_bb_dump=gold_bb_dump, + gold_dump=gold_dump).run_diff()) + + # Compare Exceptions + # replace is a fucntion that replaces strings of digits with 'd' + # this is needed so dates and times will not cause the diff to fail + replace = lambda file: re.sub(re.compile("\d"), "d", file) + output_errors = test_data.get_sorted_errors_path(DBType.OUTPUT) + gold_errors = test_data.get_sorted_errors_path(DBType.GOLD) + passed = TestResultsDiffer._compare_text(output_errors, gold_errors, + replace) + test_data.errors_diff_passed = passed + + # Compare html output + gold_report_path = test_data.get_html_report_path(DBType.GOLD) + output_report_path = test_data.get_html_report_path(DBType.OUTPUT) + passed = TestResultsDiffer._html_report_diff(gold_report_path, + output_report_path) + test_data.html_report_passed = passed + + # Clean up tmp folder + del_dir(test_data.gold_data_dir) + + except sqlite3.OperationalError as e: + Errors.print_error("Tests failed while running the diff:\n") + Errors.print_error(str(e)) + except TskDbDiffException as e: + Errors.print_error(str(e)) + except Exception as e: + Errors.print_error("Tests failed due to an error, try rebuilding or creating gold standards.\n") + Errors.print_error(str(e) + "\n") + print(traceback.format_exc()) + + def _compare_text(output_file, gold_file, process=None): + """Compare two text files. + + Args: + output_file: a pathto_File, the output text file + gold_file: a pathto_File, the input text file + pre-process: (optional) a function of String -> String that will be + called on each input file before the diff, if specified. + """ + if(not file_exists(output_file)): + return False + output_data = codecs.open(output_file, "r", "utf_8").read() + gold_data = codecs.open(gold_file, "r", "utf_8").read() + + if process is not None: + output_data = process(output_data) + gold_data = process(gold_data) + + if (not(gold_data == output_data)): + diff_path = os.path.splitext(os.path.basename(output_file))[0] + diff_path += "-Diff.txt" + diff_file = codecs.open(diff_path, "wb", "utf_8") + dffcmdlst = ["diff", output_file, gold_file] + subprocess.call(dffcmdlst, stdout = diff_file) + Errors.add_email_attachment(diff_path) + msg = "There was a difference in " + msg += os.path.basename(output_file) + ".\n" + Errors.add_email_msg(msg) + Errors.print_error(msg) + return False + else: + return True + + def _html_report_diff(gold_report_path, output_report_path): + """Compare the output and gold html reports. + + Args: + gold_report_path: a pathto_Dir, the gold HTML report directory + output_report_path: a pathto_Dir, the output HTML report directory + + Returns: + true, if the reports match, false otherwise. + """ + try: + gold_html_files = get_files_by_ext(gold_report_path, ".html") + output_html_files = get_files_by_ext(output_report_path, ".html") + + #ensure both reports have the same number of files and are in the same order + if(len(gold_html_files) != len(output_html_files)): + msg = "The reports did not have the same number or files." + msg += "One of the reports may have been corrupted." + Errors.print_error(msg) + else: + gold_html_files.sort() + output_html_files.sort() + + total = {"Gold": 0, "New": 0} + for gold, output in zip(gold_html_files, output_html_files): + count = TestResultsDiffer._compare_report_files(gold, output) + total["Gold"] += count[0] + total["New"] += count[1] + + okay = "The test report matches the gold report." + errors=["Gold report had " + str(total["Gold"]) +" errors", "New report had " + str(total["New"]) + " errors."] + print_report(errors, "REPORT COMPARISON", okay) + + if total["Gold"] == total["New"]: + return True + else: + Errors.print_error("The reports did not match each other.\n " + errors[0] +" and the " + errors[1]) + return False + except OSError as e: + e.print_error() + return False + except Exception as e: + Errors.print_error("Error: Unknown fatal error comparing reports.") + Errors.print_error(str(e) + "\n") + logging.critical(traceback.format_exc()) + return False + + def _compare_report_files(a_path, b_path): + """Compares the two specified report html files. + + Args: + a_path: a pathto_File, the first html report file + b_path: a pathto_File, the second html report file + + Returns: + a tuple of (Nat, Nat), which represent the length of each + unordered list in the html report files, or (0, 0) if the + lenghts are the same. + """ + a_file = open(a_path) + b_file = open(b_path) + a = a_file.read() + b = b_file.read() + a = a[a.find("